From f3ec015a6d2f23aa4ad9550498c76c991d742fa9 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 9 Oct 2023 13:14:47 +0200 Subject: [PATCH 001/158] update github workflow to include prod testing 9might be inn the wrong workflow) --- .github/workflows/main.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3a47ad1bb..bdba18c3e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -75,6 +75,11 @@ jobs: yarn e2e ./gradlew --stop + - name: End to end tests (production) + id: e2e-prod + run: | + src/test/bash/run-prod-e2e.sh + - name: Upload screenshots of failed e2e tests if: always() uses: actions/upload-artifact@v3 From 24dc91998f6bc1e617ea8cf5e93d25075ad4ff30 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 9 Oct 2023 13:42:28 +0200 Subject: [PATCH 002/158] insert the e2e-prod script into the github workflow as that is what we do with the other tasks --- .github/workflows/main.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bdba18c3e..a62c7eada 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -78,7 +78,13 @@ jobs: - name: End to end tests (production) id: e2e-prod run: | - src/test/bash/run-prod-e2e.sh + cp src/test/resources/config/keystore.p12 src/main/docker/etc/config + sed -i "s|contexts: prod|contexts: dev|" src/main/resources/config/application-prod.yml + ./gradlew -Pprod buildDocker -x test -x javadocJar + git checkout src/main/resources/config/application-prod.yml + docker-compose -f src/main/docker/app.yml up -d + yarn run e2e-prod + docker-compose -f src/main/docker/app.yml down -v - name: Upload screenshots of failed e2e tests if: always() From 68fc25aa6b9f4e1af1e9dc5e1ae78758d80395e4 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 9 Oct 2023 13:46:54 +0200 Subject: [PATCH 003/158] let it run on the ci for now --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a62c7eada..985e7891b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,7 +4,7 @@ name: Main # Run in master and dev branches and in all pull requests to those branches on: push: - branches: [ master, dev ] + branches: [ master, dev, 732-append-managementportal-to-baseurl ] pull_request: {} env: From f97b720f499ff5c6fef969b1ebcd9e5b6c280b06 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 9 Oct 2023 17:37:00 +0200 Subject: [PATCH 004/158] baseurl for cypress should match the ALDS --- cypress.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cypress.json b/cypress.json index 599ab3a69..b241d68f3 100644 --- a/cypress.json +++ b/cypress.json @@ -7,5 +7,5 @@ "screenshotsFolder": "src/test/javascript/e2e/cypress/screenshots", "pluginsFile": false, "fixturesFolder": false, - "baseUrl": "http://localhost:9000" + "baseUrl": "http://localhost:8081" } From 448bfbafd6cb64c5e7d303bf290d541efac900fd Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 9 Oct 2023 17:37:44 +0200 Subject: [PATCH 005/158] shutdown the docker containers, it feels like there are some persistent operations being done --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 985e7891b..fcafd0089 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -82,6 +82,7 @@ jobs: sed -i "s|contexts: prod|contexts: dev|" src/main/resources/config/application-prod.yml ./gradlew -Pprod buildDocker -x test -x javadocJar git checkout src/main/resources/config/application-prod.yml + docker-compose -f src/main/docker/app.yml down docker-compose -f src/main/docker/app.yml up -d yarn run e2e-prod docker-compose -f src/main/docker/app.yml down -v From 1e2e7ff1b6c647598f9aa0e5565bdd7c2a56e04d Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 9 Oct 2023 17:45:59 +0200 Subject: [PATCH 006/158] or de we just need to force click? --- .github/workflows/main.yml | 1 - .../e2e/cypress/integration/entities/permission.spec.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fcafd0089..985e7891b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -82,7 +82,6 @@ jobs: sed -i "s|contexts: prod|contexts: dev|" src/main/resources/config/application-prod.yml ./gradlew -Pprod buildDocker -x test -x javadocJar git checkout src/main/resources/config/application-prod.yml - docker-compose -f src/main/docker/app.yml down docker-compose -f src/main/docker/app.yml up -d yarn run e2e-prod docker-compose -f src/main/docker/app.yml down -v diff --git a/src/test/javascript/e2e/cypress/integration/entities/permission.spec.ts b/src/test/javascript/e2e/cypress/integration/entities/permission.spec.ts index 8bac2ea36..82cd18654 100644 --- a/src/test/javascript/e2e/cypress/integration/entities/permission.spec.ts +++ b/src/test/javascript/e2e/cypress/integration/entities/permission.spec.ts @@ -20,7 +20,7 @@ describe('Organization Permissions e2e test', () => { }) it('should remove user with role organization admin', () => { - cy.get('jhi-permissions button.fa-remove').eq(1).click(); + cy.get('jhi-permissions button.fa-remove').eq(1).click({force: true}); cy.get('jhi-permissions tbody tr').should('have.length', 2); }) From fa613511563757119daa384e7e160558e41856e9 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 9 Oct 2023 18:11:16 +0200 Subject: [PATCH 007/158] or both? --- .../e2e/cypress/integration/entities/permission.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/javascript/e2e/cypress/integration/entities/permission.spec.ts b/src/test/javascript/e2e/cypress/integration/entities/permission.spec.ts index 82cd18654..8bac2ea36 100644 --- a/src/test/javascript/e2e/cypress/integration/entities/permission.spec.ts +++ b/src/test/javascript/e2e/cypress/integration/entities/permission.spec.ts @@ -20,7 +20,7 @@ describe('Organization Permissions e2e test', () => { }) it('should remove user with role organization admin', () => { - cy.get('jhi-permissions button.fa-remove').eq(1).click({force: true}); + cy.get('jhi-permissions button.fa-remove').eq(1).click(); cy.get('jhi-permissions tbody tr').should('have.length', 2); }) From 2460903f666649fb672ab071efb672e0a9481c4f Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 9 Oct 2023 18:26:15 +0200 Subject: [PATCH 008/158] or both? --- .github/workflows/main.yml | 1 + src/main/resources/config/application-prod.yml | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 985e7891b..fcafd0089 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -82,6 +82,7 @@ jobs: sed -i "s|contexts: prod|contexts: dev|" src/main/resources/config/application-prod.yml ./gradlew -Pprod buildDocker -x test -x javadocJar git checkout src/main/resources/config/application-prod.yml + docker-compose -f src/main/docker/app.yml down docker-compose -f src/main/docker/app.yml up -d yarn run e2e-prod docker-compose -f src/main/docker/app.yml down -v diff --git a/src/main/resources/config/application-prod.yml b/src/main/resources/config/application-prod.yml index a97e9e277..895b3f87f 100644 --- a/src/main/resources/config/application-prod.yml +++ b/src/main/resources/config/application-prod.yml @@ -23,8 +23,8 @@ spring: driverClassName: org.postgresql.Driver url: jdbc:postgresql://localhost:5432/managementportal # name: managementportal - username: - password: + username: radarbase + password: radarbase # hikari: # data-source-properties: # cachePrepStmts: true @@ -54,7 +54,7 @@ spring: thymeleaf: cache: true liquibase: - contexts: prod + contexts: dev # =================================================================== # To enable SSL, generate a certificate using: From 836c19d33603481163907ef20ee216e2bed05b96 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 10 Oct 2023 10:49:18 +0200 Subject: [PATCH 009/158] no more alternate docker command needed for windows --- gradle/docker.gradle | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/gradle/docker.gradle b/gradle/docker.gradle index eefab18cf..ce52a366f 100644 --- a/gradle/docker.gradle +++ b/gradle/docker.gradle @@ -12,9 +12,5 @@ task buildDocker(type: Exec, dependsOn: bootWar) { include "*.war*" } } - if (OperatingSystem.current().isWindows()) { - commandLine 'cmd', '/c', 'docker', 'image', 'build', '-f', 'build/docker/Dockerfile', '-t', 'managementportal', 'build/docker/' - } else { - commandLine 'docker', 'image', 'build', '-f', 'build/docker/Dockerfile', '-t', 'managementportal', 'build/docker/' - } + commandLine 'docker', 'image', 'build', '-f', 'build/docker/Dockerfile', '-t', 'managementportal', 'build/docker/' } From b2a15493435509e4abb92f968e52a14b53de55a7 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 10 Oct 2023 11:17:42 +0200 Subject: [PATCH 010/158] apply dev context from the app.yml docker config. This removes the need for some setup during the job --- .github/workflows/main.yml | 3 --- src/main/docker/app.yml | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fcafd0089..df7ab270d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -79,10 +79,7 @@ jobs: id: e2e-prod run: | cp src/test/resources/config/keystore.p12 src/main/docker/etc/config - sed -i "s|contexts: prod|contexts: dev|" src/main/resources/config/application-prod.yml ./gradlew -Pprod buildDocker -x test -x javadocJar - git checkout src/main/resources/config/application-prod.yml - docker-compose -f src/main/docker/app.yml down docker-compose -f src/main/docker/app.yml up -d yarn run e2e-prod docker-compose -f src/main/docker/app.yml down -v diff --git a/src/main/docker/app.yml b/src/main/docker/app.yml index 902e30f3b..45b6da05b 100644 --- a/src/main/docker/app.yml +++ b/src/main/docker/app.yml @@ -7,6 +7,7 @@ services: - SPRING_DATASOURCE_URL=jdbc:postgresql://managementportal-postgresql:5432/managementportal - SPRING_DATASOURCE_USERNAME=radarbase - SPRING_DATASOURCE_PASSWORD=radarbase + - SPRING_LIQUIBASE_CONTEXTS=dev #includes testing_data, remove for production builds - MANAGEMENTPORTAL_FRONTEND_CLIENT_SECRET=secret - JHIPSTER_SLEEP=10 # gives time for the database to boot before the application - JAVA_OPTS=-Xmx512m # maximum heap size for the JVM running ManagementPortal, increase this as necessary From f1c2787cc351797d0f16acb1691ea9232d873060 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 10 Oct 2023 12:24:55 +0200 Subject: [PATCH 011/158] The test prod task fails when ran as a docker image, but pass when ran as a local build. --- .github/workflows/main.yml | 8 +++++++ .../config/application-e2e-prod-test.yml | 23 +++++++++++++++++++ .../resources/config/application-prod.yml | 14 +++++------ src/main/resources/config/application.yml | 3 +++ 4 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/config/application-e2e-prod-test.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index df7ab270d..edd2e495d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -75,6 +75,14 @@ jobs: yarn e2e ./gradlew --stop + - name: End to end tests (production build) + id: e2e-prod + run: | + docker-compose -f src/main/docker/postgresql.yml up -d + ./gradlew bootRun &>mp.log Date: Tue, 10 Oct 2023 12:59:41 +0200 Subject: [PATCH 012/158] The test prod task fails when ran as a docker image, but pass when ran as a local build. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index edd2e495d..4598f78fb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -84,7 +84,7 @@ jobs: docker-compose -f src/main/docker/postgresql.yml down -v - name: End to end tests (production) - id: e2e-prod + id: e2e-prod-docker run: | cp src/test/resources/config/keystore.p12 src/main/docker/etc/config ./gradlew -Pprod buildDocker -x test -x javadocJar From 8ec99b1f96e65abc00060e04d1031ac04728cf59 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 10 Oct 2023 14:15:24 +0200 Subject: [PATCH 013/158] remove some configurations that are already inherited from the default configs --- angular.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/angular.json b/angular.json index f257e60aa..8821b8e71 100644 --- a/angular.json +++ b/angular.json @@ -136,9 +136,7 @@ }, "configurations": { "production": { - "devServerTarget": "management-portal:serve:production", - "watch": false, - "headless": true + "devServerTarget": "management-portal:serve:production" } } } From c1dfac79c0f0ed2860ef90d1806d3b93dfdd6e1d Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 10 Oct 2023 14:19:20 +0200 Subject: [PATCH 014/158] prod docker image testing is a stub in the docker CI task production testing only runs on pre-release --- .github/workflows/main.yml | 27 ++++++++++----------------- .github/workflows/pre-release.yml | 10 ++++------ 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4598f78fb..b772a92ae 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -75,23 +75,6 @@ jobs: yarn e2e ./gradlew --stop - - name: End to end tests (production build) - id: e2e-prod - run: | - docker-compose -f src/main/docker/postgresql.yml up -d - ./gradlew bootRun &>mp.log mp.log Date: Tue, 10 Oct 2023 14:20:34 +0200 Subject: [PATCH 015/158] Change the run-prod-e2e.sh script to reflect the new changes. This script is unused in the repository and an untested copy of the github task in pre-release.yml. --- src/test/bash/run-prod-e2e.sh | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/test/bash/run-prod-e2e.sh b/src/test/bash/run-prod-e2e.sh index 06bbf1bd9..53f002c3c 100755 --- a/src/test/bash/run-prod-e2e.sh +++ b/src/test/bash/run-prod-e2e.sh @@ -1,38 +1,22 @@ #!/bin/bash -# For testing production mode e2e tests we need some tweaks: -# 1) The angular app needs to run in dev mode for protractor to work -# 2) We update the basehref of the angular app to the context path of the backend -# 3) We update the protractor configuration to the new path -# -# Then we start up a docker stack with a postgres server since production mode is configured for a +# For testing production mode e2e tests we start up a docker postgres server since production mode is configured for a # postgres database instead of in-memory database. set -e - -# only run on the release branch and master branch if it's not a tag build echo "Running production e2e tests" cp src/test/resources/config/keystore.p12 src/main/docker/etc/config cp src/test/resources/config/keystore.p12 src/main/resources/config -# set liquibase context to dev so it loads demo data -sed -i "s|contexts: prod|contexts: dev|" src/main/resources/config/application-prod.yml -./gradlew -Pprod buildDocker -x test -x javadocJar -# recover the prod liquibase context -git checkout src/main/resources/config/application-prod.yml - -docker-compose -f src/main/docker/app.yml up -d # spin up production mode application +./gradlew bootrun -Pe2e-prod-test -x test -x javadocJar & +docker-compose -f src/main/docker/postgresql.yml up -d # spin up production mode application set +e -# wait for app to be up -yarn run wait-for-managementportal -# run e2e tests against production mode -if ./gradlew generateOpenApiSpec && yarn run e2e; then +if ./gradlew generateOpenApiSpec && yarn run e2e-prod; then EXIT_STATUS=0 else EXIT_STATUS=1 fi -docker-compose -f src/main/docker/app.yml logs # show output of app startup -docker-compose -f src/main/docker/app.yml down -v # clean up containers and volumes +docker-compose -f src/main/docker/postgresql.yml down -v # clean up containers and volumes exit $EXIT_STATUS From 5c6f52b11d14d6ff0e3e5081cc159dda1a0c6cec Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 10 Oct 2023 14:35:47 +0200 Subject: [PATCH 016/158] minor updates to the README to reflect the new situation --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 74c1c8250..ee9c92467 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Management Portal is an application which is used to manage clinical studies for - [Testing](#testing) * [Client tests](#client-tests) * [Other tests](#other-tests) -- [Using Docker to simplify development (optional)](#using-docker-to-simplify-development--optional-) +- [Using Docker to simplify development (optional)](#using-docker-to-simplify-development-optional) - [Documentation](#documentation) - [Client libraries](#client-libraries) @@ -49,7 +49,7 @@ docker-compose files. 3. Now, we can start the stack with `docker-compose -f src/main/docker/management-portal.yml up -d`. This will start a Postgres database and ManagementPortal. The default password for the `admin` -account is `admin`. +account is `admin`. An angular live development server to access the managementportal can be started using the `yarn start` command (see [Development](#development)). ### Build from source @@ -68,7 +68,7 @@ You must install and configure the following dependencies on your machine to run main differences between the profiles. Configure the application using the property file at `src/main/resources/config/application-.yml`.Read more about configurations [here](#configuration) 5. Run ManagementPortal by running `./gradlew bootRun -Pprod` or `./gradlew bootRun -Pdev`. Development mode will start an in -memory database and ManagementPortal. +memory database and ManagementPortal. An angular live development server to access the managementportal can be started using the `yarn start` command (see [Development](#development)). 6. You can log in to the application using `admin:admin`. Please don't forgot to change the password of `admin`, if you are using the application on production environment. @@ -76,7 +76,6 @@ memory database and ManagementPortal. |----------------------------------|-----------------|-----------------------------------| | Database type | In-memory | Postgres | | Demo data loaded | Yes | No | -| Context path of the application | `/` | `/managementportal` | @@ -249,6 +248,8 @@ auto-refreshes when files change on your hard drive. Then open to start the interface and sign in with admin/admin. +### Managing dependencies + [Yarn][] is also used to manage CSS and JavaScript dependencies used in this application. You can upgrade dependencies by specifying a newer version in [package.json](package.json). You can also run `yarn update` and `yarn install` to manage dependencies. Add the `help` flag on any command to see how you can use it. For example, `yarn help update`. @@ -294,7 +295,7 @@ To launch your application's tests, run: ### Client tests -Unit tests are run by [Karma][] and written with [Jasmine][]. They're located in [src/test/javascript/](src/test/javascript/) and can be run with: +Unit tests are run by [Karma][] and written with [Jasmine][]. They're located in `src/test/javascript/` and can be run with: yarn test @@ -302,7 +303,7 @@ UI end-to-end tests are powered by [Cypress][], which is built on top of WebDriv and can be run by starting Spring Boot in one terminal (`./gradlew bootRun`) and running the tests (`yarn run e2e`) in a second one. ### Other tests -Performance tests are run by [Gatling][] and written in Scala. They're located in [src/test/gatling](src/test/gatling) and can be run with: +Performance tests are run by [Gatling][] and written in Scala. They're located in `src/test/gatling` and can be run with: ./gradlew gatlingRunAll From 3b00953b038f399a06260af424b5821649122ee7 Mon Sep 17 00:00:00 2001 From: Joris Borgdorff Date: Mon, 16 Oct 2023 11:31:54 +0200 Subject: [PATCH 017/158] Bump dev version --- build.gradle | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 036824c55..3041a9979 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ apply plugin: 'io.spring.dependency-management' allprojects { group 'org.radarbase' - version '2.1.0' // project version + version '2.1.1-SNAPSHOT' // project version // The comment on the previous line is only there to identify the project version line easily // with a sed command, to auto-update the version number with the prepare-release-branch.sh diff --git a/package.json b/package.json index b903347f8..3fc0fae02 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "management-portal", - "version": "2.1.0", + "version": "2.1.1", "description": "Description for ManagementPortal", "private": true, "cacheDirectories": [ From 556da3bb3e6327cf8ff038c2558ed20102b9a226 Mon Sep 17 00:00:00 2001 From: Joris Borgdorff Date: Mon, 16 Oct 2023 13:22:11 +0200 Subject: [PATCH 018/158] Update workflow versions --- .github/workflows/main.yml | 9 +++++---- .github/workflows/pre-release.yml | 10 ++++++---- .github/workflows/release.yml | 18 ++++-------------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3a47ad1bb..074d6b23e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -35,16 +35,17 @@ jobs: distribution: temurin java-version: 17 + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + - name: Cache uses: actions/cache@v3 with: path: | ${{ steps.yarn-cache-dir-path.outputs.dir }} - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-java-${{ hashFiles('**/build.gradle', '**/gradle.properties', '**/yarn.lock', '.yarnrc.yml') }} + key: ${{ runner.os }}-node-${{ hashFiles('**/build.gradle', '**/gradle.properties', '**/yarn.lock', '.yarnrc.yml') }} restore-keys: | - ${{ runner.os }}-java- + ${{ runner.os }}-node- - name: Install Yarn dependencies run: yarn install diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index 250e45551..78c7f8119 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -33,16 +33,18 @@ jobs: distribution: temurin java-version: 17 + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + - name: Cache uses: actions/cache@v3 with: path: | ${{ steps.yarn-cache-dir-path.outputs.dir }} - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-java-${{ hashFiles('**/build.gradle', '**/gradle.properties', '**/yarn.lock') }} + key: ${{ runner.os }}-rc-node-${{ hashFiles('**/build.gradle', '**/gradle.properties', '**/yarn.lock') }} restore-keys: | - ${{ runner.os }}-java- + ${{ runner.os }}-rc-node- + ${{ runner.os }}-node- # Compile the code - name: Install dependencies diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2e8421d74..9a544d4d7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,32 +23,22 @@ jobs: with: node-version: 16 - - name: Get yarn cache directory path - id: yarn-cache-dir-path - run: echo "dir=.yarn/cache" >> $GITHUB_OUTPUT - - uses: actions/setup-java@v3 with: distribution: temurin java-version: 17 - - name: Cache - uses: actions/cache@v3 + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 with: - path: | - ${{ steps.yarn-cache-dir-path.outputs.dir }} - ~/.gradle/caches - ~/.gradle/wrapper - key: ${{ runner.os }}-java-${{ hashFiles('**/build.gradle', '**/gradle.properties', '**/yarn.lock') }} - restore-keys: | - ${{ runner.os }}-java- + cache-disabled: true - name: Compile code run: ./gradlew assemble # Upload it to GitHub - name: Upload to GitHub - uses: AButler/upload-release-assets@v2.0 + uses: AButler/upload-release-assets@v2.0.2 with: files: '*/build/libs/*' repo-token: ${{ secrets.GITHUB_TOKEN }} From 1684caa0ac0694be9a716a1e930d21c3336caadb Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 14:15:02 +0200 Subject: [PATCH 019/158] Rename .java to .kt --- .../{TokenValidatorTest.java => TokenValidatorTest.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename radar-auth/src/test/java/org/radarbase/auth/authentication/{TokenValidatorTest.java => TokenValidatorTest.kt} (100%) diff --git a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.java b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt similarity index 100% rename from radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.java rename to radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt From 1c08fe00406f2a7608a8a533145b0d6159c847d6 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 14:15:02 +0200 Subject: [PATCH 020/158] last file in radar auth to kotlin --- .../auth/authentication/TokenValidatorTest.kt | 128 +++++++++--------- 1 file changed, 66 insertions(+), 62 deletions(-) diff --git a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt index 3c6314932..222a2c21c 100644 --- a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt +++ b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt @@ -1,93 +1,97 @@ -package org.radarbase.auth.authentication; +package org.radarbase.auth.authentication -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.radarbase.auth.exception.TokenValidationException; -import org.radarbase.auth.jwks.JwkAlgorithmParser; -import org.radarbase.auth.jwks.JwksTokenVerifierLoader; -import org.radarbase.auth.jwks.RSAPEMCertificateParser; -import org.radarbase.auth.util.TokenTestUtils; - -import java.util.List; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.radarbase.auth.util.TokenTestUtils.WIREMOCK_PORT; +import com.github.tomakehurst.wiremock.WireMockServer +import com.github.tomakehurst.wiremock.client.WireMock +import com.github.tomakehurst.wiremock.core.WireMockConfiguration +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.radarbase.auth.exception.TokenValidationException +import org.radarbase.auth.jwks.JwkAlgorithmParser +import org.radarbase.auth.jwks.JwksTokenVerifierLoader +import org.radarbase.auth.jwks.RSAPEMCertificateParser +import org.radarbase.auth.util.TokenTestUtils +import org.radarbase.auth.util.TokenTestUtils.WIREMOCK_PORT +import java.util.List /** * Created by dverbeec on 24/04/2017. */ - -class TokenValidatorTest { - - private static WireMockServer wireMockServer; - private TokenValidator validator; - - @BeforeAll - public static void loadToken() { - wireMockServer = new WireMockServer(new WireMockConfiguration() - .port(WIREMOCK_PORT)); - wireMockServer.start(); - } +internal class TokenValidatorTest { + private var validator: TokenValidator? = null /** * Set up a stub public key endpoint and initialize a TokenValidator object. * */ @BeforeEach - public void setUp() { - wireMockServer.stubFor(get(urlEqualTo(TokenTestUtils.PUBLIC_KEY_PATH)) - .willReturn(aResponse() + fun setUp() { + wireMockServer!!.stubFor( + WireMock.get(WireMock.urlEqualTo(TokenTestUtils.PUBLIC_KEY_PATH)) + .willReturn( + WireMock.aResponse() .withStatus(200) .withHeader("Content-type", TokenTestUtils.APPLICATION_JSON) - .withBody(TokenTestUtils.PUBLIC_KEY_BODY))); - - var algorithmParser = new JwkAlgorithmParser(List.of(new RSAPEMCertificateParser())); - var verifierLoader = new JwksTokenVerifierLoader( - "http://localhost:" + WIREMOCK_PORT + TokenTestUtils.PUBLIC_KEY_PATH, - "unit_test", - algorithmParser - ); - validator = new TokenValidator(List.of(verifierLoader)); + .withBody(TokenTestUtils.PUBLIC_KEY_BODY) + ) + ) + val algorithmParser = JwkAlgorithmParser(List.of(RSAPEMCertificateParser())) + val verifierLoader = JwksTokenVerifierLoader( + "http://localhost:" + WIREMOCK_PORT + TokenTestUtils.PUBLIC_KEY_PATH, + "unit_test", + algorithmParser + ) + validator = TokenValidator(List.of(verifierLoader)) } @AfterEach - public void reset() { - wireMockServer.resetAll(); + fun reset() { + wireMockServer!!.resetAll() } - @AfterAll - public static void tearDown() { - wireMockServer.stop(); + @Test + fun testValidToken() { + validator!!.validateBlocking(TokenTestUtils.VALID_RSA_TOKEN) } @Test - void testValidToken() { - validator.validateBlocking(TokenTestUtils.VALID_RSA_TOKEN); + fun testIncorrectAudienceToken() { + Assertions.assertThrows( + TokenValidationException::class.java + ) { validator!!.validateBlocking(TokenTestUtils.INCORRECT_AUDIENCE_TOKEN) } } @Test - void testIncorrectAudienceToken() { - assertThrows(TokenValidationException.class, - () -> validator.validateBlocking(TokenTestUtils.INCORRECT_AUDIENCE_TOKEN)); + fun testExpiredToken() { + Assertions.assertThrows( + TokenValidationException::class.java + ) { validator!!.validateBlocking(TokenTestUtils.EXPIRED_TOKEN) } } @Test - void testExpiredToken() { - assertThrows(TokenValidationException.class, - () -> validator.validateBlocking(TokenTestUtils.EXPIRED_TOKEN)); + fun testIncorrectAlgorithmToken() { + Assertions.assertThrows( + TokenValidationException::class.java + ) { validator!!.validateBlocking(TokenTestUtils.INCORRECT_ALGORITHM_TOKEN) } } - @Test - void testIncorrectAlgorithmToken() { - assertThrows(TokenValidationException.class, - () -> validator.validateBlocking(TokenTestUtils.INCORRECT_ALGORITHM_TOKEN)); + companion object { + private var wireMockServer: WireMockServer? = null + @BeforeAll + fun loadToken() { + wireMockServer = WireMockServer( + WireMockConfiguration() + .port(WIREMOCK_PORT) + ) + wireMockServer!!.start() + } + + @AfterAll + fun tearDown() { + wireMockServer!!.stop() + } } } From 31fd8b5739f21b0ed43e05500027c908a60f1fce Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 14:57:06 +0200 Subject: [PATCH 021/158] Rename .java to .kt --- .../{ApplicationProperties.java => ApplicationProperties.kt} | 0 .../config/{AsyncConfiguration.java => AsyncConfiguration.kt} | 0 .../config/{CacheConfiguration.java => CacheConfiguration.kt} | 0 .../{DatabaseConfiguration.java => DatabaseConfiguration.kt} | 0 ...imeFormatConfiguration.java => DateTimeFormatConfiguration.kt} | 0 .../config/{LocaleConfiguration.java => LocaleConfiguration.kt} | 0 ...gingAspectConfiguration.java => LoggingAspectConfiguration.kt} | 0 .../config/{LoggingConfiguration.java => LoggingConfiguration.kt} | 0 ...Auth2ServerConfiguration.java => OAuth2ServerConfiguration.kt} | 0 .../management/config/{package-info.java => package-info.kt} | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/config/{ApplicationProperties.java => ApplicationProperties.kt} (100%) rename src/main/java/org/radarbase/management/config/{AsyncConfiguration.java => AsyncConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{CacheConfiguration.java => CacheConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{DatabaseConfiguration.java => DatabaseConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{DateTimeFormatConfiguration.java => DateTimeFormatConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{LocaleConfiguration.java => LocaleConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{LoggingAspectConfiguration.java => LoggingAspectConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{LoggingConfiguration.java => LoggingConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{OAuth2ServerConfiguration.java => OAuth2ServerConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{package-info.java => package-info.kt} (100%) diff --git a/src/main/java/org/radarbase/management/config/ApplicationProperties.java b/src/main/java/org/radarbase/management/config/ApplicationProperties.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/ApplicationProperties.java rename to src/main/java/org/radarbase/management/config/ApplicationProperties.kt diff --git a/src/main/java/org/radarbase/management/config/AsyncConfiguration.java b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/AsyncConfiguration.java rename to src/main/java/org/radarbase/management/config/AsyncConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/CacheConfiguration.java b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/CacheConfiguration.java rename to src/main/java/org/radarbase/management/config/CacheConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.java b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/DatabaseConfiguration.java rename to src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.java b/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.java rename to src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/LocaleConfiguration.java b/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/LocaleConfiguration.java rename to src/main/java/org/radarbase/management/config/LocaleConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.java b/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.java rename to src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/LoggingConfiguration.java b/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/LoggingConfiguration.java rename to src/main/java/org/radarbase/management/config/LoggingConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.java b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.java rename to src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/package-info.java b/src/main/java/org/radarbase/management/config/package-info.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/package-info.java rename to src/main/java/org/radarbase/management/config/package-info.kt From 8d720529acad003e9ac27b9b2c502e45d6649220 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 14:57:06 +0200 Subject: [PATCH 022/158] first conversions, tests passing --- .../auth/authentication/TokenValidatorTest.kt | 8 +- .../config/ApplicationProperties.kt | 11 +- .../management/config/AsyncConfiguration.kt | 61 ++- .../management/config/CacheConfiguration.kt | 164 ++++--- .../config/DatabaseConfiguration.kt | 86 ++-- .../config/DateTimeFormatConfiguration.kt | 53 ++- .../management/config/LocaleConfiguration.kt | 45 +- .../config/LoggingAspectConfiguration.kt | 23 +- .../management/config/LoggingConfiguration.kt | 67 ++- .../config/OAuth2ServerConfiguration.kt | 408 +++++++++--------- .../management/config/package-info.kt | 2 +- 11 files changed, 448 insertions(+), 480 deletions(-) diff --git a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt index 222a2c21c..9b62292c8 100644 --- a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt +++ b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt @@ -15,7 +15,6 @@ import org.radarbase.auth.jwks.JwksTokenVerifierLoader import org.radarbase.auth.jwks.RSAPEMCertificateParser import org.radarbase.auth.util.TokenTestUtils import org.radarbase.auth.util.TokenTestUtils.WIREMOCK_PORT -import java.util.List /** * Created by dverbeec on 24/04/2017. @@ -38,13 +37,13 @@ internal class TokenValidatorTest { .withBody(TokenTestUtils.PUBLIC_KEY_BODY) ) ) - val algorithmParser = JwkAlgorithmParser(List.of(RSAPEMCertificateParser())) + val algorithmParser = JwkAlgorithmParser(listOf(RSAPEMCertificateParser())) val verifierLoader = JwksTokenVerifierLoader( "http://localhost:" + WIREMOCK_PORT + TokenTestUtils.PUBLIC_KEY_PATH, "unit_test", algorithmParser ) - validator = TokenValidator(List.of(verifierLoader)) + validator = TokenValidator(listOf(verifierLoader)) } @AfterEach @@ -80,6 +79,8 @@ internal class TokenValidatorTest { companion object { private var wireMockServer: WireMockServer? = null + + @JvmStatic @BeforeAll fun loadToken() { wireMockServer = WireMockServer( @@ -89,6 +90,7 @@ internal class TokenValidatorTest { wireMockServer!!.start() } + @JvmStatic @AfterAll fun tearDown() { wireMockServer!!.stop() diff --git a/src/main/java/org/radarbase/management/config/ApplicationProperties.kt b/src/main/java/org/radarbase/management/config/ApplicationProperties.kt index 4b42ad774..524c0b24f 100644 --- a/src/main/java/org/radarbase/management/config/ApplicationProperties.kt +++ b/src/main/java/org/radarbase/management/config/ApplicationProperties.kt @@ -1,13 +1,12 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.ConfigurationProperties /** * Properties specific to JHipster. * - *

Properties are configured in the application.yml file.

+ * + * Properties are configured in the application.yml file. */ @ConfigurationProperties(prefix = "application", ignoreUnknownFields = false) -public class ApplicationProperties { - -} +class ApplicationProperties diff --git a/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt index 485a9dbf9..51e7aaf21 100644 --- a/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt @@ -1,43 +1,40 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import tech.jhipster.async.ExceptionHandlingAsyncTaskExecutor; -import tech.jhipster.config.JHipsterProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; -import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.AsyncConfigurer; -import org.springframework.scheduling.annotation.EnableAsync; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.slf4j.LoggerFactory +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler +import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.scheduling.annotation.AsyncConfigurer +import org.springframework.scheduling.annotation.EnableAsync +import org.springframework.scheduling.annotation.EnableScheduling +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +import tech.jhipster.async.ExceptionHandlingAsyncTaskExecutor +import tech.jhipster.config.JHipsterProperties @Configuration @EnableAsync @EnableScheduling -public class AsyncConfiguration implements AsyncConfigurer { - - private static final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class); - +open class AsyncConfiguration : AsyncConfigurer { @Autowired - private JHipsterProperties jHipsterProperties; + private val jHipsterProperties: JHipsterProperties? = null + @Bean(name = ["taskExecutor"]) + override fun getAsyncExecutor(): ExceptionHandlingAsyncTaskExecutor { + log.debug("Creating Async Task Executor") + val executor = ThreadPoolTaskExecutor() + executor.corePoolSize = jHipsterProperties!!.async.corePoolSize + executor.maxPoolSize = jHipsterProperties.async.maxPoolSize + executor.queueCapacity = jHipsterProperties.async.queueCapacity + executor.setThreadNamePrefix("management-portal-Executor-") + return ExceptionHandlingAsyncTaskExecutor(executor) + } - @Override - @Bean(name = "taskExecutor") - public ExceptionHandlingAsyncTaskExecutor getAsyncExecutor() { - log.debug("Creating Async Task Executor"); - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize()); - executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize()); - executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity()); - executor.setThreadNamePrefix("management-portal-Executor-"); - return new ExceptionHandlingAsyncTaskExecutor(executor); + override fun getAsyncUncaughtExceptionHandler(): AsyncUncaughtExceptionHandler { + return SimpleAsyncUncaughtExceptionHandler() } - @Override - public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { - return new SimpleAsyncUncaughtExceptionHandler(); + companion object { + private val log = LoggerFactory.getLogger(AsyncConfiguration::class.java) } } diff --git a/src/main/java/org/radarbase/management/config/CacheConfiguration.kt b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt index 41b56bf88..57b0cd25e 100644 --- a/src/main/java/org/radarbase/management/config/CacheConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt @@ -1,119 +1,113 @@ -package org.radarbase.management.config; - -import com.hazelcast.config.AttributeConfig; -import com.hazelcast.config.Config; -import com.hazelcast.config.EvictionPolicy; -import com.hazelcast.config.IndexConfig; -import com.hazelcast.config.IndexType; -import com.hazelcast.config.MapConfig; -import com.hazelcast.config.NetworkConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.spring.cache.HazelcastCacheManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.cache.CacheManager; -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.session.hazelcast.Hazelcast4IndexedSessionRepository; -import org.springframework.session.hazelcast.Hazelcast4PrincipalNameExtractor; -import tech.jhipster.config.JHipsterConstants; -import tech.jhipster.config.JHipsterProperties; - -import javax.annotation.PreDestroy; -import java.util.List; - -import static com.hazelcast.config.MaxSizePolicy.USED_HEAP_SIZE; +package org.radarbase.management.config + +import com.hazelcast.config.AttributeConfig +import com.hazelcast.config.Config +import com.hazelcast.config.EvictionPolicy +import com.hazelcast.config.IndexConfig +import com.hazelcast.config.IndexType +import com.hazelcast.config.MapConfig +import com.hazelcast.config.MaxSizePolicy +import com.hazelcast.core.Hazelcast +import com.hazelcast.core.HazelcastInstance +import com.hazelcast.spring.cache.HazelcastCacheManager +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.AutoConfigureBefore +import org.springframework.cache.CacheManager +import org.springframework.cache.annotation.EnableCaching +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.core.env.Environment +import org.springframework.session.hazelcast.Hazelcast4IndexedSessionRepository +import org.springframework.session.hazelcast.Hazelcast4PrincipalNameExtractor +import tech.jhipster.config.JHipsterConstants +import tech.jhipster.config.JHipsterProperties +import javax.annotation.PreDestroy @Configuration @EnableCaching -@AutoConfigureBefore(value = {WebConfigurer.class, DatabaseConfiguration.class}) -public class CacheConfiguration { - - private static final Logger log = LoggerFactory.getLogger(CacheConfiguration.class); - +@AutoConfigureBefore(value = [WebConfigurer::class, DatabaseConfiguration::class]) +open class CacheConfiguration { @Autowired - private Environment env; - + private val env: Environment? = null @PreDestroy - public void destroy() { - log.info("Closing Cache Manager"); - Hazelcast.shutdownAll(); + fun destroy() { + log.info("Closing Cache Manager") + Hazelcast.shutdownAll() } @Bean - public CacheManager cacheManager(HazelcastInstance hazelcastInstance) { - log.debug("Starting HazelcastCacheManager"); - return new HazelcastCacheManager( - hazelcastInstance); + open fun HazelcastInstance?.cacheManager(): CacheManager { + log.debug("Starting HazelcastCacheManager") + return HazelcastCacheManager( + this + ) } @Bean - public Config hazelcastConfig(JHipsterProperties jHipsterProperties) { - Config config = new Config(); - config.setInstanceName("ManagementPortal"); - NetworkConfig networkConfig = config.getNetworkConfig(); - networkConfig.setPort(5701); - networkConfig.setPortAutoIncrement(true); + open fun hazelcastConfig(jHipsterProperties: JHipsterProperties): Config { + val config = Config() + config.setInstanceName("ManagementPortal") + val networkConfig = config.networkConfig + networkConfig.setPort(5701) + networkConfig.setPortAutoIncrement(true) // In development, remove multicast auto-configuration - if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) { - networkConfig.getInterfaces().setEnabled(true); - networkConfig.getInterfaces().setInterfaces(List.of("127.0.0.1")); - - networkConfig.getJoin().getAwsConfig().setEnabled(false); - networkConfig.getJoin().getMulticastConfig().setEnabled(false); - networkConfig.getJoin().getTcpIpConfig().setEnabled(false); - networkConfig.getJoin().getAzureConfig().setEnabled(false); - networkConfig.getJoin().getGcpConfig().setEnabled(false); - networkConfig.getJoin().getEurekaConfig().setEnabled(false); - networkConfig.getJoin().getKubernetesConfig().setEnabled(false); + if (env!!.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) { + networkConfig.interfaces.setEnabled(true) + networkConfig.interfaces.setInterfaces(listOf("127.0.0.1")) + networkConfig.join.awsConfig.setEnabled(false) + networkConfig.join.multicastConfig.setEnabled(false) + networkConfig.join.tcpIpConfig.setEnabled(false) + networkConfig.join.azureConfig.setEnabled(false) + networkConfig.join.gcpConfig.setEnabled(false) + networkConfig.join.eurekaConfig.setEnabled(false) + networkConfig.join.kubernetesConfig.setEnabled(false) } - AttributeConfig attributeConfig = new AttributeConfig() - .setName(Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE) - .setExtractorClassName(Hazelcast4PrincipalNameExtractor.class.getName()); + val attributeConfig = AttributeConfig() + .setName(Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE) + .setExtractorClassName(Hazelcast4PrincipalNameExtractor::class.java.getName()) config.getMapConfig(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME) - .addAttributeConfig(attributeConfig).addIndexConfig( - new IndexConfig(IndexType.HASH, - Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)); - config.getMapConfigs().put("default", initializeDefaultMapConfig()); - config.getMapConfigs().put("org.radarbase.management.domain.*", - initializeDomainMapConfig(jHipsterProperties)); - return config; + .addAttributeConfig(attributeConfig).addIndexConfig( + IndexConfig( + IndexType.HASH, + Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE + ) + ) + config.mapConfigs["default"] = initializeDefaultMapConfig() + config.mapConfigs["org.radarbase.management.domain.*"] = initializeDomainMapConfig(jHipsterProperties) + return config } - private MapConfig initializeDefaultMapConfig() { - MapConfig mapConfig = new MapConfig(); + private fun initializeDefaultMapConfig(): MapConfig { + val mapConfig = MapConfig() /* Number of backups. If 1 is set as the backup-count for example, then all entries of the map will be copied to another JVM for - fail-safety. Valid numbers are 0 (no backup), 1, 2, 3. */ - mapConfig.setBackupCount(0); + fail-safety. Valid numbers are 0 (no backup), 1, 2, 3. */mapConfig.setBackupCount(0) /* Valid values are: NONE (no eviction), LRU (Least Recently Used), LFU (Least Frequently Used). - NONE is the default. */ - mapConfig.getEvictionConfig().setEvictionPolicy(EvictionPolicy.LRU); + NONE is the default. */mapConfig.evictionConfig.setEvictionPolicy(EvictionPolicy.LRU) /* Maximum size of the map. When max size is reached, map is evicted based on the policy defined. Any integer between 0 and Integer.MAX_VALUE. 0 means - Integer.MAX_VALUE. Default is 0. */ - mapConfig.getEvictionConfig().setMaxSizePolicy(USED_HEAP_SIZE); - - return mapConfig; + Integer.MAX_VALUE. Default is 0. */mapConfig.evictionConfig.setMaxSizePolicy(MaxSizePolicy.USED_HEAP_SIZE) + return mapConfig } - private MapConfig initializeDomainMapConfig(JHipsterProperties jHipsterProperties) { - MapConfig mapConfig = new MapConfig(); + private fun initializeDomainMapConfig(jHipsterProperties: JHipsterProperties): MapConfig { + val mapConfig = MapConfig() mapConfig.setTimeToLiveSeconds( - jHipsterProperties.getCache().getHazelcast().getTimeToLiveSeconds()); - return mapConfig; + jHipsterProperties.cache.hazelcast.timeToLiveSeconds + ) + return mapConfig + } + + companion object { + private val log = LoggerFactory.getLogger(CacheConfiguration::class.java) } } diff --git a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt index 971954b6f..752f96662 100644 --- a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt @@ -1,58 +1,60 @@ -package org.radarbase.management.config; - -import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; -import liquibase.integration.spring.SpringLiquibase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.core.env.Profiles; -import org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import org.springframework.transaction.annotation.EnableTransactionManagement; -import tech.jhipster.config.JHipsterConstants; - -import javax.sql.DataSource; +package org.radarbase.management.config + +import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module +import liquibase.integration.spring.SpringLiquibase +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.core.env.Environment +import org.springframework.core.env.Profiles +import org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean +import org.springframework.data.jpa.repository.config.EnableJpaAuditing +import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.transaction.annotation.EnableTransactionManagement +import tech.jhipster.config.JHipsterConstants +import javax.sql.DataSource @Configuration -@EnableJpaRepositories(basePackages = "org.radarbase.management.repository", - repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class) +@EnableJpaRepositories( + basePackages = ["org.radarbase.management.repository"], + repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean::class +) @EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware") @EnableTransactionManagement -public class DatabaseConfiguration { - - private static final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class); - +open class DatabaseConfiguration { @Autowired - private Environment env; - + private val env: Environment? = null @Bean - public SpringLiquibase liquibase(DataSource dataSource, - LiquibaseProperties liquibaseProperties) { + open fun liquibase( + dataSource: DataSource?, + liquibaseProperties: LiquibaseProperties + ): SpringLiquibase { // Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start // asynchronously - SpringLiquibase liquibase = new SpringLiquibase(); - liquibase.setDataSource(dataSource); - liquibase.setChangeLog("classpath:config/liquibase/master.xml"); - liquibase.setContexts(liquibaseProperties.getContexts()); - liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema()); - liquibase.setDropFirst(liquibaseProperties.isDropFirst()); - if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE))) { - liquibase.setShouldRun(false); + val liquibase = SpringLiquibase() + liquibase.dataSource = dataSource + liquibase.changeLog = "classpath:config/liquibase/master.xml" + liquibase.contexts = liquibaseProperties.contexts + liquibase.defaultSchema = liquibaseProperties.defaultSchema + liquibase.isDropFirst = liquibaseProperties.isDropFirst + if (env!!.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE))) { + liquibase.setShouldRun(false) } else { - liquibase.setShouldRun(liquibaseProperties.isEnabled()); - log.debug("Configuring Liquibase"); + liquibase.setShouldRun(liquibaseProperties.isEnabled) + log.debug("Configuring Liquibase") } - return liquibase; + return liquibase } @Bean - public Hibernate5Module hibernate5Module() { - return new Hibernate5Module(); + open fun hibernate5Module(): Hibernate5Module { + return Hibernate5Module() + } + + companion object { + private val log = LoggerFactory.getLogger(DatabaseConfiguration::class.java) } } diff --git a/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt b/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt index 0dbf2d722..508f46ab1 100644 --- a/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt @@ -1,29 +1,23 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.springframework.context.annotation.Configuration; -import org.springframework.format.FormatterRegistry; -import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -import javax.annotation.Nonnull; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.ResolverStyle; - -import static java.time.temporal.ChronoField.HOUR_OF_DAY; -import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; -import static java.time.temporal.ChronoField.NANO_OF_SECOND; -import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; +import org.springframework.context.annotation.Configuration +import org.springframework.format.FormatterRegistry +import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeFormatterBuilder +import java.time.format.ResolverStyle +import java.time.temporal.ChronoField +import javax.annotation.Nonnull @Configuration -public class DateTimeFormatConfiguration implements WebMvcConfigurer { - - @Override - public void addFormatters(@Nonnull FormatterRegistry registry) { - DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); - registrar.setUseIsoFormat(true); - registrar.setDateTimeFormatter(new DateTimeFormatterBuilder() +open class DateTimeFormatConfiguration : WebMvcConfigurer { + override fun addFormatters(@Nonnull registry: FormatterRegistry) { + val registrar = DateTimeFormatterRegistrar() + registrar.setUseIsoFormat(true) + registrar.setDateTimeFormatter( + DateTimeFormatterBuilder() .parseCaseInsensitive() .append(DateTimeFormatter.ISO_LOCAL_DATE) .optionalStart() @@ -41,13 +35,14 @@ public class DateTimeFormatConfiguration implements WebMvcConfigurer { .appendLiteral(']') .optionalEnd() .optionalEnd() - .parseDefaulting(HOUR_OF_DAY, HOUR_OF_DAY.range().getMinimum()) - .parseDefaulting(MINUTE_OF_HOUR, MINUTE_OF_HOUR.range().getMinimum()) - .parseDefaulting(SECOND_OF_MINUTE, SECOND_OF_MINUTE.range().getMinimum()) - .parseDefaulting(NANO_OF_SECOND, NANO_OF_SECOND.range().getMinimum()) + .parseDefaulting(ChronoField.HOUR_OF_DAY, ChronoField.HOUR_OF_DAY.range().minimum) + .parseDefaulting(ChronoField.MINUTE_OF_HOUR, ChronoField.MINUTE_OF_HOUR.range().minimum) + .parseDefaulting(ChronoField.SECOND_OF_MINUTE, ChronoField.SECOND_OF_MINUTE.range().minimum) + .parseDefaulting(ChronoField.NANO_OF_SECOND, ChronoField.NANO_OF_SECOND.range().minimum) .toFormatter() .withZone(ZoneId.of("UTC")) - .withResolverStyle(ResolverStyle.LENIENT)); - registrar.registerFormatters(registry); + .withResolverStyle(ResolverStyle.LENIENT) + ) + registrar.registerFormatters(registry) } } diff --git a/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt b/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt index 3d30a9765..856175555 100644 --- a/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt @@ -1,34 +1,31 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import tech.jhipster.config.locale.AngularCookieLocaleResolver; -import org.springframework.context.EnvironmentAware; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.web.servlet.LocaleResolver; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.context.EnvironmentAware +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.core.env.Environment +import org.springframework.web.servlet.LocaleResolver +import org.springframework.web.servlet.config.annotation.InterceptorRegistry +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor +import tech.jhipster.config.locale.AngularCookieLocaleResolver @Configuration -public class LocaleConfiguration implements WebMvcConfigurer, EnvironmentAware { - - @Override - public void setEnvironment(Environment environment) { +open class LocaleConfiguration : WebMvcConfigurer, EnvironmentAware { + override fun setEnvironment(environment: Environment) { // unused } - @Bean(name = "localeResolver") - public LocaleResolver localeResolver() { - AngularCookieLocaleResolver cookieLocaleResolver = new AngularCookieLocaleResolver(); - cookieLocaleResolver.setCookieName("NG_TRANSLATE_LANG_KEY"); - return cookieLocaleResolver; + @Bean(name = ["localeResolver"]) + open fun localeResolver(): LocaleResolver { + val cookieLocaleResolver = AngularCookieLocaleResolver() + cookieLocaleResolver.cookieName = "NG_TRANSLATE_LANG_KEY" + return cookieLocaleResolver } - @Override - public void addInterceptors(InterceptorRegistry registry) { - LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); - localeChangeInterceptor.setParamName("language"); - registry.addInterceptor(localeChangeInterceptor); + override fun addInterceptors(registry: InterceptorRegistry) { + val localeChangeInterceptor = LocaleChangeInterceptor() + localeChangeInterceptor.paramName = "language" + registry.addInterceptor(localeChangeInterceptor) } } diff --git a/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt b/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt index e2f0e71f4..33bdb8a5c 100644 --- a/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt @@ -1,20 +1,19 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import tech.jhipster.config.JHipsterConstants; -import org.radarbase.management.aop.logging.LoggingAspect; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.EnableAspectJAutoProxy; -import org.springframework.context.annotation.Profile; -import org.springframework.core.env.Environment; +import org.radarbase.management.aop.logging.LoggingAspect +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.EnableAspectJAutoProxy +import org.springframework.context.annotation.Profile +import org.springframework.core.env.Environment +import tech.jhipster.config.JHipsterConstants @Configuration @EnableAspectJAutoProxy -public class LoggingAspectConfiguration { - +open class LoggingAspectConfiguration { @Bean @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) - public LoggingAspect loggingAspect(Environment env) { - return new LoggingAspect(env); + open fun loggingAspect(env: Environment?): LoggingAspect { + return LoggingAspect(env!!) } } diff --git a/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt b/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt index 1899a111e..6e6651e07 100644 --- a/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt @@ -1,46 +1,37 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import ch.qos.logback.classic.LoggerContext; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; -import tech.jhipster.config.JHipsterProperties; - -import java.util.HashMap; -import java.util.Map; - -import static tech.jhipster.config.logging.LoggingUtils.addContextListener; -import static tech.jhipster.config.logging.LoggingUtils.addJsonConsoleAppender; -import static tech.jhipster.config.logging.LoggingUtils.addLogstashTcpSocketAppender; +import ch.qos.logback.classic.LoggerContext +import com.fasterxml.jackson.databind.ObjectMapper +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Configuration +import tech.jhipster.config.JHipsterProperties +import tech.jhipster.config.logging.LoggingUtils @Configuration -public class LoggingConfiguration { - /** Logging configuration for JHipster. */ - public LoggingConfiguration(@Value("${spring.application.name}") String appName, - @Value("${server.port}") String serverPort, - JHipsterProperties jHipsterProperties, - ObjectMapper mapper) throws JsonProcessingException { - LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); - - Map map = new HashMap<>(); - map.put("app_name", appName); - map.put("app_port", serverPort); - - String customFields = mapper.writeValueAsString(map); - - JHipsterProperties.Logging loggingProperties = jHipsterProperties.getLogging(); - JHipsterProperties.Logging.Logstash logstashProperties = loggingProperties.getLogstash(); - - if (loggingProperties.isUseJsonFormat()) { - addJsonConsoleAppender(context, customFields); +open class LoggingConfiguration( + @Value("\${spring.application.name}") appName: String, + @Value("\${server.port}") serverPort: String, + jHipsterProperties: JHipsterProperties, + mapper: ObjectMapper +) { + /** Logging configuration for JHipster. */ + init { + val context = LoggerFactory.getILoggerFactory() as LoggerContext + val map: MutableMap = HashMap() + map["app_name"] = appName + map["app_port"] = serverPort + val customFields = mapper.writeValueAsString(map) + val loggingProperties = jHipsterProperties.logging + val logstashProperties = loggingProperties.logstash + if (loggingProperties.isUseJsonFormat) { + LoggingUtils.addJsonConsoleAppender(context, customFields) } - if (logstashProperties.isEnabled()) { - addLogstashTcpSocketAppender(context, customFields, logstashProperties); + if (logstashProperties.isEnabled) { + LoggingUtils.addLogstashTcpSocketAppender(context, customFields, logstashProperties) } - if (loggingProperties.isUseJsonFormat() || logstashProperties.isEnabled()) { - addContextListener(context, customFields, loggingProperties); + if (loggingProperties.isUseJsonFormat || logstashProperties.isEnabled) { + LoggingUtils.addContextListener(context, customFields, loggingProperties) } } } diff --git a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt index 7f9755c6f..ee0d02c04 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt @@ -1,311 +1,303 @@ -package org.radarbase.management.config; - -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.security.ClaimsTokenEnhancer; -import org.radarbase.management.security.Http401UnauthorizedEntryPoint; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.security.PostgresApprovalStore; -import org.radarbase.management.security.jwt.ManagementPortalJwtAccessTokenConverter; -import org.radarbase.management.security.jwt.ManagementPortalJwtTokenStore; -import org.radarbase.management.security.jwt.ManagementPortalOauthKeyStoreHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.core.annotation.Order; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.Authentication; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; -import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; -import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; -import org.springframework.security.oauth2.provider.approval.ApprovalStore; -import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore; -import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; -import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; -import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices; -import org.springframework.security.oauth2.provider.token.DefaultTokenServices; -import org.springframework.security.oauth2.provider.token.TokenEnhancer; -import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; -import org.springframework.security.oauth2.provider.token.TokenStore; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; - -import javax.sql.DataSource; -import java.util.Arrays; - -import static org.springframework.orm.jpa.vendor.Database.POSTGRESQL; +package org.radarbase.management.config + +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.security.ClaimsTokenEnhancer +import org.radarbase.management.security.Http401UnauthorizedEntryPoint +import org.radarbase.management.security.JwtAuthenticationFilter +import org.radarbase.management.security.PostgresApprovalStore +import org.radarbase.management.security.jwt.ManagementPortalJwtAccessTokenConverter +import org.radarbase.management.security.jwt.ManagementPortalJwtTokenStore +import org.radarbase.management.security.jwt.ManagementPortalOauthKeyStoreHandler +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Primary +import org.springframework.core.annotation.Order +import org.springframework.http.HttpMethod +import org.springframework.orm.jpa.vendor.Database +import org.springframework.security.authentication.AuthenticationManager +import org.springframework.security.authentication.DefaultAuthenticationEventPublisher +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter +import org.springframework.security.config.http.SessionCreationPolicy +import org.springframework.security.core.Authentication +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer +import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer +import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer +import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer +import org.springframework.security.oauth2.provider.approval.ApprovalStore +import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService +import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices +import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices +import org.springframework.security.oauth2.provider.token.DefaultTokenServices +import org.springframework.security.oauth2.provider.token.TokenEnhancer +import org.springframework.security.oauth2.provider.token.TokenEnhancerChain +import org.springframework.security.oauth2.provider.token.TokenStore +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler +import java.util.* +import javax.sql.DataSource @Configuration -public class OAuth2ServerConfiguration { - private static final Logger logger = LoggerFactory.getLogger(OAuth2ServerConfiguration.class); - +open class OAuth2ServerConfiguration { @Autowired - private DataSource dataSource; + private val dataSource: DataSource? = null @Autowired - private PasswordEncoder passwordEncoder; + private val passwordEncoder: PasswordEncoder? = null @Configuration @Order(-20) - protected static class LoginConfig extends WebSecurityConfigurerAdapter { + protected open class LoginConfig : WebSecurityConfigurerAdapter() { @Autowired - private AuthenticationManager authenticationManager; + private val authenticationManager: AuthenticationManager? = null @Autowired - private JwtAuthenticationFilter jwtAuthenticationFilter; - - @Override - protected void configure(HttpSecurity http) throws Exception { + private val jwtAuthenticationFilter: JwtAuthenticationFilter? = null + @Throws(Exception::class) + override fun configure(http: HttpSecurity) { http - .formLogin().loginPage("/login").permitAll() - .and() - .addFilterAfter(jwtAuthenticationFilter, - UsernamePasswordAuthenticationFilter.class) - .requestMatchers() - .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access") - - .and() - .authorizeRequests().anyRequest().authenticated(); + .formLogin().loginPage("/login").permitAll() + .and() + .addFilterAfter( + jwtAuthenticationFilter, + UsernamePasswordAuthenticationFilter::class.java + ) + .requestMatchers() + .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access") + .and() + .authorizeRequests().anyRequest().authenticated() } - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.parentAuthenticationManager(authenticationManager); + @Throws(Exception::class) + override fun configure(auth: AuthenticationManagerBuilder) { + auth.parentAuthenticationManager(authenticationManager) } - } @Configuration - public static class JwtAuthenticationFilterConfiguration { + open class JwtAuthenticationFilterConfiguration { @Autowired - private AuthenticationManager authenticationManager; + private val authenticationManager: AuthenticationManager? = null @Autowired - private UserRepository userRepository; + private val userRepository: UserRepository? = null @Autowired - private ManagementPortalOauthKeyStoreHandler keyStoreHandler; - + private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null @Bean - public JwtAuthenticationFilter jwtAuthenticationFilter() { - return new JwtAuthenticationFilter( - keyStoreHandler.getTokenValidator(), - authenticationManager, - userRepository, - true); + open fun jwtAuthenticationFilter(): JwtAuthenticationFilter { + return JwtAuthenticationFilter( + keyStoreHandler!!.getTokenValidator(), + authenticationManager!!, + userRepository!!, + true + ) } } @Bean - public JdbcClientDetailsService jdbcClientDetailsService() { - JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource); - clientDetailsService.setPasswordEncoder(passwordEncoder); - return clientDetailsService; + open fun jdbcClientDetailsService(): JdbcClientDetailsService { + val clientDetailsService = JdbcClientDetailsService(dataSource) + clientDetailsService.setPasswordEncoder(passwordEncoder) + return clientDetailsService } @Configuration @EnableResourceServer - protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { + protected open class ResourceServerConfiguration : ResourceServerConfigurerAdapter() { @Autowired - private ManagementPortalOauthKeyStoreHandler keyStoreHandler; + private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null @Autowired - private TokenStore tokenStore; + private val tokenStore: TokenStore? = null @Autowired - private Http401UnauthorizedEntryPoint http401UnauthorizedEntryPoint; + private val http401UnauthorizedEntryPoint: Http401UnauthorizedEntryPoint? = null @Autowired - private LogoutSuccessHandler logoutSuccessHandler; + private val logoutSuccessHandler: LogoutSuccessHandler? = null @Autowired - private AuthenticationManager authenticationManager; + private val authenticationManager: AuthenticationManager? = null @Autowired - private UserRepository userRepository; - - public JwtAuthenticationFilter jwtAuthenticationFilter() { - return new JwtAuthenticationFilter( - keyStoreHandler.getTokenValidator(), authenticationManager, userRepository + private val userRepository: UserRepository? = null + fun jwtAuthenticationFilter(): JwtAuthenticationFilter { + return JwtAuthenticationFilter( + keyStoreHandler!!.getTokenValidator(), authenticationManager!!, userRepository!! ) - .skipUrlPattern(HttpMethod.GET, "/management/health") - .skipUrlPattern(HttpMethod.GET, "/api/meta-token/*") - .skipUrlPattern(HttpMethod.GET, "/api/sitesettings") - .skipUrlPattern(HttpMethod.GET, "/images/**") - .skipUrlPattern(HttpMethod.GET, "/css/**") - .skipUrlPattern(HttpMethod.GET, "/js/**") - .skipUrlPattern(HttpMethod.GET, "/radar-baseRR.png"); + .skipUrlPattern(HttpMethod.GET, "/management/health") + .skipUrlPattern(HttpMethod.GET, "/api/meta-token/*") + .skipUrlPattern(HttpMethod.GET, "/api/sitesettings") + .skipUrlPattern(HttpMethod.GET, "/images/**") + .skipUrlPattern(HttpMethod.GET, "/css/**") + .skipUrlPattern(HttpMethod.GET, "/js/**") + .skipUrlPattern(HttpMethod.GET, "/radar-baseRR.png") } - @Override - public void configure(HttpSecurity http) throws Exception { + @Throws(Exception::class) + override fun configure(http: HttpSecurity) { http - .exceptionHandling() - .authenticationEntryPoint(http401UnauthorizedEntryPoint) - .and() - .logout() - .invalidateHttpSession(true) - .logoutUrl("/api/logout") - .logoutSuccessHandler(logoutSuccessHandler) - .and() - .csrf() - .disable() - .addFilterBefore(jwtAuthenticationFilter(), - UsernamePasswordAuthenticationFilter.class) - .headers() - .frameOptions() - .disable() - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) - .and() - .authorizeRequests() - .antMatchers("/oauth/**").permitAll() - .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() - .antMatchers("/api/register") - .hasAnyAuthority(RoleAuthority.SYS_ADMIN_AUTHORITY) - .antMatchers("/api/profile-info").permitAll() - .antMatchers("/api/sitesettings").permitAll() - .antMatchers("/api/**").authenticated() - // Allow management/health endpoint to all to allow kubernetes to be able to - // detect the health of the service - .antMatchers("/management/health").permitAll() - .antMatchers("/management/**") - .hasAnyAuthority(RoleAuthority.SYS_ADMIN_AUTHORITY) - .antMatchers("/v2/api-docs/**").permitAll() - .antMatchers("/swagger-resources/configuration/ui").permitAll() - .antMatchers("/swagger-ui/index.html") - .hasAnyAuthority(RoleAuthority.SYS_ADMIN_AUTHORITY); + .exceptionHandling() + .authenticationEntryPoint(http401UnauthorizedEntryPoint) + .and() + .logout() + .invalidateHttpSession(true) + .logoutUrl("/api/logout") + .logoutSuccessHandler(logoutSuccessHandler) + .and() + .csrf() + .disable() + .addFilterBefore( + jwtAuthenticationFilter(), + UsernamePasswordAuthenticationFilter::class.java + ) + .headers() + .frameOptions() + .disable() + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) + .and() + .authorizeRequests() + .antMatchers("/oauth/**").permitAll() + .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() + .antMatchers("/api/register") + .hasAnyAuthority(RoleAuthority.SYS_ADMIN_AUTHORITY) + .antMatchers("/api/profile-info").permitAll() + .antMatchers("/api/sitesettings").permitAll() + .antMatchers("/api/**") + .authenticated() // Allow management/health endpoint to all to allow kubernetes to be able to + // detect the health of the service + .antMatchers("/management/health").permitAll() + .antMatchers("/management/**") + .hasAnyAuthority(RoleAuthority.SYS_ADMIN_AUTHORITY) + .antMatchers("/v2/api-docs/**").permitAll() + .antMatchers("/swagger-resources/configuration/ui").permitAll() + .antMatchers("/swagger-ui/index.html") + .hasAnyAuthority(RoleAuthority.SYS_ADMIN_AUTHORITY) } - @Override - public void configure(ResourceServerSecurityConfigurer resources) throws Exception { + @Throws(Exception::class) + override fun configure(resources: ResourceServerSecurityConfigurer) { resources.resourceId("res_ManagementPortal") - .tokenStore(tokenStore) - .eventPublisher(new CustomEventPublisher()); + .tokenStore(tokenStore) + .eventPublisher(CustomEventPublisher()) } - protected static class CustomEventPublisher extends DefaultAuthenticationEventPublisher { - - @Override - public void publishAuthenticationSuccess(Authentication authentication) { + protected class CustomEventPublisher : DefaultAuthenticationEventPublisher() { + override fun publishAuthenticationSuccess(authentication: Authentication) { // OAuth2AuthenticationProcessingFilter publishes an authentication success audit // event for EVERY successful OAuth request to our API resources, this is way too // much so we override the event publisher to not publish these events. } } - } @Configuration @EnableAuthorizationServer - protected static class AuthorizationServerConfiguration extends - AuthorizationServerConfigurerAdapter { - + protected open class AuthorizationServerConfiguration : AuthorizationServerConfigurerAdapter() { @Autowired - private JpaProperties jpaProperties; + private val jpaProperties: JpaProperties? = null @Autowired @Qualifier("authenticationManagerBean") - private AuthenticationManager authenticationManager; + private val authenticationManager: AuthenticationManager? = null @Autowired - private DataSource dataSource; + private val dataSource: DataSource? = null @Autowired - private JdbcClientDetailsService jdbcClientDetailsService; + private val jdbcClientDetailsService: JdbcClientDetailsService? = null @Autowired - private ManagementPortalOauthKeyStoreHandler keyStoreHandler; - + private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null @Bean - protected AuthorizationCodeServices authorizationCodeServices() { - return new JdbcAuthorizationCodeServices(dataSource); + protected open fun authorizationCodeServices(): AuthorizationCodeServices { + return JdbcAuthorizationCodeServices(dataSource) } @Bean - public ApprovalStore approvalStore() { - if (jpaProperties.getDatabase().equals(POSTGRESQL)) { - return new PostgresApprovalStore(dataSource); + open fun approvalStore(): ApprovalStore { + return if (jpaProperties!!.database == Database.POSTGRESQL) { + PostgresApprovalStore(dataSource) } else { // to have compatibility for other databases including H2 - return new JdbcApprovalStore(dataSource); + JdbcApprovalStore(dataSource) } } @Bean - public TokenEnhancer tokenEnhancer() { - return new ClaimsTokenEnhancer(); + open fun tokenEnhancer(): TokenEnhancer { + return ClaimsTokenEnhancer() } @Bean - public TokenStore tokenStore() { - return new ManagementPortalJwtTokenStore(accessTokenConverter()); + open fun tokenStore(): TokenStore { + return ManagementPortalJwtTokenStore(accessTokenConverter()) } @Bean - public ManagementPortalJwtAccessTokenConverter accessTokenConverter() { - logger.debug("loading token converter from keystore configurations"); - return new ManagementPortalJwtAccessTokenConverter( - keyStoreHandler.getAlgorithmForSigning(), - keyStoreHandler.getVerifiers(), - keyStoreHandler.getRefreshTokenVerifiers()); + open fun accessTokenConverter(): ManagementPortalJwtAccessTokenConverter { + logger.debug("loading token converter from keystore configurations") + return ManagementPortalJwtAccessTokenConverter( + keyStoreHandler!!.getAlgorithmForSigning(), + keyStoreHandler.verifiers, + keyStoreHandler.refreshTokenVerifiers + ) } @Bean @Primary - public DefaultTokenServices tokenServices(TokenStore tokenStore) { - DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); - defaultTokenServices.setTokenStore(tokenStore); - defaultTokenServices.setSupportRefreshToken(true); - defaultTokenServices.setReuseRefreshToken(false); - return defaultTokenServices; + open fun tokenServices(tokenStore: TokenStore?): DefaultTokenServices { + val defaultTokenServices = DefaultTokenServices() + defaultTokenServices.setTokenStore(tokenStore) + defaultTokenServices.setSupportRefreshToken(true) + defaultTokenServices.setReuseRefreshToken(false) + return defaultTokenServices } - @Override - public void configure(AuthorizationServerEndpointsConfigurer endpoints) { - TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); + override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) { + val tokenEnhancerChain = TokenEnhancerChain() tokenEnhancerChain.setTokenEnhancers( - Arrays.asList(tokenEnhancer(), accessTokenConverter())); - + Arrays.asList(tokenEnhancer(), accessTokenConverter()) + ) endpoints - .authorizationCodeServices(authorizationCodeServices()) - .approvalStore(approvalStore()) - .tokenStore(tokenStore()) - .tokenEnhancer(tokenEnhancerChain) - .reuseRefreshTokens(false) - .authenticationManager(authenticationManager); + .authorizationCodeServices(authorizationCodeServices()) + .approvalStore(approvalStore()) + .tokenStore(tokenStore()) + .tokenEnhancer(tokenEnhancerChain) + .reuseRefreshTokens(false) + .authenticationManager(authenticationManager) } - @Override - public void configure(AuthorizationServerSecurityConfigurer oauthServer) { + override fun configure(oauthServer: AuthorizationServerSecurityConfigurer) { oauthServer.allowFormAuthenticationForClients() - .checkTokenAccess("isAuthenticated()") - .tokenKeyAccess("permitAll()") - .passwordEncoder(new BCryptPasswordEncoder()); + .checkTokenAccess("isAuthenticated()") + .tokenKeyAccess("permitAll()") + .passwordEncoder(BCryptPasswordEncoder()) } - @Override - public void configure(ClientDetailsServiceConfigurer clients) throws Exception { - clients.withClientDetails(jdbcClientDetailsService); + @Throws(Exception::class) + override fun configure(clients: ClientDetailsServiceConfigurer) { + clients.withClientDetails(jdbcClientDetailsService) } } + + companion object { + private val logger = LoggerFactory.getLogger(OAuth2ServerConfiguration::class.java) + } } diff --git a/src/main/java/org/radarbase/management/config/package-info.kt b/src/main/java/org/radarbase/management/config/package-info.kt index e1b91b4d3..dd8ac5d6b 100644 --- a/src/main/java/org/radarbase/management/config/package-info.kt +++ b/src/main/java/org/radarbase/management/config/package-info.kt @@ -1,4 +1,4 @@ /** * Spring Framework configuration files. */ -package org.radarbase.management.config; +package org.radarbase.management.config From 0ff9730f951d3e6b4a01c35df8cce87440e0c589 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 14:58:38 +0200 Subject: [PATCH 023/158] Rename .java to .kt --- .../config/{OpenApiConfiguration.java => OpenApiConfiguration.kt} | 0 .../{RadarTokenConfiguration.java => RadarTokenConfiguration.kt} | 0 .../{SecurityConfiguration.java => SecurityConfiguration.kt} | 0 .../config/{SourceTypeLoader.java => SourceTypeLoader.kt} | 0 .../{ThymeleafConfiguration.java => ThymeleafConfiguration.kt} | 0 .../management/config/{WebConfigurer.java => WebConfigurer.kt} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/config/{OpenApiConfiguration.java => OpenApiConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{RadarTokenConfiguration.java => RadarTokenConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{SecurityConfiguration.java => SecurityConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{SourceTypeLoader.java => SourceTypeLoader.kt} (100%) rename src/main/java/org/radarbase/management/config/{ThymeleafConfiguration.java => ThymeleafConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{WebConfigurer.java => WebConfigurer.kt} (100%) diff --git a/src/main/java/org/radarbase/management/config/OpenApiConfiguration.java b/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/OpenApiConfiguration.java rename to src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.java b/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/RadarTokenConfiguration.java rename to src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/SecurityConfiguration.java b/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/SecurityConfiguration.java rename to src/main/java/org/radarbase/management/config/SecurityConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/SourceTypeLoader.java b/src/main/java/org/radarbase/management/config/SourceTypeLoader.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/SourceTypeLoader.java rename to src/main/java/org/radarbase/management/config/SourceTypeLoader.kt diff --git a/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.java b/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/ThymeleafConfiguration.java rename to src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/WebConfigurer.java b/src/main/java/org/radarbase/management/config/WebConfigurer.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/WebConfigurer.java rename to src/main/java/org/radarbase/management/config/WebConfigurer.kt From 54e3fd777ae350a28a670769e628dac0185fddde Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 14:58:39 +0200 Subject: [PATCH 024/158] finished config folder --- .../management/config/OpenApiConfiguration.kt | 75 ++++---- .../config/RadarTokenConfiguration.kt | 37 ++-- .../config/SecurityConfiguration.kt | 167 ++++++++---------- .../management/config/SourceTypeLoader.kt | 100 +++++------ .../config/ThymeleafConfiguration.kt | 31 ++-- .../management/config/WebConfigurer.kt | 147 ++++++++------- 6 files changed, 266 insertions(+), 291 deletions(-) diff --git a/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt b/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt index b161b51e9..7e3d96126 100644 --- a/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt @@ -6,41 +6,54 @@ * * See the file LICENSE in the root of this repository. */ +package org.radarbase.management.config -package org.radarbase.management.config; - -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.info.License; -import io.swagger.v3.oas.models.security.OAuthFlow; -import io.swagger.v3.oas.models.security.OAuthFlows; -import io.swagger.v3.oas.models.security.SecurityScheme; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import tech.jhipster.config.JHipsterConstants; +import io.swagger.v3.oas.models.Components +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.info.Info +import io.swagger.v3.oas.models.info.License +import io.swagger.v3.oas.models.security.OAuthFlow +import io.swagger.v3.oas.models.security.OAuthFlows +import io.swagger.v3.oas.models.security.SecurityScheme +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Profile +import tech.jhipster.config.JHipsterConstants @Configuration @Profile(JHipsterConstants.SPRING_PROFILE_API_DOCS) -public class OpenApiConfiguration { +open class OpenApiConfiguration { @Bean - public OpenAPI customOpenAPI() { - return new OpenAPI() - .components(new Components() - .addSecuritySchemes("oauth2Login", new SecurityScheme() - .type(SecurityScheme.Type.OAUTH2) - .flows(new OAuthFlows() - .authorizationCode(new OAuthFlow() - .authorizationUrl("/oauth/authorize") - .tokenUrl("/oauth/token")) - .clientCredentials(new OAuthFlow() - .tokenUrl("/oauth/token"))))) - .info(new Info() - .title("ManagementPortal API") - .description("ManagementPortal for RADAR-base") - .license(new License() - .name("Apache 2.0") - .url("https://radar-base.org"))); + open fun customOpenAPI(): OpenAPI { + return OpenAPI() + .components( + Components() + .addSecuritySchemes( + "oauth2Login", SecurityScheme() + .type(SecurityScheme.Type.OAUTH2) + .flows( + OAuthFlows() + .authorizationCode( + OAuthFlow() + .authorizationUrl("/oauth/authorize") + .tokenUrl("/oauth/token") + ) + .clientCredentials( + OAuthFlow() + .tokenUrl("/oauth/token") + ) + ) + ) + ) + .info( + Info() + .title("ManagementPortal API") + .description("ManagementPortal for RADAR-base") + .license( + License() + .name("Apache 2.0") + .url("https://radar-base.org") + ) + ) } } diff --git a/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt b/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt index 6f5633bf4..deb2e5484 100644 --- a/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt @@ -1,30 +1,19 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.radarbase.auth.token.RadarToken; -import org.radarbase.management.security.jwt.RadarTokenLoader; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; - -import javax.annotation.Nullable; -import javax.servlet.http.HttpServletRequest; - -import static org.springframework.context.annotation.ScopedProxyMode.TARGET_CLASS; +import org.radarbase.auth.token.RadarToken +import org.radarbase.management.security.jwt.RadarTokenLoader +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Scope +import org.springframework.context.annotation.ScopedProxyMode +import javax.servlet.http.HttpServletRequest @Configuration -public class RadarTokenConfiguration { - private final RadarTokenLoader radarTokenLoader; - - @Autowired - public RadarTokenConfiguration(RadarTokenLoader radarTokenLoader) { - this.radarTokenLoader = radarTokenLoader; - } - - @Scope(value = "request", proxyMode = TARGET_CLASS) +class RadarTokenConfiguration @Autowired constructor(private val radarTokenLoader: RadarTokenLoader) { + @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) @Bean - @Nullable - public RadarToken radarToken(HttpServletRequest request) { - return radarTokenLoader.loadToken(request); + fun radarToken(request: HttpServletRequest?): RadarToken? { + return radarTokenLoader.loadToken(request!!) } } diff --git a/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt b/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt index 1f85f5b0c..8089515f7 100644 --- a/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt @@ -1,120 +1,105 @@ -package org.radarbase.management.config; +package org.radarbase.management.config - -import org.radarbase.management.security.Http401UnauthorizedEntryPoint; -import org.radarbase.management.security.RadarAuthenticationProvider; -import org.springframework.beans.factory.BeanInitializationException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; -import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; -import tech.jhipster.security.AjaxLogoutSuccessHandler; - -import javax.annotation.PostConstruct; +import org.radarbase.management.security.Http401UnauthorizedEntryPoint +import org.radarbase.management.security.RadarAuthenticationProvider +import org.springframework.beans.factory.BeanInitializationException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.ApplicationEventPublisher +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.http.HttpMethod +import org.springframework.security.authentication.AuthenticationManager +import org.springframework.security.authentication.DefaultAuthenticationEventPublisher +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.builders.WebSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter +import org.springframework.security.config.http.SessionCreationPolicy +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler +import tech.jhipster.security.AjaxLogoutSuccessHandler +import javax.annotation.PostConstruct @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) -public class SecurityConfiguration extends WebSecurityConfigurerAdapter { - private final AuthenticationManagerBuilder authenticationManagerBuilder; - - private final UserDetailsService userDetailsService; - - private final ApplicationEventPublisher applicationEventPublisher; - private final PasswordEncoder passwordEncoder; - - /** Security configuration constructor. */ - @Autowired - public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, - UserDetailsService userDetailsService, - ApplicationEventPublisher applicationEventPublisher, - PasswordEncoder passwordEncoder) { - this.authenticationManagerBuilder = authenticationManagerBuilder; - this.userDetailsService = userDetailsService; - this.applicationEventPublisher = applicationEventPublisher; - this.passwordEncoder = passwordEncoder; - } - +open class SecurityConfiguration +/** Security configuration constructor. */ @Autowired constructor( + private val authenticationManagerBuilder: AuthenticationManagerBuilder, + private val userDetailsService: UserDetailsService, + private val applicationEventPublisher: ApplicationEventPublisher, + private val passwordEncoder: PasswordEncoder +) : WebSecurityConfigurerAdapter() { @PostConstruct - public void init() { + fun init() { try { authenticationManagerBuilder - .userDetailsService(userDetailsService) - .passwordEncoder(passwordEncoder) - .and() - .authenticationProvider(new RadarAuthenticationProvider()) - .authenticationEventPublisher( - new DefaultAuthenticationEventPublisher(applicationEventPublisher)); - } catch (Exception e) { - throw new BeanInitializationException("Security configuration failed", e); + .userDetailsService(userDetailsService) + .passwordEncoder(passwordEncoder) + .and() + .authenticationProvider(RadarAuthenticationProvider()) + .authenticationEventPublisher( + DefaultAuthenticationEventPublisher(applicationEventPublisher) + ) + } catch (e: Exception) { + throw BeanInitializationException("Security configuration failed", e) } } @Bean - public LogoutSuccessHandler logoutSuccessHandler() { - return new AjaxLogoutSuccessHandler(); + open fun logoutSuccessHandler(): LogoutSuccessHandler { + return AjaxLogoutSuccessHandler() } @Bean - public Http401UnauthorizedEntryPoint http401UnauthorizedEntryPoint() { - return new Http401UnauthorizedEntryPoint(); + open fun http401UnauthorizedEntryPoint(): Http401UnauthorizedEntryPoint { + return Http401UnauthorizedEntryPoint() } - @Override - public void configure(WebSecurity web) { + override fun configure(web: WebSecurity) { web.ignoring() - .antMatchers("/") - .antMatchers("/*.{js,ico,css,html}") - .antMatchers(HttpMethod.OPTIONS, "/**") - .antMatchers("/app/**/*.{js,html}") - .antMatchers("/bower_components/**") - .antMatchers("/i18n/**") - .antMatchers("/content/**") - .antMatchers("/swagger-ui/**") - .antMatchers("/api-docs/**") - .antMatchers("/swagger-ui.html") - .antMatchers("/api-docs{,.json,.yml}") - .antMatchers("/api/register") - .antMatchers("/api/profile-info") - .antMatchers("/api/activate") - .antMatchers("/api/account/reset_password/init") - .antMatchers("/api/account/reset_password/finish") - .antMatchers("/test/**") - .antMatchers("/management/health") - .antMatchers(HttpMethod.GET, "/api/meta-token/**"); + .antMatchers("/") + .antMatchers("/*.{js,ico,css,html}") + .antMatchers(HttpMethod.OPTIONS, "/**") + .antMatchers("/app/**/*.{js,html}") + .antMatchers("/bower_components/**") + .antMatchers("/i18n/**") + .antMatchers("/content/**") + .antMatchers("/swagger-ui/**") + .antMatchers("/api-docs/**") + .antMatchers("/swagger-ui.html") + .antMatchers("/api-docs{,.json,.yml}") + .antMatchers("/api/register") + .antMatchers("/api/profile-info") + .antMatchers("/api/activate") + .antMatchers("/api/account/reset_password/init") + .antMatchers("/api/account/reset_password/finish") + .antMatchers("/test/**") + .antMatchers("/management/health") + .antMatchers(HttpMethod.GET, "/api/meta-token/**") } - @Override - public void configure(HttpSecurity http) throws Exception { + @Throws(Exception::class) + public override fun configure(http: HttpSecurity) { http - .httpBasic().realmName("ManagementPortal") - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); + .httpBasic().realmName("ManagementPortal") + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) } - @Override @Bean - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); + @Throws(Exception::class) + override fun authenticationManagerBean(): AuthenticationManager { + return super.authenticationManagerBean() } @Bean - public SecurityEvaluationContextExtension securityEvaluationContextExtension() { - return new SecurityEvaluationContextExtension(); + open fun securityEvaluationContextExtension(): SecurityEvaluationContextExtension { + return SecurityEvaluationContextExtension() } } diff --git a/src/main/java/org/radarbase/management/config/SourceTypeLoader.kt b/src/main/java/org/radarbase/management/config/SourceTypeLoader.kt index dbe666d7d..e456f9e95 100644 --- a/src/main/java/org/radarbase/management/config/SourceTypeLoader.kt +++ b/src/main/java/org/radarbase/management/config/SourceTypeLoader.kt @@ -1,20 +1,14 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.radarbase.management.service.SourceTypeService; -import org.radarbase.management.service.catalog.CatalogSourceType; -import org.radarbase.management.service.catalog.SourceTypeResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.CommandLineRunner; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.radarbase.management.service.SourceTypeService +import org.radarbase.management.service.catalog.CatalogSourceType +import org.radarbase.management.service.catalog.SourceTypeResponse +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.CommandLineRunner +import org.springframework.stereotype.Component +import org.springframework.web.client.RestClientException +import org.springframework.web.client.RestTemplate /** * Upon start of Spring application, this class automatically import the source-types provided by @@ -22,53 +16,53 @@ import org.springframework.web.client.RestTemplate; * provided and enableAutoImport is set to true. */ @Component -public class SourceTypeLoader implements CommandLineRunner { - - private static final Logger log = LoggerFactory.getLogger(SourceTypeLoader.class); - +class SourceTypeLoader : CommandLineRunner { @Autowired - private SourceTypeService sourceTypeService; + private val sourceTypeService: SourceTypeService? = null @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Override - public void run(String... args) { - if (!managementPortalProperties.getCatalogueServer().isEnableAutoImport()) { - log.info("Auto source-type import is disabled"); - return; + private val managementPortalProperties: ManagementPortalProperties? = null + override fun run(vararg args: String) { + if (!managementPortalProperties!!.catalogueServer.isEnableAutoImport) { + log.info("Auto source-type import is disabled") + return } - - String catalogServerUrl = managementPortalProperties.getCatalogueServer().getServerUrl(); - + val catalogServerUrl = managementPortalProperties.catalogueServer.serverUrl try { - RestTemplate restTemplate = new RestTemplate(); - log.debug("Requesting source-types from catalog server..."); - ResponseEntity catalogues = restTemplate - .getForEntity(catalogServerUrl, SourceTypeResponse.class); - SourceTypeResponse catalogueDto = catalogues.getBody(); + val restTemplate = RestTemplate() + log.debug("Requesting source-types from catalog server...") + val catalogues = restTemplate + .getForEntity(catalogServerUrl, SourceTypeResponse::class.java) + val catalogueDto = catalogues.body if (catalogueDto == null) { - log.warn("Catalog Service {} returned empty response", catalogServerUrl); - return; + log.warn("Catalog Service {} returned empty response", catalogServerUrl) + return } - List catalogSourceTypes = new ArrayList<>(); - addNonNull(catalogSourceTypes, catalogueDto.getPassiveSources()); - addNonNull(catalogSourceTypes, catalogueDto.getActiveSources()); - addNonNull(catalogSourceTypes, catalogueDto.getMonitorSources()); - addNonNull(catalogSourceTypes, catalogueDto.getConnectorSources()); - sourceTypeService.saveSourceTypesFromCatalogServer(catalogSourceTypes); - } catch (RestClientException e) { - log.warn("Cannot fetch source types from Catalog Service at {}: {}", catalogServerUrl, - e.toString()); - } catch (RuntimeException exe) { - log.warn("An error has occurred during auto import of source-types: {}", exe - .getMessage()); + val catalogSourceTypes: MutableList = ArrayList() + addNonNull(catalogSourceTypes, catalogueDto.passiveSources) + addNonNull(catalogSourceTypes, catalogueDto.activeSources) + addNonNull(catalogSourceTypes, catalogueDto.monitorSources) + addNonNull(catalogSourceTypes, catalogueDto.connectorSources) + sourceTypeService!!.saveSourceTypesFromCatalogServer(catalogSourceTypes) + } catch (e: RestClientException) { + log.warn( + "Cannot fetch source types from Catalog Service at {}: {}", catalogServerUrl, + e.toString() + ) + } catch (exe: RuntimeException) { + log.warn( + "An error has occurred during auto import of source-types: {}", exe + .message + ) } } - private static void addNonNull(Collection collection, Collection toAdd) { - if (toAdd != null && !toAdd.isEmpty()) { - collection.addAll(toAdd); + companion object { + private val log = LoggerFactory.getLogger(SourceTypeLoader::class.java) + private fun addNonNull(collection: MutableCollection, toAdd: Collection?) { + if (toAdd != null && !toAdd.isEmpty()) { + collection.addAll(toAdd) + } } } } diff --git a/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt b/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt index a7f77132d..16dc8fd58 100644 --- a/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt @@ -1,23 +1,22 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Description; -import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; - -import java.nio.charset.StandardCharsets; +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Description +import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver +import java.nio.charset.StandardCharsets @Configuration -public class ThymeleafConfiguration { +class ThymeleafConfiguration { @Bean @Description("Thymeleaf template resolver serving HTML 5 emails") - public ClassLoaderTemplateResolver emailTemplateResolver() { - ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver(); - emailTemplateResolver.setPrefix("templates/"); - emailTemplateResolver.setSuffix(".html"); - emailTemplateResolver.setTemplateMode("HTML"); - emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name()); - emailTemplateResolver.setOrder(1); - return emailTemplateResolver; + fun emailTemplateResolver(): ClassLoaderTemplateResolver { + val emailTemplateResolver = ClassLoaderTemplateResolver() + emailTemplateResolver.prefix = "templates/" + emailTemplateResolver.suffix = ".html" + emailTemplateResolver.setTemplateMode("HTML") + emailTemplateResolver.characterEncoding = StandardCharsets.UTF_8.name() + emailTemplateResolver.order = 1 + return emailTemplateResolver } } diff --git a/src/main/java/org/radarbase/management/config/WebConfigurer.kt b/src/main/java/org/radarbase/management/config/WebConfigurer.kt index 83d5bf0a5..1ff446223 100644 --- a/src/main/java/org/radarbase/management/config/WebConfigurer.kt +++ b/src/main/java/org/radarbase/management/config/WebConfigurer.kt @@ -1,115 +1,110 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.web.server.MimeMappings; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; -import org.springframework.boot.web.servlet.ServletContextInitializer; -import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.core.env.Profiles; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import tech.jhipster.config.JHipsterConstants; -import tech.jhipster.config.JHipsterProperties; -import tech.jhipster.web.filter.CachingHttpHeadersFilter; - -import javax.servlet.DispatcherType; -import javax.servlet.FilterRegistration; -import javax.servlet.ServletContext; -import java.io.File; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.EnumSet; +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.web.server.MimeMappings +import org.springframework.boot.web.server.WebServerFactoryCustomizer +import org.springframework.boot.web.servlet.ServletContextInitializer +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.core.env.Environment +import org.springframework.core.env.Profiles +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder +import org.springframework.security.crypto.password.PasswordEncoder +import tech.jhipster.config.JHipsterConstants +import tech.jhipster.config.JHipsterProperties +import tech.jhipster.web.filter.CachingHttpHeadersFilter +import java.io.File +import java.nio.file.Paths +import java.util.* +import javax.servlet.DispatcherType +import javax.servlet.ServletContext /** * Configuration of web application with Servlet 3.0 APIs. */ @Configuration -public class WebConfigurer implements ServletContextInitializer, - WebServerFactoryCustomizer { - - private static final Logger log = LoggerFactory.getLogger(WebConfigurer.class); - +class WebConfigurer : ServletContextInitializer, WebServerFactoryCustomizer { @Autowired - private Environment env; + private val env: Environment? = null @Autowired - private JHipsterProperties jHipsterProperties; - - @Override - public void onStartup(ServletContext servletContext) { - if (env.getActiveProfiles().length != 0) { - log.info("Web application configuration, using profiles: {}", - Arrays.asList(env.getActiveProfiles())); + private val jHipsterProperties: JHipsterProperties? = null + override fun onStartup(servletContext: ServletContext) { + if (env!!.activeProfiles.size != 0) { + log.info( + "Web application configuration, using profiles: {}", + Arrays.asList(*env.activeProfiles) + ) } if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_PRODUCTION))) { - EnumSet disps = EnumSet - .of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC); - initCachingHttpHeadersFilter(servletContext, disps); + val disps = EnumSet + .of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC) + initCachingHttpHeadersFilter(servletContext, disps) } - log.info("Web application fully configured"); + log.info("Web application fully configured") } /** * Customize the Servlet engine: Mime types, the document root, the cache. */ - - @Override - public void customize(ConfigurableServletWebServerFactory factory) { - MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT); + override fun customize(factory: ConfigurableServletWebServerFactory) { + val mappings = MimeMappings(MimeMappings.DEFAULT) // IE issue, see https://github.com/jhipster/generator-jhipster/pull/711 - mappings.add("html", "text/html;charset=utf-8"); + mappings.add("html", "text/html;charset=utf-8") // CloudFoundry issue, see https://github.com/cloudfoundry/gorouter/issues/64 - mappings.add("json", "text/html;charset=utf-8"); - factory.setMimeMappings(mappings); + mappings.add("json", "text/html;charset=utf-8") + factory.setMimeMappings(mappings) // When running in an IDE or with ./gradlew bootRun, set location of the static web assets. - setLocationForStaticAssets(factory); + setLocationForStaticAssets(factory) } - private void setLocationForStaticAssets(ConfigurableServletWebServerFactory factory) { - File root; - String prefixPath = resolvePathPrefix(); - root = new File(prefixPath + "build/www/"); + private fun setLocationForStaticAssets(factory: ConfigurableServletWebServerFactory) { + val root: File + val prefixPath = resolvePathPrefix() + root = File(prefixPath + "build/www/") if (root.exists() && root.isDirectory()) { - factory.setDocumentRoot(root); + factory.setDocumentRoot(root) } } /** * Resolve path prefix to static resources. */ - private String resolvePathPrefix() { - String fullExecutablePath = this.getClass().getResource("").getPath(); - String rootPath = Paths.get(".").toUri().normalize().getPath(); - String extractedPath = fullExecutablePath.replace(rootPath, ""); - int extractionEndIndex = extractedPath.indexOf("build/"); - if (extractionEndIndex <= 0) { - return ""; - } - return extractedPath.substring(0, extractionEndIndex); + private fun resolvePathPrefix(): String { + val fullExecutablePath = this.javaClass.getResource("").path + val rootPath = Paths.get(".").toUri().normalize().getPath() + val extractedPath = fullExecutablePath.replace(rootPath, "") + val extractionEndIndex = extractedPath.indexOf("build/") + return if (extractionEndIndex <= 0) { + "" + } else extractedPath.substring(0, extractionEndIndex) } /** * Initializes the caching HTTP Headers Filter. */ - private void initCachingHttpHeadersFilter(ServletContext servletContext, - EnumSet disps) { - log.debug("Registering Caching HTTP Headers Filter"); - FilterRegistration.Dynamic cachingHttpHeadersFilter = - servletContext.addFilter("cachingHttpHeadersFilter", - new CachingHttpHeadersFilter(jHipsterProperties)); - - cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/content/*"); - cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/app/*"); - cachingHttpHeadersFilter.setAsyncSupported(true); + private fun initCachingHttpHeadersFilter( + servletContext: ServletContext, + disps: EnumSet + ) { + log.debug("Registering Caching HTTP Headers Filter") + val cachingHttpHeadersFilter = servletContext.addFilter( + "cachingHttpHeadersFilter", + CachingHttpHeadersFilter(jHipsterProperties) + ) + cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/content/*") + cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/app/*") + cachingHttpHeadersFilter.setAsyncSupported(true) } @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); + fun passwordEncoder(): PasswordEncoder { + return BCryptPasswordEncoder() + } + + companion object { + private val log = LoggerFactory.getLogger(WebConfigurer::class.java) } } From 0dd70426cba223614398f608884d11c8b18912a8 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 15:03:01 +0200 Subject: [PATCH 025/158] Rename .java to .kt --- .../audit/{AuditEventConverter.java => AuditEventConverter.kt} | 0 .../{CustomRevisionListener.java => CustomRevisionListener.kt} | 0 ...ingSecurityAuditorAware.java => SpringSecurityAuditorAware.kt} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/config/audit/{AuditEventConverter.java => AuditEventConverter.kt} (100%) rename src/main/java/org/radarbase/management/config/audit/{CustomRevisionListener.java => CustomRevisionListener.kt} (100%) rename src/main/java/org/radarbase/management/security/{SpringSecurityAuditorAware.java => SpringSecurityAuditorAware.kt} (100%) diff --git a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.java b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/audit/AuditEventConverter.java rename to src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt diff --git a/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.java b/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.java rename to src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt diff --git a/src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.java b/src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.kt similarity index 100% rename from src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.java rename to src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.kt From 5d42dfe74654ee01850cbcfcd12bc8a2acfc3b3e Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 15:03:02 +0200 Subject: [PATCH 026/158] finished config folder --- .../config/audit/AuditEventConverter.kt | 83 +++++++++---------- .../config/audit/CustomRevisionListener.kt | 30 ++++--- .../security/SpringSecurityAuditorAware.kt | 27 +++--- 3 files changed, 63 insertions(+), 77 deletions(-) diff --git a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt index a1e7a9a13..dcfb7f086 100644 --- a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt +++ b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt @@ -1,36 +1,30 @@ -package org.radarbase.management.config.audit; +package org.radarbase.management.config.audit -import java.time.Instant; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.radarbase.management.domain.PersistentAuditEvent; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.security.web.authentication.WebAuthenticationDetails; -import org.springframework.stereotype.Component; +import org.radarbase.management.domain.PersistentAuditEvent +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.security.web.authentication.WebAuthenticationDetails +import org.springframework.stereotype.Component +import java.time.ZoneId @Component -public class AuditEventConverter { - +class AuditEventConverter { /** * Convert a list of PersistentAuditEvent to a list of AuditEvent. * * @param persistentAuditEvents the list to convert * @return the converted list. */ - public List convertToAuditEvent( - Iterable persistentAuditEvents) { + fun convertToAuditEvent( + persistentAuditEvents: Iterable? + ): List { if (persistentAuditEvents == null) { - return Collections.emptyList(); + return emptyList() } - List auditEvents = new ArrayList<>(); - for (PersistentAuditEvent persistentAuditEvent : persistentAuditEvents) { - auditEvents.add(convertToAuditEvent(persistentAuditEvent)); + val auditEvents: MutableList = ArrayList() + for (persistentAuditEvent in persistentAuditEvents) { + auditEvents.add(convertToAuditEvent(persistentAuditEvent)) } - return auditEvents; + return auditEvents } /** @@ -39,12 +33,14 @@ public class AuditEventConverter { * @param persistentAuditEvent the event to convert * @return the converted list. */ - public AuditEvent convertToAuditEvent(PersistentAuditEvent persistentAuditEvent) { - Instant instant = persistentAuditEvent.getAuditEventDate().atZone(ZoneId.systemDefault()) - .toInstant(); - return new AuditEvent(instant, persistentAuditEvent.getPrincipal(), - persistentAuditEvent.getAuditEventType(), - convertDataToObjects(persistentAuditEvent.getData())); + fun convertToAuditEvent(persistentAuditEvent: PersistentAuditEvent): AuditEvent { + val instant = persistentAuditEvent.auditEventDate.atZone(ZoneId.systemDefault()) + .toInstant() + return AuditEvent( + instant, persistentAuditEvent.principal, + persistentAuditEvent.auditEventType, + convertDataToObjects(persistentAuditEvent.data) + ) } /** @@ -54,15 +50,14 @@ public class AuditEventConverter { * @param data the data to convert * @return a map of String, Object */ - public Map convertDataToObjects(Map data) { - Map results = new HashMap<>(); - + fun convertDataToObjects(data: Map?): Map { + val results: MutableMap = HashMap() if (data != null) { - for (Map.Entry entry : data.entrySet()) { - results.put(entry.getKey(), entry.getValue()); + for ((key, value) in data) { + results[key] = value } } - return results; + return results } /** @@ -72,25 +67,21 @@ public class AuditEventConverter { * @param data the data to convert * @return a map of String, String */ - public Map convertDataToStrings(Map data) { - Map results = new HashMap<>(); - + fun convertDataToStrings(data: Map?): Map { + val results: MutableMap = HashMap() if (data != null) { - for (Map.Entry entry : data.entrySet()) { - Object val = entry.getValue(); + for ((key, value) in data) { // Extract the data that will be saved. - if (val instanceof WebAuthenticationDetails) { - WebAuthenticationDetails authenticationDetails = (WebAuthenticationDetails) val; - results.put("sessionId", authenticationDetails.getSessionId()); - } else if (val != null) { - results.put(entry.getKey(), val.toString()); + if (value is WebAuthenticationDetails) { + results["sessionId"] = value.sessionId + } else if (value != null) { + results[key] = value.toString() } else { - results.put(entry.getKey(), "null"); + results[key] = "null" } } } - - return results; + return results } } diff --git a/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt b/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt index c0ede037a..eb7f4589f 100644 --- a/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt +++ b/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt @@ -1,22 +1,20 @@ -package org.radarbase.management.config.audit; +package org.radarbase.management.config.audit -import org.hibernate.envers.RevisionListener; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.audit.CustomRevisionEntity; -import org.radarbase.management.domain.support.AutowireHelper; -import org.radarbase.management.security.SpringSecurityAuditorAware; -import org.springframework.beans.factory.annotation.Autowired; +import org.hibernate.envers.RevisionListener +import org.radarbase.management.domain.audit.CustomRevisionEntity +import org.radarbase.management.domain.support.AutowireHelper +import org.radarbase.management.security.Constants +import org.radarbase.management.security.SpringSecurityAuditorAware +import org.springframework.beans.factory.annotation.Autowired -public class CustomRevisionListener implements RevisionListener { +class CustomRevisionListener : RevisionListener { @Autowired - private SpringSecurityAuditorAware springSecurityAuditorAware; - - @Override - public void newRevision(Object revisionEntity) { - AutowireHelper.autowire(this, springSecurityAuditorAware); - CustomRevisionEntity entity = (CustomRevisionEntity) revisionEntity; - entity.setAuditor(springSecurityAuditorAware.getCurrentAuditor() - .orElse(Constants.SYSTEM_ACCOUNT)); + private val springSecurityAuditorAware: SpringSecurityAuditorAware? = null + override fun newRevision(revisionEntity: Any) { + AutowireHelper.autowire(this, springSecurityAuditorAware) + val entity = revisionEntity as CustomRevisionEntity + entity.auditor = springSecurityAuditorAware!!.currentAuditor + .orElse(Constants.SYSTEM_ACCOUNT) } } diff --git a/src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.kt b/src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.kt index 4a9a7fead..e6989ddf0 100644 --- a/src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.kt +++ b/src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.kt @@ -1,25 +1,22 @@ -package org.radarbase.management.security; +package org.radarbase.management.security -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.AuditorAware; -import org.springframework.security.core.Authentication; -import org.springframework.stereotype.Component; - -import javax.annotation.Nonnull; -import java.util.Optional; +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.AuditorAware +import org.springframework.security.core.Authentication +import org.springframework.stereotype.Component +import java.util.* +import javax.annotation.Nonnull /** * Implementation of AuditorAware based on Spring Security. */ @Component -public class SpringSecurityAuditorAware implements AuditorAware { +class SpringSecurityAuditorAware : AuditorAware { @Autowired - private Optional authentication; - - @Override + private val authentication: Optional? = null @Nonnull - public Optional getCurrentAuditor() { - return authentication.map(Authentication::getName) - .filter(n -> !n.isEmpty()); + override fun getCurrentAuditor(): Optional { + return authentication!!.map { obj: Authentication -> obj.name } + .filter { n: String -> n.isNotEmpty() } } } From 5b45fafb634ac409039451193aee2e88318b393e Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 15:03:33 +0200 Subject: [PATCH 027/158] CustomRevisionListener needs to be a @component --- .../management/config/audit/CustomRevisionListener.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt b/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt index eb7f4589f..c2279fc22 100644 --- a/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt +++ b/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt @@ -6,8 +6,9 @@ import org.radarbase.management.domain.support.AutowireHelper import org.radarbase.management.security.Constants import org.radarbase.management.security.SpringSecurityAuditorAware import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component - +@Component class CustomRevisionListener : RevisionListener { @Autowired private val springSecurityAuditorAware: SpringSecurityAuditorAware? = null From 5f8e88942fef635e2f51ec3a137ab86c32fda3e8 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 15:12:32 +0200 Subject: [PATCH 028/158] tests passing --- .../radarbase/management/config/RadarTokenConfiguration.kt | 4 ++-- .../org/radarbase/management/config/ThymeleafConfiguration.kt | 4 ++-- .../java/org/radarbase/management/config/WebConfigurer.kt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt b/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt index deb2e5484..b7b032cc1 100644 --- a/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt @@ -10,10 +10,10 @@ import org.springframework.context.annotation.ScopedProxyMode import javax.servlet.http.HttpServletRequest @Configuration -class RadarTokenConfiguration @Autowired constructor(private val radarTokenLoader: RadarTokenLoader) { +open class RadarTokenConfiguration @Autowired constructor(private val radarTokenLoader: RadarTokenLoader) { @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) @Bean - fun radarToken(request: HttpServletRequest?): RadarToken? { + open fun radarToken(request: HttpServletRequest?): RadarToken? { return radarTokenLoader.loadToken(request!!) } } diff --git a/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt b/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt index 16dc8fd58..2ef1685e6 100644 --- a/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt @@ -7,10 +7,10 @@ import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver import java.nio.charset.StandardCharsets @Configuration -class ThymeleafConfiguration { +open class ThymeleafConfiguration { @Bean @Description("Thymeleaf template resolver serving HTML 5 emails") - fun emailTemplateResolver(): ClassLoaderTemplateResolver { + open fun emailTemplateResolver(): ClassLoaderTemplateResolver { val emailTemplateResolver = ClassLoaderTemplateResolver() emailTemplateResolver.prefix = "templates/" emailTemplateResolver.suffix = ".html" diff --git a/src/main/java/org/radarbase/management/config/WebConfigurer.kt b/src/main/java/org/radarbase/management/config/WebConfigurer.kt index 1ff446223..205656634 100644 --- a/src/main/java/org/radarbase/management/config/WebConfigurer.kt +++ b/src/main/java/org/radarbase/management/config/WebConfigurer.kt @@ -25,7 +25,7 @@ import javax.servlet.ServletContext * Configuration of web application with Servlet 3.0 APIs. */ @Configuration -class WebConfigurer : ServletContextInitializer, WebServerFactoryCustomizer { +open class WebConfigurer : ServletContextInitializer, WebServerFactoryCustomizer { @Autowired private val env: Environment? = null @@ -100,7 +100,7 @@ class WebConfigurer : ServletContextInitializer, WebServerFactoryCustomizer Date: Thu, 26 Oct 2023 17:14:08 +0200 Subject: [PATCH 029/158] Rename .java to .kt --- .../audit/{CustomRevisionEntity.java => CustomRevisionEntity.kt} | 0 .../{CustomRevisionMetadata.java => CustomRevisionMetadata.kt} | 0 .../domain/audit/{EntityAuditInfo.java => EntityAuditInfo.kt} | 0 .../domain/enumeration/{ProjectStatus.java => ProjectStatus.kt} | 0 .../management/domain/enumeration/{Role.java => Role.kt} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/domain/audit/{CustomRevisionEntity.java => CustomRevisionEntity.kt} (100%) rename src/main/java/org/radarbase/management/domain/audit/{CustomRevisionMetadata.java => CustomRevisionMetadata.kt} (100%) rename src/main/java/org/radarbase/management/domain/audit/{EntityAuditInfo.java => EntityAuditInfo.kt} (100%) rename src/main/java/org/radarbase/management/domain/enumeration/{ProjectStatus.java => ProjectStatus.kt} (100%) rename src/main/java/org/radarbase/management/domain/enumeration/{Role.java => Role.kt} (100%) diff --git a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.java b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt similarity index 100% rename from src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.java rename to src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt diff --git a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.java b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt similarity index 100% rename from src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.java rename to src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt diff --git a/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.java b/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt similarity index 100% rename from src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.java rename to src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt diff --git a/src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.java b/src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.kt similarity index 100% rename from src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.java rename to src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.kt diff --git a/src/main/java/org/radarbase/management/domain/enumeration/Role.java b/src/main/java/org/radarbase/management/domain/enumeration/Role.kt similarity index 100% rename from src/main/java/org/radarbase/management/domain/enumeration/Role.java rename to src/main/java/org/radarbase/management/domain/enumeration/Role.kt From 3e127d5ae34d6111047c1e22398882d483235eef Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Thu, 26 Oct 2023 17:14:08 +0200 Subject: [PATCH 030/158] gradle build works, only test fails --- build.gradle | 1 + .../authorization/MPAuthorizationOracle.kt | 8 +- .../radarbase/auth/token/DataRadarToken.kt | 4 +- .../org/radarbase/auth/token/RadarToken.kt | 4 +- .../config/AuthorizationConfiguration.kt | 3 +- .../config/audit/AuditEventConverter.kt | 4 +- .../management/domain/AbstractEntity.java | 18 - .../management/domain/AbstractEntity.kt | 17 + .../management/domain/Authority.java | 85 --- .../radarbase/management/domain/Authority.kt | 65 ++ .../radarbase/management/domain/Group.java | 115 ---- .../org/radarbase/management/domain/Group.kt | 79 +++ .../management/domain/MetaToken.java | 194 ------ .../radarbase/management/domain/MetaToken.kt | 164 +++++ .../management/domain/Organization.java | 127 ---- .../management/domain/Organization.kt | 81 +++ .../domain/PersistentAuditEvent.java | 98 --- .../management/domain/PersistentAuditEvent.kt | 57 ++ .../radarbase/management/domain/Project.java | 311 ---------- .../radarbase/management/domain/Project.kt | 207 +++++++ .../org/radarbase/management/domain/Role.java | 180 ------ .../org/radarbase/management/domain/Role.kt | 130 ++++ .../radarbase/management/domain/Source.java | 275 --------- .../org/radarbase/management/domain/Source.kt | 189 ++++++ .../management/domain/SourceData.java | 274 -------- .../radarbase/management/domain/SourceData.kt | 171 +++++ .../management/domain/SourceType.java | 270 -------- .../radarbase/management/domain/SourceType.kt | 163 +++++ .../radarbase/management/domain/Subject.java | 292 --------- .../radarbase/management/domain/Subject.kt | 207 +++++++ .../org/radarbase/management/domain/User.java | 248 -------- .../org/radarbase/management/domain/User.kt | 146 +++++ .../domain/audit/CustomRevisionEntity.kt | 148 ++--- .../domain/audit/CustomRevisionMetadata.kt | 57 +- .../domain/audit/EntityAuditInfo.kt | 91 ++- .../domain/enumeration/ProjectStatus.kt | 8 +- .../management/domain/enumeration/Role.kt | 4 +- .../management/domain/package-info.java | 4 - .../management/domain/package-info.kt | 5 + .../support/AbstractEntityListener.java | 85 --- .../domain/support/AbstractEntityListener.kt | 87 +++ .../domain/support/AutowireHelper.java | 51 -- .../domain/support/AutowireHelper.kt | 43 ++ .../CustomAuditEventRepository.java | 8 +- .../repository/GroupRepository.java | 38 -- .../management/repository/GroupRepository.kt | 40 ++ .../repository/ProjectRepository.java | 83 --- .../repository/ProjectRepository.kt | 101 +++ .../security/ClaimsTokenEnhancer.java | 12 +- .../security/DomainUserDetailsService.java | 6 +- .../security/JwtAuthenticationFilter.kt | 20 +- .../management/service/GroupService.java | 244 -------- .../management/service/GroupService.kt | 233 +++++++ .../management/service/MailService.java | 20 +- .../management/service/MetaTokenService.java | 236 ------- .../management/service/MetaTokenService.kt | 253 ++++++++ .../service/OAuthClientService.java | 2 +- .../service/OrganizationService.java | 2 +- .../management/service/ProjectService.java | 143 ----- .../management/service/ProjectService.kt | 134 ++++ .../service/ResourceUriService.java | 2 +- .../management/service/RevisionService.java | 391 ------------ .../management/service/RevisionService.kt | 401 ++++++++++++ .../management/service/RoleService.java | 271 -------- .../management/service/RoleService.kt | 270 ++++++++ .../management/service/SourceService.java | 261 -------- .../management/service/SourceService.kt | 267 ++++++++ .../management/service/SourceTypeService.java | 36 +- .../management/service/SubjectService.java | 546 ---------------- .../management/service/SubjectService.kt | 516 ++++++++++++++++ .../management/service/UserService.java | 434 ------------- .../management/service/UserService.kt | 428 +++++++++++++ .../management/service/dto/RevisionDTO.java | 2 +- .../service/dto/RevisionInfoDTO.java | 6 +- .../{SubjectMapper.java => SubjectMapper.kt} | 63 +- .../mapper/{UserMapper.java => UserMapper.kt} | 53 +- .../decorator/ProjectMapperDecorator.java | 8 +- .../mapper/decorator/RoleMapperDecorator.java | 4 +- .../decorator/SourceMapperDecorator.java | 6 +- .../decorator/SubjectMapperDecorator.java | 173 ------ .../decorator/SubjectMapperDecorator.kt | 146 +++++ .../web/rest/MetaTokenResource.java | 84 --- .../management/web/rest/MetaTokenResource.kt | 91 +++ .../web/rest/OAuthClientsResource.java | 224 ------- .../web/rest/OAuthClientsResource.kt | 243 ++++++++ .../management/web/rest/ProjectResource.java | 367 ----------- .../management/web/rest/ProjectResource.kt | 396 ++++++++++++ .../management/web/rest/SubjectResource.java | 572 ----------------- .../management/web/rest/SubjectResource.kt | 584 ++++++++++++++++++ .../management/web/rest/UserResource.java | 282 --------- .../management/web/rest/UserResource.kt | 280 +++++++++ .../auth/authentication/OAuthHelper.java | 2 +- .../service/UserServiceIntTest.java | 72 +-- .../web/rest/AccountResourceIntTest.java | 24 +- .../web/rest/AuditResourceIntTest.java | 8 +- .../web/rest/GroupResourceIntTest.java | 70 +-- .../web/rest/OrganizationResourceIntTest.java | 16 +- .../web/rest/ProjectResourceIntTest.java | 48 +- .../web/rest/SourceDataResourceIntTest.java | 42 +- .../web/rest/SourceResourceIntTest.java | 18 +- .../web/rest/SourceTypeResourceIntTest.java | 38 +- .../web/rest/SubjectResourceIntTest.java | 24 +- .../web/rest/UserResourceIntTest.java | 92 +-- 103 files changed, 6682 insertions(+), 7524 deletions(-) delete mode 100644 src/main/java/org/radarbase/management/domain/AbstractEntity.java create mode 100644 src/main/java/org/radarbase/management/domain/AbstractEntity.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Authority.java create mode 100644 src/main/java/org/radarbase/management/domain/Authority.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Group.java create mode 100644 src/main/java/org/radarbase/management/domain/Group.kt delete mode 100644 src/main/java/org/radarbase/management/domain/MetaToken.java create mode 100644 src/main/java/org/radarbase/management/domain/MetaToken.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Organization.java create mode 100644 src/main/java/org/radarbase/management/domain/Organization.kt delete mode 100644 src/main/java/org/radarbase/management/domain/PersistentAuditEvent.java create mode 100644 src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Project.java create mode 100644 src/main/java/org/radarbase/management/domain/Project.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Role.java create mode 100644 src/main/java/org/radarbase/management/domain/Role.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Source.java create mode 100644 src/main/java/org/radarbase/management/domain/Source.kt delete mode 100644 src/main/java/org/radarbase/management/domain/SourceData.java create mode 100644 src/main/java/org/radarbase/management/domain/SourceData.kt delete mode 100644 src/main/java/org/radarbase/management/domain/SourceType.java create mode 100644 src/main/java/org/radarbase/management/domain/SourceType.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Subject.java create mode 100644 src/main/java/org/radarbase/management/domain/Subject.kt delete mode 100644 src/main/java/org/radarbase/management/domain/User.java create mode 100644 src/main/java/org/radarbase/management/domain/User.kt delete mode 100644 src/main/java/org/radarbase/management/domain/package-info.java create mode 100644 src/main/java/org/radarbase/management/domain/package-info.kt delete mode 100644 src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.java create mode 100644 src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.kt delete mode 100644 src/main/java/org/radarbase/management/domain/support/AutowireHelper.java create mode 100644 src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt delete mode 100644 src/main/java/org/radarbase/management/repository/GroupRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/GroupRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/ProjectRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/ProjectRepository.kt delete mode 100644 src/main/java/org/radarbase/management/service/GroupService.java create mode 100644 src/main/java/org/radarbase/management/service/GroupService.kt delete mode 100644 src/main/java/org/radarbase/management/service/MetaTokenService.java create mode 100644 src/main/java/org/radarbase/management/service/MetaTokenService.kt delete mode 100644 src/main/java/org/radarbase/management/service/ProjectService.java create mode 100644 src/main/java/org/radarbase/management/service/ProjectService.kt delete mode 100644 src/main/java/org/radarbase/management/service/RevisionService.java create mode 100644 src/main/java/org/radarbase/management/service/RevisionService.kt delete mode 100644 src/main/java/org/radarbase/management/service/RoleService.java create mode 100644 src/main/java/org/radarbase/management/service/RoleService.kt delete mode 100644 src/main/java/org/radarbase/management/service/SourceService.java create mode 100644 src/main/java/org/radarbase/management/service/SourceService.kt delete mode 100644 src/main/java/org/radarbase/management/service/SubjectService.java create mode 100644 src/main/java/org/radarbase/management/service/SubjectService.kt delete mode 100644 src/main/java/org/radarbase/management/service/UserService.java create mode 100644 src/main/java/org/radarbase/management/service/UserService.kt rename src/main/java/org/radarbase/management/service/mapper/{SubjectMapper.java => SubjectMapper.kt} (65%) rename src/main/java/org/radarbase/management/service/mapper/{UserMapper.java => UserMapper.kt} (51%) delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/MetaTokenResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/MetaTokenResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/ProjectResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/ProjectResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/SubjectResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/SubjectResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/UserResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/UserResource.kt diff --git a/build.gradle b/build.gradle index 3041a9979..24c364e83 100644 --- a/build.gradle +++ b/build.gradle @@ -147,6 +147,7 @@ if (project.hasProperty('prod')) { ext.findbugAnnotationVersion = '3.0.2' dependencies { + implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.10") implementation("tech.jhipster:jhipster-framework:${jhipster_server_version}") implementation("tech.jhipster:jhipster-dependencies:${jhipster_server_version}") implementation("io.micrometer:micrometer-core") diff --git a/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt b/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt index 35601eeeb..804470a50 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt @@ -24,9 +24,10 @@ class MPAuthorizationOracle( if (identity.isClientCredentials) return true - return identity.roles.forkAny { + return identity.roles?.forkAny { it.hasPermission(identity, permission, entity, entityScope) } + ?: false } /** @@ -39,7 +40,8 @@ class MPAuthorizationOracle( if (identity.isClientCredentials) return true - return identity.roles.any { it.role.mayBeGranted(permission) } + return identity.roles?.any { it.role.mayBeGranted(permission) } + ?: false } /** @@ -61,7 +63,7 @@ class MPAuthorizationOracle( val projects = mutableSetOf() val personalProjects = mutableSetOf() - identity.roles.forEach { + identity.roles?.forEach { if (it.role.mayBeGranted(permission)) { when (it.role.scope) { RoleAuthority.Scope.GLOBAL -> global = true diff --git a/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt b/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt index 7a2392ee7..27bba10c1 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt @@ -12,7 +12,7 @@ data class DataRadarToken( * Get all roles defined in this token. * @return non-null set describing the roles defined in this token. */ - override val roles: Set, + override val roles: Set?, /** * Get a list of scopes assigned to this token. @@ -101,7 +101,7 @@ data class DataRadarToken( clientId = radarToken.clientId, ) - override fun copyWithRoles(roles: Set): DataRadarToken = copy(roles = roles) + override fun copyWithRoles(roles: Set?): DataRadarToken = copy(roles = roles) companion object { fun RadarToken.toDataRadarToken(): DataRadarToken = DataRadarToken(this) diff --git a/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt b/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt index 52acb36d9..39341d0c9 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt @@ -11,7 +11,7 @@ interface RadarToken { * Get all roles defined in this token. * @return non-null set describing the roles defined in this token. */ - val roles: Set + val roles: Set? /** * Get a list of scopes assigned to this token. @@ -92,7 +92,7 @@ interface RadarToken { val isClientCredentials: Boolean get() = grantType == CLIENT_CREDENTIALS - fun copyWithRoles(roles: Set): RadarToken + fun copyWithRoles(roles: Set?): RadarToken companion object { const val CLIENT_CREDENTIALS = "client_credentials" diff --git a/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt b/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt index 96900e083..6b479d296 100644 --- a/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt @@ -18,8 +18,7 @@ open class AuthorizationConfiguration( object : EntityRelationService { override suspend fun findOrganizationOfProject(project: String): String? = withContext(Dispatchers.IO) { projectRepository.findOneWithEagerRelationshipsByName(project) - .map { it.organization.name } - .orElse(null) + ?.organization?.name } } ) diff --git a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt index dcfb7f086..09b6872b6 100644 --- a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt +++ b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt @@ -34,8 +34,8 @@ class AuditEventConverter { * @return the converted list. */ fun convertToAuditEvent(persistentAuditEvent: PersistentAuditEvent): AuditEvent { - val instant = persistentAuditEvent.auditEventDate.atZone(ZoneId.systemDefault()) - .toInstant() + val instant = persistentAuditEvent.auditEventDate?.atZone(ZoneId.systemDefault()) + ?.toInstant() return AuditEvent( instant, persistentAuditEvent.principal, persistentAuditEvent.auditEventType, diff --git a/src/main/java/org/radarbase/management/domain/AbstractEntity.java b/src/main/java/org/radarbase/management/domain/AbstractEntity.java deleted file mode 100644 index b582ee903..000000000 --- a/src/main/java/org/radarbase/management/domain/AbstractEntity.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.radarbase.management.domain; - -import org.radarbase.management.domain.support.AbstractEntityListener; - -import java.io.Serializable; - -/** - * Base abstract class for entities which will hold definitions for created, last modified by and - * created, last modified by date. These will be populated by {@link AbstractEntityListener} on - * the {@code PostLoad} trigger. Since this class is not an Entity or a MappedSuperClass, we need - * to define the entitylistener on each of the subclasses. - */ -public abstract class AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - public abstract Long getId(); -} diff --git a/src/main/java/org/radarbase/management/domain/AbstractEntity.kt b/src/main/java/org/radarbase/management/domain/AbstractEntity.kt new file mode 100644 index 000000000..33247e352 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/AbstractEntity.kt @@ -0,0 +1,17 @@ +package org.radarbase.management.domain + +import java.io.Serializable + +/** + * Base abstract class for entities which will hold definitions for created, last modified by and + * created, last modified by date. These will be populated by [AbstractEntityListener] on + * the `PostLoad` trigger. Since this class is not an Entity or a MappedSuperClass, we need + * to define the entitylistener on each of the subclasses. + */ +abstract class AbstractEntity : Serializable { + abstract val id: Long? + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/Authority.java b/src/main/java/org/radarbase/management/domain/Authority.java deleted file mode 100644 index b45cae9d4..000000000 --- a/src/main/java/org/radarbase/management/domain/Authority.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.radarbase.management.domain; - -import java.io.Serializable; -import java.util.Objects; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.envers.Audited; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.security.Constants; - -/** - * An authority (a security role) used by Spring Security. - */ -@Entity -@Audited -@Table(name = "radar_authority") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -public class Authority implements Serializable { - - private static final long serialVersionUID = 1L; - - @NotNull - @Size(min = 0, max = 50) - @Id - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(length = 50) - private String name; - - public Authority() { - // builder constructor - } - - public Authority(String authorityName) { - this.name = authorityName; - } - - public Authority(RoleAuthority role) { - this(role.getAuthority()); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Authority authority = (Authority) o; - - if (name == null || authority.name == null) { - return false; - } - - return Objects.equals(name, authority.name); - } - - @Override - public int hashCode() { - return name != null ? name.hashCode() : 0; - } - - @Override - public String toString() { - return "Authority{" - + "name='" + name + '\'' - + "}"; - } -} diff --git a/src/main/java/org/radarbase/management/domain/Authority.kt b/src/main/java/org/radarbase/management/domain/Authority.kt new file mode 100644 index 000000000..773957f64 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Authority.kt @@ -0,0 +1,65 @@ +package org.radarbase.management.domain + +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.envers.Audited +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.security.Constants +import java.io.Serializable +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.Id +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern +import javax.validation.constraints.Size + +/** + * An authority (a security role) used by Spring Security. + */ +@Entity +@Audited +@Table(name = "radar_authority") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +class Authority : Serializable { + @JvmField + @Id + @Column(length = 50) + var name: @NotNull @Size(min = 0, max = 50) @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + constructor() + + constructor(authorityName: String?) { + name = authorityName + this.name = authorityName + } + + constructor(role: RoleAuthority) : this(role.authority) + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val authority = o as Authority + return if (name == null || authority.name == null) { + false + } else name == authority.name + } + + override fun hashCode(): Int { + return if (name != null) name.hashCode() else 0 + } + + override fun toString(): String { + return ("Authority{" + + "name='" + name + '\'' + + "}") + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/Group.java b/src/main/java/org/radarbase/management/domain/Group.java deleted file mode 100644 index ccbe4e851..000000000 --- a/src/main/java/org/radarbase/management/domain/Group.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2021 The Hyve and respective contributors. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.radarbase.management.security.Constants; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; - -import java.io.Serializable; -import java.util.Objects; - -/** - * A Group. - */ -@Entity -@Table(name = "radar_group") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -public class Group extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Size(min = 1, max = 50) - @Column(name = "name", length = 50, nullable = false) - private String name; - - @JsonIgnore - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "project_id", nullable = false) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Project project; - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Group group = (Group) o; - if (group.id == null || id == null) { - return false; - } - return Objects.equals(id, group.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "Group{" - + "id=" + id + ", " - + "name=" + name + ", " - + "project='" + project.getProjectName() + "', " - + "}"; - } - -} diff --git a/src/main/java/org/radarbase/management/domain/Group.kt b/src/main/java/org/radarbase/management/domain/Group.kt new file mode 100644 index 000000000..539378939 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Group.kt @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021 The Hyve and respective contributors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.radarbase.management.security.Constants +import java.io.Serializable +import java.util.* +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern +import javax.validation.constraints.Size + +/** + * A Group. + */ +@Entity +@Table(name = "radar_group") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +class Group : AbstractEntity(), Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @JvmField + @Column(name = "name", length = 50, nullable = false) + var name: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) String? = null + + @JvmField + @JsonIgnore + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "project_id", nullable = false) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var project: Project? = null + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val group = o as Group + return if (group.id == null || id == null) { + false + } else id == group.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("Group{" + + "id=" + id + ", " + + "name=" + name + ", " + + "project='" + project?.projectName + "', " + + "}") + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/MetaToken.java b/src/main/java/org/radarbase/management/domain/MetaToken.java deleted file mode 100644 index 1353037bc..000000000 --- a/src/main/java/org/radarbase/management/domain/MetaToken.java +++ /dev/null @@ -1,194 +0,0 @@ -package org.radarbase.management.domain; - -import java.time.Instant; -import java.util.Objects; -import java.util.concurrent.ThreadLocalRandom; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.envers.Audited; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.support.AbstractEntityListener; - -@Entity -@Audited -@Table(name = "radar_meta_token") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class MetaToken extends AbstractEntity { - private static final char[] ID_CHARS = { - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', - 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', - 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '-', '.' - }; - - //https://math.stackexchange.com/questions/889538/ - // probability-of-collision-with-randomly-generated-id - // Current length of tokenName is 8 for short-lived tokens, and double that - // for persistent tokens. - public static final int SHORT_ID_LENGTH = 8; - public static final int LONG_ID_LENGTH = 16; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Pattern(regexp = Constants.TOKEN_NAME_REGEX) - @Column(name = "token_name", nullable = false, unique = true) - private String tokenName; - - @Column(name = "fetched", nullable = false) - private Boolean fetched; - - @Column(name = "expiry_date") - private Instant expiryDate = null; - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "subject_id") - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Subject subject; - - @Column(name = "client_id", nullable = false) - private String clientId; - - @Column(name = "persistent", nullable = false) - private Boolean persistent; - - /** - * Generates a alphanumeric with '.' and '-' token name. Suggested token name lengths are - * {@link #SHORT_ID_LENGTH} for short-living tokens and {@link #LONG_ID_LENGTH} for long-living - * meta tokens. - * - * @param length token length - * @return this - */ - public MetaToken generateName(int length) { - ThreadLocalRandom random = ThreadLocalRandom.current(); - char[] tokenChars = new char[length]; - for (int i = 0; i < length; i++) { - tokenChars[i] = ID_CHARS[random.nextInt(ID_CHARS.length)]; - } - tokenName = String.valueOf(tokenChars); - return this; - } - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getTokenName() { - return tokenName; - } - - public MetaToken tokenName(String tokenName) { - this.tokenName = tokenName; - return this; - } - - public boolean isFetched() { - return fetched; - } - - public MetaToken fetched(boolean fetched) { - this.fetched = fetched; - return this; - } - - public Instant getExpiryDate() { - return expiryDate; - } - - public MetaToken expiryDate(Instant expiryDate) { - this.expiryDate = expiryDate; - return this; - } - - public Subject getSubject() { - return subject; - } - - public MetaToken subject(Subject subject) { - this.subject = subject; - return this; - } - - public String getClientId() { - return clientId; - } - - public MetaToken clientId(String clientId) { - this.clientId = clientId; - return this; - } - - public boolean isValid() { - return (persistent || !fetched) && Instant.now().isBefore(expiryDate); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MetaToken metaToken = (MetaToken) o; - return Objects.equals(id, metaToken.id) - && Objects.equals(tokenName, metaToken.tokenName) - && Objects.equals(fetched, metaToken.fetched) - && Objects.equals(expiryDate, metaToken.expiryDate) - && Objects.equals(clientId, metaToken.clientId) - && Objects.equals(subject, metaToken.subject) - && Objects.equals(persistent, metaToken.persistent); - } - - @Override - public int hashCode() { - return Objects.hash(id, tokenName, fetched, expiryDate, subject, clientId, persistent); - } - - @Override - public String toString() { - return "MetaToken{" + "id=" + id - + ", tokenName='" + tokenName - + ", fetched=" + fetched - + ", expiryDate=" + expiryDate - + ", subject=" + subject - + ", clientId=" + clientId - + ", persistent=" + persistent - + '}'; - } - - public boolean isPersistent() { - return persistent; - } - - public MetaToken persistent(boolean persistent) { - this.persistent = persistent; - return this; - } -} diff --git a/src/main/java/org/radarbase/management/domain/MetaToken.kt b/src/main/java/org/radarbase/management/domain/MetaToken.kt new file mode 100644 index 000000000..5980d8329 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/MetaToken.kt @@ -0,0 +1,164 @@ +package org.radarbase.management.domain + +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.envers.Audited +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.time.Instant +import java.util.* +import java.util.concurrent.ThreadLocalRandom +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern + +@Entity +@Audited +@Table(name = "radar_meta_token") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class MetaToken : AbstractEntity() { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @Column(name = "token_name", nullable = false, unique = true) + var tokenName: @NotNull @Pattern(regexp = Constants.TOKEN_NAME_REGEX) String? = null + private set + + @Column(name = "fetched", nullable = false) + private var fetched: Boolean? = null + + @Column(name = "expiry_date") + var expiryDate: Instant? = null + private set + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "subject_id") + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var subject: Subject? = null + private set + + @Column(name = "client_id", nullable = false) + var clientId: String? = null + private set + + @Column(name = "persistent", nullable = false) + private var persistent: Boolean? = null + + /** + * Generates a alphanumeric with '.' and '-' token name. Suggested token name lengths are + * [.SHORT_ID_LENGTH] for short-living tokens and [.LONG_ID_LENGTH] for long-living + * meta tokens. + * + * @param length token length + * @return this + */ + fun generateName(length: Int): MetaToken { + val random = ThreadLocalRandom.current() + val tokenChars = CharArray(length) + for (i in 0 until length) { + tokenChars[i] = ID_CHARS[random.nextInt(ID_CHARS.size)] + } + tokenName = String(tokenChars) + return this + } + + fun tokenName(tokenName: String?): MetaToken { + this.tokenName = tokenName + return this + } + + fun isFetched(): Boolean { + return fetched!! + } + + fun fetched(fetched: Boolean): MetaToken { + this.fetched = fetched + return this + } + + fun expiryDate(expiryDate: Instant?): MetaToken { + this.expiryDate = expiryDate + return this + } + + fun subject(subject: Subject?): MetaToken { + this.subject = subject + return this + } + + fun clientId(clientId: String?): MetaToken { + this.clientId = clientId + return this + } + + val isValid: Boolean + get() = (persistent!! || !fetched!!) && Instant.now().isBefore(expiryDate) + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val metaToken = o as MetaToken + return id == metaToken.id && tokenName == metaToken.tokenName && fetched == metaToken.fetched && expiryDate == metaToken.expiryDate && clientId == metaToken.clientId && subject == metaToken.subject && persistent == metaToken.persistent + } + + override fun hashCode(): Int { + return Objects.hash(id, tokenName, fetched, expiryDate, subject, clientId, persistent) + } + + override fun toString(): String { + return ("MetaToken{" + "id=" + id + + ", tokenName='" + tokenName + + ", fetched=" + fetched + + ", expiryDate=" + expiryDate + + ", subject=" + subject + + ", clientId=" + clientId + + ", persistent=" + persistent + + '}') + } + + fun isPersistent(): Boolean { + return persistent!! + } + + fun persistent(persistent: Boolean): MetaToken { + this.persistent = persistent + return this + } + + companion object { + private val ID_CHARS = charArrayOf( + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', + 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', + 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '-', '.' + ) + + //https://math.stackexchange.com/questions/889538/ + // probability-of-collision-with-randomly-generated-id + // Current length of tokenName is 8 for short-lived tokens, and double that + // for persistent tokens. + const val SHORT_ID_LENGTH = 8 + const val LONG_ID_LENGTH = 16 + } +} diff --git a/src/main/java/org/radarbase/management/domain/Organization.java b/src/main/java/org/radarbase/management/domain/Organization.java deleted file mode 100644 index 108587d6e..000000000 --- a/src/main/java/org/radarbase/management/domain/Organization.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.radarbase.management.domain; - -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.envers.Audited; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToMany; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.util.List; -import java.util.Objects; - -/** - * An Organization. - */ -@Entity -@Audited -@Table(name = "radar_organization") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class Organization extends AbstractEntity { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "name", nullable = false, unique = true) - private String name; - - @NotNull - @Column(name = "description", nullable = false) - private String description; - - @NotNull - @Column(name = "location", nullable = false) - private String location; - - @OneToMany(mappedBy = "organization") - private List projects; - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - - public List getProjects() { - return projects; - } - - public void setProjects(List projects) { - this.projects = projects; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - var org = (Organization) o; - if (org.id == null || id == null) { - return false; - } - return Objects.equals(id, org.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "Organization{" - + "id=" + id - + ", name='" + name + "'" - + ", description='" + description + "'" - + ", location='" + location + "'" - + "}"; - } -} diff --git a/src/main/java/org/radarbase/management/domain/Organization.kt b/src/main/java/org/radarbase/management/domain/Organization.kt new file mode 100644 index 000000000..479a0f708 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Organization.kt @@ -0,0 +1,81 @@ +package org.radarbase.management.domain + +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.envers.Audited +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.util.* +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.OneToMany +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern + +/** + * An Organization. + */ +@Entity +@Audited +@Table(name = "radar_organization") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class Organization : AbstractEntity() { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @JvmField + @Column(name = "name", nullable = false, unique = true) + var name: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + @JvmField + @Column(name = "description", nullable = false) + var description: @NotNull String? = null + + @JvmField + @Column(name = "location", nullable = false) + var location: @NotNull String? = null + + @JvmField + @OneToMany(mappedBy = "organization") + var projects: List? = null + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val org = o as Organization + return if (org.id == null || id == null) { + false + } else id == org.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("Organization{" + + "id=" + id + + ", name='" + name + "'" + + ", description='" + description + "'" + + ", location='" + location + "'" + + "}") + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.java b/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.java deleted file mode 100644 index 09e21d02b..000000000 --- a/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.radarbase.management.domain; - - -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; - -import java.io.Serializable; -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.Map; -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.MapKeyColumn; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; - -/** - * Persist AuditEvent managed by the Spring Boot actuator. - * - * @see org.springframework.boot.actuate.audit.AuditEvent - */ -@Entity -@Table(name = "jhi_persistent_audit_event") -public class PersistentAuditEvent implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - @Column(name = "event_id") - private Long id; - - @NotNull - @Column(nullable = false) - private String principal; - - @Column(name = "event_date") - private LocalDateTime auditEventDate; - @Column(name = "event_type") - private String auditEventType; - - @ElementCollection - @MapKeyColumn(name = "name") - @Column(name = "value") - @CollectionTable(name = "jhi_persistent_audit_evt_data", - joinColumns = @JoinColumn(name = "event_id")) - private Map data = new HashMap<>(); - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getPrincipal() { - return principal; - } - - public void setPrincipal(String principal) { - this.principal = principal; - } - - public LocalDateTime getAuditEventDate() { - return auditEventDate; - } - - public void setAuditEventDate(LocalDateTime auditEventDate) { - this.auditEventDate = auditEventDate; - } - - public String getAuditEventType() { - return auditEventType; - } - - public void setAuditEventType(String auditEventType) { - this.auditEventType = auditEventType; - } - - public Map getData() { - return data; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setData(Map data) { - this.data = data; - } -} diff --git a/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt b/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt new file mode 100644 index 000000000..9f04a713f --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt @@ -0,0 +1,57 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import java.io.Serializable +import java.time.LocalDateTime +import javax.persistence.CollectionTable +import javax.persistence.Column +import javax.persistence.ElementCollection +import javax.persistence.Entity +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.MapKeyColumn +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull + +/** + * Persist AuditEvent managed by the Spring Boot actuator. + * + * @see org.springframework.boot.actuate.audit.AuditEvent + */ +@Entity +@Table(name = "jhi_persistent_audit_event") +class PersistentAuditEvent : Serializable { + @JvmField + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + @Column(name = "event_id") + var id: Long? = null + + @JvmField + @Column(nullable = false) + var principal: @NotNull String? = null + + @JvmField + @Column(name = "event_date") + var auditEventDate: LocalDateTime? = null + + @JvmField + @Column(name = "event_type") + var auditEventType: String? = null + + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ElementCollection + @MapKeyColumn(name = "name") + @Column(name = "value") + @CollectionTable(name = "jhi_persistent_audit_evt_data", joinColumns = [JoinColumn(name = "event_id")]) + var data: Map = HashMap() + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/Project.java b/src/main/java/org/radarbase/management/domain/Project.java deleted file mode 100644 index 04f6c9c27..000000000 --- a/src/main/java/org/radarbase/management/domain/Project.java +++ /dev/null @@ -1,311 +0,0 @@ -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.CascadeType; -import org.hibernate.annotations.DynamicInsert; -import org.hibernate.envers.Audited; -import org.hibernate.envers.NotAudited; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.enumeration.ProjectStatus; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.MapKeyColumn; -import javax.persistence.OneToMany; -import javax.persistence.OrderBy; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.io.Serializable; -import java.time.ZonedDateTime; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -import static javax.persistence.CascadeType.DETACH; -import static javax.persistence.CascadeType.REFRESH; -import static javax.persistence.CascadeType.REMOVE; - -/** - * A Project. - */ -@Entity -@Audited -@Table(name = "project") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -@DynamicInsert -public class Project extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "project_name", nullable = false, unique = true) - private String projectName; - - @NotNull - @Column(name = "description", nullable = false) - private String description; - - @Column(name = "jhi_organization") - private String organizationName; - - @ManyToOne(fetch = FetchType.EAGER) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Organization organization; - - @NotNull - @Column(name = "location", nullable = false) - private String location; - - @Column(name = "start_date") - private ZonedDateTime startDate; - - @Enumerated(EnumType.STRING) - @Column(name = "project_status") - private ProjectStatus projectStatus; - - @Column(name = "end_date") - private ZonedDateTime endDate; - - @JsonIgnore - @OneToMany(mappedBy = "project", fetch = FetchType.LAZY) - @Cascade(CascadeType.ALL) - private Set roles = new HashSet<>(); - - @ManyToMany(fetch = FetchType.LAZY) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @JoinTable(name = "project_source_type", - joinColumns = @JoinColumn(name = "projects_id", referencedColumnName = "id"), - inverseJoinColumns = @JoinColumn(name = "source_types_id", referencedColumnName = "id")) - private Set sourceTypes = new HashSet<>(); - - @ElementCollection(fetch = FetchType.EAGER) - @MapKeyColumn(name = "attribute_key") - @Column(name = "attribute_value") - @CollectionTable(name = "project_metadata", joinColumns = @JoinColumn(name = "id")) - private Map attributes = new HashMap<>(); - - @NotAudited - @OneToMany(mappedBy = "project", fetch = FetchType.LAZY, orphanRemoval = true, - cascade = {REMOVE, REFRESH, DETACH}) - @OrderBy("name ASC") - private Set groups = new HashSet<>(); - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getProjectName() { - return projectName; - } - - public Project projectName(String projectName) { - this.projectName = projectName; - return this; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - public String getDescription() { - return description; - } - - public Project description(String description) { - this.description = description; - return this; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getOrganizationName() { - return organizationName; - } - - public Project organizationName(String organizationName) { - this.organizationName = organizationName; - return this; - } - - public Set getRoles() { - return roles; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setRoles(Set roles) { - this.roles = roles; - } - - public void setOrganizationName(String organizationName) { - this.organizationName = organizationName; - } - - public Organization getOrganization() { - return organization; - } - - public Project organization(Organization organization) { - this.organization = organization; - return this; - } - - public void setOrganization(Organization organization) { - this.organization = organization; - } - - public String getLocation() { - return location; - } - - public Project location(String location) { - this.location = location; - return this; - } - - public void setLocation(String location) { - this.location = location; - } - - public ZonedDateTime getStartDate() { - return startDate; - } - - public Project startDate(ZonedDateTime startDate) { - this.startDate = startDate; - return this; - } - - public void setStartDate(ZonedDateTime startDate) { - this.startDate = startDate; - } - - public ProjectStatus getProjectStatus() { - return projectStatus; - } - - public Project projectStatus(ProjectStatus projectStatus) { - this.projectStatus = projectStatus; - return this; - } - - public void setProjectStatus(ProjectStatus projectStatus) { - this.projectStatus = projectStatus; - } - - public ZonedDateTime getEndDate() { - return endDate; - } - - public Project endDate(ZonedDateTime endDate) { - this.endDate = endDate; - return this; - } - - public void setEndDate(ZonedDateTime endDate) { - this.endDate = endDate; - } - - public Set getSourceTypes() { - return sourceTypes; - } - - public Project sourceTypes(Set sourceTypes) { - this.sourceTypes = sourceTypes; - return this; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setSourceTypes(Set sourceTypes) { - this.sourceTypes = sourceTypes; - } - - public Map getAttributes() { - return attributes; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - public Set getGroups() { - return groups; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setGroups(Set groups) { - this.groups = groups; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Project project = (Project) o; - if (project.id == null || id == null) { - return false; - } - return Objects.equals(id, project.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "Project{" - + "id=" + id - + ", projectName='" + projectName + "'" - + ", description='" + description + "'" - + ", organization='" + organizationName + "'" - + ", location='" + location + "'" - + ", startDate='" + startDate + "'" - + ", projectStatus='" + projectStatus + "'" - + ", endDate='" + endDate + "'" - + "}"; - } -} diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt new file mode 100644 index 000000000..a6da31807 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -0,0 +1,207 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.annotations.Cascade +import org.hibernate.annotations.CascadeType +import org.hibernate.annotations.DynamicInsert +import org.hibernate.envers.Audited +import org.hibernate.envers.NotAudited +import org.radarbase.management.domain.enumeration.ProjectStatus +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.io.Serializable +import java.time.ZonedDateTime +import java.util.* +import javax.persistence.CollectionTable +import javax.persistence.Column +import javax.persistence.ElementCollection +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.EnumType +import javax.persistence.Enumerated +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.JoinTable +import javax.persistence.ManyToMany +import javax.persistence.ManyToOne +import javax.persistence.MapKeyColumn +import javax.persistence.OneToMany +import javax.persistence.OrderBy +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern + +/** + * A Project. + */ +@Entity +@Audited +@Table(name = "project") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +@DynamicInsert +class Project : AbstractEntity(), Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @JvmField + @Column(name = "project_name", nullable = false, unique = true) + var projectName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + @JvmField + @Column(name = "description", nullable = false) + var description: @NotNull String? = null + + @JvmField + @Column(name = "jhi_organization") + var organizationName: String? = null + + @JvmField + @ManyToOne(fetch = FetchType.EAGER) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var organization: Organization? = null + + @JvmField + @Column(name = "location", nullable = false) + var location: @NotNull String? = null + + @JvmField + @Column(name = "start_date") + var startDate: ZonedDateTime? = null + + @JvmField + @Enumerated(EnumType.STRING) + @Column(name = "project_status") + var projectStatus: ProjectStatus? = null + + @JvmField + @Column(name = "end_date") + var endDate: ZonedDateTime? = null + + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonIgnore + @OneToMany(mappedBy = "project", fetch = FetchType.LAZY) + @Cascade(CascadeType.ALL) + var roles: Set = HashSet() + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ManyToMany(fetch = FetchType.LAZY) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @JoinTable( + name = "project_source_type", + joinColumns = [JoinColumn(name = "projects_id", referencedColumnName = "id")], + inverseJoinColumns = [JoinColumn(name = "source_types_id", referencedColumnName = "id")] + ) + var sourceTypes: Set = HashSet() + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ElementCollection(fetch = FetchType.EAGER) + @MapKeyColumn(name = "attribute_key") + @Column(name = "attribute_value") + @CollectionTable(name = "project_metadata", joinColumns = [JoinColumn(name = "id")]) + var attributes: Map = HashMap() + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @NotAudited + @OneToMany( + mappedBy = "project", + fetch = FetchType.LAZY, + orphanRemoval = true, + cascade = [javax.persistence.CascadeType.REMOVE, javax.persistence.CascadeType.REFRESH, javax.persistence.CascadeType.DETACH] + ) + @OrderBy("name ASC") + var groups: MutableSet = HashSet() + fun projectName(projectName: String?): Project { + this.projectName = projectName + return this + } + + fun description(description: String?): Project { + this.description = description + return this + } + + fun organizationName(organizationName: String?): Project { + this.organizationName = organizationName + return this + } + + fun organization(organization: Organization?): Project { + this.organization = organization + return this + } + + fun location(location: String?): Project { + this.location = location + return this + } + + fun startDate(startDate: ZonedDateTime?): Project { + this.startDate = startDate + return this + } + + fun projectStatus(projectStatus: ProjectStatus?): Project { + this.projectStatus = projectStatus + return this + } + + fun endDate(endDate: ZonedDateTime?): Project { + this.endDate = endDate + return this + } + + fun sourceTypes(sourceTypes: Set): Project { + this.sourceTypes = sourceTypes + return this + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val project = o as Project + return if (project.id == null || id == null) { + false + } else id == project.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("Project{" + + "id=" + id + + ", projectName='" + projectName + "'" + + ", description='" + description + "'" + + ", organization='" + organizationName + "'" + + ", location='" + location + "'" + + ", startDate='" + startDate + "'" + + ", projectStatus='" + projectStatus + "'" + + ", endDate='" + endDate + "'" + + "}") + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/Role.java b/src/main/java/org/radarbase/management/domain/Role.java deleted file mode 100644 index 501078f17..000000000 --- a/src/main/java/org/radarbase/management/domain/Role.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2017 The Hyve and respective contributors. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import javax.persistence.FetchType; - -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.envers.Audited; -import org.hibernate.envers.RelationTargetAuditMode; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import java.io.Serializable; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -/** - * A Role. - */ -@Entity -@Audited -@Table(name = "radar_role") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class Role extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY) - @JsonIgnore - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) - private Set users = new HashSet<>(); - - @ManyToOne(fetch = FetchType.EAGER) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Project project; - - @ManyToOne(fetch = FetchType.EAGER) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Organization organization; - - @JsonProperty() - @ManyToOne(fetch = FetchType.EAGER) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @JoinColumn(name = "authority_name", referencedColumnName = "name") - private Authority authority; - - public Role() { - // constructor for reflection - } - - public Role(Authority authority, Project project) { - this.authority = authority; - this.project = project; - } - - public Role(Authority authority) { - this.authority = authority; - } - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Set getUsers() { - return users; - } - - public Role users(Set users) { - this.users = users; - return this; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setUsers(Set users) { - this.users = users; - } - - public Organization getOrganization() { - return organization; - } - - public void setOrganization(Organization organization) { - this.organization = organization; - } - - public Project getProject() { - return project; - } - - public Role project(Project project) { - this.project = project; - return this; - } - - public void setProject(Project project) { - this.project = project; - } - - public Authority getAuthority() { - return authority; - } - - public RoleAuthority getRole() { - return RoleAuthority.valueOfAuthorityOrNull(authority.getName()); - } - - public Role authority(Authority authority) { - this.authority = authority; - return this; - } - - public void setAuthority(Authority authority) { - this.authority = authority; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Role role = (Role) o; - return Objects.equals(authority, role.authority) - && Objects.equals(project, role.project) - && Objects.equals(organization, role.organization); - } - - @Override - public int hashCode() { - return Objects.hash(authority, project, organization); - } - - @Override - public String toString() { - return "Role{" - + "id=" + id + ", " - + "organization='" + (organization == null ? "null" : organization.getName()) - + "', " - + "project='" + (project == null ? "null" : project.getProjectName()) + "', " - + "authority='" + getAuthority().getName() + "', " - + "}"; - } - -} diff --git a/src/main/java/org/radarbase/management/domain/Role.kt b/src/main/java/org/radarbase/management/domain/Role.kt new file mode 100644 index 000000000..b71751401 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Role.kt @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2017 The Hyve and respective contributors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.envers.Audited +import org.hibernate.envers.RelationTargetAuditMode +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.auth.authorization.RoleAuthority.Companion.valueOfAuthorityOrNull +import org.radarbase.management.domain.support.AbstractEntityListener +import java.io.Serializable +import java.util.* +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToMany +import javax.persistence.ManyToOne +import javax.persistence.SequenceGenerator +import javax.persistence.Table + +/** + * A Role. + */ +@Entity +@Audited +@Table(name = "radar_role") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class Role : AbstractEntity, Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY) + @JsonIgnore + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) + var users: Set = HashSet() + + @JvmField + @ManyToOne(fetch = FetchType.EAGER) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var project: Project? = null + + @JvmField + @ManyToOne(fetch = FetchType.EAGER) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var organization: Organization? = null + + @JvmField + @JsonProperty + @ManyToOne(fetch = FetchType.EAGER) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @JoinColumn(name = "authority_name", referencedColumnName = "name") + var authority: Authority? = null + + constructor() + constructor(authority: Authority?, project: Project?) { + this.authority = authority + this.project = project + } + + constructor(authority: Authority?) { + this.authority = authority + } + + fun users(users: Set): Role { + this.users = users + return this + } + + fun project(project: Project?): Role { + this.project = project + return this + } + + val role: RoleAuthority? + get() = valueOfAuthorityOrNull(authority?.name!!) + + fun authority(authority: Authority?): Role { + this.authority = authority + return this + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val role = o as Role + return authority == role.authority && project == role.project && organization == role.organization + } + + override fun hashCode(): Int { + return Objects.hash(authority, project, organization) + } + + override fun toString(): String { + return ("Role{" + + "id=" + id + ", " + + "organization='" + (if (organization == null) "null" else organization?.name) + + "', " + + "project='" + (if (project == null) "null" else project?.projectName) + "', " + + "authority='" + authority?.name + "', " + + "}") + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/Source.java b/src/main/java/org/radarbase/management/domain/Source.java deleted file mode 100644 index bffb3828d..000000000 --- a/src/main/java/org/radarbase/management/domain/Source.java +++ /dev/null @@ -1,275 +0,0 @@ -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.envers.Audited; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.MapKeyColumn; -import javax.persistence.PrePersist; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; - -/** - * A Source. - */ -@Entity -@Audited -@Table(name = "radar_source") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class Source extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Column(name = "source_id", nullable = false, unique = true) - private UUID sourceId; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "source_name", nullable = false, unique = true) - private String sourceName; - - @Column(name = "expected_source_name") - private String expectedSourceName; - - @NotNull - @Column(name = "assigned", nullable = false) - private Boolean assigned; - - @NotNull - @Column(name = "deleted", nullable = false) - private Boolean deleted = false; - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "subject_id") - @JsonIgnore - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Subject subject; - - @ManyToOne(fetch = FetchType.EAGER) - private SourceType sourceType; - - @ManyToOne(fetch = FetchType.LAZY) - private Project project; - - @ElementCollection(fetch = FetchType.EAGER) - @MapKeyColumn(name = "attribute_key") - @Column(name = "attribute_value") - @CollectionTable(name = "source_metadata", joinColumns = @JoinColumn(name = "id")) - private Map attributes = new HashMap<>(); - - /** - * Default constructor. Needed for other JPA operations. - */ - public Source() { - // default constructor - } - - /** - * Constructor with SourceType. This will assign sourceType and assign default values for - * sourceId and sourceName. - * @param sourceType sourceType of the source. - */ - public Source(SourceType sourceType) { - this.sourceType = sourceType; - this.generateUuid(); - } - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public UUID getSourceId() { - return sourceId; - } - - public Source sourceId(UUID devicePhysicalId) { - this.sourceId = devicePhysicalId; - return this; - } - - public void setSourceId(UUID sourceId) { - // pass - this.sourceId = sourceId; - } - - /** - * Add default values for sourceId and sourceName if they are not provided before persisting - * this object. The default for sourceId is to generate a new UUID. The default for - * sourceName is to take to model name, and append a dash followed by the first 8 characters - * of the string representation of the UUID. - */ - @PrePersist - public final void generateUuid() { - if (this.sourceId == null) { - this.sourceId = UUID.randomUUID(); - } - if (this.sourceName == null) { - this.sourceName = String.join("-", this.getSourceType().getModel(), - this.sourceId.toString().substring(0, 8)); - } - } - - public Boolean isAssigned() { - return assigned; - } - - public Source assigned(Boolean assigned) { - this.assigned = assigned; - return this; - } - - public void setAssigned(Boolean assigned) { - this.assigned = assigned; - } - - public Boolean isDeleted() { - return deleted; - } - - public Source deleted(Boolean deleted) { - this.deleted = deleted; - return this; - } - - public void setDeleted(Boolean deleted) { - this.deleted = deleted; - } - - public void setSourceType(SourceType sourceType) { - this.sourceType = sourceType; - } - - public SourceType getSourceType() { - return sourceType; - } - - public Source sourceType(SourceType sourceType) { - this.sourceType = sourceType; - return this; - } - - public void setProject(Project project) { - this.project = project; - } - - public Project getProject() { - return project; - } - - public Source project(Project project) { - this.project = project; - return this; - } - - public Subject getSubject() { - return subject; - } - - public Source subject(Subject subject) { - this.subject = subject; - return this; - } - - public String getSourceName() { - return sourceName; - } - - public void setSourceName(String sourceName) { - this.sourceName = sourceName; - } - - public Source sourceName(String sourceName) { - this.sourceName = sourceName; - return this; - } - - public String getExpectedSourceName() { - return expectedSourceName; - } - - public void setExpectedSourceName(String expectedSourceName) { - this.expectedSourceName = expectedSourceName; - } - - public Map getAttributes() { - return attributes; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - public void setSubject(Subject subject) { - this.subject = subject; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Source source = (Source) o; - if (source.id == null || id == null) { - return false; - } - return Objects.equals(id, source.id) - && Objects.equals(sourceId, source.sourceId); - } - - @Override - public int hashCode() { - return Objects.hash(id , sourceId); - } - - @Override - public String toString() { - return "Source{" - + "id=" + id - + ", sourceId='" + sourceId + '\'' - + ", sourceName='" + sourceName + '\'' - + ", assigned=" + assigned - + ", sourceType=" + sourceType - + ", project=" + project - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/domain/Source.kt b/src/main/java/org/radarbase/management/domain/Source.kt new file mode 100644 index 000000000..7e308f5f9 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Source.kt @@ -0,0 +1,189 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.envers.Audited +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.io.Serializable +import java.util.* +import javax.persistence.CollectionTable +import javax.persistence.Column +import javax.persistence.ElementCollection +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne +import javax.persistence.MapKeyColumn +import javax.persistence.PrePersist +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern + +/** + * A Source. + */ +@Entity +@Audited +@Table(name = "radar_source") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class Source : AbstractEntity, Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + // pass + @JvmField + @Column(name = "source_id", nullable = false, unique = true) + var sourceId: @NotNull UUID? = null + + @JvmField + @Column(name = "source_name", nullable = false, unique = true) + var sourceName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + @JvmField + @Column(name = "expected_source_name") + var expectedSourceName: String? = null + + @Column(name = "assigned", nullable = false) + var isAssigned: @NotNull Boolean? = null + + @Column(name = "deleted", nullable = false) + var isDeleted: @NotNull Boolean? = false + + @JvmField + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "subject_id") + @JsonIgnore + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var subject: Subject? = null + + @JvmField + @ManyToOne(fetch = FetchType.EAGER) + var sourceType: SourceType? = null + + @JvmField + @ManyToOne(fetch = FetchType.LAZY) + var project: Project? = null + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ElementCollection(fetch = FetchType.EAGER) + @MapKeyColumn(name = "attribute_key") + @Column(name = "attribute_value") + @CollectionTable(name = "source_metadata", joinColumns = [JoinColumn(name = "id")]) + var attributes: Map = HashMap() + + /** + * Default constructor. Needed for other JPA operations. + */ + constructor() + + /** + * Constructor with SourceType. This will assign sourceType and assign default values for + * sourceId and sourceName. + * @param sourceType sourceType of the source. + */ + constructor(sourceType: SourceType?) { + this.sourceType = sourceType + generateUuid() + } + + fun sourceId(devicePhysicalId: UUID?): Source { + sourceId = devicePhysicalId + return this + } + + /** + * Add default values for sourceId and sourceName if they are not provided before persisting + * this object. The default for sourceId is to generate a new UUID. The default for + * sourceName is to take to model name, and append a dash followed by the first 8 characters + * of the string representation of the UUID. + */ + @PrePersist + fun generateUuid() { + if (sourceId == null) { + sourceId = UUID.randomUUID() + } + if (sourceName == null) { + sourceName = java.lang.String.join( + "-", sourceType?.model, + sourceId.toString().substring(0, 8) + ) + } + } + + fun assigned(assigned: Boolean?): Source { + isAssigned = assigned + return this + } + + fun deleted(deleted: Boolean?): Source { + isDeleted = deleted + return this + } + + fun sourceType(sourceType: SourceType?): Source { + this.sourceType = sourceType + return this + } + + fun project(project: Project?): Source { + this.project = project + return this + } + + fun subject(subject: Subject?): Source { + this.subject = subject + return this + } + + fun sourceName(sourceName: String?): Source { + this.sourceName = sourceName + return this + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val source = o as Source + return if (source.id == null || id == null) { + false + } else id == source.id && sourceId == source.sourceId + } + + override fun hashCode(): Int { + return Objects.hash(id, sourceId) + } + + override fun toString(): String { + return ("Source{" + + "id=" + id + + ", sourceId='" + sourceId + '\'' + + ", sourceName='" + sourceName + '\'' + + ", assigned=" + isAssigned + + ", sourceType=" + sourceType + + ", project=" + project + + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/SourceData.java b/src/main/java/org/radarbase/management/domain/SourceData.java deleted file mode 100644 index 0e222c656..000000000 --- a/src/main/java/org/radarbase/management/domain/SourceData.java +++ /dev/null @@ -1,274 +0,0 @@ -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.envers.Audited; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToOne; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.io.Serializable; -import java.util.Objects; - -/** - * A SourceData. - */ -@Entity -@Audited -@Table(name = "source_data") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class SourceData extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - //SourceData type e.g. ACCELEROMETER, TEMPERATURE. - @NotNull - @Column(name = "source_data_type", nullable = false) - private String sourceDataType; - - // this will be the unique human readable identifier of - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "source_data_name", nullable = false, unique = true) - private String sourceDataName; - - //Default data frequency - @Column(name = "frequency") - private String frequency; - - //Measurement unit. - @Column(name = "unit") - private String unit; - - // Define if the samples are RAW data or instead they the result of some computation - @Column(name = "processing_state") - private String processingState; - - // the storage - @Column(name = "data_class") - private String dataClass; - - @Column(name = "key_schema") - private String keySchema; - - - @Column(name = "value_schema") - private String valueSchema; - - // source data topic - @Column(name = "topic") - private String topic; - - // app provider - @Column(name = "provider") - private String provider; - - @Column(name = "enabled") - private boolean enabled = true; - - @ManyToOne(fetch = FetchType.LAZY) - @JsonIgnoreProperties({"sourceData"}) // avoids infinite recursion in JSON serialization - private SourceType sourceType; - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getSourceDataType() { - return sourceDataType; - } - - public SourceData sourceDataType(String sourceDataType) { - this.sourceDataType = sourceDataType; - return this; - } - - public SourceData sourceDataName(String sourceDataName) { - this.sourceDataName = sourceDataName; - return this; - } - - public void setSourceDataType(String sourceDataType) { - this.sourceDataType = sourceDataType; - } - - public String getProcessingState() { - return processingState; - } - - public SourceData processingState(String processingState) { - this.processingState = processingState; - return this; - } - - public void setProcessingState(String processingState) { - this.processingState = processingState; - } - - public String getKeySchema() { - return keySchema; - } - - public SourceData keySchema(String keySchema) { - this.keySchema = keySchema; - return this; - } - - public void setKeySchema(String keySchema) { - this.keySchema = keySchema; - } - - public String getFrequency() { - return frequency; - } - - public SourceData frequency(String frequency) { - this.frequency = frequency; - return this; - } - - public void setFrequency(String frequency) { - this.frequency = frequency; - } - - public SourceType getSourceType() { - return sourceType; - } - - public void setSourceType(SourceType sourceType) { - this.sourceType = sourceType; - } - - public SourceData sourceType(SourceType sourceType) { - this.sourceType = sourceType; - return this; - } - - public String getUnit() { - return unit; - } - - public void setUnit(String unit) { - this.unit = unit; - } - - public SourceData unit(String unit) { - this.unit = unit; - return this; - } - - - public String getDataClass() { - return dataClass; - } - - public void setDataClass(String dataClass) { - this.dataClass = dataClass; - } - - public String getValueSchema() { - return valueSchema; - } - - public void setValueSchema(String valueSchema) { - this.valueSchema = valueSchema; - } - - public SourceData valueSchema(String valueSchema) { - this.valueSchema = valueSchema; - return this; - } - - public String getTopic() { - return topic; - } - - public void setTopic(String topic) { - this.topic = topic; - } - - public SourceData topic(String topic) { - this.topic = topic; - return this; - } - - public String getProvider() { - return provider; - } - - public void setProvider(String provider) { - this.provider = provider; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getSourceDataName() { - return sourceDataName; - } - - public void setSourceDataName(String sourceDataName) { - this.sourceDataName = sourceDataName; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - SourceData sourceData = (SourceData) o; - if (sourceData.id == null || id == null) { - return false; - } - return Objects.equals(id, sourceData.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "SourceData{" + "id=" + id + ", sourceDataType='" + sourceDataType + '\'' - + ", frequency='" - + frequency + '\'' + ", unit='" + unit + '\'' + ", processingState=" - + processingState - + ", dataClass='" + dataClass + '\'' + ", keySchema='" + keySchema + '\'' - + ", valueSchema='" + valueSchema + '\'' + ", topic='" + topic + '\'' - + ", provider='" - + provider + '\'' + ", enabled=" + enabled + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/domain/SourceData.kt b/src/main/java/org/radarbase/management/domain/SourceData.kt new file mode 100644 index 000000000..28a8805b3 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/SourceData.kt @@ -0,0 +1,171 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.envers.Audited +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.io.Serializable +import java.util.* +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.ManyToOne +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern + +/** + * A SourceData. + */ +@Entity +@Audited +@Table(name = "source_data") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class SourceData : AbstractEntity(), Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + //SourceData type e.g. ACCELEROMETER, TEMPERATURE. + @JvmField + @Column(name = "source_data_type", nullable = false) + var sourceDataType: @NotNull String? = null + + // this will be the unique human readable identifier of + @JvmField + @Column(name = "source_data_name", nullable = false, unique = true) + var sourceDataName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + //Default data frequency + @JvmField + @Column(name = "frequency") + var frequency: String? = null + + //Measurement unit. + @JvmField + @Column(name = "unit") + var unit: String? = null + + // Define if the samples are RAW data or instead they the result of some computation + @JvmField + @Column(name = "processing_state") + var processingState: String? = null + + // the storage + @JvmField + @Column(name = "data_class") + var dataClass: String? = null + + @JvmField + @Column(name = "key_schema") + var keySchema: String? = null + + @JvmField + @Column(name = "value_schema") + var valueSchema: String? = null + + // source data topic + @JvmField + @Column(name = "topic") + var topic: String? = null + + // app provider + @JvmField + @Column(name = "provider") + var provider: String? = null + + @Column(name = "enabled") + var isEnabled = true + + @JvmField + @ManyToOne(fetch = FetchType.LAZY) + @JsonIgnoreProperties("sourceData") // avoids infinite recursion in JSON serialization + var sourceType: SourceType? = null + fun sourceDataType(sourceDataType: String?): SourceData { + this.sourceDataType = sourceDataType + return this + } + + fun sourceDataName(sourceDataName: String?): SourceData { + this.sourceDataName = sourceDataName + return this + } + + fun processingState(processingState: String?): SourceData { + this.processingState = processingState + return this + } + + fun keySchema(keySchema: String?): SourceData { + this.keySchema = keySchema + return this + } + + fun frequency(frequency: String?): SourceData { + this.frequency = frequency + return this + } + + fun sourceType(sourceType: SourceType?): SourceData { + this.sourceType = sourceType + return this + } + + fun unit(unit: String?): SourceData { + this.unit = unit + return this + } + + fun valueSchema(valueSchema: String?): SourceData { + this.valueSchema = valueSchema + return this + } + + fun topic(topic: String?): SourceData { + this.topic = topic + return this + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val sourceData = o as SourceData + return if (sourceData.id == null || id == null) { + false + } else id == sourceData.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("SourceData{" + "id=" + id + ", sourceDataType='" + sourceDataType + '\'' + + ", frequency='" + + frequency + '\'' + ", unit='" + unit + '\'' + ", processingState=" + + processingState + + ", dataClass='" + dataClass + '\'' + ", keySchema='" + keySchema + '\'' + + ", valueSchema='" + valueSchema + '\'' + ", topic='" + topic + '\'' + + ", provider='" + + provider + '\'' + ", enabled=" + isEnabled + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/SourceType.java b/src/main/java/org/radarbase/management/domain/SourceType.java deleted file mode 100644 index e2c86f11a..000000000 --- a/src/main/java/org/radarbase/management/domain/SourceType.java +++ /dev/null @@ -1,270 +0,0 @@ -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import javax.persistence.FetchType; - -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.CascadeType; -import org.hibernate.envers.Audited; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToMany; -import javax.persistence.OneToMany; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.io.Serializable; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -/** - * A SourceType. - */ -@Entity -@Audited -@Table(name = "source_type") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class SourceType extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "producer") - private String producer; - - @Column(name = "name") - private String name; - - @Column(name = "description") - private String description; - - @Column(name = "assessment_type") - private String assessmentType; - - @Column(name = "app_provider") - private String appProvider; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "model", nullable = false) - private String model; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "catalog_version", nullable = false) - private String catalogVersion; - - @NotNull - @Column(name = "source_type_scope", nullable = false) - private String sourceTypeScope; - - @NotNull - @Column(name = "dynamic_registration", nullable = false) - private Boolean canRegisterDynamically = false; - - @OneToMany(mappedBy = "sourceType", orphanRemoval = true, fetch = FetchType.LAZY) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @Cascade({CascadeType.DELETE, CascadeType.SAVE_UPDATE}) - private Set sourceData = new HashSet<>(); - - @ManyToMany(mappedBy = "sourceTypes", fetch = FetchType.LAZY) - @JsonIgnore - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Set projects = new HashSet<>(); - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getProducer() { - return producer; - } - - public SourceType producer(String producer) { - this.producer = producer; - return this; - } - - public void setProducer(String producer) { - this.producer = producer; - } - - public String getModel() { - return model; - } - - public SourceType model(String model) { - this.model = model; - return this; - } - - public void setModel(String model) { - this.model = model; - } - - public String getCatalogVersion() { - return catalogVersion; - } - - public void setCatalogVersion(String catalogVersion) { - this.catalogVersion = catalogVersion; - } - - public SourceType catalogVersion(String catalogVersion) { - this.catalogVersion = catalogVersion; - return this; - } - - public String getSourceTypeScope() { - return sourceTypeScope; - } - - public SourceType sourceTypeScope(String sourceTypeScope) { - this.sourceTypeScope = sourceTypeScope; - return this; - } - - public void setSourceTypeScope(String sourceTypeScope) { - this.sourceTypeScope = sourceTypeScope; - } - - public Set getSourceData() { - return sourceData; - } - - public SourceType sourceData(Set sourceData) { - this.sourceData = sourceData; - return this; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setSourceData(Set sourceData) { - this.sourceData = sourceData; - } - - public Set getProjects() { - return projects; - } - - public SourceType projects(Set projects) { - this.projects = projects; - return this; - } - - public Boolean getCanRegisterDynamically() { - return canRegisterDynamically; - } - - public void setCanRegisterDynamically(Boolean canRegisterDynamically) { - this.canRegisterDynamically = canRegisterDynamically; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getAssessmentType() { - return assessmentType; - } - - public void setAssessmentType(String assessmentType) { - this.assessmentType = assessmentType; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setProjects(Set projects) { - this.projects = projects; - } - - public String getAppProvider() { - return appProvider; - } - - public void setAppProvider(String appProvider) { - this.appProvider = appProvider; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - SourceType sourceType = (SourceType) o; - if (sourceType.id == null || id == null) { - return false; - } - return Objects.equals(id, sourceType.id) - && Objects.equals(producer, sourceType.producer) - && Objects.equals(model, sourceType.model) - && Objects.equals(catalogVersion, sourceType.catalogVersion) - && Objects.equals(canRegisterDynamically, sourceType.canRegisterDynamically) - && Objects.equals(sourceTypeScope, sourceType.sourceTypeScope) - && Objects.equals(name, sourceType.name) - && Objects.equals(description, sourceType.description) - && Objects.equals(appProvider, sourceType.appProvider) - && Objects.equals(assessmentType, sourceType.assessmentType); - } - - @Override - public int hashCode() { - return Objects.hash(id, model, producer, catalogVersion, canRegisterDynamically, - sourceTypeScope, name, description, appProvider, assessmentType); - } - - @Override - public String toString() { - return "SourceType{" - + "id=" + id - + ", producer='" + producer + '\'' - + ", model='" + model + '\'' - + ", catalogVersion='" + catalogVersion + '\'' - + ", sourceTypeScope=" + sourceTypeScope - + ", canRegisterDynamically=" + canRegisterDynamically - + ", name='" + name + '\'' - + ", description=" + description - + ", appProvider=" + appProvider - + ", assessmentType=" + assessmentType - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/domain/SourceType.kt b/src/main/java/org/radarbase/management/domain/SourceType.kt new file mode 100644 index 000000000..cb89cefd7 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/SourceType.kt @@ -0,0 +1,163 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.annotations.Cascade +import org.hibernate.annotations.CascadeType +import org.hibernate.envers.Audited +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.io.Serializable +import java.util.* +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.ManyToMany +import javax.persistence.OneToMany +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern + +/** + * A SourceType. + */ +@Entity +@Audited +@Table(name = "source_type") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class SourceType : AbstractEntity(), Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @JvmField + @Column(name = "producer") + var producer: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + @JvmField + @Column(name = "name") + var name: String? = null + + @JvmField + @Column(name = "description") + var description: String? = null + + @JvmField + @Column(name = "assessment_type") + var assessmentType: String? = null + + @JvmField + @Column(name = "app_provider") + var appProvider: String? = null + + @JvmField + @Column(name = "model", nullable = false) + var model: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + @JvmField + @Column(name = "catalog_version", nullable = false) + var catalogVersion: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + @JvmField + @Column(name = "source_type_scope", nullable = false) + var sourceTypeScope: @NotNull String? = null + + @JvmField + @Column(name = "dynamic_registration", nullable = false) + var canRegisterDynamically: @NotNull Boolean? = false + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @OneToMany(mappedBy = "sourceType", orphanRemoval = true, fetch = FetchType.LAZY) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @Cascade( + CascadeType.DELETE, CascadeType.SAVE_UPDATE + ) + var sourceData: Set = HashSet() + + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ManyToMany(mappedBy = "sourceTypes", fetch = FetchType.LAZY) + @JsonIgnore + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var projects: Set = HashSet() + fun producer(producer: String?): SourceType { + this.producer = producer + return this + } + + fun model(model: String?): SourceType { + this.model = model + return this + } + + fun catalogVersion(catalogVersion: String?): SourceType { + this.catalogVersion = catalogVersion + return this + } + + fun sourceTypeScope(sourceTypeScope: String?): SourceType { + this.sourceTypeScope = sourceTypeScope + return this + } + + fun sourceData(sourceData: Set): SourceType { + this.sourceData = sourceData + return this + } + + fun projects(projects: Set): SourceType { + this.projects = projects + return this + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val sourceType = o as SourceType + return if (sourceType.id == null || id == null) { + false + } else id == sourceType.id && producer == sourceType.producer && model == sourceType.model && catalogVersion == sourceType.catalogVersion && canRegisterDynamically == sourceType.canRegisterDynamically && sourceTypeScope == sourceType.sourceTypeScope && name == sourceType.name && description == sourceType.description && appProvider == sourceType.appProvider && assessmentType == sourceType.assessmentType + } + + override fun hashCode(): Int { + return Objects.hash( + id, model, producer, catalogVersion, canRegisterDynamically, + sourceTypeScope, name, description, appProvider, assessmentType + ) + } + + override fun toString(): String { + return ("SourceType{" + + "id=" + id + + ", producer='" + producer + '\'' + + ", model='" + model + '\'' + + ", catalogVersion='" + catalogVersion + '\'' + + ", sourceTypeScope=" + sourceTypeScope + + ", canRegisterDynamically=" + canRegisterDynamically + + ", name='" + name + '\'' + + ", description=" + description + + ", appProvider=" + appProvider + + ", assessmentType=" + assessmentType + + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/Subject.java b/src/main/java/org/radarbase/management/domain/Subject.java deleted file mode 100644 index c05b743f9..000000000 --- a/src/main/java/org/radarbase/management/domain/Subject.java +++ /dev/null @@ -1,292 +0,0 @@ -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import org.hibernate.annotations.BatchSize; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.CascadeType; -import org.hibernate.envers.Audited; -import org.hibernate.envers.RelationTargetAuditMode; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.MapKeyColumn; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import java.io.Serializable; -import java.time.LocalDate; -import java.time.ZonedDateTime; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -import static org.radarbase.auth.authorization.RoleAuthority.INACTIVE_PARTICIPANT; -import static org.radarbase.auth.authorization.RoleAuthority.PARTICIPANT; - -/** - * A Subject. - */ -@Entity -@Audited -@Table(name = "subject") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class Subject extends AbstractEntity implements Serializable { - private static final long serialVersionUID = 1L; - private static final Set PARTICIPANT_TYPES = Set.of( - PARTICIPANT.getAuthority(), - INACTIVE_PARTICIPANT.getAuthority()); - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @Column(name = "external_link") - private String externalLink; - - @Column(name = "external_id") - private String externalId; - - @NotNull - @Column(name = "removed", nullable = false) - private Boolean removed = false; - - @OneToOne - @JoinColumn(unique = true, name = "user_id") - @Cascade(CascadeType.ALL) - private User user; - - @OneToMany(mappedBy = "subject", fetch = FetchType.LAZY) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @Cascade(CascadeType.SAVE_UPDATE) - private Set sources = new HashSet<>(); - - @ElementCollection(fetch = FetchType.EAGER) - @MapKeyColumn(name = "attribute_key") - @Column(name = "attribute_value") - @CollectionTable(name = "subject_metadata", joinColumns = @JoinColumn(name = "id")) - @Cascade(CascadeType.ALL) - @BatchSize(size = 50) - private Map attributes = new HashMap<>(); - - @OneToMany(mappedBy = "subject", orphanRemoval = true, fetch = FetchType.LAZY) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @JsonIgnore - private final Set metaTokens = new HashSet<>(); - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "group_id") - @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) - private Group group; - - @Column(name = "date_of_birth") - private LocalDate dateOfBirth; - - @Column(name = "enrollment_date") - private ZonedDateTime enrollmentDate; - - @Column(name = "person_name") - private String personName; - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getExternalLink() { - return externalLink; - } - - public Subject externalLink(String externalLink) { - this.externalLink = externalLink; - return this; - } - - public void setExternalLink(String externalLink) { - this.externalLink = externalLink; - } - - public String getExternalId() { - return externalId; - } - - public Subject externalId(String enternalId) { - this.externalId = enternalId; - return this; - } - - public void setExternalId(String externalId) { - this.externalId = externalId; - } - - public Boolean isRemoved() { - return removed; - } - - public Subject removed(Boolean removed) { - this.removed = removed; - return this; - } - - public void setRemoved(Boolean removed) { - this.removed = removed; - } - - public User getUser() { - return user; - } - - public Subject user(User usr) { - this.user = usr; - return this; - } - - public void setUser(User usr) { - this.user = usr; - } - - public Set getSources() { - return sources; - } - - public Subject sources(Set sources) { - this.sources = sources; - return this; - } - - public void setSources(Set sources) { - this.sources = sources; - } - - public Map getAttributes() { - return attributes; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - public Set getMetaTokens() { - return metaTokens; - } - - public void setGroup(Group group) { - this.group = group; - } - - public Group getGroup() { - return this.group; - } - - public void setDateOfBirth(LocalDate dateOfBirth) { - this.dateOfBirth = dateOfBirth; - } - - public LocalDate getDateOfBirth() { - return this.dateOfBirth; - } - - public void setEnrollmentDate(ZonedDateTime enrollmentDate) { - this.enrollmentDate = enrollmentDate; - } - - public ZonedDateTime getEnrollmentDate() { - return this.enrollmentDate; - } - - public void setPersonName(String personName) { - this.personName = personName; - } - - public String getPersonName() { - return this.personName; - } - - /** - * Gets the active project of subject. - * - *

There can be only one role with PARTICIPANT authority - * and the project that is related to that role is the active role.

- * - * @return {@link Project} currently active project of subject. - */ - public Optional getActiveProject() { - return this.getUser().getRoles().stream() - .filter(r -> r.getAuthority().getName().equals(PARTICIPANT.getAuthority())) - .findFirst() - .map(Role::getProject); - } - - /** - * Get the active project of a subject, and otherwise the - * inactive project. - * @return the project a subject belongs to, if any. - */ - public Optional getAssociatedProject() { - return this.getUser().getRoles().stream() - .filter(r -> PARTICIPANT_TYPES.contains(r.getAuthority().getName())) - .max(Comparator.comparing(r -> r.getAuthority().getName())) - .map(Role::getProject); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Subject subject = (Subject) o; - if (subject.id == null || id == null) { - return false; - } - return Objects.equals(id, subject.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "Subject{" - + "id=" + id - + ", externalLink='" + externalLink + '\'' - + ", externalId='" + externalId + '\'' - + ", removed=" + removed - + ", user=" + user - + ", sources=" + sources - + ", attributes=" + attributes - + ", group=" + group - + "}"; - } -} diff --git a/src/main/java/org/radarbase/management/domain/Subject.kt b/src/main/java/org/radarbase/management/domain/Subject.kt new file mode 100644 index 000000000..e5e1217e7 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Subject.kt @@ -0,0 +1,207 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import org.hibernate.annotations.BatchSize +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.annotations.Cascade +import org.hibernate.annotations.CascadeType +import org.hibernate.envers.Audited +import org.hibernate.envers.RelationTargetAuditMode +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.domain.support.AbstractEntityListener +import java.io.Serializable +import java.time.LocalDate +import java.time.ZonedDateTime +import java.util.* +import javax.persistence.CollectionTable +import javax.persistence.Column +import javax.persistence.ElementCollection +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne +import javax.persistence.MapKeyColumn +import javax.persistence.OneToMany +import javax.persistence.OneToOne +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull + +/** + * A Subject. + */ +@Entity +@Audited +@Table(name = "subject") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class Subject( + @Id @GeneratedValue( + strategy = GenerationType.SEQUENCE, + generator = "sequenceGenerator" + ) @SequenceGenerator( + name = "sequenceGenerator", + initialValue = 1000, + sequenceName = "hibernate_sequence" + ) override var id: Long? = null +) : AbstractEntity(), Serializable { + + @JvmField + @Column(name = "external_link") + var externalLink: String? = null + + @JvmField + @Column(name = "external_id") + var externalId: String? = null + + @Column(name = "removed", nullable = false) + var isRemoved: @NotNull Boolean? = false + + @JvmField + @OneToOne + @JoinColumn(unique = true, name = "user_id") + @Cascade(CascadeType.ALL) + var user: User? = null + + @JvmField + @OneToMany(mappedBy = "subject", fetch = FetchType.LAZY) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @Cascade( + CascadeType.SAVE_UPDATE + ) + var sources: MutableSet = HashSet() + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ElementCollection(fetch = FetchType.EAGER) + @MapKeyColumn(name = "attribute_key") + @Column(name = "attribute_value") + @CollectionTable(name = "subject_metadata", joinColumns = [JoinColumn(name = "id")]) + @Cascade( + CascadeType.ALL + ) + @BatchSize(size = 50) + var attributes: Map = HashMap() + + @OneToMany(mappedBy = "subject", orphanRemoval = true, fetch = FetchType.LAZY) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @JsonIgnore + val metaTokens: Set = HashSet() + + @JvmField + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "group_id") + @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) + var group: Group? = null + + @JvmField + @Column(name = "date_of_birth") + var dateOfBirth: LocalDate? = null + + @JvmField + @Column(name = "enrollment_date") + var enrollmentDate: ZonedDateTime? = null + + @JvmField + @Column(name = "person_name") + var personName: String? = null + fun externalLink(externalLink: String?): Subject { + this.externalLink = externalLink + return this + } + + fun externalId(enternalId: String?): Subject { + externalId = enternalId + return this + } + + fun removed(removed: Boolean?): Subject { + isRemoved = removed + return this + } + + fun user(usr: User?): Subject { + user = usr + return this + } + + fun sources(sources: MutableSet): Subject { + this.sources = sources + return this + } + + val activeProject: Project? + /** + * Gets the active project of subject. + * + * + * There can be only one role with PARTICIPANT authority + * and the project that is related to that role is the active role. + * + * @return [Project] currently active project of subject. + */ + get() = user?.roles + ?.first { r -> r.authority?.name == RoleAuthority.PARTICIPANT.authority } + ?.project + val associatedProject: Project? + /** + * Get the active project of a subject, and otherwise the + * inactive project. + * @return the project a subject belongs to, if any. + */ + get() { + val user = user ?: return null + return user.roles?.asIterable() + ?.filter { r -> PARTICIPANT_TYPES.contains(r.authority?.name) } + ?.sortedBy { it.authority?.name }?.first() + .let { obj: Role? -> obj?.project } + + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val subject = other as Subject + return if (subject.id == null || id == null) { + false + } else id == subject.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("Subject{" + + "id=" + id + + ", externalLink='" + externalLink + '\'' + + ", externalId='" + externalId + '\'' + + ", removed=" + isRemoved + + ", user=" + user + + ", sources=" + sources + + ", attributes=" + attributes + + ", group=" + group + + "}") + } + + companion object { + private const val serialVersionUID = 1L + private val PARTICIPANT_TYPES = java.util.Set.of( + RoleAuthority.PARTICIPANT.authority, + RoleAuthority.INACTIVE_PARTICIPANT.authority + ) + } +} diff --git a/src/main/java/org/radarbase/management/domain/User.java b/src/main/java/org/radarbase/management/domain/User.java deleted file mode 100644 index 67a977f10..000000000 --- a/src/main/java/org/radarbase/management/domain/User.java +++ /dev/null @@ -1,248 +0,0 @@ -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import org.hibernate.annotations.BatchSize; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.CascadeType; -import org.hibernate.envers.Audited; -import org.hibernate.validator.constraints.Email; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; -import java.io.Serializable; -import java.time.ZonedDateTime; -import java.util.HashSet; -import java.util.Locale; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * A user. - */ -@Entity -@Audited -@Table(name = "radar_user") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class User extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Size(min = 1, max = 50) - @Column(length = 50, unique = true, nullable = false) - private String login; - - @JsonIgnore - @NotNull - @Size(min = 60, max = 60) - @Column(name = "password_hash", length = 60) - private String password; - - @Size(max = 50) - @Column(name = "first_name", length = 50) - private String firstName; - - @Size(max = 50) - @Column(name = "last_name", length = 50) - private String lastName; - - @Email - @Size(min = 5, max = 100) - @Column(length = 100, unique = true, nullable = true) - private String email; - - @NotNull - @Column(nullable = false) - private boolean activated = false; - - @Size(min = 2, max = 5) - @Column(name = "lang_key", length = 5) - private String langKey; - - @Size(max = 20) - @Column(name = "activation_key", length = 20) - @JsonIgnore - private String activationKey; - - @Size(max = 20) - @Column(name = "reset_key", length = 20) - private String resetKey; - - @Column(name = "reset_date") - private ZonedDateTime resetDate = null; - - @ManyToMany(fetch = FetchType.EAGER) - @JoinTable( - name = "role_users", - joinColumns = {@JoinColumn(name = "users_id", referencedColumnName = "id")}, - inverseJoinColumns = {@JoinColumn(name = "roles_id", referencedColumnName = "id")}) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @BatchSize(size = 20) - @Cascade(CascadeType.SAVE_UPDATE) - private Set roles = new HashSet<>(); - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getLogin() { - return login; - } - - //Lowercase the login before saving it in database - public void setLogin(String login) { - this.login = login.toLowerCase(Locale.ENGLISH); - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public boolean getActivated() { - return activated; - } - - public void setActivated(boolean activated) { - this.activated = activated; - } - - public String getActivationKey() { - return activationKey; - } - - public void setActivationKey(String activationKey) { - this.activationKey = activationKey; - } - - public String getResetKey() { - return resetKey; - } - - public void setResetKey(String resetKey) { - this.resetKey = resetKey; - } - - public ZonedDateTime getResetDate() { - return resetDate; - } - - public void setResetDate(ZonedDateTime resetDate) { - this.resetDate = resetDate; - } - - public String getLangKey() { - return langKey; - } - - public void setLangKey(String langKey) { - this.langKey = langKey; - } - - public Set getRoles() { - return roles; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setRoles(Set roles) { - this.roles = roles; - } - - /** Authorities tha ta user has. */ - public Set getAuthorities() { - return roles.stream() - .map(Role::getAuthority) - .collect(Collectors.toSet()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - User user = (User) o; - - return login.equals(user.login); - } - - @Override - public int hashCode() { - return login.hashCode(); - } - - @Override - public String toString() { - return "User{" - + "login='" + login + '\'' - + ", firstName='" + firstName + '\'' - + ", lastName='" + lastName + '\'' - + ", email='" + email + '\'' - + ", activated='" + activated + '\'' - + ", langKey='" + langKey + '\'' - + ", activationKey='" + activationKey + '\'' - + "}"; - } -} diff --git a/src/main/java/org/radarbase/management/domain/User.kt b/src/main/java/org/radarbase/management/domain/User.kt new file mode 100644 index 000000000..ddf37bf9b --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/User.kt @@ -0,0 +1,146 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import org.hibernate.annotations.BatchSize +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.annotations.Cascade +import org.hibernate.annotations.CascadeType +import org.hibernate.envers.Audited +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.io.Serializable +import java.time.ZonedDateTime +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.JoinTable +import javax.persistence.ManyToMany +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.Email +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern +import javax.validation.constraints.Size + +/** + * A user. + */ +@Entity +@Audited +@Table(name = "radar_user") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class User : AbstractEntity(), Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @Column(length = 50, unique = true, nullable = false) + var login: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) String? = null + private set + + @JvmField + @JsonIgnore + @Column(name = "password_hash", length = 60) + var password: @NotNull @Size(min = 60, max = 60) String? = null + + @JvmField + @Column(name = "first_name", length = 50) + var firstName: @Size(max = 50) String? = null + + @JvmField + @Column(name = "last_name", length = 50) + var lastName: @Size(max = 50) String? = null + + @JvmField + @Column(length = 100, unique = true, nullable = true) + var email: @Email @Size(min = 5, max = 100) String? = null + + @JvmField + @Column(nullable = false) + var activated: @NotNull Boolean = false + + @JvmField + @Column(name = "lang_key", length = 5) + var langKey: @Size(min = 2, max = 5) String? = null + + @JvmField + @Column(name = "activation_key", length = 20) + @JsonIgnore + var activationKey: @Size(max = 20) String? = null + + @JvmField + @Column(name = "reset_key", length = 20) + var resetKey: @Size(max = 20) String? = null + + @JvmField + @Column(name = "reset_date") + var resetDate: ZonedDateTime? = null + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable( + name = "role_users", + joinColumns = [JoinColumn(name = "users_id", referencedColumnName = "id")], + inverseJoinColumns = [JoinColumn(name = "roles_id", referencedColumnName = "id")] + ) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @BatchSize(size = 20) + @Cascade( + CascadeType.SAVE_UPDATE + ) + //TODO remove ? + var roles: MutableSet? = HashSet() + + //Lowercase the login before saving it in database + fun setLogin(login: String) { + this.login = login.lowercase() + } + + val authorities: Set? + /** Authorities that a user has. */ + get() = roles?.map { obj: Role? -> obj?.authority }?.toSet() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val user = other as User + return login == user.login + } + + override fun hashCode(): Int { + return login.hashCode() + } + + override fun toString(): String { + return ("User{" + + "login='" + login + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", email='" + email + '\'' + + ", activated='" + activated + '\'' + + ", langKey='" + langKey + '\'' + + ", activationKey='" + activationKey + '\'' + + "}") + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt index e6c749397..0cf7486dc 100644 --- a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt +++ b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt @@ -1,115 +1,85 @@ -package org.radarbase.management.domain.audit; - -import org.hibernate.annotations.Fetch; -import org.hibernate.annotations.FetchMode; -import org.hibernate.envers.ModifiedEntityNames; -import org.hibernate.envers.RevisionEntity; -import org.hibernate.envers.RevisionNumber; -import org.hibernate.envers.RevisionTimestamp; -import org.radarbase.management.config.audit.CustomRevisionListener; - -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import java.io.Serializable; -import java.util.Date; -import java.util.Objects; -import java.util.Set; +package org.radarbase.management.domain.audit + +import org.hibernate.annotations.Fetch +import org.hibernate.annotations.FetchMode +import org.hibernate.envers.ModifiedEntityNames +import org.hibernate.envers.RevisionEntity +import org.hibernate.envers.RevisionNumber +import org.hibernate.envers.RevisionTimestamp +import org.radarbase.management.config.audit.CustomRevisionListener +import java.io.Serializable +import java.util.* +import javax.persistence.Column +import javax.persistence.ElementCollection +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.JoinTable +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.persistence.Temporal +import javax.persistence.TemporalType @Entity -@RevisionEntity(CustomRevisionListener.class) +@RevisionEntity(CustomRevisionListener::class) @Table(name = "_revisions_info") -public class CustomRevisionEntity implements Serializable { - private static final long serialVersionUID = 8530213963961662300L; - +class CustomRevisionEntity : Serializable { + @JvmField @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "revisionGenerator") - @SequenceGenerator(name = "revisionGenerator", initialValue = 2, allocationSize = 50, - sequenceName = "sequence_revision") + @SequenceGenerator( + name = "revisionGenerator", + initialValue = 2, + allocationSize = 50, + sequenceName = "sequence_revision" + ) @RevisionNumber - private int id; + var id = 0 + @JvmField + @get:Temporal(TemporalType.TIMESTAMP) @RevisionTimestamp - private Date timestamp; - - private String auditor; + var timestamp: Date? = null + @JvmField + var auditor: String? = null + @JvmField @ElementCollection(fetch = FetchType.EAGER) - @JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV")) + @JoinTable(name = "REVCHANGES", joinColumns = [JoinColumn(name = "REV")]) @Column(name = "ENTITYNAME") - @Fetch(FetchMode.JOIN) + @Fetch( + FetchMode.JOIN + ) @ModifiedEntityNames - private Set modifiedEntityNames; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @Temporal(TemporalType.TIMESTAMP) - public Date getTimestamp() { - return timestamp; - } - - public void setTimestamp(Date timestamp) { - this.timestamp = timestamp; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + var modifiedEntityNames: Set? = null + override fun equals(o: Any?): Boolean { + if (this === o) { + return true } - if (!(o instanceof CustomRevisionEntity)) { - return false; + if (o !is CustomRevisionEntity) { + return false } - CustomRevisionEntity that = (CustomRevisionEntity) o; - return id == that.id && Objects.equals(timestamp, that.timestamp) && Objects - .equals(auditor, that.auditor) && Objects - .equals(modifiedEntityNames, that.modifiedEntityNames); + val that = o + return id == that.id && timestamp == that.timestamp && auditor == that.auditor && modifiedEntityNames == that.modifiedEntityNames } - @Override - public int hashCode() { - return Objects.hash(id, timestamp, auditor, modifiedEntityNames); + override fun hashCode(): Int { + return Objects.hash(id, timestamp, auditor, modifiedEntityNames) } - @Override - public String toString() { - return "CustomRevisionEntity{" + override fun toString(): String { + return ("CustomRevisionEntity{" + "id=" + id + ", timestamp=" + timestamp + ", auditor='" + auditor + '\'' + ", modifiedEntityNames=" + modifiedEntityNames - + '}'; - } - - public String getAuditor() { - return auditor; - } - - public void setAuditor(String auditor) { - this.auditor = auditor; - } - - public Set getModifiedEntityNames() { - return modifiedEntityNames; + + '}') } - public void setModifiedEntityNames(Set modifiedEntityNames) { - this.modifiedEntityNames = modifiedEntityNames; + companion object { + private const val serialVersionUID = 8530213963961662300L } } diff --git a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt index cc978c922..d23f92927 100644 --- a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt +++ b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt @@ -1,61 +1,52 @@ -package org.radarbase.management.domain.audit; +package org.radarbase.management.domain.audit -import org.springframework.data.history.RevisionMetadata; -import org.springframework.util.Assert; +import org.springframework.data.history.RevisionMetadata +import org.springframework.util.Assert +import java.time.Instant +import java.util.* -import java.time.Instant; -import java.util.Optional; - -public class CustomRevisionMetadata implements RevisionMetadata { - - private final CustomRevisionEntity entity; +class CustomRevisionMetadata(entity: CustomRevisionEntity) : RevisionMetadata { + private val entity: CustomRevisionEntity /** - * Creates a new {@link CustomRevisionMetadata}. + * Creates a new [CustomRevisionMetadata]. * - * @param entity must not be {@literal null}. + * @param entity must not be null. */ - public CustomRevisionMetadata(CustomRevisionEntity entity) { - Assert.notNull(entity, "The CustomRevisionEntity can not be null"); - this.entity = entity; + init { + Assert.notNull(entity, "The CustomRevisionEntity can not be null") + this.entity = entity } /* * (non-Javadoc) * @see org.springframework.data.history.RevisionMetadata#getRevisionNumber() */ - @Override - public Optional getRevisionNumber() { - return Optional.of(entity.getId()); + override fun getRevisionNumber(): Optional { + return Optional.of(entity.id) } - @Override - public Integer getRequiredRevisionNumber() { - return RevisionMetadata.super.getRequiredRevisionNumber(); + override fun getRequiredRevisionNumber(): Int { + return super.getRequiredRevisionNumber() } - @Override - public Optional getRevisionInstant() { - return Optional.ofNullable(entity.getTimestamp()).map(ts -> ts.toInstant()); + override fun getRevisionInstant(): Optional { + return Optional.ofNullable(entity.timestamp).map { ts: Date -> ts.toInstant() } } - @Override - public Instant getRequiredRevisionInstant() { - return RevisionMetadata.super.getRequiredRevisionInstant(); + override fun getRequiredRevisionInstant(): Instant { + return super.getRequiredRevisionInstant() } /* * (non-Javadoc) * @see org.springframework.data.history.RevisionMetadata#getDelegate() */ - @SuppressWarnings("unchecked") - @Override - public T getDelegate() { - return (T) entity; + override fun getDelegate(): T { + return entity as T } - @Override - public RevisionType getRevisionType() { - return RevisionMetadata.super.getRevisionType(); + override fun getRevisionType(): RevisionMetadata.RevisionType { + return super.getRevisionType() } } diff --git a/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt b/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt index 742aeed78..cd1d2b73d 100644 --- a/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt +++ b/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt @@ -1,83 +1,62 @@ -package org.radarbase.management.domain.audit; +package org.radarbase.management.domain.audit -import java.time.ZonedDateTime; -import java.util.Objects; +import java.time.ZonedDateTime /** * POJO only used to easily get entity audit information, i.e. created by, created at, modified * by and modified at. */ -public class EntityAuditInfo { - private ZonedDateTime createdAt; - private String createdBy; - private ZonedDateTime lastModifiedAt; - private String lastModifiedBy; +class EntityAuditInfo { + var createdAt: ZonedDateTime? = null + private set + var createdBy: String? = null + private set + var lastModifiedAt: ZonedDateTime? = null + private set + var lastModifiedBy: String? = null + private set - public ZonedDateTime getCreatedAt() { - return createdAt; + fun setCreatedAt(createdAt: ZonedDateTime?): EntityAuditInfo { + this.createdAt = createdAt + return this } - public EntityAuditInfo setCreatedAt(ZonedDateTime createdAt) { - this.createdAt = createdAt; - return this; + fun setCreatedBy(createdBy: String?): EntityAuditInfo { + this.createdBy = createdBy + return this } - public String getCreatedBy() { - return createdBy; + fun setLastModifiedAt(lastModifiedAt: ZonedDateTime?): EntityAuditInfo { + this.lastModifiedAt = lastModifiedAt + return this } - public EntityAuditInfo setCreatedBy(String createdBy) { - this.createdBy = createdBy; - return this; + fun setLastModifiedBy(lastModifiedBy: String?): EntityAuditInfo { + this.lastModifiedBy = lastModifiedBy + return this } - public ZonedDateTime getLastModifiedAt() { - return lastModifiedAt; - } - - public EntityAuditInfo setLastModifiedAt(ZonedDateTime lastModifiedAt) { - this.lastModifiedAt = lastModifiedAt; - return this; - } - - public String getLastModifiedBy() { - return lastModifiedBy; - } - - public EntityAuditInfo setLastModifiedBy(String lastModifiedBy) { - this.lastModifiedBy = lastModifiedBy; - return this; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + override fun equals(o: Any?): Boolean { + if (this === o) { + return true } - if (o == null || getClass() != o.getClass()) { - return false; + if (o == null || javaClass != o.javaClass) { + return false } - - EntityAuditInfo that = (EntityAuditInfo) o; - - return Objects.equals(createdAt, that.createdAt) - && Objects.equals(createdBy, that.createdBy) - && Objects.equals(lastModifiedAt, that.lastModifiedAt) - && Objects.equals(lastModifiedBy, that.lastModifiedBy); + val that = o as EntityAuditInfo + return createdAt == that.createdAt && createdBy == that.createdBy && lastModifiedAt == that.lastModifiedAt && lastModifiedBy == that.lastModifiedBy } - @Override - public int hashCode() { - return lastModifiedAt != null ? lastModifiedAt.hashCode() : 0; + override fun hashCode(): Int { + return if (lastModifiedAt != null) lastModifiedAt.hashCode() else 0 } - @Override - public String toString() { - return "EntityAuditInfo{" + override fun toString(): String { + return ("EntityAuditInfo{" + "createdAt=" + createdAt + ", createdBy='" + createdBy + '\'' + ", lastModifiedAt=" + lastModifiedAt + ", lastModifiedBy='" + lastModifiedBy + '\'' - + '}'; + + '}') } } diff --git a/src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.kt b/src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.kt index 710a74c68..568e9a8f0 100644 --- a/src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.kt +++ b/src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.kt @@ -1,8 +1,10 @@ -package org.radarbase.management.domain.enumeration; +package org.radarbase.management.domain.enumeration /** * The ProjectStatus enumeration. */ -public enum ProjectStatus { - PLANNING, ONGOING, ENDED +enum class ProjectStatus { + PLANNING, + ONGOING, + ENDED } diff --git a/src/main/java/org/radarbase/management/domain/enumeration/Role.kt b/src/main/java/org/radarbase/management/domain/enumeration/Role.kt index 5d10fc809..58b1cc2b8 100644 --- a/src/main/java/org/radarbase/management/domain/enumeration/Role.kt +++ b/src/main/java/org/radarbase/management/domain/enumeration/Role.kt @@ -1,9 +1,9 @@ -package org.radarbase.management.domain.enumeration; +package org.radarbase.management.domain.enumeration /** * The Role enumeration. */ -public enum Role { +enum class Role { ROLE_ADMIN, ROLE_USER, ROLE_SYS_ADMIN, diff --git a/src/main/java/org/radarbase/management/domain/package-info.java b/src/main/java/org/radarbase/management/domain/package-info.java deleted file mode 100644 index 9a9323dd8..000000000 --- a/src/main/java/org/radarbase/management/domain/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * JPA domain objects. - */ -package org.radarbase.management.domain; diff --git a/src/main/java/org/radarbase/management/domain/package-info.kt b/src/main/java/org/radarbase/management/domain/package-info.kt new file mode 100644 index 000000000..302bbf388 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/package-info.kt @@ -0,0 +1,5 @@ +/** + * JPA domain objects. + */ +package org.radarbase.management.domain + diff --git a/src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.java b/src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.java deleted file mode 100644 index 410c0391f..000000000 --- a/src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.radarbase.management.domain.support; - -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.AbstractEntity; -import org.radarbase.management.security.SpringSecurityAuditorAware; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import javax.persistence.PostPersist; -import javax.persistence.PostRemove; -import javax.persistence.PostUpdate; - -/** - * Entity listener that contains all listeners that should fire on AbstractEntity's. This - * listener will publish entity events to log, to have a uniform, centralized logging of entity - * operations. Also, it will populate the created_by, created_at, last_modified_by and - * last_modified_at fields using Envers audits when an entity is loaded. - */ -@Component -public class AbstractEntityListener { - - public static final String ENTITY_CREATED = "ENTITY_CREATED"; - public static final String ENTITY_UPDATED = "ENTITY_UPDATED"; - public static final String ENTITY_REMOVED = "ENTITY_REMOVED"; - - private static final Logger log = LoggerFactory.getLogger(AbstractEntityListener.class); - private static final String TEMPLATE = "[{}] by {}: entityClass={}, entity={}"; - - @Autowired - private SpringSecurityAuditorAware springSecurityAuditorAware; - - /** - * Event listener to log a persist event. - * - * @param entity the entity that is persisted - */ - @PostPersist - public void publishPersistEvent(AbstractEntity entity) { - AutowireHelper.autowire(this, springSecurityAuditorAware); - log.info(TEMPLATE, ENTITY_CREATED, springSecurityAuditorAware.getCurrentAuditor() - .orElse(Constants.SYSTEM_ACCOUNT), - entity.getClass().getName(), entity.toString()); - } - - /** - * Event listener to log an update event. - * - * @param entity the entity that is updated - */ - @PostUpdate - public void publishUpdateEvent(AbstractEntity entity) { - AutowireHelper.autowire(this, springSecurityAuditorAware); - log.info(TEMPLATE, ENTITY_UPDATED, springSecurityAuditorAware.getCurrentAuditor() - .orElse(Constants.SYSTEM_ACCOUNT), - entity.getClass().getName(), entity.toString()); - } - - /** - * Event listener to log a remove event. - * - * @param entity the entity that is removed - */ - @PostRemove - public void publishRemoveEvent(AbstractEntity entity) { - AutowireHelper.autowire(this, springSecurityAuditorAware); - log.info(TEMPLATE, ENTITY_REMOVED, springSecurityAuditorAware.getCurrentAuditor() - .orElse(Constants.SYSTEM_ACCOUNT), - entity.getClass().getName(), entity.toString()); - } - - /** - * When an entity is loaded, find out the repository of the entity, load the revision log, - * and use it to populate the created and last modified fields. - * - * @param entity the entity that was loaded. - *//* - @PostLoad - public void populateAuditMetaData(AbstractEntity entity) { - - }*/ - - -} diff --git a/src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.kt b/src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.kt new file mode 100644 index 000000000..affea0bbd --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.kt @@ -0,0 +1,87 @@ +package org.radarbase.management.domain.support + +import org.radarbase.management.domain.AbstractEntity +import org.radarbase.management.security.Constants +import org.radarbase.management.security.SpringSecurityAuditorAware +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component +import javax.persistence.PostPersist +import javax.persistence.PostRemove +import javax.persistence.PostUpdate + +/** + * Entity listener that contains all listeners that should fire on AbstractEntity's. This + * listener will publish entity events to log, to have a uniform, centralized logging of entity + * operations. Also, it will populate the created_by, created_at, last_modified_by and + * last_modified_at fields using Envers audits when an entity is loaded. + */ +@Component +class AbstractEntityListener { + @Autowired + private val springSecurityAuditorAware: SpringSecurityAuditorAware? = null + + /** + * Event listener to log a persist event. + * + * @param entity the entity that is persisted + */ + @PostPersist + fun publishPersistEvent(entity: AbstractEntity) { + AutowireHelper.autowire(this, springSecurityAuditorAware) + log.info( + TEMPLATE, ENTITY_CREATED, springSecurityAuditorAware!!.currentAuditor + .orElse(Constants.SYSTEM_ACCOUNT), + entity.javaClass.getName(), entity.toString() + ) + } + + /** + * Event listener to log an update event. + * + * @param entity the entity that is updated + */ + @PostUpdate + fun publishUpdateEvent(entity: AbstractEntity) { + AutowireHelper.autowire(this, springSecurityAuditorAware) + log.info( + TEMPLATE, ENTITY_UPDATED, springSecurityAuditorAware!!.currentAuditor + .orElse(Constants.SYSTEM_ACCOUNT), + entity.javaClass.getName(), entity.toString() + ) + } + + /** + * Event listener to log a remove event. + * + * @param entity the entity that is removed + */ + @PostRemove + fun publishRemoveEvent(entity: AbstractEntity) { + AutowireHelper.autowire(this, springSecurityAuditorAware) + log.info( + TEMPLATE, ENTITY_REMOVED, springSecurityAuditorAware!!.currentAuditor + .orElse(Constants.SYSTEM_ACCOUNT), + entity.javaClass.getName(), entity.toString() + ) + } + + /** + * When an entity is loaded, find out the repository of the entity, load the revision log, + * and use it to populate the created and last modified fields. + * + * @param entity the entity that was loaded. + */ + /* + @PostLoad + public void populateAuditMetaData(AbstractEntity entity) { + + }*/ + companion object { + const val ENTITY_CREATED = "ENTITY_CREATED" + const val ENTITY_UPDATED = "ENTITY_UPDATED" + const val ENTITY_REMOVED = "ENTITY_REMOVED" + private val log = LoggerFactory.getLogger(AbstractEntityListener::class.java) + private const val TEMPLATE = "[{}] by {}: entityClass={}, entity={}" + } +} diff --git a/src/main/java/org/radarbase/management/domain/support/AutowireHelper.java b/src/main/java/org/radarbase/management/domain/support/AutowireHelper.java deleted file mode 100644 index fa9881a01..000000000 --- a/src/main/java/org/radarbase/management/domain/support/AutowireHelper.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.radarbase.management.domain.support; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.stereotype.Component; - -/** - * Class to inject dependencies into classes that do not support Autowire, such as JPA event - * listeners. - */ -@Component -public final class AutowireHelper implements ApplicationContextAware { - - private static final AutowireHelper INSTANCE = new AutowireHelper(); - private static ApplicationContext applicationContext; - - private AutowireHelper() { - // Utility class - } - - /** - * Tries to autowire the specified instance of the class if one of the specified beans which - * need to be autowired are null. - * - * @param classToAutowire the instance of the class which holds @Autowire annotations - * @param beansToAutowireInClass the beans which have the @Autowire annotation in the specified - * {#classToAutowire} - */ - public static void autowire(Object classToAutowire, Object... beansToAutowireInClass) { - for (Object bean : beansToAutowireInClass) { - if (bean == null) { - applicationContext.getAutowireCapableBeanFactory().autowireBean(classToAutowire); - return; - } - } - } - - @Override - public void setApplicationContext(final ApplicationContext applicationContext) { - AutowireHelper.applicationContext = applicationContext; - } - - /** - * Get the singleton instance. - * - * @return the singleton instance. - */ - public static AutowireHelper getInstance() { - return INSTANCE; - } -} diff --git a/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt b/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt new file mode 100644 index 000000000..defda715f --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt @@ -0,0 +1,43 @@ +package org.radarbase.management.domain.support + +import org.springframework.context.ApplicationContext +import org.springframework.context.ApplicationContextAware +import org.springframework.stereotype.Component + +/** + * Class to inject dependencies into classes that do not support Autowire, such as JPA event + * listeners. + */ +@Component +class AutowireHelper private constructor() : ApplicationContextAware { + override fun setApplicationContext(applicationContext: ApplicationContext) { + Companion.applicationContext = applicationContext + } + + companion object { + /** + * Get the singleton instance. + * + * @return the singleton instance. + */ + val instance = AutowireHelper() + private var applicationContext: ApplicationContext? = null + + /** + * Tries to autowire the specified instance of the class if one of the specified beans which + * need to be autowired are null. + * + * @param classToAutowire the instance of the class which holds @Autowire annotations + * @param beansToAutowireInClass the beans which have the @Autowire annotation in the specified + * {#classToAutowire} + */ + fun autowire(classToAutowire: Any?, vararg beansToAutowireInClass: Any?) { + for (bean in beansToAutowireInClass) { + if (bean == null) { + applicationContext!!.autowireCapableBeanFactory.autowireBean(classToAutowire) + return + } + } + } + } +} diff --git a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java index 3c9e2af1d..48af8daa1 100644 --- a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java +++ b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java @@ -52,10 +52,10 @@ public void add(AuditEvent event) { if (!AUTHORIZATION_FAILURE.equals(eventType) && !Constants.ANONYMOUS_USER.equals(event.getPrincipal())) { PersistentAuditEvent persistentAuditEvent = new PersistentAuditEvent(); - persistentAuditEvent.setPrincipal(event.getPrincipal()); - persistentAuditEvent.setAuditEventType(eventType); - persistentAuditEvent.setAuditEventDate(LocalDateTime.ofInstant(event.getTimestamp(), - ZoneId.systemDefault())); + persistentAuditEvent.principal = event.getPrincipal(); + persistentAuditEvent.auditEventType = eventType; + persistentAuditEvent.auditEventDate = LocalDateTime.ofInstant(event.getTimestamp(), + ZoneId.systemDefault()); persistentAuditEvent.setData(auditEventConverter.convertDataToStrings(event.getData())); persistenceAuditEventRepository.save(persistentAuditEvent); } diff --git a/src/main/java/org/radarbase/management/repository/GroupRepository.java b/src/main/java/org/radarbase/management/repository/GroupRepository.java deleted file mode 100644 index 538286b9d..000000000 --- a/src/main/java/org/radarbase/management/repository/GroupRepository.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.repository; - -import org.radarbase.management.domain.Group; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -import java.util.Optional; - -@RepositoryDefinition(domainClass = Group.class, idClass = Long.class) -public interface GroupRepository extends JpaRepository, - RevisionRepository { - @Query("SELECT group FROM Group group " - + "WHERE group.project.id = :project_id " - + "AND group.name = :group_name") - Optional findByProjectIdAndName( - @Param("project_id") Long id, - @Param("group_name") String groupName); - - @Query("SELECT group FROM Group group " - + "LEFT JOIN Project project on group.project = project " - + "WHERE group.project.projectName = :project_name " - + "AND group.name = :group_name") - Optional findByProjectNameAndName( - @Param("project_name") String projectName, - @Param("group_name") String groupName); -} diff --git a/src/main/java/org/radarbase/management/repository/GroupRepository.kt b/src/main/java/org/radarbase/management/repository/GroupRepository.kt new file mode 100644 index 000000000..cd704bf5c --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/GroupRepository.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Group +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param + +@RepositoryDefinition(domainClass = Group::class, idClass = Long::class) +interface GroupRepository : JpaRepository, RevisionRepository { + @Query( + "SELECT group FROM Group group " + + "WHERE group.project.id = :project_id " + + "AND group.name = :group_name" + ) + fun findByProjectIdAndName( + @Param("project_id") id: Long?, + @Param("group_name") groupName: String? + ): Group? + + @Query( + "SELECT group FROM Group group " + + "LEFT JOIN Project project on group.project = project " + + "WHERE group.project.projectName = :project_name " + + "AND group.name = :group_name" + ) + fun findByProjectNameAndName( + @Param("project_name") projectName: String?, + @Param("group_name") groupName: String? + ): Group? +} diff --git a/src/main/java/org/radarbase/management/repository/ProjectRepository.java b/src/main/java/org/radarbase/management/repository/ProjectRepository.java deleted file mode 100644 index a6f81ee60..000000000 --- a/src/main/java/org/radarbase/management/repository/ProjectRepository.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.radarbase.management.repository; - -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.SourceType; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -import java.util.Collection; -import java.util.List; -import java.util.Optional; - -/** - * Spring Data JPA repository for the Project entity. - */ -@SuppressWarnings("unused") -@RepositoryDefinition(domainClass = Project.class, idClass = Long.class) -public interface ProjectRepository extends JpaRepository, - RevisionRepository { - @Query(value = "select distinct project from Project project " - + "left join fetch project.sourceTypes", - countQuery = "select distinct count(project) from Project project") - Page findAllWithEagerRelationships(Pageable pageable); - - @Query(value = "select distinct project from Project project " - + "left join fetch project.sourceTypes " - + "WHERE project.projectName in (:projectNames) " - + "OR project.organization.name in (:organizationNames)", - countQuery = "select distinct count(project) from Project project " - + "WHERE project.projectName in (:projectNames) " - + "OR project.organization.name in (:organizationNames)") - Page findAllWithEagerRelationshipsInOrganizationsOrProjects( - Pageable pageable, - @Param("organizationNames") Collection organizationNames, - @Param("projectNames") Collection projectNames); - - @Query("select project from Project project " - + "WHERE project.organization.name = :organization_name") - List findAllByOrganizationName( - @Param("organization_name") String organizationName); - - @Query("select project from Project project " - + "left join fetch project.sourceTypes s " - + "left join fetch project.groups " - + "left join fetch project.organization " - + "where project.id = :id") - Optional findOneWithEagerRelationships(@Param("id") Long id); - - @Query("select project from Project project " - + "left join fetch project.organization " - + "where project.id = :id") - Optional findByIdWithOrganization(@Param("id") Long id); - - @Query("select project from Project project " - + "left join fetch project.sourceTypes " - + "left join fetch project.groups " - + "left join fetch project.organization " - + "where project.projectName = :name") - Optional findOneWithEagerRelationshipsByName(@Param("name") String name); - - @Query("select project.id from Project project " - + "where project.projectName =:name") - Optional findProjectIdByName(@Param("name") String name); - - @Query("select project from Project project " - + "left join fetch project.groups " - + "where project.projectName = :name") - Optional findOneWithGroupsByName(@Param("name") String name); - - @Query("select project.sourceTypes from Project project WHERE project.id = :id") - List findSourceTypesByProjectId(@Param("id") Long id); - - @Query("select distinct sourceType from Project project " - + "left join project.sourceTypes sourceType " - + "where project.id =:id " - + "and sourceType.id = :sourceTypeId ") - Optional findSourceTypeByProjectIdAndSourceTypeId(@Param("id") Long id, - @Param("sourceTypeId") Long sourceTypeId); -} diff --git a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt new file mode 100644 index 000000000..bc0e44b8f --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt @@ -0,0 +1,101 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.SourceType +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param +import java.util.* + +/** + * Spring Data JPA repository for the Project entity. + */ +@Suppress("unused") +@RepositoryDefinition(domainClass = Project::class, idClass = Long::class) +interface ProjectRepository : JpaRepository, RevisionRepository { + @Query( + value = "select distinct project from Project project " + + "left join fetch project.sourceTypes", + countQuery = "select distinct count(project) from Project project" + ) + fun findAllWithEagerRelationships(pageable: Pageable?): Page? + + @Query( + value = "select distinct project from Project project " + + "left join fetch project.sourceTypes " + + "WHERE project.projectName in (:projectNames) " + + "OR project.organization.name in (:organizationNames)", + countQuery = "select distinct count(project) from Project project " + + "WHERE project.projectName in (:projectNames) " + + "OR project.organization.name in (:organizationNames)" + ) + fun findAllWithEagerRelationshipsInOrganizationsOrProjects( + pageable: Pageable?, + @Param("organizationNames") organizationNames: Collection?, + @Param("projectNames") projectNames: Collection? + ): Page? + + @Query( + "select project from Project project " + + "WHERE project.organization.name = :organization_name" + ) + fun findAllByOrganizationName( + @Param("organization_name") organizationName: String? + ): List? + + @Query( + "select project from Project project " + + "left join fetch project.sourceTypes s " + + "left join fetch project.groups " + + "left join fetch project.organization " + + "where project.id = :id" + ) + fun findOneWithEagerRelationships(@Param("id") id: Long?): Project? + + @Query( + "select project from Project project " + + "left join fetch project.organization " + + "where project.id = :id" + ) + fun findByIdWithOrganization(@Param("id") id: Long?): Project? + + @Query( + "select project from Project project " + + "left join fetch project.sourceTypes " + + "left join fetch project.groups " + + "left join fetch project.organization " + + "where project.projectName = :name" + ) + fun findOneWithEagerRelationshipsByName(@Param("name") name: String?): Project? + + @Query( + "select project.id from Project project " + + "where project.projectName =:name" + ) + fun findProjectIdByName(@Param("name") name: String?): Long? + + @Query( + "select project from Project project " + + "left join fetch project.groups " + + "where project.projectName = :name" + ) + fun findOneWithGroupsByName(@Param("name") name: String?): Project? + + @Query("select project.sourceTypes from Project project WHERE project.id = :id") + fun findSourceTypesByProjectId(@Param("id") id: Long?): List? + + @Query( + "select distinct sourceType from Project project " + + "left join project.sourceTypes sourceType " + + "where project.id =:id " + + "and sourceType.id = :sourceTypeId " + ) + fun findSourceTypeByProjectIdAndSourceTypeId( + @Param("id") id: Long?, + @Param("sourceTypeId") sourceTypeId: Long? + ): Optional? +} diff --git a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java index fc3a3a553..2382e7067 100644 --- a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java +++ b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java @@ -71,14 +71,14 @@ public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, userRepository.findOneByLogin(userName) .ifPresent(user -> { - var roles = user.getRoles().stream() + var roles = user.roles.stream() .map(role -> { - var auth = role.getAuthority().getName(); + var auth = role.authority.name; return switch (role.getRole().getScope()) { case GLOBAL -> auth; - case ORGANIZATION -> role.getOrganization().getName() + case ORGANIZATION -> role.organization.name + ":" + auth; - case PROJECT -> role.getProject().getProjectName() + case PROJECT -> role.project.projectName + ":" + auth; }; }) @@ -90,7 +90,7 @@ public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, Set newScopes = currentScopes.stream() .filter(scope -> { Permission permission = Permission.ofScope(scope); - var roleAuthorities = user.getRoles().stream() + var roleAuthorities = user.roles.stream() .map(Role::getRole) .collect(Collectors.toCollection(() -> EnumSet.noneOf(RoleAuthority.class))); @@ -107,7 +107,7 @@ public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, List assignedSources = subjectRepository.findSourcesBySubjectLogin(userName); List sourceIds = assignedSources.stream() - .map(s -> s.getSourceId().toString()) + .map(s -> s.sourceId.toString()) .toList(); additionalInfo.put(SOURCES_CLAIM, sourceIds); } diff --git a/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java b/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java index 3accf81bb..14a85f33f 100644 --- a/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java +++ b/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java @@ -39,18 +39,18 @@ public UserDetails loadUserByUsername(final String login) { User user = userRepository.findOneWithRolesByLogin(lowercaseLogin) .orElseThrow(() -> new UsernameNotFoundException( "User " + lowercaseLogin + " was not found in the database")); - if (!user.getActivated()) { + if (!user.activated) { throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated"); } List grantedAuthorities = user.getAuthorities().stream() - .map(authority -> new SimpleGrantedAuthority(authority.getName())) + .map(authority -> new SimpleGrantedAuthority(authority.name)) .collect(Collectors.toList()); return new org.springframework.security.core.userdetails.User( lowercaseLogin, - user.getPassword(), + user.password, grantedAuthorities); } } diff --git a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt index fd72bbb6a..6abd75069 100644 --- a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt +++ b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt @@ -5,24 +5,21 @@ import org.radarbase.auth.authorization.AuthorityReference import org.radarbase.auth.authorization.RoleAuthority import org.radarbase.auth.exception.TokenValidationException import org.radarbase.auth.token.RadarToken -import org.radarbase.management.config.OAuth2ServerConfiguration import org.radarbase.management.domain.Role import org.radarbase.management.domain.User import org.radarbase.management.repository.UserRepository import org.slf4j.LoggerFactory import org.springframework.http.HttpHeaders import org.springframework.http.HttpMethod -import org.springframework.security.authentication.AnonymousAuthenticationToken import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.core.Authentication -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.context.SecurityContextHolder import org.springframework.security.oauth2.provider.OAuth2Authentication import org.springframework.security.web.util.matcher.AntPathRequestMatcher import org.springframework.web.cors.CorsUtils import org.springframework.web.filter.OncePerRequestFilter import java.io.IOException +import java.io.Serializable import java.time.Instant import javax.annotation.Nonnull import javax.servlet.FilterChain @@ -189,15 +186,16 @@ class JwtAuthenticationFilter @JvmOverloads constructor( * from the database. * @return set of authority references. */ - val User.authorityReferences: Set - get() = roles.mapTo(HashSet()) { role: Role -> - val auth = role.role - val referent = when (auth.scope) { + val User.authorityReferences: Set? + get() = roles?.mapTo(HashSet()) { role: Role? -> + val auth = role?.role + val referent = when (auth?.scope) { RoleAuthority.Scope.GLOBAL -> null - RoleAuthority.Scope.ORGANIZATION -> role.organization.name - RoleAuthority.Scope.PROJECT -> role.project.projectName + RoleAuthority.Scope.ORGANIZATION -> role.organization?.name + RoleAuthority.Scope.PROJECT -> role.project?.projectName + null -> null } - AuthorityReference(auth, referent) + AuthorityReference(auth!!, referent) } diff --git a/src/main/java/org/radarbase/management/service/GroupService.java b/src/main/java/org/radarbase/management/service/GroupService.java deleted file mode 100644 index 016349e3f..000000000 --- a/src/main/java/org/radarbase/management/service/GroupService.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.service; - -import org.radarbase.management.domain.Group; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.repository.GroupRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.service.dto.GroupDTO; -import org.radarbase.management.service.mapper.GroupMapper; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ConflictException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.radarbase.management.web.rest.vm.GroupPatchOperation; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import javax.transaction.Transactional; -import java.util.ArrayList; -import java.util.List; - -import static org.radarbase.management.web.rest.errors.EntityName.GROUP; -import static org.radarbase.management.web.rest.errors.EntityName.PROJECT; -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_GROUP_EXISTS; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_GROUP_NOT_FOUND; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_VALIDATION; - -/** - * Service to manage project groups. - */ -@Service -public class GroupService { - @Autowired - private GroupRepository groupRepository; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private GroupMapper groupMapper; - - /** - * Get the group by name. - * @param projectName project name - * @param groupName group name - * @return group - * @throws NotFoundException if the project or group is not found. - */ - @Transactional - public GroupDTO getGroup(String projectName, String groupName) { - return groupMapper.groupToGroupDTOFull(groupRepository.findByProjectNameAndName(projectName, - groupName) - .orElseThrow(() -> new NotFoundException( - "Group " + groupName + " not found in project " + projectName, - GROUP, ERR_GROUP_NOT_FOUND))); - } - - /** - * Delete the group by name. - * @param projectName project name - * @param groupName group name - * @param unlinkSubjects unset group for each linked subject - * @throws NotFoundException if the project or group is not found. - */ - @Transactional - public void deleteGroup(String projectName, String groupName, boolean unlinkSubjects) { - Group group = groupRepository.findByProjectNameAndName(projectName, groupName) - .orElseThrow(() -> new NotFoundException( - "Group " + groupName + " not found in project " + projectName, - GROUP, ERR_GROUP_NOT_FOUND)); - - if (!unlinkSubjects) { - var subjectCount = subjectRepository.countByGroupId(group.getId()); - if (subjectCount > 0) { - var msg = "Group " + groupName + " has subjects. " - + "Add `unlinkSubjects=true` query param to confirm deletion"; - throw new ConflictException(msg, GROUP, ERR_VALIDATION); - } - } - groupRepository.delete(group); - } - - /** - * Create the group. - * @param projectName project name - * @param groupDto group values - * @throws NotFoundException if the project is not found. - * @throws ConflictException if the group name already exists. - */ - @Transactional - public GroupDTO createGroup(String projectName, GroupDTO groupDto) { - Project project = projectRepository.findOneWithGroupsByName(projectName) - .orElseThrow(() -> new NotFoundException( - "Project with name " + projectName + " not found", - PROJECT, ERR_PROJECT_NAME_NOT_FOUND)); - - if (project.getGroups().stream() - .anyMatch(g -> g.getName().equals(groupDto.getName()))) { - throw new ConflictException( - "Group " + groupDto.getName() + " already exists in project " + projectName, - GROUP, ERR_GROUP_EXISTS); - } - Group group = groupMapper.groupDTOToGroup(groupDto); - group.setProject(project); - - GroupDTO groupDtoResult = groupMapper.groupToGroupDTOFull(groupRepository.save(group)); - project.getGroups().add(group); - projectRepository.save(project); - return groupDtoResult; - } - - /** - * List all groups in a project. - * @param projectName project name - * @throws NotFoundException if the project is not found. - */ - public List listGroups(String projectName) { - Project project = projectRepository.findOneWithGroupsByName(projectName) - .orElseThrow(() -> new NotFoundException( - "Project with name " + projectName + " not found", - PROJECT, ERR_PROJECT_NAME_NOT_FOUND)); - return groupMapper.groupToGroupDTOs(project.getGroups()); - } - - /** - * Add subjects to group. - * @param projectName project name - * @param groupName group name - * @param subjectsToAdd patch items for subjects to be added - * @param subjectsToRemove patch items for subjects to be removed - * @throws NotFoundException if the project or group is not found. - */ - @Transactional - public void updateGroupSubjects( - String projectName, String groupName, - List subjectsToAdd, - List subjectsToRemove - ) { - Group group = groupRepository - .findByProjectNameAndName(projectName, groupName) - .orElseThrow(() -> new NotFoundException( - "Group " + groupName + " not found in project " + projectName, - GROUP, ERR_GROUP_NOT_FOUND)); - - List entitiesToAdd = getSubjectEntities(projectName, subjectsToAdd); - List entitiesToRemove = getSubjectEntities(projectName, subjectsToRemove); - - if (!entitiesToAdd.isEmpty()) { - List idsToAdd = entitiesToAdd.stream() - .map(Subject::getId) - .toList(); - subjectRepository.setGroupIdByIds(group.getId(), idsToAdd); - } - - if (!entitiesToRemove.isEmpty()) { - List idsToRemove = entitiesToRemove.stream() - .map(Subject::getId) - .toList(); - subjectRepository.unsetGroupIdByIds(idsToRemove); - } - } - - private List getSubjectEntities( - String projectName, - List subjectsToModify - ) { - List logins = new ArrayList<>(); - List ids = new ArrayList<>(); - - extractSubjectIdentities(subjectsToModify, logins, ids); - - List subjectEntities = new ArrayList<>(subjectsToModify.size()); - if (!ids.isEmpty()) { - subjectEntities.addAll(subjectRepository.findAllById(ids)); - } - if (!logins.isEmpty()) { - subjectEntities.addAll(subjectRepository.findAllBySubjectLogins(logins)); - } - - for (Subject s : subjectEntities) { - String login = s.getUser().getLogin(); - if (s.getActiveProject().isEmpty()) { - throw new BadRequestException( - "Subject " + login + " is not assigned to a project", - SUBJECT, ERR_VALIDATION); - } - if (!projectName.equals(s.getActiveProject().get().getProjectName())) { - throw new BadRequestException( - "Subject " + login + " belongs to a different project", - SUBJECT, ERR_VALIDATION); - } - } - - return subjectEntities; - } - - private void extractSubjectIdentities( - List subjectsToModify, - List logins, - List ids - ) { - // Each item should specify either a login or an ID, - // since having both will require an extra validation step - // to reject e.g. {id: 1, login: "subject-id-42"}. - // Whether the IDs and logins exist and belong to the project - // should be checked later - for (var item : subjectsToModify) { - String login = item.getLogin(); - Long id = item.getId(); - if (id == null && login == null) { - throw new BadRequestException( - "Subject identification must be specified", - GROUP, ERR_VALIDATION); - } - if (id != null && login != null) { - throw new BadRequestException( - "Subject identification must be specify either ID or Login. " - + "Do not provide both values to avoid potential confusion.", - GROUP, ERR_VALIDATION); - } - - if (id != null) { - ids.add(id); - } - if (login != null) { - logins.add(login); - } - } - } -} diff --git a/src/main/java/org/radarbase/management/service/GroupService.kt b/src/main/java/org/radarbase/management/service/GroupService.kt new file mode 100644 index 000000000..b30b94195 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/GroupService.kt @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.service + +import org.radarbase.management.domain.Group +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.GroupRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.service.dto.GroupDTO +import org.radarbase.management.service.mapper.GroupMapper +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.ConflictException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.radarbase.management.web.rest.vm.GroupPatchOperation.SubjectPatchValue +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import javax.transaction.Transactional + +/** + * Service to manage project groups. + */ +@Service +open class GroupService( + @Autowired private val groupRepository: GroupRepository, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val groupMapper: GroupMapper +) { + + /** + * Get the group by name. + * @param projectName project name + * @param groupName group name + * @return group + * @throws NotFoundException if the project or group is not found. + */ + @Throws(NotFoundException::class) + @Transactional + open fun getGroup(projectName: String, groupName: String): GroupDTO { + return groupMapper.groupToGroupDTOFull( + groupRepository.findByProjectNameAndName( + projectName, + groupName + ) + ?: throw NotFoundException( + "Group $groupName not found in project $projectName", + EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + ) + ) + } + + /** + * Delete the group by name. + * @param projectName project name + * @param groupName group name + * @param unlinkSubjects unset group for each linked subject + * @throws NotFoundException if the project or group is not found. + */ + @Transactional + open fun deleteGroup(projectName: String, groupName: String, unlinkSubjects: Boolean) { + val group = groupRepository.findByProjectNameAndName(projectName, groupName) + ?: throw NotFoundException( + "Group $groupName not found in project $projectName", + EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + ) + if (!unlinkSubjects) { + val subjectCount = subjectRepository.countByGroupId(group.id) + if (subjectCount > 0) { + val msg = ("Group " + groupName + " has subjects. " + + "Add `unlinkSubjects=true` query param to confirm deletion") + throw ConflictException(msg, EntityName.GROUP, ErrorConstants.ERR_VALIDATION) + } + } + groupRepository.delete(group) + } + + /** + * Create the group. + * @param projectName project name + * @param groupDto group values + * @throws NotFoundException if the project is not found. + * @throws ConflictException if the group name already exists. + */ + @Transactional + open fun createGroup(projectName: String, groupDto: GroupDTO): GroupDTO { + val project = projectRepository.findOneWithGroupsByName(projectName) + ?: throw NotFoundException( + "Project with name $projectName not found", + EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND + ) + if (project.groups.stream() + .anyMatch { g: Group -> g.name == groupDto.name } + ) { + throw ConflictException( + "Group " + groupDto.name + " already exists in project " + projectName, + EntityName.GROUP, ErrorConstants.ERR_GROUP_EXISTS + ) + } + val group = groupMapper.groupDTOToGroup(groupDto) + group.project = project + val groupDtoResult = groupMapper.groupToGroupDTOFull(groupRepository.save(group)) + project.groups.add(group) + projectRepository.save(project) + return groupDtoResult + } + + /** + * List all groups in a project. + * @param projectName project name + * @throws NotFoundException if the project is not found. + */ + fun listGroups(projectName: String): List { + val project = projectRepository.findOneWithGroupsByName(projectName) + ?: throw NotFoundException( + "Project with name $projectName not found", + EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND + ) + return groupMapper.groupToGroupDTOs(project.groups) + } + + /** + * Add subjects to group. + * @param projectName project name + * @param groupName group name + * @param subjectsToAdd patch items for subjects to be added + * @param subjectsToRemove patch items for subjects to be removed + * @throws NotFoundException if the project or group is not found. + */ + @Transactional + open fun updateGroupSubjects( + projectName: String, groupName: String, + subjectsToAdd: List, + subjectsToRemove: List + ) { + + groupRepository ?: throw NullPointerException() + + val group = groupRepository.findByProjectNameAndName(projectName, groupName) + ?: throw NotFoundException( + "Group $groupName not found in project $projectName", + EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + ) + + val entitiesToAdd = getSubjectEntities(projectName, subjectsToAdd) + val entitiesToRemove = getSubjectEntities(projectName, subjectsToRemove) + if (entitiesToAdd.isNotEmpty()) { + val idsToAdd = entitiesToAdd.stream() + .map(Subject::id) + .toList() + subjectRepository.setGroupIdByIds(group.id, idsToAdd) + } + if (entitiesToRemove.isNotEmpty()) { + val idsToRemove = entitiesToRemove.stream() + .map(Subject::id) + .toList() + subjectRepository.unsetGroupIdByIds(idsToRemove) + } + } + + private fun getSubjectEntities( + projectName: String, + subjectsToModify: List + ): List { + val logins: MutableList = ArrayList() + val ids: MutableList = ArrayList() + extractSubjectIdentities(subjectsToModify, logins, ids) + val subjectEntities: MutableList = ArrayList(subjectsToModify.size) + if (!ids.isEmpty()) { + subjectEntities.addAll(subjectRepository.findAllById(ids)) + } + if (!logins.isEmpty()) { + subjectEntities.addAll(subjectRepository.findAllBySubjectLogins(logins)) + } + for (s in subjectEntities) { + val login = s.user!!.login + s.activeProject ?: throw BadRequestException( + "Subject $login is not assigned to a project", + EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION + ) + if (projectName != s.activeProject!!.projectName) { + throw BadRequestException( + "Subject $login belongs to a different project", + EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION + ) + } + } + return subjectEntities + } + + private fun extractSubjectIdentities( + subjectsToModify: List, + logins: MutableList, + ids: MutableList + ) { + // Each item should specify either a login or an ID, + // since having both will require an extra validation step + // to reject e.g. {id: 1, login: "subject-id-42"}. + // Whether the IDs and logins exist and belong to the project + // should be checked later + for (item in subjectsToModify) { + val login = item.login + val id = item.id + if (id == null && login == null) { + throw BadRequestException( + "Subject identification must be specified", + EntityName.GROUP, ErrorConstants.ERR_VALIDATION + ) + } + if (id != null && login != null) { + throw BadRequestException( + "Subject identification must be specify either ID or Login. " + + "Do not provide both values to avoid potential confusion.", + EntityName.GROUP, ErrorConstants.ERR_VALIDATION + ) + } + if (id != null) { + ids.add(id) + } + if (login != null) { + logins.add(login) + } + } + } +} diff --git a/src/main/java/org/radarbase/management/service/MailService.java b/src/main/java/org/radarbase/management/service/MailService.java index 5dbcb30d6..788222773 100644 --- a/src/main/java/org/radarbase/management/service/MailService.java +++ b/src/main/java/org/radarbase/management/service/MailService.java @@ -81,15 +81,15 @@ public void sendEmail(String to, String subject, String content, boolean isMulti */ @Async public void sendActivationEmail(User user) { - log.debug("Sending activation email to '{}'", user.getEmail()); - Locale locale = Locale.forLanguageTag(user.getLangKey()); + log.debug("Sending activation email to '{}'", user.email); + Locale locale = Locale.forLanguageTag(user.langKey); Context context = new Context(locale); context.setVariable(USER, user); context.setVariable(BASE_URL, managementPortalProperties.getCommon().getManagementPortalBaseUrl()); String content = templateEngine.process("activationEmail", context); String subject = messageSource.getMessage("email.activation.title", null, locale); - sendEmail(user.getEmail(), subject, content, false, true); + sendEmail(user.email, subject, content, false, true); } /** @@ -98,8 +98,8 @@ public void sendActivationEmail(User user) { */ @Async public void sendCreationEmail(User user, long duration) { - log.debug("Sending creation email to '{}'", user.getEmail()); - Locale locale = Locale.forLanguageTag(user.getLangKey()); + log.debug("Sending creation email to '{}'", user.email); + Locale locale = Locale.forLanguageTag(user.langKey); Context context = new Context(locale); context.setVariable(USER, user); context.setVariable(BASE_URL, @@ -107,7 +107,7 @@ public void sendCreationEmail(User user, long duration) { context.setVariable(EXPIRY, Duration.ofSeconds(duration).toHours()); String content = templateEngine.process("creationEmail", context); String subject = messageSource.getMessage("email.activation.title", null, locale); - sendEmail(user.getEmail(), subject, content, false, true); + sendEmail(user.email, subject, content, false, true); } /** @@ -118,7 +118,7 @@ public void sendCreationEmail(User user, long duration) { @Async public void sendCreationEmailForGivenEmail(User user, String email) { log.debug("Sending creation email to '{}'", email); - Locale locale = Locale.forLanguageTag(user.getLangKey()); + Locale locale = Locale.forLanguageTag(user.langKey); Context context = new Context(locale); context.setVariable(USER, user); context.setVariable(BASE_URL, @@ -134,14 +134,14 @@ public void sendCreationEmailForGivenEmail(User user, String email) { */ @Async public void sendPasswordResetMail(User user) { - log.debug("Sending password reset email to '{}'", user.getEmail()); - Locale locale = Locale.forLanguageTag(user.getLangKey()); + log.debug("Sending password reset email to '{}'", user.email); + Locale locale = Locale.forLanguageTag(user.langKey); Context context = new Context(locale); context.setVariable(USER, user); context.setVariable(BASE_URL, managementPortalProperties.getCommon().getManagementPortalBaseUrl()); String content = templateEngine.process("passwordResetEmail", context); String subject = messageSource.getMessage("email.reset.title", null, locale); - sendEmail(user.getEmail(), subject, content, false, true); + sendEmail(user.email, subject, content, false, true); } } diff --git a/src/main/java/org/radarbase/management/service/MetaTokenService.java b/src/main/java/org/radarbase/management/service/MetaTokenService.java deleted file mode 100644 index 248c07a9f..000000000 --- a/src/main/java/org/radarbase/management/service/MetaTokenService.java +++ /dev/null @@ -1,236 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.MetaToken; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.repository.MetaTokenRepository; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.dto.ClientPairInfoDTO; -import org.radarbase.management.service.dto.TokenDTO; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.InvalidStateException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.radarbase.management.web.rest.errors.RequestGoneException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.validation.ConstraintViolationException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.time.Duration; -import java.time.Instant; -import java.time.format.DateTimeParseException; -import java.util.Collections; - -import static org.radarbase.management.domain.MetaToken.LONG_ID_LENGTH; -import static org.radarbase.management.domain.MetaToken.SHORT_ID_LENGTH; -import static org.radarbase.management.web.rest.MetaTokenResource.DEFAULT_META_TOKEN_TIMEOUT; -import static org.radarbase.management.web.rest.MetaTokenResource.DEFAULT_PERSISTENT_META_TOKEN_TIMEOUT; -import static org.radarbase.management.web.rest.errors.EntityName.META_TOKEN; -import static org.radarbase.management.web.rest.errors.EntityName.OAUTH_CLIENT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_PERSISTENT_TOKEN_DISABLED; - -/** - * Created by nivethika. - * - *

Service to delegate MetaToken handling.

- * - */ -@Service -@Transactional -public class MetaTokenService { - - private static final Logger log = LoggerFactory.getLogger(MetaTokenService.class); - - @Autowired - private MetaTokenRepository metaTokenRepository; - - @Autowired - private OAuthClientService oAuthClientService; - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Autowired - private SubjectService subjectService; - - /** - * Save a metaToken. - * - * @param metaToken the entity to save - * @return the persisted entity - */ - public MetaToken save(MetaToken metaToken) { - log.debug("Request to save MetaToken : {}", metaToken); - return metaTokenRepository.save(metaToken); - } - - /** - * Get one project by id. - * - * @param tokenName the id of the entity - * @return the entity - */ - public TokenDTO fetchToken(String tokenName) throws MalformedURLException { - log.debug("Request to get Token : {}", tokenName); - MetaToken metaToken = getToken(tokenName); - // process the response if the token is not fetched or not expired - if (metaToken.isValid()) { - String refreshToken = oAuthClientService.createAccessToken( - metaToken.getSubject().getUser(), - metaToken.getClientId()) - .getRefreshToken() - .getValue(); - - // create response - TokenDTO result = new TokenDTO(refreshToken, - new URL(managementPortalProperties.getCommon().getBaseUrl()), - subjectService.getPrivacyPolicyUrl(metaToken.getSubject())); - - // change fetched status to true. - if (!metaToken.isFetched()) { - metaToken.fetched(true); - save(metaToken); - } - return result; - } else { - throw new RequestGoneException("Token " + tokenName + " already fetched or expired. ", - META_TOKEN, "error.TokenCannotBeSent"); - } - } - - /** - * Gets a token from databased using the tokenName. - * - * @param tokenName tokenName. - * @return fetched token as {@link MetaToken}. - */ - @Transactional(readOnly = true) - public MetaToken getToken(String tokenName) { - return metaTokenRepository.findOneByTokenName(tokenName) - .orElseThrow(() -> new NotFoundException("Meta token not found with tokenName", - META_TOKEN, - ErrorConstants.ERR_TOKEN_NOT_FOUND, - Collections.singletonMap("tokenName", tokenName))); - } - - /** - * Saves a unique meta-token instance, by checking for token-name collision. - * If a collision is detection, we try to save the token with a new tokenName - * @return an unique token - */ - public MetaToken saveUniqueToken(Subject subject, String clientId, Boolean - fetched, Instant expiryTime, boolean persistent) { - MetaToken metaToken = new MetaToken() - .generateName(persistent ? LONG_ID_LENGTH : SHORT_ID_LENGTH) - .fetched(fetched) - .expiryDate(expiryTime) - .subject(subject) - .clientId(clientId) - .persistent(persistent); - - try { - return metaTokenRepository.save(metaToken); - } catch (ConstraintViolationException e) { - log.warn("Unique constraint violation catched... Trying to save with new tokenName"); - return saveUniqueToken(subject, clientId, fetched, expiryTime, persistent); - } - } - - /** - * Creates meta token for oauth-subject pair. - * @param subject to create token for - * @param clientId using which client id - * @param persistent whether to persist the token after it is has been fetched - * @return {@link ClientPairInfoDTO} to return. - * @throws URISyntaxException when token URI cannot be formed properly. - * @throws MalformedURLException when token URL cannot be formed properly. - */ - public ClientPairInfoDTO createMetaToken(Subject subject, String clientId, boolean persistent) - throws URISyntaxException, MalformedURLException, NotAuthorizedException { - Duration timeout = getMetaTokenTimeout(persistent, subject.getActiveProject() - .orElseThrow(() -> new NotAuthorizedException( - "Cannot calculate meta-token duration without configured project"))); - - // tokenName should be generated - MetaToken metaToken = saveUniqueToken(subject, clientId, false, - Instant.now().plus(timeout), persistent); - - if (metaToken.getId() != null && metaToken.getTokenName() != null) { - // get base url from settings - String baseUrl = managementPortalProperties.getCommon().getManagementPortalBaseUrl(); - // create complete uri string - String tokenUrl = baseUrl + ResourceUriService.getUri(metaToken).getPath(); - // create response - return new ClientPairInfoDTO(new URL(baseUrl), metaToken.getTokenName(), - new URL(tokenUrl), timeout); - } else { - throw new InvalidStateException("Could not create a valid token", OAUTH_CLIENT, - "error.couldNotCreateToken"); - } - } - - /** - * Gets the meta-token timeout from config file. If the config is not mentioned or in wrong - * format, it will return default value. - * - * @return meta-token timeout duration. - * @throws BadRequestException if a persistent token is requested but it is not configured. - */ - public Duration getMetaTokenTimeout(boolean persistent, Project project) { - String timeoutConfig; - Duration defaultTimeout; - - if (persistent) { - timeoutConfig = managementPortalProperties.getOauth().getPersistentMetaTokenTimeout(); - if (timeoutConfig == null || timeoutConfig.isEmpty()) { - throw new BadRequestException( - "Cannot create persistent token: not supported in configuration.", - META_TOKEN, ERR_PERSISTENT_TOKEN_DISABLED); - } - defaultTimeout = DEFAULT_PERSISTENT_META_TOKEN_TIMEOUT; - } else { - timeoutConfig = managementPortalProperties.getOauth().getMetaTokenTimeout(); - defaultTimeout = DEFAULT_META_TOKEN_TIMEOUT; - if (timeoutConfig == null || timeoutConfig.isEmpty()) { - return defaultTimeout; - } - } - - try { - return Duration.parse(timeoutConfig); - } catch (DateTimeParseException e) { - // if the token timeout cannot be read, log the error and use the default value. - log.warn("Cannot parse meta-token timeout config. Using default value {}", - defaultTimeout, e); - return defaultTimeout; - } - } - - /** - * Expired and fetched tokens are deleted after 1 month. - *

This is scheduled to get triggered first day of the month.

- */ - @Scheduled(cron = "0 0 0 1 * ?") - public void removeStaleTokens() { - log.info("Scheduled scan for expired and fetched meta-tokens starting now"); - - metaTokenRepository.findAllByFetchedOrExpired(Instant.now()) - .forEach(metaToken -> { - log.info("Deleting deleting expired or fetched token {}", - metaToken.getTokenName()); - metaTokenRepository.delete(metaToken); - }); - } - - public void delete(MetaToken token) { - metaTokenRepository.delete(token); - } -} diff --git a/src/main/java/org/radarbase/management/service/MetaTokenService.kt b/src/main/java/org/radarbase/management/service/MetaTokenService.kt new file mode 100644 index 000000000..9a8bfe961 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/MetaTokenService.kt @@ -0,0 +1,253 @@ +package org.radarbase.management.service + +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.MetaToken +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.MetaTokenRepository +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.dto.ClientPairInfoDTO +import org.radarbase.management.service.dto.TokenDTO +import org.radarbase.management.web.rest.MetaTokenResource +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidStateException +import org.radarbase.management.web.rest.errors.NotFoundException +import org.radarbase.management.web.rest.errors.RequestGoneException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.net.MalformedURLException +import java.net.URISyntaxException +import java.net.URL +import java.time.Duration +import java.time.Instant +import java.time.format.DateTimeParseException +import java.util.* +import java.util.function.Consumer +import javax.validation.ConstraintViolationException + +/** + * Created by nivethika. + * + * + * Service to delegate MetaToken handling. + * + */ +@Service +@Transactional +open class MetaTokenService { + @Autowired + private val metaTokenRepository: MetaTokenRepository? = null + + @Autowired + private val oAuthClientService: OAuthClientService? = null + + @Autowired + private val managementPortalProperties: ManagementPortalProperties? = null + + @Autowired + private val subjectService: SubjectService? = null + + /** + * Save a metaToken. + * + * @param metaToken the entity to save + * @return the persisted entity + */ + fun save(metaToken: MetaToken): MetaToken { + log.debug("Request to save MetaToken : {}", metaToken) + return metaTokenRepository!!.save(metaToken) + } + + /** + * Get one project by id. + * + * @param tokenName the id of the entity + * @return the entity + */ + @Throws(MalformedURLException::class) + fun fetchToken(tokenName: String): TokenDTO { + log.debug("Request to get Token : {}", tokenName) + val metaToken = getToken(tokenName) + // process the response if the token is not fetched or not expired + return if (metaToken.isValid) { + val refreshToken = oAuthClientService!!.createAccessToken( + metaToken.subject!!.user, + metaToken.clientId + ) + .refreshToken + .value + + // create response + val result = TokenDTO( + refreshToken, + URL(managementPortalProperties!!.common.baseUrl), + subjectService!!.getPrivacyPolicyUrl(metaToken.subject!!) + ) + + // change fetched status to true. + if (!metaToken.isFetched()) { + metaToken.fetched(true) + save(metaToken) + } + result + } else { + throw RequestGoneException( + "Token $tokenName already fetched or expired. ", + EntityName.META_TOKEN, "error.TokenCannotBeSent" + ) + } + } + + /** + * Gets a token from databased using the tokenName. + * + * @param tokenName tokenName. + * @return fetched token as [MetaToken]. + */ + @Transactional(readOnly = true) + open fun getToken(tokenName: String): MetaToken { + return metaTokenRepository!!.findOneByTokenName(tokenName) + .orElseThrow { + NotFoundException( + "Meta token not found with tokenName", + EntityName.META_TOKEN, + ErrorConstants.ERR_TOKEN_NOT_FOUND, + Collections.singletonMap("tokenName", tokenName) + ) + } + } + + /** + * Saves a unique meta-token instance, by checking for token-name collision. + * If a collision is detection, we try to save the token with a new tokenName + * @return an unique token + */ + fun saveUniqueToken( + subject: Subject?, + clientId: String?, + fetched: Boolean?, + expiryTime: Instant?, + persistent: Boolean + ): MetaToken { + val metaToken = MetaToken() + .generateName(if (persistent) MetaToken.LONG_ID_LENGTH else MetaToken.SHORT_ID_LENGTH) + .fetched(fetched!!) + .expiryDate(expiryTime) + .subject(subject) + .clientId(clientId) + .persistent(persistent) + return try { + metaTokenRepository!!.save(metaToken) + } catch (e: ConstraintViolationException) { + log.warn("Unique constraint violation catched... Trying to save with new tokenName") + saveUniqueToken(subject, clientId, fetched, expiryTime, persistent) + } + } + + /** + * Creates meta token for oauth-subject pair. + * @param subject to create token for + * @param clientId using which client id + * @param persistent whether to persist the token after it is has been fetched + * @return [ClientPairInfoDTO] to return. + * @throws URISyntaxException when token URI cannot be formed properly. + * @throws MalformedURLException when token URL cannot be formed properly. + */ + @Throws(URISyntaxException::class, MalformedURLException::class, NotAuthorizedException::class) + fun createMetaToken(subject: Subject, clientId: String?, persistent: Boolean): ClientPairInfoDTO { + val timeout = getMetaTokenTimeout(persistent, project = subject.activeProject + ?:throw NotAuthorizedException("Cannot calculate meta-token duration without configured project") + ) + + // tokenName should be generated + val metaToken = saveUniqueToken( + subject, clientId, false, + Instant.now().plus(timeout), persistent + ) + return if (metaToken.id != null && metaToken.tokenName != null) { + // get base url from settings + val baseUrl = managementPortalProperties!!.common.managementPortalBaseUrl + // create complete uri string + val tokenUrl = baseUrl + ResourceUriService.getUri(metaToken).getPath() + // create response + ClientPairInfoDTO( + URL(baseUrl), metaToken.tokenName, + URL(tokenUrl), timeout + ) + } else { + throw InvalidStateException( + "Could not create a valid token", EntityName.OAUTH_CLIENT, + "error.couldNotCreateToken" + ) + } + } + + /** + * Gets the meta-token timeout from config file. If the config is not mentioned or in wrong + * format, it will return default value. + * + * @return meta-token timeout duration. + * @throws BadRequestException if a persistent token is requested but it is not configured. + */ + fun getMetaTokenTimeout(persistent: Boolean, project: Project?): Duration { + val timeoutConfig: String? + val defaultTimeout: Duration + if (persistent) { + timeoutConfig = managementPortalProperties!!.oauth.persistentMetaTokenTimeout + if (timeoutConfig == null || timeoutConfig.isEmpty()) { + throw BadRequestException( + "Cannot create persistent token: not supported in configuration.", + EntityName.META_TOKEN, ErrorConstants.ERR_PERSISTENT_TOKEN_DISABLED + ) + } + defaultTimeout = MetaTokenResource.DEFAULT_PERSISTENT_META_TOKEN_TIMEOUT + } else { + timeoutConfig = managementPortalProperties!!.oauth.metaTokenTimeout + defaultTimeout = MetaTokenResource.DEFAULT_META_TOKEN_TIMEOUT + if (timeoutConfig == null || timeoutConfig.isEmpty()) { + return defaultTimeout + } + } + return try { + Duration.parse(timeoutConfig) + } catch (e: DateTimeParseException) { + // if the token timeout cannot be read, log the error and use the default value. + log.warn( + "Cannot parse meta-token timeout config. Using default value {}", + defaultTimeout, e + ) + defaultTimeout + } + } + + /** + * Expired and fetched tokens are deleted after 1 month. + * + * This is scheduled to get triggered first day of the month. + */ + @Scheduled(cron = "0 0 0 1 * ?") + fun removeStaleTokens() { + log.info("Scheduled scan for expired and fetched meta-tokens starting now") + metaTokenRepository!!.findAllByFetchedOrExpired(Instant.now()) + .forEach(Consumer { metaToken: MetaToken -> + log.info( + "Deleting deleting expired or fetched token {}", + metaToken.tokenName + ) + metaTokenRepository.delete(metaToken) + }) + } + + fun delete(token: MetaToken) { + metaTokenRepository!!.delete(token) + } + + companion object { + private val log = LoggerFactory.getLogger(MetaTokenService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/service/OAuthClientService.java b/src/main/java/org/radarbase/management/service/OAuthClientService.java index cf79f846d..afc8fcf2e 100644 --- a/src/main/java/org/radarbase/management/service/OAuthClientService.java +++ b/src/main/java/org/radarbase/management/service/OAuthClientService.java @@ -163,7 +163,7 @@ public ClientDetails createClientDetail(ClientDetailsDTO clientDetailsDto) { */ public OAuth2AccessToken createAccessToken(User user, String clientId) { Set authorities = user.getAuthorities().stream() - .map(a -> new SimpleGrantedAuthority(a.getName())) + .map(a -> new SimpleGrantedAuthority(a.name)) .collect(Collectors.toSet()); // lookup the OAuth client // getOAuthClient checks if the id exists diff --git a/src/main/java/org/radarbase/management/service/OrganizationService.java b/src/main/java/org/radarbase/management/service/OrganizationService.java index df6c66cbc..b1d7a1703 100644 --- a/src/main/java/org/radarbase/management/service/OrganizationService.java +++ b/src/main/java/org/radarbase/management/service/OrganizationService.java @@ -122,7 +122,7 @@ public List findAllProjectsByOrganizationName(String organizationNam projectStream = projectRepository.findAllByOrganizationName(organizationName).stream(); } else if (referents.hasAnyProjects()) { projectStream = projectRepository.findAllByOrganizationName(organizationName).stream() - .filter(project -> referents.hasAnyProject(project.getProjectName())); + .filter(project -> referents.hasAnyProject(project.projectName)); } else { return List.of(); } diff --git a/src/main/java/org/radarbase/management/service/ProjectService.java b/src/main/java/org/radarbase/management/service/ProjectService.java deleted file mode 100644 index ef55bd111..000000000 --- a/src/main/java/org/radarbase/management/service/ProjectService.java +++ /dev/null @@ -1,143 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.service.mapper.SourceTypeMapper; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collections; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.PROJECT_READ; -import static org.radarbase.management.web.rest.errors.EntityName.PROJECT; - -/** - * Service Implementation for managing Project. - */ -@Service -@Transactional -public class ProjectService { - - private static final Logger log = LoggerFactory.getLogger(ProjectService.class); - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private ProjectMapper projectMapper; - - @Autowired - private SourceTypeMapper sourceTypeMapper; - - @Autowired - private AuthService authService; - - - /** - * Save a project. - * - * @param projectDto the entity to save - * @return the persisted entity - */ - public ProjectDTO save(ProjectDTO projectDto) { - log.debug("Request to save Project : {}", projectDto); - Project project = projectMapper.projectDTOToProject(projectDto); - project = projectRepository.save(project); - return projectMapper.projectToProjectDTO(project); - } - - /** - * Get all the projects. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public Page findAll(Boolean fetchMinimal, Pageable pageable) { - Page projects; - - var referents = authService.referentsByScope(PROJECT_READ); - if (referents.isEmpty()) { - projects = new PageImpl<>(List.of()); - } else if (referents.getGlobal()) { - projects = projectRepository.findAllWithEagerRelationships(pageable); - } else { - projects = projectRepository.findAllWithEagerRelationshipsInOrganizationsOrProjects( - pageable, referents.getOrganizations(), referents.getAllProjects()); - } - - if (!fetchMinimal) { - return projects.map(projectMapper::projectToProjectDTO); - } else { - return projects.map(projectMapper::projectToMinimalProjectDetailsDTO); - } - } - - /** - * Get one project by id. - * - * @param id the id of the entity - * @return the entity - */ - @Transactional(readOnly = true) - public ProjectDTO findOne(Long id) { - log.debug("Request to get Project : {}", id); - return projectRepository.findOneWithEagerRelationships(id) - .map(projectMapper::projectToProjectDTO) - .orElseThrow(() -> new NotFoundException("Project not found with id", PROJECT, - ErrorConstants.ERR_PROJECT_ID_NOT_FOUND, - Collections.singletonMap("id", id.toString()))); - } - - /** - * Get one project by name. - * - * @param name the name of the entity - * @return the entity - */ - @Transactional(readOnly = true) - public ProjectDTO findOneByName(String name) { - log.debug("Request to get Project by name: {}", name); - return projectRepository.findOneWithEagerRelationshipsByName(name) - .map(projectMapper::projectToProjectDTO) - .orElseThrow(() -> new NotFoundException( - "Project not found with projectName " + name, - PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND, - Collections.singletonMap("projectName", name))); - } - - /** - * Get source-types assigned to a project. - * - * @param id the id of the project - * @return the list of source-types assigned. - */ - @Transactional(readOnly = true) - public List findSourceTypesByProjectId(Long id) { - log.debug("Request to get Project.sourceTypes of project: {}", id); - List sourceTypes = projectRepository.findSourceTypesByProjectId(id); - return sourceTypeMapper.sourceTypesToSourceTypeDTOs(sourceTypes); - } - - /** - * Delete the project by id. - * - * @param id the id of the entity - */ - public void delete(Long id) { - log.debug("Request to delete Project : {}", id); - projectRepository.deleteById(id); - } -} diff --git a/src/main/java/org/radarbase/management/service/ProjectService.kt b/src/main/java/org/radarbase/management/service/ProjectService.kt new file mode 100644 index 000000000..5f273f341 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/ProjectService.kt @@ -0,0 +1,134 @@ +package org.radarbase.management.service + +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.Project +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SourceTypeDTO +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.service.mapper.SourceTypeMapper +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Page +import org.springframework.data.domain.PageImpl +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.util.* + +/** + * Service Implementation for managing Project. + */ +@Service +@Transactional +open class ProjectService( + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val sourceTypeMapper: SourceTypeMapper, + @Autowired private val authService: AuthService +) { + + /** + * Save a project. + * + * @param projectDto the entity to save + * @return the persisted entity + */ + fun save(projectDto: ProjectDTO?): ProjectDTO { + log.debug("Request to save Project : {}", projectDto) + var project = projectMapper.projectDTOToProject(projectDto) + project = projectRepository.save(project) + return projectMapper.projectToProjectDTO(project) + } + + /** + * Get all the projects. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(fetchMinimal: Boolean?, pageable: Pageable?): Page<*> { + val projects: Page? + val referents = authService.referentsByScope(Permission.PROJECT_READ) + projects = if (referents.isEmpty()) { + PageImpl(listOf()) + } else if (referents.global) { + projectRepository.findAllWithEagerRelationships(pageable) + } else { + projectRepository.findAllWithEagerRelationshipsInOrganizationsOrProjects( + pageable, referents.organizations, referents.allProjects + ) + } + return if (!fetchMinimal!!) { + projects!!.map { project: Project? -> projectMapper.projectToProjectDTO(project) } + } else { + projects!!.map { project: Project? -> projectMapper.projectToMinimalProjectDetailsDTO(project) } + } + } + + /** + * Get one project by id. + * + * @param id the id of the entity + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOne(id: Long): ProjectDTO { + log.debug("Request to get Project : {}", id) + return projectRepository.findOneWithEagerRelationships(id) + .let { project: Project? -> projectMapper.projectToProjectDTO(project) } ?: throw NotFoundException( + "Project not found with id", + EntityName.PROJECT, + ErrorConstants.ERR_PROJECT_ID_NOT_FOUND, + Collections.singletonMap("id", id.toString()) + ) + } + + /** + * Get one project by name. + * + * @param name the name of the entity + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOneByName(name: String): ProjectDTO { + log.debug("Request to get Project by name: {}", name) + return projectRepository.findOneWithEagerRelationshipsByName(name) + .let { project: Project? -> projectMapper.projectToProjectDTO(project) } ?: throw NotFoundException( + "Project not found with projectName $name", + EntityName.PROJECT, + ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND, + Collections.singletonMap("projectName", name) + ) + } + + /** + * Get source-types assigned to a project. + * + * @param id the id of the project + * @return the list of source-types assigned. + */ + @Transactional(readOnly = true) + open fun findSourceTypesByProjectId(id: Long?): List { + log.debug("Request to get Project.sourceTypes of project: {}", id) + val sourceTypes = projectRepository.findSourceTypesByProjectId(id) + return sourceTypeMapper.sourceTypesToSourceTypeDTOs(sourceTypes) + } + + /** + * Delete the project by id. + * + * @param id the id of the entity + */ + fun delete(id: Long) { + log.debug("Request to delete Project : {}", id) + projectRepository.deleteById(id) + } + + companion object { + private val log = LoggerFactory.getLogger(ProjectService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/service/ResourceUriService.java b/src/main/java/org/radarbase/management/service/ResourceUriService.java index f16481f85..1c23760c8 100644 --- a/src/main/java/org/radarbase/management/service/ResourceUriService.java +++ b/src/main/java/org/radarbase/management/service/ResourceUriService.java @@ -105,7 +105,7 @@ public static URI getUri(SourceDTO resource) throws URISyntaxException { * @throws URISyntaxException See {@link URI#URI(String)} */ public static URI getUri(Source resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "sources", resource.getSourceName())); + return new URI(HeaderUtil.buildPath("api", "sources", resource.sourceName)); } /** diff --git a/src/main/java/org/radarbase/management/service/RevisionService.java b/src/main/java/org/radarbase/management/service/RevisionService.java deleted file mode 100644 index 627cdaf17..000000000 --- a/src/main/java/org/radarbase/management/service/RevisionService.java +++ /dev/null @@ -1,391 +0,0 @@ -package org.radarbase.management.service; - -import static java.util.stream.Collectors.toList; -import static org.radarbase.management.web.rest.errors.EntityName.REVISION; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_REVISIONS_NOT_FOUND; -import static org.springframework.transaction.annotation.Isolation.REPEATABLE_READ; - -import java.lang.reflect.InvocationTargetException; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.function.Function; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.NonUniqueResultException; -import javax.persistence.PersistenceContext; -import javax.validation.constraints.NotNull; -import org.hibernate.envers.AuditReader; -import org.hibernate.envers.AuditReaderFactory; -import org.hibernate.envers.RevisionType; -import org.hibernate.envers.exception.AuditException; -import org.hibernate.envers.query.AuditEntity; -import org.hibernate.envers.query.AuditQuery; -import org.hibernate.envers.query.criteria.AuditCriterion; -import org.mapstruct.Mapper; -import org.radarbase.management.domain.AbstractEntity; -import org.radarbase.management.domain.audit.CustomRevisionEntity; -import org.radarbase.management.domain.audit.CustomRevisionMetadata; -import org.radarbase.management.domain.audit.EntityAuditInfo; -import org.radarbase.management.repository.CustomRevisionEntityRepository; -import org.radarbase.management.service.dto.RevisionDTO; -import org.radarbase.management.service.dto.RevisionInfoDTO; -import org.radarbase.management.web.rest.errors.InvalidStateException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.data.history.Revision; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(isolation = REPEATABLE_READ, readOnly = true) -public class RevisionService implements ApplicationContextAware { - private static final Logger log = LoggerFactory.getLogger(RevisionService.class); - private static volatile ApplicationContext applicationContext; - - @PersistenceContext - private EntityManager entityManager; - private final CustomRevisionEntityRepository revisionEntityRepository; - - private final ConcurrentMap, Function> dtoMapperMap = - new ConcurrentHashMap<>(); - - public RevisionService(@Autowired CustomRevisionEntityRepository revisionEntityRepository) { - this.revisionEntityRepository = revisionEntityRepository; - } - - /** - * Find audit info for a given entity. The audit info includes created by, created at, last - * modified by and last modified at. - * - * @param entity the entity to look up - * @return the audit information. The fields in this object can be null if that information - * was not available. - */ - public EntityAuditInfo getAuditInfo(AbstractEntity entity) { - AuditReader auditReader = getAuditReader(); - try { - // find first revision of the entity - Object[] firstRevision = (Object[]) auditReader.createQuery() - .forRevisionsOfEntity(entity.getClass(), false, true) - .add(AuditEntity.id().eq(entity.getId())) - .add(AuditEntity.revisionNumber().minimize() - .computeAggregationInInstanceContext()) - .getSingleResult(); - CustomRevisionEntity first = (CustomRevisionEntity) firstRevision[1]; - - // find last revision of the entity - Object[] lastRevision = (Object[]) auditReader.createQuery() - .forRevisionsOfEntity(entity.getClass(), false, true) - .add(AuditEntity.id().eq(entity.getId())) - .add(AuditEntity.revisionNumber().maximize() - .computeAggregationInInstanceContext()) - .getSingleResult(); - CustomRevisionEntity last = (CustomRevisionEntity) lastRevision[1]; - - // now populate the result object and return it - return new EntityAuditInfo() - .setCreatedAt(ZonedDateTime.ofInstant(first.getTimestamp().toInstant(), - ZoneId.systemDefault())) - .setCreatedBy(first.getAuditor()) - .setLastModifiedAt(ZonedDateTime.ofInstant(last.getTimestamp().toInstant(), - ZoneId.systemDefault())) - .setLastModifiedBy(last.getAuditor()); - } catch (NonUniqueResultException ex) { - // should not happen since we call 'minimize' - throw new IllegalStateException("Query for revision returned a " - + "non-unique result. Please report this to the administrator together with " - + "the request issued.", ex); - } catch (NoResultException ex) { - // we did not find any auditing info, so we just return an empty object - return new EntityAuditInfo(); - } - } - - /** - * Find a specific revision of a specific entity. The repository methods seem not to be able - * to find back a deleted entity with their findRevision method. - * - * @param revisionNb the revision number - * @param id the entity id - * @param clazz the entity class - * @param the entity class - * @return the entity at the specified revision - */ - @SuppressWarnings("unchecked") - public R findRevision( - Integer revisionNb, - Long id, - Class clazz, - Function dtoMapper - ) { - T value = (T) getAuditReader().createQuery() - .forRevisionsOfEntity(clazz, true, true) - .add(AuditEntity.id().eq(id)) - .add(AuditEntity.revisionNumber().eq(revisionNb)) - .getSingleResult(); - return value != null ? dtoMapper.apply(value) : null; - } - - /** - * Get a page of revisions. - * - * @param pageable Page information - * @return the page of revisions {@link RevisionInfoDTO} - */ - public Page getRevisions(Pageable pageable) { - return revisionEntityRepository.findAll(pageable) - .map(rev -> RevisionInfoDTO.from(rev, getChangesForRevision(rev.getId()))); - } - - /** - * Get a page of revisions for a given entity. - * - * @param pageable the page information - * @param entity the entity for which to get the revisions - * @return the requested page of revisions for the given entity - */ - public Page getRevisionsForEntity(Pageable pageable, AbstractEntity entity) { - AuditReader auditReader = getAuditReader(); - Number count = (Number) auditReader.createQuery() - .forRevisionsOfEntity(entity.getClass(), false, true) - .add(AuditEntity.id().eq(entity.getId())) - .addProjection(AuditEntity.revisionNumber().count()) - .getSingleResult(); - - // find all revisions of the entity class that have the correct id - AuditQuery query = auditReader.createQuery() - .forRevisionsOfEntity(entity.getClass(), false, true) - .add(AuditEntity.id().eq(entity.getId())); - - // add the page sorting information to the query - if (pageable.getSort() != null) { - pageable.getSort() - .forEach(order -> query.addOrder(order.getDirection().isAscending() - ? AuditEntity.property(order.getProperty()).asc() - : AuditEntity.property(order.getProperty()).desc())); - } - - // add the page constraints (offset and amount of results) - query.setFirstResult(Math.toIntExact(pageable.getOffset())) - .setMaxResults(Math.toIntExact(pageable.getPageSize())); - - Function dtoMapper = getDtoMapper(entity.getClass()); - - @SuppressWarnings("unchecked") - List resultList = (List) query.getResultList(); - @SuppressWarnings({"unchecked", "rawtypes"}) - List revisionDtos = resultList.stream() - .map(objArray -> new RevisionDTO( - Revision.of( - new CustomRevisionMetadata((CustomRevisionEntity) objArray[1]), - objArray[0]), - (RevisionType) objArray[2], - dtoMapper.apply(objArray[0]))) - .collect(toList()); - - return new PageImpl<>(revisionDtos, pageable, count.longValue()); - } - - /** - * Get a single revision. - * - * @param revision the revision number - * @return the revision - * @throws NotFoundException if the revision number does not exist - */ - public RevisionInfoDTO getRevision(Integer revision) throws NotFoundException { - CustomRevisionEntity revisionEntity = revisionEntityRepository.findById(revision) - .orElse(null); - if (revisionEntity == null) { - throw new NotFoundException("Revision not found with revision id", REVISION, - ERR_REVISIONS_NOT_FOUND, - Collections.singletonMap("revision-id", revision.toString())); - } - return RevisionInfoDTO.from(revisionEntity, getChangesForRevision(revision)); - } - - /** - * Get changes for a specific revision number, ordered by revision type. - * - * @param revision the revision number - * @return A map with as keys the revision types, and as values the list of changed objects - * of that type - */ - public Map> getChangesForRevision(Integer revision) { - // Custom implementation not using crosstyperevisionchangesreader. - // It seems we need to clear the entitymanager before using the - // crosstyperevisionchangesreader, or we get incorrect results: deleted entities do not - // show up in revisions where they were still around. However clearing for every request - // causes the revisions api to be quite slow so we retrieve the changes manually using - // the AuditReader. - CustomRevisionEntity revisionEntity = revisionEntityRepository.findById(revision) - .orElse(null); - if (revisionEntity == null) { - throw new NotFoundException("The requested revision could not be found.", REVISION, - ERR_REVISIONS_NOT_FOUND, - Collections.singletonMap("revision-id", revision.toString())); - } - AuditReader auditReader = getAuditReader(); - - Map> result = new HashMap<>(5); - - for (RevisionType revisionType : RevisionType.values()) { - result.put(revisionType, new ArrayList<>()); - } - - for (String entityName : revisionEntity.getModifiedEntityNames()) { - String cleanedEntityName = entityName.replace("org.radarcns.", "org.radarbase."); - Class entityClass = classForEntityName(cleanedEntityName); - Function dtoMapper = getDtoMapper(entityClass); - - for (RevisionType revisionType : RevisionType.values()) { - //noinspection unchecked - result.get(revisionType) - .addAll((List)auditReader.createQuery() - .forEntitiesModifiedAtRevision(entityClass, revision) - .add(AuditEntity.revisionType().eq(revisionType)) - .getResultList() - .stream() - .map(dtoMapper) - .filter(Objects::nonNull) - .collect(toList())); - } - } - - return result; - } - - /** - * Dynamically find the Mapstruct mapper that can map the entity to it's DTO counterpart, - * then do the mapping and return the DTO. - * - * @param entity the entity to map to it's DTO form - * @return the DTO form of the given entity - */ - private Object toDto(Object entity) { - return entity != null ? getDtoMapper(entity.getClass()).apply(entity) : null; - } - - private Function getDtoMapper(@NotNull Class entity) { - return dtoMapperMap.computeIfAbsent(entity, this::addMapperForClass); - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - RevisionService.applicationContext = applicationContext; - } - - /** - *

Find the latest revision of an entity of a given class, that matches given criteria. This - * is useful for finding deleted entities by properties other than their primary key. The - * criteria should be defined such that zero or one entities match.

- * - *

Example: {@code getLatestRevisionForEntity(Subject.class, Arrays.asList(AuditEntity - * .property("user.login").eq(requestedLogin)))}.

- * @param clazz The entity class - * @param criteria The list of criteria that will be added to the audit query - * @return The DTO version of the latest revision of the requested entity, or an empty - * optional if no entity was found matching the given criteria. - * @throws AuditException if the entity is not audited - * @throws NonUniqueResultException if multiple enities match the criteria - */ - public Optional getLatestRevisionForEntity( - Class clazz, - List criteria - ) throws AuditException, NonUniqueResultException { - AuditQuery query = getAuditReader().createQuery() - .forRevisionsOfEntity(clazz, true, true) - .add(AuditEntity.revisionNumber().maximize() - .computeAggregationInInstanceContext()); - criteria.forEach(query::add); - try { - return Optional.ofNullable(toDto(query.getSingleResult())); - } catch (NoResultException ex) { - log.debug("No entity of type " + clazz.getName() + " found in the revision history " - + "with the given criteria", ex); - return Optional.empty(); - } - } - - private Function addMapperForClass(Class clazz) { - // get a list of @Mapper annotated components - ClassPathScanningCandidateComponentProvider scanner = new - ClassPathScanningCandidateComponentProvider(true); - scanner.addIncludeFilter(new AnnotationTypeFilter(Mapper.class)); - // look only in the mapper package - return scanner.findCandidateComponents("org.radarbase.management.service.mapper").stream() - .flatMap(bd -> { - final Object mapper = beanFromDefinition(bd); - // now we look for the correct method in the bean - return Arrays.stream(mapper.getClass().getMethods()) - // look for methods that return our entity's DTO, and take exactly one - // argument of the same type as our entity - .filter(m -> - m.getGenericReturnType().getTypeName().endsWith( - clazz.getSimpleName() + "DTO") - && m.getGenericParameterTypes().length == 1 - && m.getGenericParameterTypes()[0].getTypeName().equals( - clazz.getTypeName())) - .>map(method -> obj -> { - if (obj == null) { - return null; - } - try { - return method.invoke(mapper, obj); - } catch (IllegalAccessException | InvocationTargetException ex) { - log.error(ex.getMessage(), ex); - return null; - } - }); - }) - .findAny() - .orElse(obj -> null); - } - - private Object beanFromDefinition(BeanDefinition beanDefinition) { - String className = beanDefinition.getBeanClassName(); - // get the bean for the given class - try { - return applicationContext.getBean(Class.forName(className)); - } catch (ClassNotFoundException ex) { - // should not happen, we got the classname from the bean definition - throw new InvalidStateException( - ex.getMessage(), REVISION, "error.classNotFound"); - } - } - - private Class classForEntityName(String entityName) { - try { - return Class.forName(entityName); - } catch (ClassNotFoundException ex) { - // this should not happen - log.error("Unable to load class for modified entity", ex); - throw new InvalidStateException(ex.getMessage(), REVISION, "error.classNotFound"); - } - } - - private AuditReader getAuditReader() { - return AuditReaderFactory.get(entityManager); - } -} diff --git a/src/main/java/org/radarbase/management/service/RevisionService.kt b/src/main/java/org/radarbase/management/service/RevisionService.kt new file mode 100644 index 000000000..dcf742280 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/RevisionService.kt @@ -0,0 +1,401 @@ +package org.radarbase.management.service + +import org.hibernate.envers.AuditReader +import org.hibernate.envers.AuditReaderFactory +import org.hibernate.envers.RevisionType +import org.hibernate.envers.exception.AuditException +import org.hibernate.envers.query.AuditEntity +import org.hibernate.envers.query.criteria.AuditCriterion +import org.mapstruct.Mapper +import org.radarbase.management.domain.AbstractEntity +import org.radarbase.management.domain.audit.CustomRevisionEntity +import org.radarbase.management.domain.audit.CustomRevisionMetadata +import org.radarbase.management.domain.audit.EntityAuditInfo +import org.radarbase.management.repository.CustomRevisionEntityRepository +import org.radarbase.management.service.dto.RevisionDTO +import org.radarbase.management.service.dto.RevisionInfoDTO +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidStateException +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.BeansException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.config.BeanDefinition +import org.springframework.context.ApplicationContext +import org.springframework.context.ApplicationContextAware +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider +import org.springframework.core.type.filter.AnnotationTypeFilter +import org.springframework.data.domain.Page +import org.springframework.data.domain.PageImpl +import org.springframework.data.domain.Pageable +import org.springframework.data.domain.Sort +import org.springframework.data.history.Revision +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Isolation +import org.springframework.transaction.annotation.Transactional +import java.lang.reflect.InvocationTargetException +import java.lang.reflect.Method +import java.time.ZoneId +import java.time.ZonedDateTime +import java.util.* +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.ConcurrentMap +import java.util.function.Consumer +import java.util.function.Function +import java.util.stream.Collectors +import java.util.stream.Stream +import javax.persistence.EntityManager +import javax.persistence.NoResultException +import javax.persistence.NonUniqueResultException +import javax.persistence.PersistenceContext +import javax.validation.constraints.NotNull + +@Service +@Transactional(isolation = Isolation.REPEATABLE_READ, readOnly = true) +open class RevisionService(@param:Autowired private val revisionEntityRepository: CustomRevisionEntityRepository) : + ApplicationContextAware { + @PersistenceContext + private val entityManager: EntityManager? = null + private val dtoMapperMap: ConcurrentMap?, Function> = ConcurrentHashMap() + + /** + * Find audit info for a given entity. The audit info includes created by, created at, last + * modified by and last modified at. + * + * @param entity the entity to look up + * @return the audit information. The fields in this object can be null if that information + * was not available. + */ + fun getAuditInfo(entity: AbstractEntity): EntityAuditInfo { + val auditReader = auditReader + return try { + // find first revision of the entity + val firstRevision = auditReader.createQuery() + .forRevisionsOfEntity(entity.javaClass, false, true) + .add(AuditEntity.id().eq(entity.id)) + .add( + AuditEntity.revisionNumber().minimize() + .computeAggregationInInstanceContext() + ) + .singleResult as Array + val first = firstRevision[1] as CustomRevisionEntity + + // find last revision of the entity + val lastRevision = auditReader.createQuery() + .forRevisionsOfEntity(entity.javaClass, false, true) + .add(AuditEntity.id().eq(entity.id)) + .add( + AuditEntity.revisionNumber().maximize() + .computeAggregationInInstanceContext() + ) + .singleResult as Array + val last = lastRevision[1] as CustomRevisionEntity + + // now populate the result object and return it + EntityAuditInfo() + .setCreatedAt( + ZonedDateTime.ofInstant( + first.timestamp!!.toInstant(), + ZoneId.systemDefault() + ) + ) + .setCreatedBy(first.auditor) + .setLastModifiedAt( + ZonedDateTime.ofInstant( + last.timestamp!!.toInstant(), + ZoneId.systemDefault() + ) + ) + .setLastModifiedBy(last.auditor) + } catch (ex: NonUniqueResultException) { + // should not happen since we call 'minimize' + throw IllegalStateException( + "Query for revision returned a " + + "non-unique result. Please report this to the administrator together with " + + "the request issued.", ex + ) + } catch (ex: NoResultException) { + // we did not find any auditing info, so we just return an empty object + EntityAuditInfo() + } + } + + /** + * Find a specific revision of a specific entity. The repository methods seem not to be able + * to find back a deleted entity with their findRevision method. + * + * @param revisionNb the revision number + * @param id the entity id + * @param clazz the entity class + * @param the entity class + * @return the entity at the specified revision + */ + fun findRevision( + revisionNb: Int?, + id: Long?, + clazz: Class?, + dtoMapper: Function + ): R? { + val value: T? = auditReader.createQuery() + .forRevisionsOfEntity(clazz, true, true) + .add(AuditEntity.id().eq(id)) + .add(AuditEntity.revisionNumber().eq(revisionNb)) + .singleResult as T + return if (value != null) dtoMapper.apply(value) else null + } + + /** + * Get a page of revisions. + * + * @param pageable Page information + * @return the page of revisions [RevisionInfoDTO] + */ + fun getRevisions(pageable: Pageable?): Page { + return revisionEntityRepository.findAll(pageable) + .map { rev: CustomRevisionEntity -> RevisionInfoDTO.from(rev, getChangesForRevision(rev.id)) } + } + + /** + * Get a page of revisions for a given entity. + * + * @param pageable the page information + * @param entity the entity for which to get the revisions + * @return the requested page of revisions for the given entity + */ + fun getRevisionsForEntity(pageable: Pageable, entity: AbstractEntity): Page { + val auditReader = auditReader + val count = auditReader.createQuery() + .forRevisionsOfEntity(entity.javaClass, false, true) + .add(AuditEntity.id().eq(entity.id)) + .addProjection(AuditEntity.revisionNumber().count()) + .singleResult as Number + + // find all revisions of the entity class that have the correct id + val query = auditReader.createQuery() + .forRevisionsOfEntity(entity.javaClass, false, true) + .add(AuditEntity.id().eq(entity.id)) + + // add the page sorting information to the query + if (pageable.sort != null) { + pageable.sort + .forEach(Consumer { order: Sort.Order -> + query.addOrder( + if (order.direction.isAscending) AuditEntity.property( + order.property + ).asc() else AuditEntity.property(order.property).desc() + ) + }) + } + + // add the page constraints (offset and amount of results) + query.setFirstResult(Math.toIntExact(pageable.offset)) + .setMaxResults(Math.toIntExact(pageable.pageSize.toLong())) + val dtoMapper = getDtoMapper(entity.javaClass) + val resultList = query.resultList as List?> + val revisionDtos = resultList.stream() + .map { objArray: Array? -> + RevisionDTO( + Revision.of( + CustomRevisionMetadata((objArray!![1] as CustomRevisionEntity)), + objArray[0] + ), + objArray[2] as RevisionType, + dtoMapper.apply(objArray[0]) + ) + } + .collect(Collectors.toList()) + return PageImpl(revisionDtos, pageable, count.toLong()) + } + + /** + * Get a single revision. + * + * @param revision the revision number + * @return the revision + * @throws NotFoundException if the revision number does not exist + */ + @Throws(NotFoundException::class) + fun getRevision(revision: Int): RevisionInfoDTO { + val revisionEntity = revisionEntityRepository.findById(revision) + .orElse(null) + ?: throw NotFoundException( + "Revision not found with revision id", EntityName.REVISION, + ErrorConstants.ERR_REVISIONS_NOT_FOUND, + Collections.singletonMap("revision-id", revision.toString()) + ) + return RevisionInfoDTO.from(revisionEntity, getChangesForRevision(revision)) + } + + /** + * Get changes for a specific revision number, ordered by revision type. + * + * @param revision the revision number + * @return A map with as keys the revision types, and as values the list of changed objects + * of that type + */ + fun getChangesForRevision(revision: Int): Map> { + // Custom implementation not using crosstyperevisionchangesreader. + // It seems we need to clear the entitymanager before using the + // crosstyperevisionchangesreader, or we get incorrect results: deleted entities do not + // show up in revisions where they were still around. However, clearing for every request + // causes the revisions api to be quite slow, so we retrieve the changes manually using + // the AuditReader. + val revisionEntity = revisionEntityRepository.findById(revision) + .orElse(null) + ?: throw NotFoundException( + "The requested revision could not be found.", EntityName.REVISION, + ErrorConstants.ERR_REVISIONS_NOT_FOUND, + Collections.singletonMap("revision-id", revision.toString()) + ) + val auditReader = auditReader + val result: MutableMap> = HashMap(5) + for (revisionType in RevisionType.values()) { + result[revisionType] = ArrayList() + } + for (entityName in revisionEntity.modifiedEntityNames!!) { + val cleanedEntityName = entityName.replace("org.radarcns.", "org.radarbase.") + val entityClass = classForEntityName(cleanedEntityName) + val dtoMapper = getDtoMapper(entityClass) + for (revisionType in RevisionType.values()) { + result[revisionType] + ?.addAll( + (listOf(auditReader.createQuery() + .forEntitiesModifiedAtRevision(entityClass, revision) + .add(AuditEntity.revisionType().eq(revisionType)) + .resultList + .let { toDto(it) } as Collection<*>) + )) + } + } + return result + } + + /** + * Dynamically find the Mapstruct mapper that can map the entity to it's DTO counterpart, + * then do the mapping and return the DTO. + * + * @param entity the entity to map to it's DTO form + * @return the DTO form of the given entity + */ + private fun toDto(entity: Any?): Any? { + return if (entity != null) getDtoMapper(entity.javaClass).apply(entity) else null + } + + private fun getDtoMapper(entity: @NotNull Class<*>?): Function { + return dtoMapperMap.computeIfAbsent(entity) { clazz: Class<*>? -> addMapperForClass(clazz) } + } + + @Throws(BeansException::class) + override fun setApplicationContext(applicationContext: ApplicationContext) { + Companion.applicationContext = applicationContext + } + + /** + * + * Find the latest revision of an entity of a given class, that matches given criteria. This + * is useful for finding deleted entities by properties other than their primary key. The + * criteria should be defined such that zero or one entities match. + * + * + * Example: `getLatestRevisionForEntity(Subject.class, Arrays.asList(AuditEntity + * .property("user.login").eq(requestedLogin)))`. + * @param clazz The entity class + * @param criteria The list of criteria that will be added to the audit query + * @return The DTO version of the latest revision of the requested entity, or an empty + * optional if no entity was found matching the given criteria. + * @throws AuditException if the entity is not audited + * @throws NonUniqueResultException if multiple enities match the criteria + */ + @Throws(AuditException::class, NonUniqueResultException::class) + fun getLatestRevisionForEntity( + clazz: Class<*>, + criteria: List + ): Optional { + val query = auditReader.createQuery() + .forRevisionsOfEntity(clazz, true, true) + .add( + AuditEntity.revisionNumber().maximize() + .computeAggregationInInstanceContext() + ) + criteria.forEach(Consumer { criterion: AuditCriterion? -> query.add(criterion) }) + return try { + Optional.ofNullable(toDto(query.singleResult)) + } catch (ex: NoResultException) { + log.debug( + "No entity of type " + clazz.getName() + " found in the revision history " + + "with the given criteria", ex + ) + Optional.empty() + } + } + + private fun addMapperForClass(clazz: Class<*>?): Function { + // get a list of @Mapper annotated components + val scanner = ClassPathScanningCandidateComponentProvider(true) + scanner.addIncludeFilter(AnnotationTypeFilter(Mapper::class.java)) + // look only in the mapper package + return scanner.findCandidateComponents("org.radarbase.management.service.mapper").stream() + .flatMap(Function>> { bd: BeanDefinition -> + val mapper = beanFromDefinition(bd) + Arrays.stream(mapper.javaClass.getMethods()) // look for methods that return our entity's DTO, and take exactly one + // argument of the same type as our entity + .filter { m: Method -> + m.genericReturnType.typeName.endsWith( + clazz!!.getSimpleName() + "DTO" + ) && m.genericParameterTypes.size == 1 && m.genericParameterTypes[0].typeName == clazz.getTypeName() + } + .map(Function { method: Method -> + Function { obj: Any? -> + if (obj == null) { + return@Function null + } + try { + return@Function method.invoke(mapper, obj) + } catch (ex: IllegalAccessException) { + log.error(ex.message, ex) + return@Function null + } catch (ex: InvocationTargetException) { + log.error(ex.message, ex) + return@Function null + } + } + }) + }) + .findAny() + .orElse(Function { obj: Any? -> null }) + } + + private fun beanFromDefinition(beanDefinition: BeanDefinition): Any { + val className = beanDefinition.beanClassName + // get the bean for the given class + return try { + applicationContext!!.getBean(Class.forName(className)) + } catch (ex: ClassNotFoundException) { + // should not happen, we got the classname from the bean definition + throw InvalidStateException( + ex.message, EntityName.REVISION, "error.classNotFound" + ) + } + } + + private fun classForEntityName(entityName: String): Class<*> { + return try { + Class.forName(entityName) + } catch (ex: ClassNotFoundException) { + // this should not happen + log.error("Unable to load class for modified entity", ex) + throw InvalidStateException(ex.message, EntityName.REVISION, "error.classNotFound") + } + } + + private val auditReader: AuditReader + private get() = AuditReaderFactory.get(entityManager) + + companion object { + private val log = LoggerFactory.getLogger(RevisionService::class.java) + + @Volatile + private var applicationContext: ApplicationContext? = null + } +} diff --git a/src/main/java/org/radarbase/management/service/RoleService.java b/src/main/java/org/radarbase/management/service/RoleService.java deleted file mode 100644 index b12a329eb..000000000 --- a/src/main/java/org/radarbase/management/service/RoleService.java +++ /dev/null @@ -1,271 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.AuthorityRepository; -import org.radarbase.management.repository.OrganizationRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.RoleRepository; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.mapper.RoleMapper; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Consumer; - -import static org.radarbase.management.web.rest.errors.EntityName.USER; - -/** - * Service Implementation for managing Project. - */ -@Service -@Transactional -public class RoleService { - - private static final Logger log = LoggerFactory.getLogger(RoleService.class); - - @Autowired - private RoleRepository roleRepository; - - @Autowired - private AuthorityRepository authorityRepository; - - @Autowired - private OrganizationRepository organizationRepository; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private RoleMapper roleMapper; - - @Autowired - private UserService userService; - - /** - * Save a role. - * - * @param roleDto the entity to save - * @return the persisted entity - */ - public RoleDTO save(RoleDTO roleDto) { - log.debug("Request to save Role : {}", roleDto); - Role role = roleMapper.roleDTOToRole(roleDto); - role = roleRepository.save(role); - return roleMapper.roleToRoleDTO(role); - } - - /** - * Get the roles the currently authenticated user has access to. - * - *

A system administrator has access to all the roles. A project administrator has access - * to the roles in their own project.

- * - * @return the list of entities - */ - @Transactional(readOnly = true) - public List findAll() { - Optional optUser = userService.getUserWithAuthorities(); - if (optUser.isEmpty()) { - // return an empty list if we do not have a current user (e.g. with client credentials - // oauth2 grant) - return Collections.emptyList(); - } - User currentUser = optUser.get(); - List currentUserAuthorities = currentUser.getAuthorities().stream() - .map(Authority::getName) - .toList(); - - if (currentUserAuthorities.contains(RoleAuthority.SYS_ADMIN.getAuthority())) { - log.debug("Request to get all Roles"); - return roleRepository.findAll().stream() - .map(roleMapper::roleToRoleDTO) - .toList(); - } else if (currentUserAuthorities.contains(RoleAuthority.PROJECT_ADMIN.getAuthority())) { - log.debug("Request to get project admin's project Projects"); - return currentUser.getRoles().stream() - .filter(role -> RoleAuthority.PROJECT_ADMIN.getAuthority() - .equals(role.getAuthority().getName())) - .map(r -> r.getProject().getProjectName()) - .distinct() - .flatMap(name -> roleRepository.findAllRolesByProjectName(name).stream()) - .map(roleMapper::roleToRoleDTO) - .toList(); - } else { - return Collections.emptyList(); - } - } - - /** - * Get all Admin roles. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public List findSuperAdminRoles() { - log.debug("Request to get admin Roles"); - - return roleRepository - .findRolesByAuthorityName(RoleAuthority.SYS_ADMIN.getAuthority()).stream() - .map(roleMapper::roleToRoleDTO) - .toList(); - } - - /** - * Get one role by id. - * - * @param id the id of the entity - * @return the entity - */ - @Transactional(readOnly = true) - public RoleDTO findOne(Long id) { - log.debug("Request to get Role : {}", id); - Role role = roleRepository.findById(id).get(); - return roleMapper.roleToRoleDTO(role); - } - - /** - * Delete the role by id. - * - * @param id the id of the entity - */ - public void delete(Long id) { - log.debug("Request to delete Role : {}", id); - roleRepository.deleteById(id); - } - - /** - * Get the predefined role authority from a RoleDTO. - * @param roleDto roleDto to parse - * @return role authority - * @throws BadRequestException if the roleauthority is not found or does not correctly - * specify an organization or project ID. - */ - public static RoleAuthority getRoleAuthority(RoleDTO roleDto) { - RoleAuthority authority; - try { - authority = RoleAuthority.valueOfAuthority(roleDto.getAuthorityName()); - } catch (IllegalArgumentException ex) { - throw new BadRequestException("Authority not found with " - + "authorityName", USER, ErrorConstants.ERR_INVALID_AUTHORITY, - Collections.singletonMap("authorityName", - roleDto.getAuthorityName())); - } - if (authority.getScope() == RoleAuthority.Scope.ORGANIZATION - && roleDto.getOrganizationId() == null) { - throw new BadRequestException("Authority with " - + "authorityName should have organization ID", - USER, ErrorConstants.ERR_INVALID_AUTHORITY, - Collections.singletonMap("authorityName", roleDto.getAuthorityName())); - } - if (authority.getScope() == RoleAuthority.Scope.PROJECT - && roleDto.getProjectId() == null) { - throw new BadRequestException("Authority with " - + "authorityName should have project ID", - USER, ErrorConstants.ERR_INVALID_AUTHORITY, - Collections.singletonMap("authorityName", roleDto.getAuthorityName())); - } - return authority; - } - - /** - * Get or create given global role. - * @param role to get or create - * @return role from database - */ - public Role getGlobalRole(RoleAuthority role) { - return roleRepository.findRolesByAuthorityName(role.getAuthority()).stream() - .findAny() - .orElseGet(() -> createNewRole(role, r -> { })); - } - - /** - * Get or create given organization role. - * @param role to get or create - * @param organizationId organization ID - * @return role from database - */ - public Role getOrganizationRole(RoleAuthority role, Long organizationId) { - return roleRepository.findOneByOrganizationIdAndAuthorityName( - organizationId, role.getAuthority()) - .orElseGet(() -> createNewRole(role, r -> { - r.setOrganization(organizationRepository.findById(organizationId) - .orElseThrow(() -> new NotFoundException( - "Cannot find organization for authority", - USER, ErrorConstants.ERR_INVALID_AUTHORITY, - Map.of("authorityName", role.getAuthority(), - "projectId", - organizationId.toString())))); - })); - } - - /** - * Get or create given project role. - * @param role to get or create - * @param projectId organization ID - * @return role from database - */ - public Role getProjectRole(RoleAuthority role, Long projectId) { - return roleRepository.findOneByProjectIdAndAuthorityName( - projectId, role.getAuthority()) - .orElseGet(() -> createNewRole(role, r -> { - r.setProject(projectRepository.findByIdWithOrganization(projectId) - .orElseThrow(() -> new NotFoundException( - "Cannot find project for authority", - USER, ErrorConstants.ERR_INVALID_AUTHORITY, - Map.of("authorityName", role.getAuthority(), - "projectId", - projectId.toString())))); - })); - } - - /** - * Get all roles related to a project. - * @param projectName the project name - * @return the roles - */ - public List getRolesByProject(String projectName) { - log.debug("Request to get all Roles for projectName " + projectName); - - return roleRepository.findAllRolesByProjectName(projectName).stream() - .map(roleMapper::roleToRoleDTO) - .toList(); - } - - private Authority getAuthority(RoleAuthority role) { - return authorityRepository.findByAuthorityName(role.getAuthority()) - .orElseGet(() -> authorityRepository.saveAndFlush(new Authority(role))); - } - - private Role createNewRole(RoleAuthority role, Consumer apply) { - Role newRole = new Role(); - newRole.setAuthority(getAuthority(role)); - apply.accept(newRole); - return roleRepository.save(newRole); - } - - /** - * Get the role related to the given project with the given authority name. - * @param projectName the project name - * @param authorityName the authority name - * @return an {@link Optional} containing the role if it exists, and empty otherwise - */ - public Optional findOneByProjectNameAndAuthorityName(String projectName, - String authorityName) { - log.debug("Request to get role of project {} and authority {}", projectName, authorityName); - return roleRepository.findOneByProjectNameAndAuthorityName(projectName, authorityName) - .map(roleMapper::roleToRoleDTO); - } -} diff --git a/src/main/java/org/radarbase/management/service/RoleService.kt b/src/main/java/org/radarbase/management/service/RoleService.kt new file mode 100644 index 000000000..c350c19ea --- /dev/null +++ b/src/main/java/org/radarbase/management/service/RoleService.kt @@ -0,0 +1,270 @@ +package org.radarbase.management.service + +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.auth.authorization.RoleAuthority.Companion.valueOfAuthority +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.Role +import org.radarbase.management.repository.AuthorityRepository +import org.radarbase.management.repository.OrganizationRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.RoleRepository +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.mapper.RoleMapper +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.util.* +import java.util.Map +import java.util.function.Consumer + +/** + * Service Implementation for managing Project. + */ +@Service +@Transactional +open class RoleService { + @Autowired + private val roleRepository: RoleRepository? = null + + @Autowired + private val authorityRepository: AuthorityRepository? = null + + @Autowired + private val organizationRepository: OrganizationRepository? = null + + @Autowired + private val projectRepository: ProjectRepository? = null + + @Autowired + private val roleMapper: RoleMapper? = null + + @Autowired + private val userService: UserService? = null + + /** + * Save a role. + * + * @param roleDto the entity to save + * @return the persisted entity + */ + fun save(roleDto: RoleDTO?): RoleDTO { + log.debug("Request to save Role : {}", roleDto) + var role = roleMapper!!.roleDTOToRole(roleDto) + role = roleRepository!!.save(role) + return roleMapper.roleToRoleDTO(role) + } + + /** + * Get the roles the currently authenticated user has access to. + * + * + * A system administrator has access to all the roles. A project administrator has access + * to the roles in their own project. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(): List { + val optUser = userService!!.userWithAuthorities + if (optUser.isEmpty) { + // return an empty list if we do not have a current user (e.g. with client credentials + // oauth2 grant) + return emptyList() + } + val currentUser = optUser.get() + val currentUserAuthorities: List? = currentUser.authorities?.map { auth -> auth?.name!! } + return if (currentUserAuthorities?.contains(RoleAuthority.SYS_ADMIN.authority) == true) { + log.debug("Request to get all Roles") + roleRepository!!.findAll().stream().map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }.toList() + } else (if (currentUserAuthorities?.contains(RoleAuthority.PROJECT_ADMIN.authority) == true) { + log.debug("Request to get project admin's project Projects") + currentUser.roles?.filter { role: Role? -> + (RoleAuthority.PROJECT_ADMIN.authority == role?.authority?.name) + }?.map { r: Role? -> r?.project?.projectName }?.distinct() + ?.flatMap { name: String? -> roleRepository!!.findAllRolesByProjectName(name) } + ?.map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }?.toList() + } else { + emptyList() + }) as List + } + + /** + * Get all Admin roles. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findSuperAdminRoles(): List { + log.debug("Request to get admin Roles") + return roleRepository?.findRolesByAuthorityName(RoleAuthority.SYS_ADMIN.authority) + ?.map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }?.toList()!! + } + + /** + * Get one role by id. + * + * @param id the id of the entity + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOne(id: Long): RoleDTO { + log.debug("Request to get Role : {}", id) + val role = roleRepository!!.findById(id).get() + return roleMapper!!.roleToRoleDTO(role) + } + + /** + * Delete the role by id. + * + * @param id the id of the entity + */ + fun delete(id: Long) { + log.debug("Request to delete Role : {}", id) + roleRepository!!.deleteById(id) + } + + /** + * Get or create given global role. + * @param role to get or create + * @return role from database + */ + fun getGlobalRole(role: RoleAuthority): Role { + return roleRepository!!.findRolesByAuthorityName(role.authority).stream().findAny() + .orElseGet { createNewRole(role) { r: Role? -> } } + } + + /** + * Get or create given organization role. + * @param role to get or create + * @param organizationId organization ID + * @return role from database + */ + fun getOrganizationRole(role: RoleAuthority, organizationId: Long): Role { + return roleRepository!!.findOneByOrganizationIdAndAuthorityName( + organizationId, role.authority + ).orElseGet { + createNewRole(role) { r: Role -> + r.organization = organizationRepository!!.findById(organizationId).orElseThrow { + NotFoundException( + "Cannot find organization for authority", + EntityName.USER, + ErrorConstants.ERR_INVALID_AUTHORITY, + Map.of( + "authorityName", role.authority, "projectId", organizationId.toString() + ) + ) + } + } + } + } + + /** + * Get or create given project role. + * @param role to get or create + * @param projectId organization ID + * @return role from database + */ + fun getProjectRole(role: RoleAuthority, projectId: Long): Role { + return roleRepository!!.findOneByProjectIdAndAuthorityName( + projectId, role.authority + ).orElseGet { + createNewRole(role) { r: Role -> + r.project = projectRepository!!.findByIdWithOrganization(projectId) ?: throw NotFoundException( + "Cannot find project for authority", + EntityName.USER, + ErrorConstants.ERR_INVALID_AUTHORITY, + Map.of( + "authorityName", role.authority, "projectId", projectId.toString() + ) + ) + } + } + } + + /** + * Get all roles related to a project. + * @param projectName the project name + * @return the roles + */ + fun getRolesByProject(projectName: String): List { + log.debug("Request to get all Roles for projectName $projectName") + return roleRepository!!.findAllRolesByProjectName(projectName).stream() + .map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }.toList() + } + + private fun getAuthority(role: RoleAuthority): Authority { + return authorityRepository!!.findByAuthorityName(role.authority) + .orElseGet { authorityRepository.saveAndFlush(Authority(role)) } + } + + private fun createNewRole(role: RoleAuthority, apply: Consumer): Role { + val newRole = Role() + newRole.authority = getAuthority(role) + apply.accept(newRole) + return roleRepository!!.save(newRole) + } + + /** + * Get the role related to the given project with the given authority name. + * @param projectName the project name + * @param authorityName the authority name + * @return an [Optional] containing the role if it exists, and empty otherwise + */ + fun findOneByProjectNameAndAuthorityName( + projectName: String?, authorityName: String? + ): Optional { + log.debug("Request to get role of project {} and authority {}", projectName, authorityName) + return roleRepository!!.findOneByProjectNameAndAuthorityName(projectName, authorityName) + .map { role: Role? -> roleMapper!!.roleToRoleDTO(role) } + } + + companion object { + private val log = LoggerFactory.getLogger(RoleService::class.java) + + /** + * Get the predefined role authority from a RoleDTO. + * @param roleDto roleDto to parse + * @return role authority + * @throws BadRequestException if the roleauthority is not found or does not correctly + * specify an organization or project ID. + */ + @JvmStatic + fun getRoleAuthority(roleDto: RoleDTO): RoleAuthority { + val authority: RoleAuthority + authority = try { + valueOfAuthority(roleDto.authorityName) + } catch (ex: IllegalArgumentException) { + throw BadRequestException( + "Authority not found with " + "authorityName", + EntityName.USER, + ErrorConstants.ERR_INVALID_AUTHORITY, + Collections.singletonMap( + "authorityName", roleDto.authorityName + ) + ) + } + if (authority.scope === RoleAuthority.Scope.ORGANIZATION && roleDto.organizationId == null) { + throw BadRequestException( + "Authority with " + "authorityName should have organization ID", + EntityName.USER, + ErrorConstants.ERR_INVALID_AUTHORITY, + Collections.singletonMap("authorityName", roleDto.authorityName) + ) + } + if (authority.scope === RoleAuthority.Scope.PROJECT && roleDto.projectId == null) { + throw BadRequestException( + "Authority with " + "authorityName should have project ID", + EntityName.USER, + ErrorConstants.ERR_INVALID_AUTHORITY, + Collections.singletonMap("authorityName", roleDto.authorityName) + ) + } + return authority + } + } +} diff --git a/src/main/java/org/radarbase/management/service/SourceService.java b/src/main/java/org/radarbase/management/service/SourceService.java deleted file mode 100644 index a63fe32ca..000000000 --- a/src/main/java/org/radarbase/management/service/SourceService.java +++ /dev/null @@ -1,261 +0,0 @@ -package org.radarbase.management.service; - - -import org.radarbase.management.domain.Source; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.SourceRepository; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.mapper.SourceMapper; -import org.radarbase.management.service.mapper.SourceTypeMapper; -import org.radarbase.management.web.rest.errors.InvalidRequestException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.history.Revision; -import org.springframework.data.history.Revisions; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import static org.hibernate.id.IdentifierGenerator.ENTITY_NAME; -import static org.radarbase.auth.authorization.Permission.SOURCE_UPDATE; -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE; - -/** - * Service Implementation for managing Source. - */ -@Service -@Transactional -public class SourceService { - - private static final Logger log = LoggerFactory.getLogger(SourceService.class); - - @Autowired - private SourceRepository sourceRepository; - - @Autowired - private SourceMapper sourceMapper; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private SourceTypeMapper sourceTypeMapper; - @Autowired - private AuthService authService; - - /** - * Save a Source. - * - * @param sourceDto the entity to save - * @return the persisted entity - */ - public SourceDTO save(SourceDTO sourceDto) { - log.debug("Request to save Source : {}", sourceDto); - Source source = sourceMapper.sourceDTOToSource(sourceDto); - source = sourceRepository.save(source); - return sourceMapper.sourceToSourceDTO(source); - } - - /** - * Get all the Sources. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public List findAll() { - return sourceRepository - .findAll() - .stream() - .map(sourceMapper::sourceToSourceDTO) - .toList(); - } - - /** - * Get all the sourceData with pagination. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public Page findAll(Pageable pageable) { - log.debug("Request to get SourceData with pagination"); - return sourceRepository - .findAll(pageable) - .map(sourceMapper::sourceToSourceDTO); - } - - /** - * Get one source by name. - * - * @param sourceName the name of the source - * @return the entity - */ - @Transactional(readOnly = true) - public Optional findOneByName(String sourceName) { - log.debug("Request to get Source : {}", sourceName); - return sourceRepository.findOneBySourceName(sourceName) - .map(sourceMapper::sourceToSourceDTO); - } - - /** - * Get one source by id. - * - * @param id the id of the source - * @return the entity - */ - @Transactional(readOnly = true) - public Optional findOneById(Long id) { - log.debug("Request to get Source by id: {}", id); - return Optional.ofNullable(sourceRepository.findById(id).orElse(null)) - .map(sourceMapper::sourceToSourceDTO); - } - - /** - * Delete the device by id. - * - * @param id the id of the entity - */ - @Transactional - public void delete(Long id) { - log.info("Request to delete Source : {}", id); - Revisions sourceHistory = sourceRepository.findRevisions(id); - List sources = sourceHistory.getContent().stream() - .map(Revision::getEntity) - .filter(Source::isAssigned) - .toList(); - if (sources.isEmpty()) { - sourceRepository.deleteById(id); - } else { - Map errorParams = new HashMap<>(); - errorParams.put("message", "Cannot delete source with sourceId "); - errorParams.put("id", Long.toString(id)); - throw new InvalidRequestException("Cannot delete a source that was once assigned.", - SOURCE, "error.usedSourceDeletion", errorParams); - } - } - - /** - * Returns all sources by project in {@link SourceDTO} format. - * - * @return list of sources - */ - public Page findAllByProjectId(Long projectId, Pageable pageable) { - return sourceRepository.findAllSourcesByProjectId(pageable, projectId) - .map(sourceMapper::sourceToSourceWithoutProjectDTO); - } - - /** - * Returns all sources by project in {@link MinimalSourceDetailsDTO} format. - * - * @return list of sources - */ - public Page findAllMinimalSourceDetailsByProject(Long projectId, - Pageable pageable) { - return sourceRepository.findAllSourcesByProjectId(pageable, projectId) - .map(sourceMapper::sourceToMinimalSourceDetailsDTO); - } - - /** - * Returns list of not-assigned sources by project id. - */ - public List findAllByProjectAndAssigned(Long projectId, boolean assigned) { - return sourceMapper.sourcesToSourceDTOs( - sourceRepository.findAllSourcesByProjectIdAndAssigned(projectId, assigned)); - } - - /** - * Returns list of not-assigned sources by project id. - */ - public List findAllMinimalSourceDetailsByProjectAndAssigned( - Long projectId, boolean assigned) { - return sourceRepository - .findAllSourcesByProjectIdAndAssigned(projectId, assigned) - .stream() - .map(sourceMapper::sourceToMinimalSourceDetailsDTO) - .toList(); - } - - /** - * This method does a safe update of source assigned to a subject. It will allow updates of - * attributes only. - * - * @param sourceToUpdate source fetched from database - * @param attributes value to update - * @return Updated {@link MinimalSourceDetailsDTO} of source - */ - public MinimalSourceDetailsDTO safeUpdateOfAttributes(Source sourceToUpdate, - Map attributes) { - - // update source attributes - Map updatedAttributes = new HashMap<>(); - updatedAttributes.putAll(sourceToUpdate.getAttributes()); - updatedAttributes.putAll(attributes); - - sourceToUpdate.setAttributes(updatedAttributes); - // rest of the properties should not be updated from this request. - return sourceMapper.sourceToMinimalSourceDetailsDTO(sourceRepository.save(sourceToUpdate)); - } - - /** - * Updates a source. - * Does not allow to transfer a source, if it is currently assigned. - * Does not allow to transfer if new project does not have valid source-type. - * - * @param sourceDto source details to update. - * @return updated source. - */ - @Transactional - public Optional updateSource(SourceDTO sourceDto) - throws NotAuthorizedException { - Optional existingSourceOpt = sourceRepository.findById(sourceDto.getId()); - if (existingSourceOpt.isEmpty()) { - return Optional.empty(); - } - Source existingSource = existingSourceOpt.get(); - authService.checkPermission(SOURCE_UPDATE, e -> { - e.source(existingSource.getSourceName()); - if (existingSource.getProject() != null) { - e.project(existingSource.getProject().getProjectName()); - } - if (existingSource.getSubject() != null - && existingSource.getSubject().getUser() != null) { - e.subject(existingSource.getSubject().getUser().getLogin()); - } - }); - - // if the source is being transferred to another project. - if (!existingSource.getProject().getId().equals(sourceDto.getProject().getId())) { - if (existingSource.isAssigned()) { - throw new InvalidRequestException("Cannot transfer an assigned source", SOURCE, - "error.sourceIsAssigned"); - } - - // check whether source-type of the device is assigned to the new project - // to be transferred. - Optional sourceType = projectRepository - .findSourceTypeByProjectIdAndSourceTypeId(sourceDto.getProject().getId(), - existingSource.getSourceType().getId()); - - if (sourceType.isEmpty()) { - throw new InvalidRequestException( - "Cannot transfer a source to a project which doesn't have compatible " - + "source-type", ENTITY_NAME, "error.invalidTransfer"); - } - // set old source-type, ensures compatibility - sourceDto.setSourceType( - sourceTypeMapper.sourceTypeToSourceTypeDTO(existingSource.getSourceType())); - - } - - return Optional.of(save(sourceDto)); - } -} diff --git a/src/main/java/org/radarbase/management/service/SourceService.kt b/src/main/java/org/radarbase/management/service/SourceService.kt new file mode 100644 index 000000000..a470c0393 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/SourceService.kt @@ -0,0 +1,267 @@ +package org.radarbase.management.service + +import org.hibernate.id.IdentifierGenerator +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.Source +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.SourceRepository +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.SourceDTO +import org.radarbase.management.service.mapper.SourceMapper +import org.radarbase.management.service.mapper.SourceTypeMapper +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.InvalidRequestException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.history.Revision +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.util.* + +/** + * Service Implementation for managing Source. + */ +@Service +@Transactional +open class SourceService { + @Autowired + private val sourceRepository: SourceRepository? = null + + @Autowired + private val sourceMapper: SourceMapper? = null + + @Autowired + private val projectRepository: ProjectRepository? = null + + @Autowired + private val sourceTypeMapper: SourceTypeMapper? = null + + @Autowired + private val authService: AuthService? = null + + /** + * Save a Source. + * + * @param sourceDto the entity to save + * @return the persisted entity + */ + fun save(sourceDto: SourceDTO?): SourceDTO { + log.debug("Request to save Source : {}", sourceDto) + var source = sourceMapper!!.sourceDTOToSource(sourceDto) + source = sourceRepository!!.save(source) + return sourceMapper.sourceToSourceDTO(source) + } + + /** + * Get all the Sources. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(): List? { + return sourceRepository + ?.findAll() + ?.stream() + ?.map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + ?.toList() + } + + /** + * Get all the sourceData with pagination. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(pageable: Pageable?): Page? { + log.debug("Request to get SourceData with pagination") + return pageable?.let { + sourceRepository + ?.findAll(it) + ?.map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + } + } + + /** + * Get one source by name. + * + * @param sourceName the name of the source + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOneByName(sourceName: String?): Optional { + log.debug("Request to get Source : {}", sourceName) + return sourceRepository!!.findOneBySourceName(sourceName) + .map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + } + + /** + * Get one source by id. + * + * @param id the id of the source + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOneById(id: Long): Optional { + log.debug("Request to get Source by id: {}", id) + return Optional.ofNullable(sourceRepository!!.findById(id).orElse(null)) + .map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + } + + /** + * Delete the device by id. + * + * @param id the id of the entity + */ + @Transactional + open fun delete(id: Long) { + log.info("Request to delete Source : {}", id) + val sourceHistory = sourceRepository!!.findRevisions(id) + val sources = sourceHistory.content + .map { obj: Revision -> obj.entity } + .filter{ it.isAssigned + ?: false } + .toList() + if (sources.isEmpty()) { + sourceRepository.deleteById(id) + } else { + val errorParams: MutableMap = HashMap() + errorParams["message"] = "Cannot delete source with sourceId " + errorParams["id"] = id.toString() + throw InvalidRequestException( + "Cannot delete a source that was once assigned.", + EntityName.SOURCE, "error.usedSourceDeletion", errorParams + ) + } + } + + /** + * Returns all sources by project in [SourceDTO] format. + * + * @return list of sources + */ + fun findAllByProjectId(projectId: Long?, pageable: Pageable?): Page { + return sourceRepository!!.findAllSourcesByProjectId(pageable, projectId) + .map { source: Source? -> sourceMapper!!.sourceToSourceWithoutProjectDTO(source) } + } + + /** + * Returns all sources by project in [MinimalSourceDetailsDTO] format. + * + * @return list of sources + */ + fun findAllMinimalSourceDetailsByProject( + projectId: Long?, + pageable: Pageable? + ): Page { + return sourceRepository!!.findAllSourcesByProjectId(pageable, projectId) + .map { source: Source? -> sourceMapper!!.sourceToMinimalSourceDetailsDTO(source) } + } + + /** + * Returns list of not-assigned sources by project id. + */ + fun findAllByProjectAndAssigned(projectId: Long?, assigned: Boolean): List { + return sourceMapper!!.sourcesToSourceDTOs( + sourceRepository!!.findAllSourcesByProjectIdAndAssigned(projectId, assigned) + ) + } + + /** + * Returns list of not-assigned sources by project id. + */ + fun findAllMinimalSourceDetailsByProjectAndAssigned( + projectId: Long?, assigned: Boolean + ): List { + return sourceRepository + ?.findAllSourcesByProjectIdAndAssigned(projectId, assigned) + ?.map { source -> sourceMapper!!.sourceToMinimalSourceDetailsDTO(source) } + ?.toList() + ?: listOf() + } + + /** + * This method does a safe update of source assigned to a subject. It will allow updates of + * attributes only. + * + * @param sourceToUpdate source fetched from database + * @param attributes value to update + * @return Updated [MinimalSourceDetailsDTO] of source + */ + fun safeUpdateOfAttributes( + sourceToUpdate: Source, + attributes: Map? + ): MinimalSourceDetailsDTO { + + // update source attributes + val updatedAttributes: MutableMap = HashMap() + updatedAttributes.putAll(sourceToUpdate.attributes) + updatedAttributes.putAll(attributes!!) + sourceToUpdate.attributes = updatedAttributes + // rest of the properties should not be updated from this request. + return sourceMapper!!.sourceToMinimalSourceDetailsDTO(sourceRepository!!.save(sourceToUpdate)) + } + + /** + * Updates a source. + * Does not allow to transfer a source, if it is currently assigned. + * Does not allow to transfer if new project does not have valid source-type. + * + * @param sourceDto source details to update. + * @return updated source. + */ + @Transactional + @Throws(NotAuthorizedException::class) + open fun updateSource(sourceDto: SourceDTO): Optional { + val existingSourceOpt = sourceRepository!!.findById(sourceDto.id) + if (existingSourceOpt.isEmpty) { + return Optional.empty() + } + val existingSource = existingSourceOpt.get() + authService!!.checkPermission(Permission.SOURCE_UPDATE, { (_, project, subject, _, source): EntityDetails -> + source + if (existingSource.project != null) { + project + } + if (existingSource.subject != null + && existingSource.subject!!.user != null + ) { + subject + } + }) + + // if the source is being transferred to another project. + if (existingSource.project!!.id != sourceDto.project.id) { + if (existingSource.isAssigned!!) { + throw InvalidRequestException( + "Cannot transfer an assigned source", EntityName.SOURCE, + "error.sourceIsAssigned" + ) + } + + // check whether source-type of the device is assigned to the new project + // to be transferred. + val sourceType = projectRepository + ?.findSourceTypeByProjectIdAndSourceTypeId( + sourceDto.project.id, + existingSource.sourceType!!.id + ) + if (sourceType!!.isEmpty) { + throw InvalidRequestException( + "Cannot transfer a source to a project which doesn't have compatible " + + "source-type", IdentifierGenerator.ENTITY_NAME, "error.invalidTransfer" + ) + } + // set old source-type, ensures compatibility + sourceDto.sourceType = sourceTypeMapper!!.sourceTypeToSourceTypeDTO(existingSource.sourceType) + } + return Optional.of(save(sourceDto)) + } + + companion object { + private val log = LoggerFactory.getLogger(SourceService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/service/SourceTypeService.java b/src/main/java/org/radarbase/management/service/SourceTypeService.java index 655c27fde..7cdc9d44a 100644 --- a/src/main/java/org/radarbase/management/service/SourceTypeService.java +++ b/src/main/java/org/radarbase/management/service/SourceTypeService.java @@ -65,11 +65,11 @@ public SourceTypeDTO save(SourceTypeDTO sourceTypeDto) { log.debug("Request to save SourceType : {}", sourceTypeDto); SourceType sourceType = sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDto); // populate the SourceType of our SourceData's - for (SourceData data : sourceType.getSourceData()) { - data.setSourceType(sourceType); + for (SourceData data : sourceType.sourceData) { + data.sourceType = sourceType; } sourceType = sourceTypeRepository.save(sourceType); - sourceDataRepository.saveAll(sourceType.getSourceData()); + sourceDataRepository.saveAll(sourceType.sourceData); return sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); } @@ -179,12 +179,12 @@ public void saveSourceTypesFromCatalogServer(List catalogSour // check whether a source-type is already available with given config if (sourceTypeRepository.hasOneByProducerAndModelAndVersion( - sourceType.getProducer(), sourceType.getModel(), - sourceType.getCatalogVersion())) { + sourceType.producer, sourceType.model, + sourceType.catalogVersion)) { // skip for existing source-types - log.info("Source-type {} is already available ", sourceType.getProducer() - + "_" + sourceType.getModel() - + "_" + sourceType.getCatalogVersion()); + log.info("Source-type {} is already available ", sourceType.producer + + "_" + sourceType.model + + "_" + sourceType.catalogVersion); } else { try { // create new source-type @@ -208,10 +208,10 @@ private void saveSourceData(SourceType sourceType, CatalogSourceData catalogSour .catalogSourceDataToSourceData(catalogSourceData); // sourceDataName should be unique // generated by combining sourceDataType and source-type configs - sourceData.sourceDataName(sourceType.getProducer() - + "_" + sourceType.getModel() - + "_" + sourceType.getCatalogVersion() - + "_" + sourceData.getSourceDataType()); + sourceData.sourceDataName(sourceType.producer + + "_" + sourceType.model + + "_" + sourceType.catalogVersion + + "_" + sourceData.sourceDataType); sourceData.sourceType(sourceType); sourceDataRepository.save(sourceData); } catch (RuntimeException ex) { @@ -220,21 +220,21 @@ private void saveSourceData(SourceType sourceType, CatalogSourceData catalogSour } private static boolean isSourceTypeValid(SourceType sourceType) { - if (sourceType.getProducer() == null) { + if (sourceType.producer == null) { log.warn("Catalog source-type {} does not have a vendor. " - + "Skipping importing this type", sourceType.getName()); + + "Skipping importing this type", sourceType.name); return false; } - if (sourceType.getModel() == null) { + if (sourceType.model == null) { log.warn("Catalog source-type {} does not have a model. " - + "Skipping importing this type", sourceType.getName()); + + "Skipping importing this type", sourceType.name); return false; } - if (sourceType.getCatalogVersion() == null) { + if (sourceType.catalogVersion == null) { log.warn("Catalog source-type {} does not have a version. " - + "Skipping importing this type", sourceType.getName()); + + "Skipping importing this type", sourceType.name); return false; } return true; diff --git a/src/main/java/org/radarbase/management/service/SubjectService.java b/src/main/java/org/radarbase/management/service/SubjectService.java deleted file mode 100644 index 6339760c3..000000000 --- a/src/main/java/org/radarbase/management/service/SubjectService.java +++ /dev/null @@ -1,546 +0,0 @@ -package org.radarbase.management.service; - -import org.hibernate.envers.query.AuditEntity; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.Group; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.Source; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.AuthorityRepository; -import org.radarbase.management.repository.GroupRepository; -import org.radarbase.management.repository.RoleRepository; -import org.radarbase.management.repository.SourceRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.repository.filters.SubjectSpecification; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.service.mapper.SourceMapper; -import org.radarbase.management.service.mapper.SubjectMapper; -import org.radarbase.management.web.rest.criteria.SubjectCriteria; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ConflictException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.InvalidStateException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.history.Revisions; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Nonnull; -import java.net.MalformedURLException; -import java.net.URL; -import java.time.ZonedDateTime; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.radarbase.auth.authorization.Permission.SUBJECT_READ; -import static org.radarbase.auth.authorization.RoleAuthority.INACTIVE_PARTICIPANT; -import static org.radarbase.auth.authorization.RoleAuthority.PARTICIPANT; -import static org.radarbase.management.service.dto.ProjectDTO.PRIVACY_POLICY_URL; -import static org.radarbase.management.web.rest.errors.EntityName.GROUP; -import static org.radarbase.management.web.rest.errors.EntityName.OAUTH_CLIENT; -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE_TYPE; -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_GROUP_NOT_FOUND; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_NO_VALID_PRIVACY_POLICY_URL_CONFIGURED; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SOURCE_NOT_FOUND; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SUBJECT_NOT_FOUND; - -/** - * Created by nivethika on 26-5-17. - */ -@Service -@Transactional -public class SubjectService { - - private static final Logger log = LoggerFactory.getLogger(SubjectService.class); - - @Autowired - private SubjectMapper subjectMapper; - - @Autowired - private ProjectMapper projectMapper; - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private SourceRepository sourceRepository; - - @Autowired - private SourceMapper sourceMapper; - - @Autowired - private RoleRepository roleRepository; - - @Autowired - private GroupRepository groupRepository; - - @Autowired - private RevisionService revisionService; - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Autowired - private PasswordService passwordService; - - @Autowired - private AuthorityRepository authorityRepository; - - @Autowired - private AuthService authService; - - /** - * Create a new subject. - * - * @param subjectDto the subject information - * @return the newly created subject - */ - @Transactional - public SubjectDTO createSubject(SubjectDTO subjectDto) { - Subject subject = subjectMapper.subjectDTOToSubject(subjectDto); - //assign roles - User user = subject.getUser(); - Project project = projectMapper.projectDTOToProject(subjectDto.getProject()); - Role projectParticipantRole = getProjectParticipantRole(project, PARTICIPANT); - Set roles = user.getRoles(); - roles.add(projectParticipantRole); - - // Set group - subject.setGroup(getSubjectGroup(project, subjectDto.getGroup())); - - // set password and reset keys - user.setPassword(passwordService.generateEncodedPassword()); - user.setResetKey(passwordService.generateResetKey()); - // setting default language key to "en", required to set email context, Find a workaround - user.setLangKey("en"); - user.setResetDate(ZonedDateTime.now()); - // default subject is activated. - user.setActivated(true); - //set if any devices are set as assigned - if (subject.getSources() != null && !subject.getSources().isEmpty()) { - subject.getSources().forEach(s -> s.assigned(true).subject(subject)); - } - if (subject.getEnrollmentDate() == null) { - subject.setEnrollmentDate(ZonedDateTime.now()); - } - sourceRepository.saveAll(subject.getSources()); - return subjectMapper.subjectToSubjectReducedProjectDTO(subjectRepository.save(subject)); - } - - private Group getSubjectGroup(Project project, String groupName) { - if (project == null || groupName == null) { - return null; - } - return groupRepository.findByProjectIdAndName(project.getId(), groupName) - .orElseThrow(() -> new BadRequestException( - "Group " + groupName + " does not exist in project " - + project.getProjectName(), - GROUP, - ERR_GROUP_NOT_FOUND) - ); - } - - /** - * Fetch Participant role of the project if available, otherwise create a new Role and assign. - * - * @param project project subject is assigned to - * @return relevant Participant role - * @throws java.util.NoSuchElementException if the authority name is not in the database - */ - private Role getProjectParticipantRole(Project project, RoleAuthority authority) { - return roleRepository.findOneByProjectIdAndAuthorityName(project.getId(), - authority.getAuthority()) - .orElseGet(() -> { - Role subjectRole = new Role(); - Authority auth = authorityRepository.findByAuthorityName( - authority.getAuthority()) - .orElseGet(() -> authorityRepository.save(new Authority(authority))); - subjectRole.setAuthority(auth); - subjectRole.setProject(project); - return roleRepository.save(subjectRole); - }); - } - - - /** - * Update a subject's information. - * - * @param newSubjectDto the new subject information - * @return the updated subject - */ - @Transactional - public SubjectDTO updateSubject(SubjectDTO newSubjectDto) { - if (newSubjectDto.getId() == null) { - return createSubject(newSubjectDto); - } - Subject subjectFromDb = ensureSubject(newSubjectDto); - Set sourcesToUpdate = subjectFromDb.getSources(); - //set only the devices assigned to a subject as assigned - subjectMapper.safeUpdateSubjectFromDTO(newSubjectDto, subjectFromDb); - sourcesToUpdate.addAll(subjectFromDb.getSources()); - subjectFromDb.getSources() - .forEach(s -> s.subject(subjectFromDb).assigned(true)); - sourceRepository.saveAll(sourcesToUpdate); - // update participant role - subjectFromDb.getUser().setRoles(updateParticipantRoles(subjectFromDb, newSubjectDto)); - // Set group - subjectFromDb.setGroup(getSubjectGroup( - subjectFromDb.getActiveProject().orElse(null), - newSubjectDto.getGroup())); - return subjectMapper.subjectToSubjectReducedProjectDTO( - subjectRepository.save(subjectFromDb)); - } - - private Set updateParticipantRoles(Subject subject, SubjectDTO subjectDto) { - if (subjectDto.getProject() == null || subjectDto.getProject().getProjectName() == null) { - return subject.getUser().getRoles(); - } - - Stream existingRoles = subject.getUser().getRoles().stream() - .map(role -> { - // make participant inactive in projects that do not match the new project - if (role.getAuthority().getName().equals(PARTICIPANT.getAuthority()) - && !role.getProject().getProjectName().equals( - subjectDto.getProject().getProjectName())) { - return getProjectParticipantRole(role.getProject(), INACTIVE_PARTICIPANT); - } else { - // do not modify other roles. - return role; - } - }); - - // Ensure that given project is present - Stream newProjectRole = Stream.of(getProjectParticipantRole( - projectMapper.projectDTOToProject(subjectDto.getProject()), PARTICIPANT)); - - return Stream.concat(existingRoles, newProjectRole) - .collect(Collectors.toSet()); - } - - /** - * Discontinue the given subject. - * - *

A discontinued subject is not deleted from the database, but will be prevented from - * logging into the system, sending data, or otherwise interacting with the system.

- * - * @param subjectDto the subject to discontinue - * @return the discontinued subject - */ - public SubjectDTO discontinueSubject(SubjectDTO subjectDto) { - Subject subject = ensureSubject(subjectDto); - // reset all the sources assigned to a subject to unassigned - unassignAllSources(subject); - - // set the removed flag and deactivate the user to prevent them from refreshing their - // access token - subject.setRemoved(true); - subject.getUser().setActivated(false); - return subjectMapper.subjectToSubjectReducedProjectDTO(subjectRepository.save(subject)); - } - - private Subject ensureSubject(SubjectDTO subjectDto) { - return subjectRepository.findById(subjectDto.getId()) - .orElseThrow(() -> new NotFoundException( - "Subject with ID " + subjectDto.getId() + " not found.", - SUBJECT, ERR_SUBJECT_NOT_FOUND)); - } - - /** - * Unassign all sources from a subject. This method saves the unassigned sources, but does NOT - * save the subject in question. This is the responsibility of the caller. - * - * @param subject The subject for which to unassign all sources - */ - private void unassignAllSources(Subject subject) { - subject.getSources().forEach(source -> { - source.setAssigned(false); - source.setSubject(null); - source.setDeleted(true); - sourceRepository.save(source); - }); - subject.getSources().clear(); - } - - /** - * Creates or updates a source for a subject. It creates and assigns a source of a for a - * dynamicallyRegister-able sourceType. Currently, it is allowed to create only once source of a - * dynamicallyRegistrable sourceType per subject. Otherwise finds the matching source and - * updates meta-data. - */ - @Transactional - public MinimalSourceDetailsDTO assignOrUpdateSource(Subject subject, SourceType sourceType, - Project project, MinimalSourceDetailsDTO sourceRegistrationDto) { - Source assignedSource; - - if (sourceRegistrationDto.getSourceId() != null) { - // update meta-data and source-name for existing sources - assignedSource = updateSourceAssignedSubject(subject, sourceRegistrationDto); - - } else if (sourceType.getCanRegisterDynamically()) { - List sources = subjectRepository - .findSubjectSourcesBySourceType(subject.getUser().getLogin(), - sourceType.getProducer(), sourceType.getModel(), - sourceType.getCatalogVersion()); - // create a source and register meta data - // we allow only one source of a source-type per subject - if (sources.isEmpty()) { - Source source = new Source(sourceType) - .project(project) - .assigned(true) - .sourceType(sourceType) - .subject(subject); - source.getAttributes().putAll(sourceRegistrationDto.getAttributes()); - // if source name is provided update source name - if (sourceRegistrationDto.getSourceName() != null) { - // append the auto generated source-name to given source-name to avoid conflicts - source.setSourceName( - sourceRegistrationDto.getSourceName() + "_" + source.getSourceName()); - } - // make sure there is no source available on the same name. - if (sourceRepository.findOneBySourceName(source.getSourceName()).isPresent()) { - throw new ConflictException("SourceName already in use. Cannot create a " - + "source with existing source-name ", SUBJECT, - ErrorConstants.ERR_SOURCE_NAME_EXISTS, - Collections.singletonMap("source-name", source.getSourceName())); - } - source = sourceRepository.save(source); - - assignedSource = source; - subject.getSources().add(source); - } else { - throw new ConflictException( - "A Source of SourceType with the specified producer, model and version" - + " was already registered for subject login", - SUBJECT, ErrorConstants.ERR_SOURCE_TYPE_EXISTS, - sourceTypeAttributes(sourceType, subject)); - } - } else { - // new source since sourceId == null, but canRegisterDynamically == false - throw new BadRequestException("The source type is not eligible for dynamic " - + "registration", SOURCE_TYPE, "error.InvalidDynamicSourceRegistration", - sourceTypeAttributes(sourceType, subject)); - } - - subjectRepository.save(subject); - return sourceMapper.sourceToMinimalSourceDetailsDTO(assignedSource); - } - - private static Map sourceTypeAttributes(SourceType sourceType, - Subject subject) { - Map errorParams = new HashMap<>(); - errorParams.put("producer", sourceType.getProducer()); - errorParams.put("model", sourceType.getModel()); - errorParams.put("catalogVersion", sourceType.getCatalogVersion()); - errorParams.put("userId", subject.getUser().getLogin()); - return errorParams; - } - - /** - * Updates source name and attributes of the source assigned to subject. Otherwise returns - * {@link NotFoundException}. - * @param subject subject - * @param sourceRegistrationDto details of source which need to be updated. - * @return Updated {@link Source} instance. - */ - private Source updateSourceAssignedSubject(Subject subject, - MinimalSourceDetailsDTO sourceRegistrationDto) { - // for manually registered devices only add meta-data - Source source = subjectRepository.findSubjectSourcesBySourceId( - subject.getUser().getLogin(), sourceRegistrationDto.getSourceId()) - .orElseThrow(() -> { - Map errorParams = new HashMap<>(); - errorParams.put("sourceId", sourceRegistrationDto.getSourceId().toString()); - errorParams.put("subject-login", subject.getUser().getLogin()); - return new NotFoundException( "No source with source-id to assigned to the " - + "subject with subject-login", SUBJECT, ERR_SOURCE_NOT_FOUND, - errorParams); - }); - - if (sourceRegistrationDto.getSourceName() != null) { - source.setSourceName(sourceRegistrationDto.getSourceName()); - } - source.getAttributes().putAll(sourceRegistrationDto.getAttributes()); - source.setAssigned(true); - source.setSubject(subject); - - return sourceRepository.save(source); - } - - /** - * Gets all sources assigned to the subject identified by :login. - * - * @return list of sources - */ - public List getSources(Subject subject) { - List sources = subjectRepository.findSourcesBySubjectLogin(subject.getUser() - .getLogin()); - - return sourceMapper.sourcesToMinimalSourceDetailsDTOs(sources); - } - - /** - * Delete the subject with the given login from the database. - * - * @param login the login - */ - public void deleteSubject(String login) { - subjectRepository.findOneWithEagerBySubjectLogin(login).ifPresent(subject -> { - unassignAllSources(subject); - subjectRepository.delete(subject); - log.debug("Deleted Subject: {}", subject); - }); - } - - /** - * Finds all sources of subject including inactive sources. - * - * @param subject of whom the sources should be retrieved. - * @return list of {@link MinimalSourceDetailsDTO} of sources. - */ - public List findSubjectSourcesFromRevisions(Subject subject) { - Revisions revisions = subjectRepository.findRevisions(subject.getId()); - // collect distinct sources in a set - Set sources = revisions - .getContent().stream().flatMap(p -> p.getEntity().getSources().stream()) - .filter(distinctByKey(Source::getSourceId)) - .collect(Collectors.toSet()); - return sources.stream().map(p -> sourceMapper.sourceToMinimalSourceDetailsDTO(p)) - .toList(); - } - - /** - * Get a specific revision for a given subject. - * - * @param login the login of the subject - * @param revision the revision number - * @return the subject at the given revision - * @throws NotFoundException if there was no subject with the given login at the given - * revision number - */ - public SubjectDTO findRevision(String login, Integer revision) - throws NotFoundException, NotAuthorizedException { - // first get latest known version of the subject, if it's deleted we can't load the entity - // directly by e.g. findOneByLogin - SubjectDTO latest = getLatestRevision(login); - authService.checkPermission(SUBJECT_READ, e -> e - .project(latest.getProject().getProjectName()) - .subject(latest.getLogin())); - SubjectDTO sub = revisionService - .findRevision(revision, latest.getId(), Subject.class, - subjectMapper::subjectToSubjectReducedProjectDTO); - - if (sub == null) { - throw new NotFoundException("subject not found for given login and revision.", SUBJECT, - ERR_SUBJECT_NOT_FOUND, Collections.singletonMap("subjectLogin", login)); - } - return sub; - } - - /** - * Get latest known revision of a subject with the given login. - * - * @param login the login of the subject - * @return the latest revision for that subject - * @throws NotFoundException if no subject was found with the given login - */ - public SubjectDTO getLatestRevision(String login) throws NotFoundException { - UserDTO user = (UserDTO) revisionService.getLatestRevisionForEntity(User.class, - List.of(AuditEntity.property("login").eq(login))) - .orElseThrow(() -> new NotFoundException("Subject latest revision not found " - + "for login" , SUBJECT, ERR_SUBJECT_NOT_FOUND, - Collections.singletonMap("subjectLogin", login))); - return (SubjectDTO) revisionService.getLatestRevisionForEntity(Subject.class, - List.of(AuditEntity.property("user").eq(user))) - .orElseThrow(() -> new NotFoundException("Subject latest revision not found " - + "for login" , SUBJECT, ERR_SUBJECT_NOT_FOUND, - Collections.singletonMap("subjectLogin", login))); - } - - private static Predicate distinctByKey(Function keyExtractor) { - final Set seen = new HashSet<>(); - return t -> seen.add(keyExtractor.apply(t)); - } - - - /** - * Finds {@link Subject} from databased from login provided. - * @param login of subject to look for. - * @return {@link Subject} loaded. - */ - @Nonnull - public Subject findOneByLogin(String login) { - Optional subject = subjectRepository.findOneWithEagerBySubjectLogin(login); - return subject.orElseThrow(() -> - new NotFoundException("Subject not found with login", SUBJECT, - ERR_SUBJECT_NOT_FOUND) - ); - } - - /** - * Find all subjects matching given filter. - * @param criteria filter and sort for subjects. - * @return page of subjects matching filter. - */ - public Page findAll(SubjectCriteria criteria) { - // Pageable is required to set the page limit, - // but the page should always be zero - // since the lastLoadedId param defines the offset - // within the query specification - return subjectRepository.findAll(new SubjectSpecification(criteria), - criteria.getPageable()); - } - - /** - * Gets relevant privacy-policy-url for this subject. - *

- * If the active project of the subject has a valid privacy-policy-url returns that url. - * Otherwise, it loads the default URL from ManagementPortal configurations that is - * general. - *

- * @param subject to get relevant policy url - * @return URL of privacy policy for this token - */ - protected URL getPrivacyPolicyUrl(Subject subject) { - - // load default url from config - String policyUrl = subject.getActiveProject() - .map(p -> p.getAttributes().get(PRIVACY_POLICY_URL)) - .filter(u -> !u.isEmpty()) - .orElse(managementPortalProperties.getCommon().getPrivacyPolicyUrl()); - - try { - return new URL(policyUrl); - } catch (MalformedURLException e) { - Map params = new HashMap<>(); - params.put("url" , policyUrl); - params.put("message" , e.getMessage()); - throw new InvalidStateException("No valid privacy-policy Url configured. Please " - + "verify your project's privacy-policy url and/or general url config", - OAUTH_CLIENT, ERR_NO_VALID_PRIVACY_POLICY_URL_CONFIGURED, - params); - } - } -} diff --git a/src/main/java/org/radarbase/management/service/SubjectService.kt b/src/main/java/org/radarbase/management/service/SubjectService.kt new file mode 100644 index 000000000..56571a6b8 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/SubjectService.kt @@ -0,0 +1,516 @@ +package org.radarbase.management.service + +import org.hibernate.envers.query.AuditEntity +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.Group +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.Source +import org.radarbase.management.domain.SourceType +import org.radarbase.management.domain.Subject +import org.radarbase.management.domain.User +import org.radarbase.management.repository.AuthorityRepository +import org.radarbase.management.repository.GroupRepository +import org.radarbase.management.repository.RoleRepository +import org.radarbase.management.repository.SourceRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.repository.filters.SubjectSpecification +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.service.mapper.SourceMapper +import org.radarbase.management.service.mapper.SubjectMapper +import org.radarbase.management.web.rest.criteria.SubjectCriteria +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.ConflictException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidStateException +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Page +import org.springframework.data.history.Revision +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.net.MalformedURLException +import java.net.URL +import java.time.ZonedDateTime +import java.util.* +import java.util.function.Consumer +import java.util.function.Function +import java.util.function.Predicate +import javax.annotation.Nonnull + +/** + * Created by nivethika on 26-5-17. + */ +@Service +@Transactional +open class SubjectService( + @Autowired private val subjectMapper: SubjectMapper, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val sourceRepository: SourceRepository, + @Autowired private val sourceMapper: SourceMapper, + @Autowired private val roleRepository: RoleRepository, + @Autowired private val groupRepository: GroupRepository, + @Autowired private val revisionService: RevisionService, + @Autowired private val managementPortalProperties: ManagementPortalProperties, + @Autowired private val passwordService: PasswordService, + @Autowired private val authorityRepository: AuthorityRepository, + @Autowired private val authService: AuthService +) { + + /** + * Create a new subject. + * + * @param subjectDto the subject information + * @return the newly created subject + */ + @Transactional + open fun createSubject(subjectDto: SubjectDTO): SubjectDTO? { + val subject = subjectMapper.subjectDTOToSubject(subjectDto) + if (subject == null) throw NullPointerException() + //assign roles + val user = subject.user + val project = projectMapper.projectDTOToProject(subjectDto.project) + val projectParticipantRole = getProjectParticipantRole(project, RoleAuthority.PARTICIPANT) + val roles = user!!.roles + roles?.add(projectParticipantRole) + + // Set group + subject.group = getSubjectGroup(project, subjectDto.group) + + // set password and reset keys + user.password = passwordService.generateEncodedPassword() + user.resetKey = passwordService.generateResetKey() + // setting default language key to "en", required to set email context, Find a workaround + user.langKey = "en" + user.resetDate = ZonedDateTime.now() + // default subject is activated. + user.activated = true + //set if any devices are set as assigned + if (subject.sources.isNotEmpty()) { + subject.sources.forEach(Consumer { s: Source -> s.assigned(true).subject(subject) }) + } + if (subject.enrollmentDate == null) { + subject.enrollmentDate = ZonedDateTime.now() + } + sourceRepository.saveAll(subject.sources) + return subjectMapper.subjectToSubjectReducedProjectDTO(subjectRepository.save(subject)) + } + + private fun getSubjectGroup(project: Project?, groupName: String?): Group? { + return if (project == null || groupName == null) { + null + } else groupRepository.findByProjectIdAndName(project.id, groupName) ?: throw BadRequestException( + "Group " + groupName + " does not exist in project " + project.projectName, + EntityName.GROUP, + ErrorConstants.ERR_GROUP_NOT_FOUND + ) + } + + /** + * Fetch Participant role of the project if available, otherwise create a new Role and assign. + * + * @param project project subject is assigned to + * @return relevant Participant role + * @throws java.util.NoSuchElementException if the authority name is not in the database + */ + private fun getProjectParticipantRole(project: Project?, authority: RoleAuthority): Role { + return roleRepository.findOneByProjectIdAndAuthorityName( + project!!.id, authority.authority + ).orElseGet { + val subjectRole = Role() + val auth = authorityRepository.findByAuthorityName( + authority.authority + ).orElseGet { authorityRepository.save(Authority(authority)) } + subjectRole.authority = auth + subjectRole.project = project + roleRepository.save(subjectRole) + } + } + + /** + * Update a subject's information. + * + * @param newSubjectDto the new subject information + * @return the updated subject + */ + @Transactional + open fun updateSubject(newSubjectDto: SubjectDTO): SubjectDTO? { + if (newSubjectDto.id == null) { + return createSubject(newSubjectDto) + } + val subjectFromDb = ensureSubject(newSubjectDto) + val sourcesToUpdate = subjectFromDb.sources + //set only the devices assigned to a subject as assigned + subjectMapper.safeUpdateSubjectFromDTO(newSubjectDto, subjectFromDb) + sourcesToUpdate.addAll(subjectFromDb.sources) + subjectFromDb.sources.forEach(Consumer { s: Source -> s.subject(subjectFromDb).assigned(true) }) + sourceRepository.saveAll(sourcesToUpdate) + // update participant role + subjectFromDb.user!!.roles = updateParticipantRoles(subjectFromDb, newSubjectDto) + // Set group + subjectFromDb.group = getSubjectGroup( + subjectFromDb.activeProject, newSubjectDto.group + ) + return subjectMapper.subjectToSubjectReducedProjectDTO( + subjectRepository.save(subjectFromDb) + ) + } + + private fun updateParticipantRoles(subject: Subject, subjectDto: SubjectDTO): MutableSet? { + if (subjectDto.project == null || subjectDto.project.projectName == null) { + return subject.user!!.roles + } + val existingRoles = subject.user!!.roles?.map { + // make participant inactive in projects that do not match the new project + if (it.authority!!.name == RoleAuthority.PARTICIPANT.authority && it.project!!.projectName != subjectDto.project.projectName) { + return@map getProjectParticipantRole(it.project, RoleAuthority.INACTIVE_PARTICIPANT) + } else { + // do not modify other roles. + return@map it + } + }?.toMutableSet() + + // Ensure that given project is present + val newProjectRole = + getProjectParticipantRole(projectMapper.projectDTOToProject(subjectDto.project), RoleAuthority.PARTICIPANT) + existingRoles?.add(newProjectRole) + + return existingRoles + + } + + /** + * Discontinue the given subject. + * + * + * A discontinued subject is not deleted from the database, but will be prevented from + * logging into the system, sending data, or otherwise interacting with the system. + * + * @param subjectDto the subject to discontinue + * @return the discontinued subject + */ + fun discontinueSubject(subjectDto: SubjectDTO): SubjectDTO? { + val subject = ensureSubject(subjectDto) + // reset all the sources assigned to a subject to unassigned + unassignAllSources(subject) + + // set the removed flag and deactivate the user to prevent them from refreshing their + // access token + subject.isRemoved = true + subject.user!!.activated = false + return subjectMapper.subjectToSubjectReducedProjectDTO(subjectRepository.save(subject)) + } + + private fun ensureSubject(subjectDto: SubjectDTO): Subject { + return subjectRepository.findById(subjectDto.id).orElseThrow { + NotFoundException( + "Subject with ID " + subjectDto.id + " not found.", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND + ) + } + } + + /** + * Unassign all sources from a subject. This method saves the unassigned sources, but does NOT + * save the subject in question. This is the responsibility of the caller. + * + * @param subject The subject for which to unassign all sources + */ + private fun unassignAllSources(subject: Subject) { + subject.sources.forEach(Consumer { source: Source -> + source.isAssigned = false + source.subject = null + source.isDeleted = true + sourceRepository.save(source) + }) + subject.sources.clear() + } + + /** + * Creates or updates a source for a subject. It creates and assigns a source of a for a + * dynamicallyRegister-able sourceType. Currently, it is allowed to create only once source of a + * dynamicallyRegistrable sourceType per subject. Otherwise finds the matching source and + * updates meta-data. + */ + @Transactional + open fun assignOrUpdateSource( + subject: Subject, sourceType: SourceType, project: Project?, sourceRegistrationDto: MinimalSourceDetailsDTO + ): MinimalSourceDetailsDTO { + val assignedSource: Source + if (sourceRegistrationDto.sourceId != null) { + // update meta-data and source-name for existing sources + assignedSource = updateSourceAssignedSubject(subject, sourceRegistrationDto) + } else if (sourceType.canRegisterDynamically!!) { + val sources = subjectRepository.findSubjectSourcesBySourceType( + subject.user!!.login, sourceType.producer, sourceType.model, sourceType.catalogVersion + ) + // create a source and register metadata + // we allow only one source of a source-type per subject + if (sources.isNullOrEmpty()) { + var source = Source(sourceType).project(project).assigned(true).sourceType(sourceType).subject(subject) + source.attributes += sourceRegistrationDto.attributes + // if source name is provided update source name + if (sourceRegistrationDto.sourceName != null) { + // append the auto generated source-name to given source-name to avoid conflicts + source.sourceName = sourceRegistrationDto.sourceName + "_" + source.sourceName + } + // make sure there is no source available on the same name. + if (sourceRepository.findOneBySourceName(source.sourceName).isPresent) { + throw ConflictException( + "SourceName already in use. Cannot create a " + "source with existing source-name ", + EntityName.SUBJECT, + ErrorConstants.ERR_SOURCE_NAME_EXISTS, + Collections.singletonMap("source-name", source.sourceName) + ) + } + source = sourceRepository.save(source) + assignedSource = source + subject.sources.add(source) + } else { + throw ConflictException( + "A Source of SourceType with the specified producer, model and version" + " was already registered for subject login", + EntityName.SUBJECT, + ErrorConstants.ERR_SOURCE_TYPE_EXISTS, + sourceTypeAttributes(sourceType, subject) + ) + } + } else { + // new source since sourceId == null, but canRegisterDynamically == false + throw BadRequestException( + "The source type is not eligible for dynamic " + "registration", + EntityName.SOURCE_TYPE, + "error.InvalidDynamicSourceRegistration", + sourceTypeAttributes(sourceType, subject) + ) + } + subjectRepository.save(subject) + return sourceMapper.sourceToMinimalSourceDetailsDTO(assignedSource) + } + + /** + * Updates source name and attributes of the source assigned to subject. Otherwise returns + * [NotFoundException]. + * @param subject subject + * @param sourceRegistrationDto details of source which need to be updated. + * @return Updated [Source] instance. + */ + private fun updateSourceAssignedSubject( + subject: Subject, sourceRegistrationDto: MinimalSourceDetailsDTO + ): Source { + // for manually registered devices only add meta-data + val source = subjectRepository.findSubjectSourcesBySourceId( + subject.user!!.login, sourceRegistrationDto.sourceId + ).orElseThrow { + val errorParams: MutableMap = HashMap() + errorParams["sourceId"] = sourceRegistrationDto.sourceId.toString() + errorParams["subject-login"] = subject.user!!.login + NotFoundException( + "No source with source-id to assigned to the " + "subject with subject-login", + EntityName.SUBJECT, + ErrorConstants.ERR_SOURCE_NOT_FOUND, + errorParams + ) + } + if (sourceRegistrationDto.sourceName != null) { + source.sourceName = sourceRegistrationDto.sourceName + } + source.attributes += sourceRegistrationDto.attributes + source.isAssigned = true + source.subject = subject + return sourceRepository.save(source) + } + + /** + * Gets all sources assigned to the subject identified by :login. + * + * @return list of sources + */ + fun getSources(subject: Subject): List { + val sources = subjectRepository.findSourcesBySubjectLogin( + subject.user?.login + ) + return sourceMapper.sourcesToMinimalSourceDetailsDTOs(sources) + } + + /** + * Delete the subject with the given login from the database. + * + * @param login the login + */ + fun deleteSubject(login: String?) { + subjectRepository.findOneWithEagerBySubjectLogin(login).ifPresent { subject: Subject -> + unassignAllSources(subject) + subjectRepository.delete(subject) + log.debug("Deleted Subject: {}", subject) + } + } + + /** + * Finds all sources of subject including inactive sources. + * + * @param subject of whom the sources should be retrieved. + * @return list of [MinimalSourceDetailsDTO] of sources. + */ + fun findSubjectSourcesFromRevisions(subject: Subject): List? { + val revisions = subject.id?.let { subjectRepository.findRevisions(it) } + // collect distinct sources in a set + val sources: List? = revisions?.content?.flatMap { p: Revision -> p.entity.sources } + ?.distinctBy { obj: Source -> obj.sourceId } + + return sources?.map { p: Source? -> sourceMapper.sourceToMinimalSourceDetailsDTO(p) }?.toList() + } + + /** + * Get a specific revision for a given subject. + * + * @param login the login of the subject + * @param revision the revision number + * @return the subject at the given revision + * @throws NotFoundException if there was no subject with the given login at the given + * revision number + */ + @Throws(NotFoundException::class, NotAuthorizedException::class) + fun findRevision(login: String?, revision: Int?): SubjectDTO { + // first get latest known version of the subject, if it's deleted we can't load the entity + // directly by e.g. findOneByLogin + val latest = getLatestRevision(login) + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> + e.project(latest.project.projectName).subject(latest.getLogin()) + }) + return revisionService.findRevision( + revision, + latest.id, + Subject::class.java, + subjectMapper::subjectToSubjectReducedProjectDTO + ) ?: throw NotFoundException( + "subject not found for given login and revision.", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) + } + + /** + * Get latest known revision of a subject with the given login. + * + * @param login the login of the subject + * @return the latest revision for that subject + * @throws NotFoundException if no subject was found with the given login + */ + @Throws(NotFoundException::class) + fun getLatestRevision(login: String?): SubjectDTO { + val user = revisionService.getLatestRevisionForEntity( + User::class.java, java.util.List.of(AuditEntity.property("login").eq(login)) + ).orElseThrow { + NotFoundException( + "Subject latest revision not found " + "for login", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) + } as UserDTO + return revisionService.getLatestRevisionForEntity( + Subject::class.java, java.util.List.of(AuditEntity.property("user").eq(user)) + ).orElseThrow { + NotFoundException( + "Subject latest revision not found " + "for login", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) + } as SubjectDTO + } + + /** + * Finds [Subject] from databased from login provided. + * @param login of subject to look for. + * @return [Subject] loaded. + */ + @Nonnull + fun findOneByLogin(login: String?): Subject { + val subject = subjectRepository.findOneWithEagerBySubjectLogin(login) + return subject.orElseThrow { + NotFoundException( + "Subject not found with login", EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND + ) + } + } + + /** + * Find all subjects matching given filter. + * @param criteria filter and sort for subjects. + * @return page of subjects matching filter. + */ + fun findAll(criteria: SubjectCriteria): Page { + // Pageable is required to set the page limit, + // but the page should always be zero + // since the lastLoadedId param defines the offset + // within the query specification + return subjectRepository.findAll( + SubjectSpecification(criteria), criteria.pageable + ) + } + + /** + * Gets relevant privacy-policy-url for this subject. + * + * + * If the active project of the subject has a valid privacy-policy-url returns that url. + * Otherwise, it loads the default URL from ManagementPortal configurations that is + * general. + * + * @param subject to get relevant policy url + * @return URL of privacy policy for this token + */ + fun getPrivacyPolicyUrl(subject: Subject): URL { + + // load default url from config + val policyUrl: String = subject.activeProject?.attributes?.get(ProjectDTO.PRIVACY_POLICY_URL) + ?: managementPortalProperties.common.privacyPolicyUrl + return try { + URL(policyUrl) + } catch (e: MalformedURLException) { + val params: MutableMap = HashMap() + params["url"] = policyUrl + params["message"] = e.message + throw InvalidStateException( + "No valid privacy-policy Url configured. Please " + "verify your project's privacy-policy url and/or general url config", + EntityName.OAUTH_CLIENT, + ErrorConstants.ERR_NO_VALID_PRIVACY_POLICY_URL_CONFIGURED, + params + ) + } + } + + companion object { + private val log = LoggerFactory.getLogger(SubjectService::class.java) + private fun sourceTypeAttributes( + sourceType: SourceType, subject: Subject + ): Map { + val errorParams: MutableMap = HashMap() + errorParams["producer"] = sourceType.producer + errorParams["model"] = sourceType.model + errorParams["catalogVersion"] = sourceType.catalogVersion + errorParams["userId"] = subject.user!!.login + return errorParams + } + + private fun distinctByKey(keyExtractor: Function): Predicate { + val seen: MutableSet = HashSet() + return Predicate { t: T -> seen.add(keyExtractor.apply(t)) } + } + } +} diff --git a/src/main/java/org/radarbase/management/service/UserService.java b/src/main/java/org/radarbase/management/service/UserService.java deleted file mode 100644 index 5968685b2..000000000 --- a/src/main/java/org/radarbase/management/service/UserService.java +++ /dev/null @@ -1,434 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.repository.filters.UserFilter; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.security.SecurityUtils; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.UserMapper; -import org.radarbase.management.web.rest.errors.ConflictException; -import org.radarbase.management.web.rest.errors.InvalidRequestException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.time.Period; -import java.time.ZonedDateTime; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.radarbase.auth.authorization.Permission.ROLE_UPDATE; -import static org.radarbase.auth.authorization.RoleAuthority.INACTIVE_PARTICIPANT; -import static org.radarbase.auth.authorization.RoleAuthority.PARTICIPANT; -import static org.radarbase.management.service.RoleService.getRoleAuthority; -import static org.radarbase.management.web.rest.errors.EntityName.USER; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_EMAIL_EXISTS; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_ENTITY_NOT_FOUND; - -/** - * Service class for managing users. - */ -@Service -@Transactional -public class UserService { - - private static final Logger log = LoggerFactory.getLogger(UserService.class); - - @Autowired - private UserRepository userRepository; - - @Autowired - private PasswordService passwordService; - - @Autowired - private RoleService roleService; - - @Autowired - private UserMapper userMapper; - - @Autowired - private RevisionService revisionService; - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Autowired - private AuthService authService; - - /** - * Activate a user with the given activation key. - * @param key the activation key - * @return an {@link Optional} which is populated with the activated user if the registration - * key was found, and is empty otherwise. - */ - public Optional activateRegistration(String key) { - log.debug("Activating user for activation key {}", key); - return userRepository.findOneByActivationKey(key) - .map(user -> { - // activate given user for the registration key. - user.setActivated(true); - user.setActivationKey(null); - log.debug("Activated user: {}", user); - return user; - }); - } - - /** - * Update a user password with a given reset key. - * @param newPassword the updated password - * @param key the reset key - * @return an {@link Optional} which is populated with the user whose password was reset if - * the reset key was found, and is empty otherwise - */ - public Optional completePasswordReset(String newPassword, String key) { - log.debug("Reset user password for reset key {}", key); - - return userRepository.findOneByResetKey(key) - .filter(user -> { - ZonedDateTime oneDayAgo = ZonedDateTime.now() - .minusSeconds(managementPortalProperties.getCommon() - .getActivationKeyTimeoutInSeconds()); - return user.getResetDate().isAfter(oneDayAgo); - }) - .map(user -> { - user.setPassword(passwordService.encode(newPassword)); - user.setResetKey(null); - user.setResetDate(null); - user.setActivated(true); - return user; - }); - } - - /** - * Find the deactivated user and set the user's reset key to a new random value and set their - * reset date to now. - * Note: We do not use activation key for activating an account. It happens by resetting - * generated password. Resetting activation is by resetting reset-key and reset-date to now. - * @param login the login of the user - * @return an {@link Optional} which holds the user if an deactivated user was found with the - * given login, and is empty otherwise - */ - public Optional requestActivationReset(String login) { - return userRepository.findOneByLogin(login) - .filter((p) -> !p.getActivated()) - .map(user -> { - user.setResetKey(passwordService.generateResetKey()); - user.setResetDate(ZonedDateTime.now()); - return user; - }); - } - - /** - * Set a user's reset key to a new random value and set their reset date to now. - * @param mail the email address of the user - * @return an {@link Optional} which holds the user if an activated user was found with the - * given email address, and is empty otherwise - */ - public Optional requestPasswordReset(String mail) { - return userRepository.findOneByEmail(mail) - .filter(User::getActivated) - .map(user -> { - user.setResetKey(passwordService.generateResetKey()); - user.setResetDate(ZonedDateTime.now()); - return user; - }); - } - - /** - * Add a new user to the database. - * - *

The new user will not be activated and have a random password assigned. It is the - * responsibility of the caller to make sure the new user has a means of activating their - * account.

- * @param userDto the user information - * @return the newly created user - */ - public User createUser(UserDTO userDto) throws NotAuthorizedException { - User user = new User(); - user.setLogin(userDto.getLogin()); - user.setFirstName(userDto.getFirstName()); - user.setLastName(userDto.getLastName()); - user.setEmail(userDto.getEmail()); - if (userDto.getLangKey() == null) { - user.setLangKey("en"); // default language - } else { - user.setLangKey(userDto.getLangKey()); - } - user.setPassword(passwordService.generateEncodedPassword()); - user.setResetKey(passwordService.generateResetKey()); - user.setResetDate(ZonedDateTime.now()); - user.setActivated(false); - - user.setRoles(getUserRoles(userDto.getRoles(), Set.of())); - user = userRepository.save(user); - log.debug("Created Information for User: {}", user); - return user; - } - - private Set getUserRoles(Set roleDtos, Set oldRoles) - throws NotAuthorizedException { - if (roleDtos == null) { - return null; - } - var roles = roleDtos.stream() - .map(roleDto -> { - RoleAuthority authority = getRoleAuthority(roleDto); - return switch (authority.getScope()) { - case GLOBAL -> roleService.getGlobalRole(authority); - case ORGANIZATION -> roleService.getOrganizationRole(authority, - roleDto.getOrganizationId()); - case PROJECT -> roleService.getProjectRole(authority, - roleDto.getProjectId()); - }; - }) - .collect(Collectors.toSet()); - - checkAuthorityForRoleChange(roles, oldRoles); - - return roles; - } - - private void checkAuthorityForRoleChange(Set roles, Set oldRoles) - throws NotAuthorizedException { - var updatedRoles = new HashSet<>(roles); - updatedRoles.removeAll(oldRoles); - for (Role r : updatedRoles) { - checkAuthorityForRoleChange(r); - } - - var removedRoles = new HashSet<>(oldRoles); - removedRoles.removeAll(roles); - for (Role r : removedRoles) { - checkAuthorityForRoleChange(r); - } - } - - private void checkAuthorityForRoleChange(Role role) - throws NotAuthorizedException { - authService.checkPermission(ROLE_UPDATE, e -> { - switch (role.getRole().getScope()) { - case GLOBAL -> { } - case ORGANIZATION -> e.organization(role.getOrganization().getName()); - case PROJECT -> { - if (role.getProject().getOrganization() != null) { - e.organization(role.getProject().getOrganization().getName()); - } - e.project(role.getProject().getProjectName()); - } - default -> throw new IllegalStateException("Unknown authority scope."); - } - }); - } - - /** - * Update basic information (first name, last name, email, language) for the current user. - * - * @param firstName first name of user - * @param lastName last name of user - * @param email email id of user - * @param langKey language key - */ - public void updateUser(String userName, String firstName, String lastName, - String email, String langKey) { - Optional userWithEmail = userRepository.findOneByEmail(email); - User user; - if (userWithEmail.isPresent()) { - user = userWithEmail.get(); - if (!user.getLogin().equalsIgnoreCase(userName)) { - throw new ConflictException("Email address " + email + " already in use", USER, - ERR_EMAIL_EXISTS, Map.of("email", email)); - } - } else { - user = userRepository.findOneByLogin(userName) - .orElseThrow(() -> new NotFoundException( - "User with login " + userName + " not found", USER, - ERR_ENTITY_NOT_FOUND, Map.of("user", userName))); - } - - user.setFirstName(firstName); - user.setLastName(lastName); - user.setEmail(email); - user.setLangKey(langKey); - log.debug("Changed Information for User: {}", user); - userRepository.save(user); - } - - /** - * Update all information for a specific user, and return the modified user. - * - * @param userDto user to update - * @return updated user - */ - @Transactional - public Optional updateUser(UserDTO userDto) throws NotAuthorizedException { - Optional userOpt = userRepository.findById(userDto.getId()); - if (userOpt.isPresent()) { - User user = userOpt.get(); - user.setFirstName(userDto.getFirstName()); - user.setLastName(userDto.getLastName()); - user.setEmail(userDto.getEmail()); - user.setActivated(userDto.isActivated()); - user.setLangKey(userDto.getLangKey()); - Set managedRoles = user.getRoles(); - Set oldRoles = Set.copyOf(managedRoles); - managedRoles.clear(); - managedRoles.addAll(getUserRoles(userDto.getRoles(), oldRoles)); - - user = userRepository.save(user); - log.debug("Changed Information for User: {}", user); - return Optional.of(userMapper.userToUserDTO(user)); - } else { - return Optional.empty(); - } - } - - /** - * Delete the user with the given login. - * @param login the login to delete - */ - public void deleteUser(String login) { - userRepository.findOneByLogin(login).ifPresent(user -> { - userRepository.delete(user); - log.debug("Deleted User: {}", user); - }); - } - - /** - * Change the password of the user with the given login. - * @param password the new password - */ - public void changePassword(String password) { - String currentUser = SecurityUtils.getCurrentUserLogin() - .orElseThrow(() -> new InvalidRequestException( - "Cannot change password of unknown user", null, - ERR_ENTITY_NOT_FOUND)); - changePassword(currentUser, password); - } - - /** - * Change the user's password. - * @param password the new password - * @param login of the user to change password - */ - public void changePassword(String login, String password) { - userRepository.findOneByLogin(login).ifPresent(user -> { - String encryptedPassword = passwordService.encode(password); - user.setPassword(encryptedPassword); - log.debug("Changed password for User: {}", user); - }); - } - - /** - * Get a page of users. - * @param pageable the page information - * @return the requested page of users - */ - @Transactional(readOnly = true) - public Page getAllManagedUsers(Pageable pageable) { - log.debug("Request to get all Users"); - return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER) - .map(userMapper::userToUserDTO); - } - - /** - * Get the user with the given login. - * @param login the login - * @return an {@link Optional} which holds the user if one was found with the given login, - * and is empty otherwise - */ - @Transactional(readOnly = true) - public Optional getUserWithAuthoritiesByLogin(String login) { - return userRepository.findOneWithRolesByLogin(login).map(userMapper::userToUserDTO); - } - - /** - * Get the current user. - * @return the currently authenticated user, or null if no user is currently authenticated - */ - @Transactional(readOnly = true) - public Optional getUserWithAuthorities() { - return SecurityUtils.getCurrentUserLogin() - .flatMap(currentUser -> userRepository.findOneWithRolesByLogin(currentUser)); - } - - - /** - * Not activated users should be automatically deleted after 3 days.

This is scheduled to - * get fired everyday, at 01:00 (am). This is aimed at users, not subjects. So filter our - * users with *PARTICIPANT role and perform the action.

- */ - @Scheduled(cron = "0 0 1 * * ?") - public void removeNotActivatedUsers() { - log.info("Scheduled scan for expired user accounts starting now"); - ZonedDateTime cutoff = ZonedDateTime.now().minus(Period.ofDays(3)); - - List authorities = Arrays.asList( - PARTICIPANT.getAuthority(), INACTIVE_PARTICIPANT.getAuthority()); - - userRepository.findAllByActivatedAndAuthoritiesNot(false, authorities).stream() - .filter(user -> revisionService.getAuditInfo(user).getCreatedAt().isBefore(cutoff)) - .forEach(user -> { - try { - userRepository.delete(user); - log.info("Deleted not activated user after 3 days: {}", user.getLogin()); - } catch (DataIntegrityViolationException ex) { - log.error("Could not delete user with login " + user.getLogin(), ex); - } - }); - } - - /** - * Find all user with given filter. - * - * @param userFilter filtering for users. - * @param pageable paging information - * @param includeProvenance whether to include created and modification fields. - * @return page of users. - */ - public Page findUsers(UserFilter userFilter, Pageable pageable, - boolean includeProvenance) { - return userRepository.findAll(userFilter, pageable) - .map(includeProvenance - ? userMapper::userToUserDTO - : userMapper::userToUserDTONoProvenance); - } - - /** - * Update the roles of the given user. - * @param login user login - * @param roleDtos new roles to set - * @throws NotAuthorizedException if the current user is not allowed to modify the roles - * of the target user. - */ - @Transactional - public void updateRoles(String login, Set roleDtos) throws NotAuthorizedException { - var user = userRepository.findOneByLogin(login) - .orElseThrow(() -> new NotFoundException( - "User with login " + login + " not found", USER, - ERR_ENTITY_NOT_FOUND, Map.of("user", login))); - - Set managedRoles = user.getRoles(); - Set oldRoles = Set.copyOf(managedRoles); - managedRoles.clear(); - managedRoles.addAll(getUserRoles(roleDtos, oldRoles)); - userRepository.save(user); - } -} diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt new file mode 100644 index 000000000..36c8355cb --- /dev/null +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -0,0 +1,428 @@ +package org.radarbase.management.service + +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.User +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.repository.filters.UserFilter +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.security.SecurityUtils +import org.radarbase.management.service.RoleService.Companion.getRoleAuthority +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.UserMapper +import org.radarbase.management.web.rest.errors.ConflictException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidRequestException +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.dao.DataIntegrityViolationException +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.time.Period +import java.time.ZonedDateTime +import java.util.* +import java.util.Map +import java.util.function.Function +import java.util.stream.Collectors +import kotlin.collections.HashSet +import kotlin.collections.MutableSet +import kotlin.collections.Set +import kotlin.collections.setOf + +/** + * Service class for managing users. + */ +@Service +@Transactional +open class UserService( + @Autowired private val userRepository: UserRepository, + @Autowired private val passwordService: PasswordService, + @Autowired private val roleService: RoleService, + @Autowired private val userMapper: UserMapper, + @Autowired private val revisionService: RevisionService, + @Autowired private val managementPortalProperties: ManagementPortalProperties, + @Autowired private val authService: AuthService +) { + + /** + * Activate a user with the given activation key. + * @param key the activation key + * @return an [Optional] which is populated with the activated user if the registration + * key was found, and is empty otherwise. + */ + fun activateRegistration(key: String?): Optional { + log.debug("Activating user for activation key {}", key) + return userRepository.findOneByActivationKey(key).map { user: User -> + // activate given user for the registration key. + user.activated = true + user.activationKey = null + log.debug("Activated user: {}", user) + user + } + } + + /** + * Update a user password with a given reset key. + * @param newPassword the updated password + * @param key the reset key + * @return an [Optional] which is populated with the user whose password was reset if + * the reset key was found, and is empty otherwise + */ + fun completePasswordReset(newPassword: String?, key: String?): Optional { + log.debug("Reset user password for reset key {}", key) + return userRepository.findOneByResetKey(key).filter { user: User -> + val oneDayAgo = ZonedDateTime.now().minusSeconds( + managementPortalProperties.common.activationKeyTimeoutInSeconds.toLong() + ) + user.resetDate!!.isAfter(oneDayAgo) + }.map { user: User -> + user.password = passwordService.encode(newPassword) + user.resetKey = null + user.resetDate = null + user.activated = true + user + } + } + + /** + * Find the deactivated user and set the user's reset key to a new random value and set their + * reset date to now. + * Note: We do not use activation key for activating an account. It happens by resetting + * generated password. Resetting activation is by resetting reset-key and reset-date to now. + * @param login the login of the user + * @return an [Optional] which holds the user if an deactivated user was found with the + * given login, and is empty otherwise + */ + fun requestActivationReset(login: String?): Optional { + return userRepository.findOneByLogin(login).filter { p: User -> !p.activated }.map { user: User -> + user.resetKey = passwordService.generateResetKey() + user.resetDate = ZonedDateTime.now() + user + } + } + + /** + * Set a user's reset key to a new random value and set their reset date to now. + * @param mail the email address of the user + * @return an [Optional] which holds the user if an activated user was found with the + * given email address, and is empty otherwise + */ + fun requestPasswordReset(mail: String?): Optional { + return userRepository.findOneByEmail(mail).filter(User::activated).map { user: User -> + user.resetKey = passwordService.generateResetKey() + user.resetDate = ZonedDateTime.now() + user + } + } + + /** + * Add a new user to the database. + * + * + * The new user will not be activated and have a random password assigned. It is the + * responsibility of the caller to make sure the new user has a means of activating their + * account. + * @param userDto the user information + * @return the newly created user + */ + @Throws(NotAuthorizedException::class) + fun createUser(userDto: UserDTO): User { + var user = User() + user.setLogin(userDto.login) + user.firstName = userDto.firstName + user.lastName = userDto.lastName + user.email = userDto.email + if (userDto.langKey == null) { + user.langKey = "en" // default language + } else { + user.langKey = userDto.langKey + } + user.password = passwordService.generateEncodedPassword() + user.resetKey = passwordService.generateResetKey() + user.resetDate = ZonedDateTime.now() + user.activated = false + user.roles = getUserRoles(userDto.roles, setOf()) + user = userRepository.save(user) + log.debug("Created Information for User: {}", user) + return user + } + + @Throws(NotAuthorizedException::class) + private fun getUserRoles(roleDtos: Set?, oldRoles: Set): MutableSet? { + if (roleDtos == null) { + return null + } + val roles = roleDtos.stream().map { roleDto: RoleDTO -> + val authority = getRoleAuthority(roleDto) + when (authority.scope) { + RoleAuthority.Scope.GLOBAL -> roleService.getGlobalRole(authority) + RoleAuthority.Scope.ORGANIZATION -> roleService.getOrganizationRole( + authority, roleDto.organizationId + ) + + RoleAuthority.Scope.PROJECT -> roleService.getProjectRole( + authority, roleDto.projectId + ) + } + }.collect(Collectors.toSet()) + checkAuthorityForRoleChange(roles, oldRoles) + return roles + } + + @Throws(NotAuthorizedException::class) + private fun checkAuthorityForRoleChange(roles: Set, oldRoles: Set) { + val updatedRoles = HashSet(roles) + updatedRoles.removeAll(oldRoles) + for (r in updatedRoles) { + checkAuthorityForRoleChange(r) + } + val removedRoles = HashSet(oldRoles) + removedRoles.removeAll(roles) + for (r in removedRoles) { + checkAuthorityForRoleChange(r) + } + } + + @Throws(NotAuthorizedException::class) + private fun checkAuthorityForRoleChange(role: Role) { + authService.checkPermission(Permission.ROLE_UPDATE, { e: EntityDetails -> + when (role.role?.scope) { + RoleAuthority.Scope.GLOBAL -> {} + RoleAuthority.Scope.ORGANIZATION -> e.organization(role.organization?.name) + RoleAuthority.Scope.PROJECT -> { + if (role.project?.organization != null) { + e.organization(role.project?.organization?.name) + } + e.project(role.project?.projectName) + } + + else -> throw IllegalStateException("Unknown authority scope.") + } + }) + } + + /** + * Update basic information (first name, last name, email, language) for the current user. + * + * @param firstName first name of user + * @param lastName last name of user + * @param email email id of user + * @param langKey language key + */ + fun updateUser( + userName: String, firstName: String?, lastName: String?, email: String, langKey: String? + ) { + val userWithEmail = userRepository.findOneByEmail(email) + val user: User + if (userWithEmail.isPresent) { + user = userWithEmail.get() + if (!user.login.equals(userName, ignoreCase = true)) { + throw ConflictException( + "Email address $email already in use", + EntityName.USER, + ErrorConstants.ERR_EMAIL_EXISTS, + Map.of("email", email) + ) + } + } else { + user = userRepository.findOneByLogin(userName).orElseThrow { + NotFoundException( + "User with login $userName not found", + EntityName.USER, + ErrorConstants.ERR_ENTITY_NOT_FOUND, + Map.of("user", userName) + ) + } + } + user.firstName = firstName + user.lastName = lastName + user.email = email + user.langKey = langKey + log.debug("Changed Information for User: {}", user) + userRepository.save(user) + } + + /** + * Update all information for a specific user, and return the modified user. + * + * @param userDto user to update + * @return updated user + */ + @Transactional + @Throws(NotAuthorizedException::class) + open fun updateUser(userDto: UserDTO): UserDTO? { + val userOpt = userRepository.findById(userDto.id) + return if (userOpt.isPresent) { + var user = userOpt.get() + user.firstName = userDto.firstName + user.lastName = userDto.lastName + user.email = userDto.email + user.activated = userDto.isActivated + user.langKey = userDto.langKey + val managedRoles = user.roles + val oldRoles = java.util.Set.copyOf(managedRoles) + managedRoles?.clear() + managedRoles?.addAll(getUserRoles(userDto.roles, oldRoles)!!) + user = userRepository.save(user) + log.debug("Changed Information for User: {}", user) + userMapper.userToUserDTO(user) + } else { + null + } + } + + /** + * Delete the user with the given login. + * @param login the login to delete + */ + fun deleteUser(login: String?) { + userRepository.findOneByLogin(login).ifPresent { user: User -> + userRepository.delete(user) + log.debug("Deleted User: {}", user) + } + } + + /** + * Change the password of the user with the given login. + * @param password the new password + */ + fun changePassword(password: String?) { + val currentUser = SecurityUtils.getCurrentUserLogin().orElseThrow { + InvalidRequestException( + "Cannot change password of unknown user", null, ErrorConstants.ERR_ENTITY_NOT_FOUND + ) + } + changePassword(currentUser, password) + } + + /** + * Change the user's password. + * @param password the new password + * @param login of the user to change password + */ + fun changePassword(login: String?, password: String?) { + userRepository.findOneByLogin(login).ifPresent { user: User -> + val encryptedPassword = passwordService.encode(password) + user.password = encryptedPassword + log.debug("Changed password for User: {}", user) + } + } + + /** + * Get a page of users. + * @param pageable the page information + * @return the requested page of users + */ + @Transactional(readOnly = true) + open fun getAllManagedUsers(pageable: Pageable?): Page { + log.debug("Request to get all Users") + return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER) + .map { user: User? -> userMapper.userToUserDTO(user) } + } + + /** + * Get the user with the given login. + * @param login the login + * @return an [Optional] which holds the user if one was found with the given login, + * and is empty otherwise + */ + @Transactional(readOnly = true) + open fun getUserWithAuthoritiesByLogin(login: String?): Optional { + return userRepository.findOneWithRolesByLogin(login).map { user: User? -> userMapper.userToUserDTO(user) } + } + + @get:Transactional(readOnly = true) + open val userWithAuthorities: Optional + /** + * Get the current user. + * @return the currently authenticated user, or null if no user is currently authenticated + */ + get() = SecurityUtils.getCurrentUserLogin() + .flatMap { currentUser: String? -> userRepository.findOneWithRolesByLogin(currentUser) } + + /** + * Not activated users should be automatically deleted after 3 days. + * + * This is scheduled to + * get fired everyday, at 01:00 (am). This is aimed at users, not subjects. So filter our + * users with *PARTICIPANT role and perform the action. + */ + @Scheduled(cron = "0 0 1 * * ?") + fun removeNotActivatedUsers() { + log.info("Scheduled scan for expired user accounts starting now") + val cutoff = ZonedDateTime.now().minus(Period.ofDays(3)) + val authorities = Arrays.asList( + RoleAuthority.PARTICIPANT.authority, RoleAuthority.INACTIVE_PARTICIPANT.authority + ) + userRepository.findAllByActivatedAndAuthoritiesNot(false, authorities).stream() + .filter { user: User? -> user?.let { revisionService.getAuditInfo(it).createdAt }!!.isBefore(cutoff) } + .forEach { user: User -> + try { + userRepository.delete(user) + log.info("Deleted not activated user after 3 days: {}", user.login) + } catch (ex: DataIntegrityViolationException) { + log.error("Could not delete user with login " + user.login, ex) + } + } + } + + /** + * Find all user with given filter. + * + * @param userFilter filtering for users. + * @param pageable paging information + * @param includeProvenance whether to include created and modification fields. + * @return page of users. + */ + fun findUsers( + userFilter: UserFilter, pageable: Pageable?, includeProvenance: Boolean + ): Page? { + return pageable?.let { + userRepository.findAll(userFilter, it) + .map(if (includeProvenance) Function { user: User? -> userMapper.userToUserDTO(user) } else Function { user: User? -> + userMapper.userToUserDTONoProvenance( + user + ) + }) + } + } + + /** + * Update the roles of the given user. + * @param login user login + * @param roleDtos new roles to set + * @throws NotAuthorizedException if the current user is not allowed to modify the roles + * of the target user. + */ + @Transactional + @Throws(NotAuthorizedException::class) + open fun updateRoles(login: String, roleDtos: Set?) { + val user = userRepository.findOneByLogin(login).orElseThrow { + NotFoundException( + "User with login $login not found", + EntityName.USER, + ErrorConstants.ERR_ENTITY_NOT_FOUND, + Map.of("user", login) + ) + } + val managedRoles = user.roles + val oldRoles = java.util.Set.copyOf(managedRoles) + managedRoles?.clear() + managedRoles?.addAll(getUserRoles(roleDtos, oldRoles)!!) + userRepository.save(user) + } + + companion object { + private val log = LoggerFactory.getLogger(UserService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java b/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java index acbbc51f7..9cf948d11 100644 --- a/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java +++ b/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java @@ -26,7 +26,7 @@ public RevisionDTO() { public RevisionDTO(Revision revision, RevisionType revisionType, Object entity) { id = revision.getRequiredRevisionNumber().intValue(); timestamp = revision.getRequiredRevisionInstant(); - author = ((CustomRevisionEntity) revision.getMetadata().getDelegate()).getAuditor(); + author = ((CustomRevisionEntity) revision.getMetadata().getDelegate()).auditor; this.entity = entity; this.revisionType = revisionType; } diff --git a/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java b/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java index 93b4bb9c0..1b957e1de 100644 --- a/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java +++ b/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java @@ -73,9 +73,9 @@ public void setChanges(Map>> changes) { public static RevisionInfoDTO from(CustomRevisionEntity revisionEntity, Map> changes) { RevisionInfoDTO result = new RevisionInfoDTO(); - result.setAuthor(revisionEntity.getAuditor()); - result.setTimestamp(revisionEntity.getTimestamp()); - result.setId(revisionEntity.getId()); + result.setAuthor(revisionEntity.auditor); + result.setTimestamp(revisionEntity.timestamp); + result.setId(revisionEntity.id); result.setChanges(changes.entrySet().stream() .filter(e -> e.getValue() != null) .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream() diff --git a/src/main/java/org/radarbase/management/service/mapper/SubjectMapper.java b/src/main/java/org/radarbase/management/service/mapper/SubjectMapper.kt similarity index 65% rename from src/main/java/org/radarbase/management/service/mapper/SubjectMapper.java rename to src/main/java/org/radarbase/management/service/mapper/SubjectMapper.kt index 14a1fd3e1..efeaa0eb1 100644 --- a/src/main/java/org/radarbase/management/service/mapper/SubjectMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/SubjectMapper.kt @@ -1,24 +1,26 @@ -package org.radarbase.management.service.mapper; +package org.radarbase.management.service.mapper -import java.util.List; -import org.mapstruct.DecoratedWith; -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.MappingTarget; -import org.mapstruct.Named; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.mapper.decorator.SubjectMapperDecorator; +import org.mapstruct.DecoratedWith +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.MappingTarget +import org.mapstruct.Named +import org.radarbase.management.domain.Subject +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.mapper.decorator.SubjectMapperDecorator /** * Mapper for the entity Subject and its DTO SubjectDTO. */ -@Mapper(componentModel = "spring", uses = {UserMapper.class, ProjectMapper.class, - SourceMapper.class, RoleMapper.class}) -@DecoratedWith(SubjectMapperDecorator.class) -public interface SubjectMapper { - +@Mapper( + componentModel = "spring", + uses = [UserMapper::class, ProjectMapper::class, SourceMapper::class, RoleMapper::class] +) +@DecoratedWith( + SubjectMapperDecorator::class +) +interface SubjectMapper { @Mapping(source = "user.login", target = "login") @Mapping(target = "status", ignore = true) @Mapping(target = "project", ignore = true) @@ -28,7 +30,7 @@ public interface SubjectMapper { @Mapping(target = "lastModifiedBy", ignore = true) @Mapping(target = "lastModifiedDate", ignore = true) @Mapping(source = "user.roles", target = "roles") - SubjectDTO subjectToSubjectDTO(Subject subject); + fun subjectToSubjectDTO(subject: Subject?): SubjectDTO? @Mapping(source = "user.login", target = "login") @Mapping(source = "group.name", target = "group") @@ -39,7 +41,7 @@ public interface SubjectMapper { @Mapping(target = "lastModifiedBy", ignore = true) @Mapping(target = "lastModifiedDate", ignore = true) @Mapping(source = "user.roles", target = "roles") - SubjectDTO subjectToSubjectReducedProjectDTO(Subject subject); + fun subjectToSubjectReducedProjectDTO(subject: Subject?): SubjectDTO? @Named(value = "subjectReducedProjectDTO") @Mapping(source = "user.login", target = "login") @@ -51,25 +53,25 @@ public interface SubjectMapper { @Mapping(target = "lastModifiedBy", ignore = true) @Mapping(target = "lastModifiedDate", ignore = true) @Mapping(source = "user.roles", target = "roles") - SubjectDTO subjectToSubjectWithoutProjectDTO(Subject subject); + fun subjectToSubjectWithoutProjectDTO(subject: Subject?): SubjectDTO? - @IterableMapping(qualifiedByName = "subjectReducedProjectDTO") - List subjectsToSubjectReducedProjectDTOs(List subjects); + @IterableMapping(qualifiedByName = ["subjectReducedProjectDTO"]) + fun subjectsToSubjectReducedProjectDTOs(subjects: List?): List? @Mapping(source = "login", target = "user.login") @Mapping(target = "group", ignore = true) @Mapping(target = "user.email", ignore = true) @Mapping(target = "user.activated", ignore = true) @Mapping(target = "removed", ignore = true) - @Mapping(source = "roles" , target = "user.roles") + @Mapping(source = "roles", target = "user.roles") @Mapping(target = "metaTokens", ignore = true) - Subject subjectDTOToSubject(SubjectDTO subjectDto); + fun subjectDTOToSubject(subjectDto: SubjectDTO?): Subject? @Mapping(target = "user", ignore = true) @Mapping(target = "removed", ignore = true) @Mapping(target = "metaTokens", ignore = true) @Mapping(target = "group", ignore = true) - Subject safeUpdateSubjectFromDTO(SubjectDTO subjectDto, @MappingTarget Subject subject); + fun safeUpdateSubjectFromDTO(subjectDto: SubjectDTO?, @MappingTarget subject: Subject?): Subject? /** * Generating the fromId for all mappers if the databaseType is sql, as the class has @@ -79,15 +81,12 @@ public interface SubjectMapper { * @param id id of the entity * @return the entity instance */ - - default Subject subjectFromId(Long id) { + fun subjectFromId(id: Long?): Subject? { if (id == null) { - return null; + return null } - Subject subject = new Subject(); - subject.setId(id); - return subject; + val subject = Subject() + subject.id = id + return subject } - - } diff --git a/src/main/java/org/radarbase/management/service/mapper/UserMapper.java b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt similarity index 51% rename from src/main/java/org/radarbase/management/service/mapper/UserMapper.java rename to src/main/java/org/radarbase/management/service/mapper/UserMapper.kt index 9ba2236cb..affe9f120 100644 --- a/src/main/java/org/radarbase/management/service/mapper/UserMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt @@ -1,56 +1,55 @@ -package org.radarbase.management.service.mapper; +package org.radarbase.management.service.mapper -import org.mapstruct.DecoratedWith; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.MappingConstants; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.User; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.decorator.UserMapperDecorator; - -import java.util.Set; -import java.util.stream.Collectors; +import org.mapstruct.DecoratedWith +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.MappingConstants +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.User +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.decorator.UserMapperDecorator +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern +import javax.validation.constraints.Size /** * Mapper for the entity User and its DTO UserDTO. */ -@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, - uses = {ProjectMapper.class, RoleMapper.class}) -@DecoratedWith(UserMapperDecorator.class) -public interface UserMapper { - +@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, uses = [ProjectMapper::class, RoleMapper::class]) +@DecoratedWith( + UserMapperDecorator::class +) +interface UserMapper { @Mapping(target = "createdBy", ignore = true) @Mapping(target = "createdDate", ignore = true) @Mapping(target = "lastModifiedBy", ignore = true) @Mapping(target = "lastModifiedDate", ignore = true) @Mapping(target = "accessToken", ignore = true) - UserDTO userToUserDTO(User user); + fun userToUserDTO(user: User?): UserDTO? @Mapping(target = "createdBy", ignore = true) @Mapping(target = "createdDate", ignore = true) @Mapping(target = "lastModifiedBy", ignore = true) @Mapping(target = "lastModifiedDate", ignore = true) @Mapping(target = "accessToken", ignore = true) - UserDTO userToUserDTONoProvenance(User user); + fun userToUserDTONoProvenance(user: User?): UserDTO? @Mapping(target = "activationKey", ignore = true) @Mapping(target = "resetKey", ignore = true) @Mapping(target = "resetDate", ignore = true) @Mapping(target = "password", ignore = true) @Mapping(target = "authorities", ignore = true) - User userDTOToUser(UserDTO userDto); + fun userDTOToUser(userDto: UserDTO?): User? /** - * Map a set of {@link Authority}s to a set of strings that are the authority names. + * Map a set of [Authority]s to a set of strings that are the authority names. * @param authorities the authorities to map * @return the set of strings if authorities is not null, null otherwise */ - default Set stringsFromAuthorities(Set authorities) { - if (authorities == null) { - return null; - } - return authorities.stream().map(Authority::getName) - .collect(Collectors.toSet()); + fun stringsFromAuthorities(authorities: Set?): Set<@NotNull @Size( + max = 50, + min = 0 + ) @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") String?>? { + return authorities?.map{ it?.name }?.toSet() } } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java index 91219392c..4d60d9afa 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java @@ -43,7 +43,7 @@ public ProjectDTO projectToProjectDTO(Project project) { } ProjectDTO dto = delegate.projectToProjectDTO(project); - dto.setHumanReadableProjectName(project.getAttributes().get(HUMAN_READABLE_PROJECT_NAME)); + dto.setHumanReadableProjectName(project.attributes.get(HUMAN_READABLE_PROJECT_NAME)); try { dto.setPersistentTokenTimeout( @@ -62,7 +62,7 @@ public ProjectDTO projectToProjectDTOReduced(Project project) { return null; } ProjectDTO dto = delegate.projectToProjectDTOReduced(project); - dto.setHumanReadableProjectName(project.getAttributes().get(HUMAN_READABLE_PROJECT_NAME)); + dto.setHumanReadableProjectName(project.attributes.get(HUMAN_READABLE_PROJECT_NAME)); dto.setSourceTypes(null); return dto; } @@ -76,7 +76,7 @@ public Project projectDTOToProject(ProjectDTO projectDto) { Project project = delegate.projectDTOToProject(projectDto); String projectName = projectDto.getHumanReadableProjectName(); if (projectName != null && !projectName.isEmpty()) { - project.getAttributes().put(HUMAN_READABLE_PROJECT_NAME, projectName); + project.attributes.put(HUMAN_READABLE_PROJECT_NAME, projectName); } var orgDto = projectDto.getOrganization(); @@ -86,7 +86,7 @@ public Project projectDTOToProject(ProjectDTO projectDto) { ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, Collections.singletonMap("name", orgDto.getName()))); - project.setOrganization(org); + project.organization = org; } return project; diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java index 0c7b8c481..581ca9995 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java @@ -32,8 +32,8 @@ public Role roleDTOToRole(RoleDTO roleDto) { Role role = delegate.roleDTOToRole(roleDto); - if (role.getAuthority() == null) { - role.setAuthority(authorityRepository.getById(roleDto.getAuthorityName())); + if (role.authority == null) { + role.authority = authorityRepository.getById(roleDto.getAuthorityName()); } return role; diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java index 0980bb6fb..fd69ec511 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java @@ -54,11 +54,11 @@ public Source sourceDTOToSource(SourceDTO sourceDto) { SOURCE, ERR_SOURCE_NOT_FOUND, Map.of("sourceId", sourceDto.getId().toString()))); if (sourceDto.getSubjectLogin() == null) { - source.setSubject(existingSource.getSubject()); + source.subject = existingSource.subject; } else { - source.setSubject(subjectRepository + source.subject = subjectRepository .findOneWithEagerBySubjectLogin(sourceDto.getSubjectLogin()) - .orElseThrow(NoSuchElementException::new)); + .orElseThrow(NoSuchElementException::new); } } return source; diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.java deleted file mode 100644 index 0d52e8024..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.java +++ /dev/null @@ -1,173 +0,0 @@ -package org.radarbase.management.service.mapper.decorator; - -import org.mapstruct.MappingTarget; -import org.radarbase.management.domain.Group; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.domain.audit.EntityAuditInfo; -import org.radarbase.management.repository.GroupRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.service.RevisionService; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.dto.SubjectDTO.SubjectStatus; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.service.mapper.SubjectMapper; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_GROUP_NOT_FOUND; - -/** - * Created by nivethika on 30-8-17. - */ -public abstract class SubjectMapperDecorator implements SubjectMapper { - - @Autowired - @Qualifier("delegate") - private SubjectMapper delegate; - - @Autowired - private ProjectMapper projectMapper; - - @Autowired - private RevisionService revisionService; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private GroupRepository groupRepository; - - @Override - public SubjectDTO subjectToSubjectDTO(Subject subject) { - if (subject == null) { - return null; - } - SubjectDTO dto = subjectToSubjectWithoutProjectDTO(subject); - Project project = subject.getActiveProject() - .flatMap(p -> projectRepository.findOneWithEagerRelationships(p.getId())) - .orElse(null); - dto.setProject(projectMapper.projectToProjectDTO(project)); - - addAuditInfo(subject, dto); - - return dto; - } - - @Override - public SubjectDTO subjectToSubjectReducedProjectDTO(Subject subject) { - if (subject == null) { - return null; - } - SubjectDTO dto = subjectToSubjectWithoutProjectDTO(subject); - - subject.getActiveProject() - .ifPresent(project -> dto.setProject( - projectMapper.projectToProjectDTOReduced(project))); - - addAuditInfo(subject, dto); - - return dto; - } - - private void addAuditInfo(Subject subject, SubjectDTO dto) { - EntityAuditInfo auditInfo = revisionService.getAuditInfo(subject); - dto.setCreatedDate(auditInfo.getCreatedAt()); - dto.setCreatedBy(auditInfo.getCreatedBy()); - dto.setLastModifiedDate(auditInfo.getLastModifiedAt()); - dto.setLastModifiedBy(auditInfo.getLastModifiedBy()); - } - - @Override - public SubjectDTO subjectToSubjectWithoutProjectDTO(Subject subject) { - if (subject == null) { - return null; - } - SubjectDTO dto = delegate.subjectToSubjectWithoutProjectDTO(subject); - dto.setStatus(getSubjectStatus(subject)); - - return dto; - } - - @Override - public Subject subjectDTOToSubject(SubjectDTO subjectDto) { - if (subjectDto == null) { - return null; - } - - Subject subject = delegate.subjectDTOToSubject(subjectDto); - setSubjectStatus(subjectDto, subject); - subject.setGroup(getGroup(subjectDto)); - - return subject; - } - - private Group getGroup(SubjectDTO subjectDto) { - if (subjectDto.getGroup() == null) { - return null; - } else if (subjectDto.getProject().getId() != null) { - return groupRepository.findByProjectIdAndName( - subjectDto.getProject().getId(), subjectDto.getGroup()) - .orElseThrow(() -> new BadRequestException( - "Group " + subjectDto.getGroup() + " not found in project " - + subjectDto.getProject().getId(), - SUBJECT, ERR_GROUP_NOT_FOUND)); - } else if (subjectDto.getProject().getProjectName() != null) { - return groupRepository.findByProjectNameAndName( - subjectDto.getProject().getProjectName(), subjectDto.getGroup()) - .orElseThrow(() -> new BadRequestException( - "Group " + subjectDto.getGroup() + " not found in project " - + subjectDto.getProject().getProjectName(), - SUBJECT, ERR_GROUP_NOT_FOUND)); - } else { - throw new BadRequestException( - "Group " + subjectDto.getGroup() + " cannot be found without a project", - SUBJECT, ERR_GROUP_NOT_FOUND); - } - } - - @Override - public Subject safeUpdateSubjectFromDTO(SubjectDTO subjectDto, @MappingTarget Subject subject) { - Subject subjectRetrieved = delegate.safeUpdateSubjectFromDTO(subjectDto, subject); - setSubjectStatus(subjectDto, subjectRetrieved); - subject.setGroup(getGroup(subjectDto)); - return subjectRetrieved; - } - - private SubjectStatus getSubjectStatus(Subject subject) { - if (!subject.getUser().getActivated() && !subject.isRemoved()) { - return SubjectStatus.DEACTIVATED; - } else if (subject.getUser().getActivated() && !subject.isRemoved()) { - return SubjectStatus.ACTIVATED; - } else if (!subject.getUser().getActivated() && subject.isRemoved()) { - return SubjectStatus.DISCONTINUED; - } - return SubjectStatus.INVALID; - } - - private void setSubjectStatus(SubjectDTO subjectDto, Subject subject) { - switch (subjectDto.getStatus()) { - case DEACTIVATED: - subject.getUser().setActivated(false); - subject.setRemoved(false); - break; - case ACTIVATED: - subject.getUser().setActivated(true); - subject.setRemoved(false); - break; - case DISCONTINUED: - subject.getUser().setActivated(false); - subject.setRemoved(true); - break; - case INVALID: - subject.getUser().setActivated(true); - subject.setRemoved(true); - break; - default: - break; - } - } - -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt new file mode 100644 index 000000000..b48f35bfc --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt @@ -0,0 +1,146 @@ +package org.radarbase.management.service.mapper.decorator + +import org.mapstruct.MappingTarget +import org.radarbase.management.domain.Group +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.GroupRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.RevisionService +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.dto.SubjectDTO.SubjectStatus +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.service.mapper.SubjectMapper +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier + +/** + * Created by nivethika on 30-8-17. + */ +abstract class SubjectMapperDecorator( + @Autowired @Qualifier("delegate") private val delegate: SubjectMapper, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val revisionService: RevisionService, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val groupRepository: GroupRepository +) : SubjectMapper { + + override fun subjectToSubjectDTO(subject: Subject?): SubjectDTO? { + if (subject == null) { + return null + } + val dto = subjectToSubjectWithoutProjectDTO(subject) + val project = subject.activeProject + .let { p -> projectRepository!!.findOneWithEagerRelationships(p?.id) } + dto!!.project = projectMapper!!.projectToProjectDTO(project) + addAuditInfo(subject, dto) + return dto + } + + override fun subjectToSubjectReducedProjectDTO(subject: Subject?): SubjectDTO? { + if (subject == null) { + return null + } + val dto = subjectToSubjectWithoutProjectDTO(subject) + subject.activeProject?.let { project -> dto!!.project = projectMapper!!.projectToProjectDTOReduced(project) } + addAuditInfo(subject, dto) + return dto + } + + private fun addAuditInfo(subject: Subject, dto: SubjectDTO?) { + val auditInfo = revisionService!!.getAuditInfo(subject) + dto!!.createdDate = auditInfo.createdAt + dto.createdBy = auditInfo.createdBy + dto.lastModifiedDate = auditInfo.lastModifiedAt + dto.lastModifiedBy = auditInfo.lastModifiedBy + } + + override fun subjectToSubjectWithoutProjectDTO(subject: Subject?): SubjectDTO? { + if (subject == null) { + return null + } + val dto = delegate!!.subjectToSubjectWithoutProjectDTO(subject) + dto!!.status = getSubjectStatus(subject) + return dto + } + + override fun subjectDTOToSubject(subjectDto: SubjectDTO?): Subject? { + if (subjectDto == null) { + return null + } + val subject = delegate!!.subjectDTOToSubject(subjectDto) + setSubjectStatus(subjectDto, subject) + subject!!.group = getGroup(subjectDto) + return subject + } + + private fun getGroup(subjectDto: SubjectDTO?): Group? { + return if (subjectDto!!.group == null) { + null + } else if (subjectDto.project.id != null) { + groupRepository.findByProjectIdAndName(subjectDto.project.id, subjectDto.group) + ?: throw BadRequestException( + "Group " + subjectDto.group + " not found in project " + + subjectDto.project.id, + EntityName.SUBJECT, ErrorConstants.ERR_GROUP_NOT_FOUND) + } else if (subjectDto.project.projectName != null) { + groupRepository.findByProjectNameAndName(subjectDto.project.projectName, subjectDto.group) + ?: throw BadRequestException( + "Group " + subjectDto.group + " not found in project " + + subjectDto.project.projectName, + EntityName.SUBJECT, ErrorConstants.ERR_GROUP_NOT_FOUND + ) + } else { + throw BadRequestException( + "Group " + subjectDto.group + " cannot be found without a project", + EntityName.SUBJECT, ErrorConstants.ERR_GROUP_NOT_FOUND + ) + } + } + + override fun safeUpdateSubjectFromDTO(subjectDto: SubjectDTO?, @MappingTarget subject: Subject?): Subject? { + val subjectRetrieved = delegate.safeUpdateSubjectFromDTO(subjectDto, subject) + setSubjectStatus(subjectDto, subjectRetrieved) + subject!!.group = getGroup(subjectDto) + return subjectRetrieved + } + + private fun getSubjectStatus(subject: Subject): SubjectStatus { + if (!subject.user!!.activated && !subject.isRemoved!!) { + return SubjectStatus.DEACTIVATED + } else if (subject.user!!.activated && !subject.isRemoved!!) { + return SubjectStatus.ACTIVATED + } else if (!subject.user!!.activated && subject.isRemoved!!) { + return SubjectStatus.DISCONTINUED + } + return SubjectStatus.INVALID + } + + private fun setSubjectStatus(subjectDto: SubjectDTO?, subject: Subject?) { + when (subjectDto!!.status) { + SubjectStatus.DEACTIVATED -> { + subject!!.user!!.activated = false + subject.isRemoved = false + } + + SubjectStatus.ACTIVATED -> { + subject!!.user!!.activated = true + subject.isRemoved = false + } + + SubjectStatus.DISCONTINUED -> { + subject!!.user!!.activated = false + subject.isRemoved = true + } + + SubjectStatus.INVALID -> { + subject!!.user!!.activated = true + subject.isRemoved = true + } + + else -> {} + } + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/MetaTokenResource.java b/src/main/java/org/radarbase/management/web/rest/MetaTokenResource.java deleted file mode 100644 index 39b68d62d..000000000 --- a/src/main/java/org/radarbase/management/web/rest/MetaTokenResource.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.radarbase.management.web.rest; - - -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.domain.MetaToken; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.MetaTokenService; -import org.radarbase.management.service.dto.ClientPairInfoDTO; -import org.radarbase.management.service.dto.TokenDTO; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.net.MalformedURLException; -import java.time.Duration; - -import static org.radarbase.auth.authorization.Permission.SUBJECT_UPDATE; - -@RestController -@RequestMapping("/api") -public class MetaTokenResource { - - private static final Logger log = LoggerFactory.getLogger(OAuthClientsResource.class); - - public static final Duration DEFAULT_META_TOKEN_TIMEOUT = Duration.ofHours(1); - public static final Duration DEFAULT_PERSISTENT_META_TOKEN_TIMEOUT = Duration.ofDays(31); - - @Autowired - private MetaTokenService metaTokenService; - - @Autowired - private AuthService authService; - - /** - * GET /api/meta-token/:tokenName. - * - *

Get refresh-token available under this tokenName.

- * - * @param tokenName the tokenName given after pairing the subject with client - * @return the client as a {@link ClientPairInfoDTO} - */ - @GetMapping("/meta-token/{tokenName:" + Constants.TOKEN_NAME_REGEX + "}") - @Timed - public ResponseEntity getTokenByTokenName(@PathVariable("tokenName") String tokenName) - throws MalformedURLException { - log.info("Requesting token with tokenName {}", tokenName); - return ResponseEntity.ok().body(metaTokenService.fetchToken(tokenName)); - } - - /** - * DELETE /api/meta-token/:tokenName. - * - *

Delete refresh-token available under this tokenName.

- * - * @param tokenName the tokenName given after pairing the subject with client - * @return the client as a {@link ClientPairInfoDTO} - */ - @DeleteMapping("/meta-token/{tokenName:" + Constants.TOKEN_NAME_REGEX + "}") - @Timed - public ResponseEntity deleteTokenByTokenName(@PathVariable("tokenName") String tokenName) - throws NotAuthorizedException { - log.info("Requesting token with tokenName {}", tokenName); - MetaToken metaToken = metaTokenService.getToken(tokenName); - Subject subject = metaToken.getSubject(); - String project = subject.getActiveProject() - .orElseThrow(() -> new NotAuthorizedException( - "Cannot establish authority of subject without active project affiliation." - )) - .getProjectName(); - String user = subject.getUser().getLogin(); - authService.checkPermission(SUBJECT_UPDATE, e -> e.project(project).subject(user)); - metaTokenService.delete(metaToken); - return ResponseEntity.noContent().build(); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/MetaTokenResource.kt b/src/main/java/org/radarbase/management/web/rest/MetaTokenResource.kt new file mode 100644 index 000000000..bbf0a0b2b --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/MetaTokenResource.kt @@ -0,0 +1,91 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.MetaTokenService +import org.radarbase.management.service.dto.TokenDTO +import org.radarbase.management.web.rest.OAuthClientsResource +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import java.net.MalformedURLException +import java.time.Duration + +@RestController +@RequestMapping("/api") +class MetaTokenResource { + @Autowired + private val metaTokenService: MetaTokenService? = null + + @Autowired + private val authService: AuthService? = null + + /** + * GET /api/meta-token/:tokenName. + * + * + * Get refresh-token available under this tokenName. + * + * @param tokenName the tokenName given after pairing the subject with client + * @return the client as a [ClientPairInfoDTO] + */ + @GetMapping("/meta-token/{tokenName:" + Constants.TOKEN_NAME_REGEX + "}") + @Timed + @Throws( + MalformedURLException::class + ) + fun getTokenByTokenName(@PathVariable("tokenName") tokenName: String?): ResponseEntity { + log.info("Requesting token with tokenName {}", tokenName) + return ResponseEntity.ok().body(tokenName?.let { metaTokenService!!.fetchToken(it) }) + } + + /** + * DELETE /api/meta-token/:tokenName. + * + * + * Delete refresh-token available under this tokenName. + * + * @param tokenName the tokenName given after pairing the subject with client + * @return the client as a [ClientPairInfoDTO] + */ + @DeleteMapping("/meta-token/{tokenName:" + Constants.TOKEN_NAME_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun deleteTokenByTokenName(@PathVariable("tokenName") tokenName: String?): ResponseEntity { + log.info("Requesting token with tokenName {}", tokenName) + val metaToken = tokenName?.let { metaTokenService!!.getToken(it) } + val subject = metaToken?.subject + val project: String = subject!! + .activeProject + ?.projectName + ?: + throw NotAuthorizedException( + "Cannot establish authority of subject without active project affiliation." + ) + val user = subject.user!!.login + authService!!.checkPermission( + Permission.SUBJECT_UPDATE, + { e: EntityDetails -> e.project(project).subject(user) }) + metaTokenService?.delete(metaToken) + return ResponseEntity.noContent().build() + } + + companion object { + private val log = LoggerFactory.getLogger(OAuthClientsResource::class.java) + @JvmField + val DEFAULT_META_TOKEN_TIMEOUT = Duration.ofHours(1) + @JvmField + val DEFAULT_PERSISTENT_META_TOKEN_TIMEOUT = Duration.ofDays(31) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.java b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.java deleted file mode 100644 index 41a5cf880..000000000 --- a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.java +++ /dev/null @@ -1,224 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.domain.User; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.MetaTokenService; -import org.radarbase.management.service.OAuthClientService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.SubjectService; -import org.radarbase.management.service.UserService; -import org.radarbase.management.service.dto.ClientDetailsDTO; -import org.radarbase.management.service.dto.ClientPairInfoDTO; -import org.radarbase.management.service.mapper.ClientDetailsMapper; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.boot.actuate.audit.AuditEventRepository; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.OAUTHCLIENTS_CREATE; -import static org.radarbase.auth.authorization.Permission.OAUTHCLIENTS_DELETE; -import static org.radarbase.auth.authorization.Permission.OAUTHCLIENTS_READ; -import static org.radarbase.auth.authorization.Permission.OAUTHCLIENTS_UPDATE; -import static org.radarbase.auth.authorization.Permission.SUBJECT_UPDATE; -import static org.radarbase.management.service.OAuthClientService.checkProtected; -import static org.radarbase.management.web.rest.errors.EntityName.OAUTH_CLIENT; -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SUBJECT_NOT_FOUND; - -/** - * Created by dverbeec on 5/09/2017. - */ -@RestController -@RequestMapping("/api") -public class OAuthClientsResource { - - private static final Logger log = LoggerFactory.getLogger(OAuthClientsResource.class); - - - @Autowired - private OAuthClientService oAuthClientService; - - @Autowired - private MetaTokenService metaTokenService; - - @Autowired - private ClientDetailsMapper clientDetailsMapper; - - @Autowired - private SubjectService subjectService; - - @Autowired - private UserService userService; - - @Autowired - private AuditEventRepository eventRepository; - - @Autowired - private AuthService authService; - - /** - * GET /api/oauth-clients. - * - *

Retrieve a list of currently registered OAuth clients.

- * - * @return the list of registered clients as a list of {@link ClientDetailsDTO} - */ - @GetMapping("/oauth-clients") - @Timed - public ResponseEntity> getOAuthClients() throws NotAuthorizedException { - authService.checkPermission(OAUTHCLIENTS_READ); - return ResponseEntity.ok().body(clientDetailsMapper - .clientDetailsToClientDetailsDTO(oAuthClientService.findAllOAuthClients())); - } - - /** - * GET /api/oauth-clients/:id. - * - *

Get details on a specific client.

- * - * @param id the client id for which to fetch the details - * @return the client as a {@link ClientDetailsDTO} - */ - @GetMapping("/oauth-clients/{id:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity getOAuthClientById(@PathVariable("id") String id) - throws NotAuthorizedException { - authService.checkPermission(OAUTHCLIENTS_READ); - // getOAuthClient checks if the id exists - return ResponseEntity.ok().body(clientDetailsMapper - .clientDetailsToClientDetailsDTO(oAuthClientService.findOneByClientId(id))); - } - - /** - * PUT /api/oauth-clients. - * - *

Update an existing OAuth client.

- * - * @param clientDetailsDto The client details to update - * @return The updated OAuth client. - */ - @PutMapping("/oauth-clients") - @Timed - public ResponseEntity updateOAuthClient(@Valid @RequestBody ClientDetailsDTO - clientDetailsDto) throws NotAuthorizedException { - authService.checkPermission(OAUTHCLIENTS_UPDATE); - // getOAuthClient checks if the id exists - checkProtected(oAuthClientService.findOneByClientId(clientDetailsDto.getClientId())); - - ClientDetails updated = oAuthClientService.updateOauthClient(clientDetailsDto); - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(OAUTH_CLIENT, - clientDetailsDto.getClientId())) - .body(clientDetailsMapper.clientDetailsToClientDetailsDTO(updated)); - } - - /** - * DELETE /api/oauth-clients/:id. - * - *

Delete the OAuth client with the specified client id.

- * - * @param id The id of the client to delete - * @return a ResponseEntity indicating success or failure - */ - @DeleteMapping("/oauth-clients/{id:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity deleteOAuthClient(@PathVariable String id) - throws NotAuthorizedException { - authService.checkPermission(OAUTHCLIENTS_DELETE); - // getOAuthClient checks if the id exists - checkProtected(oAuthClientService.findOneByClientId(id)); - oAuthClientService.deleteClientDetails(id); - return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(OAUTH_CLIENT, id)) - .build(); - } - - /** - * POST /api/oauth-clients. - * - *

Register a new oauth client.

- * - * @param clientDetailsDto The OAuth client to be registered - * @return a response indicating success or failure - * @throws URISyntaxException if there was a problem formatting the URI to the new entity - */ - @PostMapping("/oauth-clients") - @Timed - public ResponseEntity createOAuthClient(@Valid @RequestBody ClientDetailsDTO - clientDetailsDto) throws URISyntaxException, NotAuthorizedException { - authService.checkPermission(OAUTHCLIENTS_CREATE); - ClientDetails created = oAuthClientService.createClientDetail(clientDetailsDto); - return ResponseEntity.created(ResourceUriService.getUri(clientDetailsDto)) - .headers(HeaderUtil.createEntityCreationAlert(OAUTH_CLIENT, created.getClientId())) - .body(clientDetailsMapper.clientDetailsToClientDetailsDTO(created)); - } - - /** - * GET /oauth-clients/pair. - * - *

Generates OAuth2 refresh tokens for the given user, to be used to bootstrap the - * authentication of client apps. This will generate a refresh token which can be used at the - * /oauth/token endpoint to get a new access token and refresh token.

- * - * @param login the login of the subject for whom to generate pairing information - * @param clientId the OAuth client id - * @return a ClientPairInfoDTO with status 200 (OK) - */ - @GetMapping("/oauth-clients/pair") - @Timed - public ResponseEntity getRefreshToken(@RequestParam String login, - @RequestParam(value = "clientId") String clientId, - @RequestParam(value = "persistent", defaultValue = "false") Boolean persistent) - throws NotAuthorizedException, URISyntaxException, MalformedURLException { - authService.checkScope(SUBJECT_UPDATE); - User currentUser = userService.getUserWithAuthorities() - // We only allow this for actual logged in users for now, not for client_credentials - .orElseThrow(() -> new AccessDeniedException( - "You must be a logged in user to access this resource")); - - // lookup the subject - Subject subject = subjectService.findOneByLogin(login); - String project = subject.getActiveProject() - .map(Project::getProjectName) - .orElseThrow(() -> new NotFoundException( - "Project for subject " + login + " not found", SUBJECT, - ERR_SUBJECT_NOT_FOUND)); - - // Users who can update a subject can also generate a refresh token for that subject - authService.checkPermission(SUBJECT_UPDATE, e -> e.project(project).subject(login)); - - ClientPairInfoDTO cpi = metaTokenService.createMetaToken(subject, clientId, persistent); - // generate audit event - eventRepository.add(new AuditEvent(currentUser.getLogin(), "PAIR_CLIENT_REQUEST", - "client_id=" + clientId, "subject_login=" + login)); - log.info("[{}] by {}: client_id={}, subject_login={}", "PAIR_CLIENT_REQUEST", currentUser - .getLogin(), clientId, login); - return new ResponseEntity<>(cpi, HttpStatus.OK); - } - -} diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt new file mode 100644 index 000000000..aecb4af9a --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt @@ -0,0 +1,243 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.MetaTokenService +import org.radarbase.management.service.OAuthClientService +import org.radarbase.management.service.ResourceUriService +import org.radarbase.management.service.SubjectService +import org.radarbase.management.service.UserService +import org.radarbase.management.service.dto.ClientDetailsDTO +import org.radarbase.management.service.dto.ClientPairInfoDTO +import org.radarbase.management.service.mapper.ClientDetailsMapper +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.radarbase.management.web.rest.util.HeaderUtil +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.boot.actuate.audit.AuditEventRepository +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.security.access.AccessDeniedException +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import java.net.MalformedURLException +import java.net.URISyntaxException +import javax.validation.Valid + +/** + * Created by dverbeec on 5/09/2017. + */ +@RestController +@RequestMapping("/api") +class OAuthClientsResource { + @Autowired + private val oAuthClientService: OAuthClientService? = null + + @Autowired + private val metaTokenService: MetaTokenService? = null + + @Autowired + private val clientDetailsMapper: ClientDetailsMapper? = null + + @Autowired + private val subjectService: SubjectService? = null + + @Autowired + private val userService: UserService? = null + + @Autowired + private val eventRepository: AuditEventRepository? = null + + @Autowired + private val authService: AuthService? = null + + @get:Throws(NotAuthorizedException::class) + @get:Timed + @get:GetMapping("/oauth-clients") + val oAuthClients: ResponseEntity> + /** + * GET /api/oauth-clients. + * + * + * Retrieve a list of currently registered OAuth clients. + * + * @return the list of registered clients as a list of [ClientDetailsDTO] + */ + get() { + authService!!.checkPermission(Permission.OAUTHCLIENTS_READ) + return ResponseEntity.ok().body( + clientDetailsMapper + ?.clientDetailsToClientDetailsDTO(oAuthClientService!!.findAllOAuthClients()) + ) + } + + /** + * GET /api/oauth-clients/:id. + * + * + * Get details on a specific client. + * + * @param id the client id for which to fetch the details + * @return the client as a [ClientDetailsDTO] + */ + @GetMapping("/oauth-clients/{id:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getOAuthClientById(@PathVariable("id") id: String?): ResponseEntity { + authService!!.checkPermission(Permission.OAUTHCLIENTS_READ) + // getOAuthClient checks if the id exists + return ResponseEntity.ok().body( + clientDetailsMapper + ?.clientDetailsToClientDetailsDTO(oAuthClientService!!.findOneByClientId(id)) + ) + } + + /** + * PUT /api/oauth-clients. + * + * + * Update an existing OAuth client. + * + * @param clientDetailsDto The client details to update + * @return The updated OAuth client. + */ + @PutMapping("/oauth-clients") + @Timed + @Throws(NotAuthorizedException::class) + fun updateOAuthClient(@RequestBody clientDetailsDto: @Valid ClientDetailsDTO?): ResponseEntity { + authService!!.checkPermission(Permission.OAUTHCLIENTS_UPDATE) + // getOAuthClient checks if the id exists + OAuthClientService.checkProtected(oAuthClientService!!.findOneByClientId(clientDetailsDto!!.clientId)) + val updated = oAuthClientService.updateOauthClient(clientDetailsDto) + return ResponseEntity.ok() + .headers( + HeaderUtil.createEntityUpdateAlert( + EntityName.OAUTH_CLIENT, + clientDetailsDto.clientId + ) + ) + .body(clientDetailsMapper!!.clientDetailsToClientDetailsDTO(updated)) + } + + /** + * DELETE /api/oauth-clients/:id. + * + * + * Delete the OAuth client with the specified client id. + * + * @param id The id of the client to delete + * @return a ResponseEntity indicating success or failure + */ + @DeleteMapping("/oauth-clients/{id:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun deleteOAuthClient(@PathVariable id: String?): ResponseEntity { + authService!!.checkPermission(Permission.OAUTHCLIENTS_DELETE) + // getOAuthClient checks if the id exists + OAuthClientService.checkProtected(oAuthClientService!!.findOneByClientId(id)) + oAuthClientService.deleteClientDetails(id) + return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(EntityName.OAUTH_CLIENT, id)) + .build() + } + + /** + * POST /api/oauth-clients. + * + * + * Register a new oauth client. + * + * @param clientDetailsDto The OAuth client to be registered + * @return a response indicating success or failure + * @throws URISyntaxException if there was a problem formatting the URI to the new entity + */ + @PostMapping("/oauth-clients") + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createOAuthClient(@RequestBody clientDetailsDto: @Valid ClientDetailsDTO?): ResponseEntity { + authService!!.checkPermission(Permission.OAUTHCLIENTS_CREATE) + val created = oAuthClientService!!.createClientDetail(clientDetailsDto) + return ResponseEntity.created(ResourceUriService.getUri(clientDetailsDto)) + .headers(HeaderUtil.createEntityCreationAlert(EntityName.OAUTH_CLIENT, created.clientId)) + .body(clientDetailsMapper!!.clientDetailsToClientDetailsDTO(created)) + } + + /** + * GET /oauth-clients/pair. + * + * + * Generates OAuth2 refresh tokens for the given user, to be used to bootstrap the + * authentication of client apps. This will generate a refresh token which can be used at the + * /oauth/token endpoint to get a new access token and refresh token. + * + * @param login the login of the subject for whom to generate pairing information + * @param clientId the OAuth client id + * @return a ClientPairInfoDTO with status 200 (OK) + */ + @GetMapping("/oauth-clients/pair") + @Timed + @Throws(NotAuthorizedException::class, URISyntaxException::class, MalformedURLException::class) + fun getRefreshToken( + @RequestParam login: String, + @RequestParam(value = "clientId") clientId: String, + @RequestParam(value = "persistent", defaultValue = "false") persistent: Boolean? + ): ResponseEntity { + authService!!.checkScope(Permission.SUBJECT_UPDATE) + val currentUser = + userService!!.userWithAuthorities // We only allow this for actual logged in users for now, not for client_credentials + .orElseThrow { + AccessDeniedException( + "You must be a logged in user to access this resource" + ) + } + + // lookup the subject + val subject = subjectService!!.findOneByLogin(login) + val project: String = subject.activeProject + ?.projectName + ?: throw NotFoundException( + "Project for subject $login not found", EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND + ) + + + // Users who can update a subject can also generate a refresh token for that subject + authService.checkPermission( + Permission.SUBJECT_UPDATE, + { e: EntityDetails -> e.subject(login) }) + val cpi = metaTokenService!!.createMetaToken(subject, clientId, persistent!!) + // generate audit event + eventRepository!!.add( + AuditEvent( + currentUser.login, "PAIR_CLIENT_REQUEST", + "client_id=$clientId", "subject_login=$login" + ) + ) + log.info( + "[{}] by {}: client_id={}, subject_login={}", "PAIR_CLIENT_REQUEST", currentUser + .login, clientId, login + ) + return ResponseEntity(cpi, HttpStatus.OK) + } + + companion object { + private val log = LoggerFactory.getLogger(OAuthClientsResource::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.java b/src/main/java/org/radarbase/management/web/rest/ProjectResource.java deleted file mode 100644 index c2b6ac1db..000000000 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.java +++ /dev/null @@ -1,367 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import io.swagger.v3.oas.annotations.Parameter; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ProjectService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.RoleService; -import org.radarbase.management.service.SourceService; -import org.radarbase.management.service.SubjectService; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.mapper.SubjectMapper; -import org.radarbase.management.web.rest.criteria.SubjectCriteria; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ErrorVM; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.PROJECT_CREATE; -import static org.radarbase.auth.authorization.Permission.PROJECT_DELETE; -import static org.radarbase.auth.authorization.Permission.PROJECT_READ; -import static org.radarbase.auth.authorization.Permission.PROJECT_UPDATE; -import static org.radarbase.auth.authorization.Permission.ROLE_READ; -import static org.radarbase.auth.authorization.Permission.SOURCE_READ; -import static org.radarbase.auth.authorization.Permission.SUBJECT_READ; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_PROJECT_NOT_EMPTY; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_VALIDATION; - -/** - * REST controller for managing Project. - */ -@RestController -@RequestMapping("/api") -public class ProjectResource { - - private static final Logger log = LoggerFactory.getLogger(ProjectResource.class); - - private static final String ENTITY_NAME = "project"; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private ProjectService projectService; - - @Autowired - private RoleService roleService; - - @Autowired - private SubjectMapper subjectMapper; - - @Autowired - private SubjectService subjectService; - - @Autowired - private SourceService sourceService; - - @Autowired - private AuthService authService; - - /** - * POST /projects : Create a new project. - * - * @param projectDto the projectDto to create - * @return the ResponseEntity with status 201 (Created) and with body the new projectDto, or - * with status 400 (Bad Request) if the project has already an ID - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PostMapping("/projects") - @Timed - public ResponseEntity createProject(@Valid @RequestBody ProjectDTO projectDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save Project : {}", projectDto); - var org = projectDto.getOrganization(); - if (org == null || org.getName() == null) { - throw new BadRequestException("Organization must be provided", - ENTITY_NAME, ERR_VALIDATION); - } - authService.checkPermission(PROJECT_CREATE, e -> e.organization(org.getName())); - - if (projectDto.getId() != null) { - return ResponseEntity.badRequest() - .headers(HeaderUtil.createFailureAlert( - ENTITY_NAME, "idexists", "A new project cannot already have an ID")) - .body(null); - } - if (projectRepository.findOneWithEagerRelationshipsByName(projectDto.getProjectName()) - .isPresent()) { - return ResponseEntity.badRequest() - .headers(HeaderUtil.createFailureAlert( - ENTITY_NAME, "nameexists", "A project with this name already exists")) - .body(null); - } - ProjectDTO result = projectService.save(projectDto); - return ResponseEntity.created(ResourceUriService.getUri(result)) - .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getProjectName())) - .body(result); - } - - /** - * PUT /projects : Updates an existing project. - * - * @param projectDto the projectDto to update - * @return the ResponseEntity with status 200 (OK) and with body the updated projectDto, or with - * status 400 (Bad Request) if the projectDto is not valid, or with status 500 (Internal - * Server Error) if the projectDto couldnt be updated - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PutMapping("/projects") - @Timed - public ResponseEntity updateProject(@Valid @RequestBody ProjectDTO projectDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update Project : {}", projectDto); - if (projectDto.getId() == null) { - return createProject(projectDto); - } - // When a client wants to link the project to the default organization, - // this must be done explicitly. - var org = projectDto.getOrganization(); - if (org == null || org.getName() == null) { - throw new BadRequestException("Organization must be provided", - ENTITY_NAME, ERR_VALIDATION); - } - // When clients want to transfer a project, - // they must have permissions to modify both new & old organizations - var existingProject = projectService.findOne(projectDto.getId()); - if (!existingProject.getProjectName().equals(projectDto.getProjectName())) { - throw new BadRequestException("The project name cannot be modified.", ENTITY_NAME, - ERR_VALIDATION); - } - - var newOrgName = org.getName(); - authService.checkPermission(PROJECT_UPDATE, e -> e - .organization(newOrgName) - .project(existingProject.getProjectName())); - - var oldOrgName = existingProject.getOrganization().getName(); - if (!newOrgName.equals(oldOrgName)) { - authService.checkPermission(PROJECT_UPDATE, e -> e.organization(oldOrgName)); - authService.checkPermission(PROJECT_UPDATE, e -> e.organization(newOrgName)); - } - - ProjectDTO result = projectService.save(projectDto); - return ResponseEntity.ok() - .headers(HeaderUtil - .createEntityUpdateAlert(ENTITY_NAME, projectDto.getProjectName())) - .body(result); - } - - /** - * GET /projects : get all the projects. - * - * @return the ResponseEntity with status 200 (OK) and the list of projects in body - */ - @GetMapping("/projects") - @Timed - public ResponseEntity getAllProjects( - @PageableDefault(size = Integer.MAX_VALUE) Pageable pageable, - @RequestParam(name = "minimized", required = false, defaultValue = "false") Boolean - minimized) throws NotAuthorizedException { - log.debug("REST request to get Projects"); - authService.checkPermission(PROJECT_READ); - Page page = projectService.findAll(minimized, pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/api/projects"); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } - - /** - * GET /projects/:projectName : get the project with this name. - * - * @param projectName the projectName of the projectDTO to retrieve - * @return the ResponseEntity with status 200 (OK) and with body the projectDTO, or with status - * 404 (Not Found) - */ - @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity getProject(@PathVariable String projectName) - throws NotAuthorizedException { - authService.checkScope(PROJECT_READ); - log.debug("REST request to get Project : {}", projectName); - ProjectDTO projectDto = projectService.findOneByName(projectName); - authService.checkPermission(PROJECT_READ, e -> e - .organization(projectDto.getOrganization().getName()) - .project(projectDto.getProjectName())); - return ResponseEntity.ok(projectDto); - } - - /** - * GET /projects/:projectName : get the "projectName" project. - * - * @param projectName the projectName of the projectDTO to retrieve - * @return the ResponseEntity with status 200 (OK) and with body the projectDTO, or with status - * 404 (Not Found) - */ - @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/source-types") - @Timed - public List getSourceTypesOfProject(@PathVariable String projectName) - throws NotAuthorizedException { - authService.checkScope(PROJECT_READ); - log.debug("REST request to get Project : {}", projectName); - ProjectDTO projectDto = projectService.findOneByName(projectName); - authService.checkPermission(PROJECT_READ, e -> e - .organization(projectDto.getOrganization().getName()) - .project(projectDto.getProjectName())); - return projectService.findSourceTypesByProjectId(projectDto.getId()); - } - - - /** - * DELETE /projects/:projectName : delete the "projectName" project. - * - * @param projectName the projectName of the projectDTO to delete - * @return the ResponseEntity with status 200 (OK) - */ - @DeleteMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity deleteProject(@PathVariable String projectName) - throws NotAuthorizedException { - authService.checkScope(PROJECT_DELETE); - log.debug("REST request to delete Project : {}", projectName); - ProjectDTO projectDto = projectService.findOneByName(projectName); - authService.checkPermission(PROJECT_DELETE, e -> e - .organization(projectDto.getOrganization().getName()) - .project(projectDto.getProjectName())); - - try { - projectService.delete(projectDto.getId()); - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, projectName)) - .build(); - } catch (DataIntegrityViolationException ex) { - return ResponseEntity.badRequest() - .body(new ErrorVM(ERR_PROJECT_NOT_EMPTY, ex.getMessage())); - } - } - - /** - * GET /projects/{projectName}/roles : get all the roles created for this project. - * - * @return the ResponseEntity with status 200 (OK) and the list of roles in body - */ - @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/roles") - @Timed - public ResponseEntity> getRolesByProject(@PathVariable String projectName) - throws NotAuthorizedException { - authService.checkScope(ROLE_READ); - log.debug("REST request to get all Roles for project {}", projectName); - ProjectDTO projectDto = projectService.findOneByName(projectName); - authService.checkPermission(ROLE_READ, e -> e - .organization(projectDto.getOrganization().getName()) - .project(projectDto.getProjectName())); - return ResponseEntity.ok(roleService.getRolesByProject(projectName)); - } - - /** - * GET /projects/{projectName}/sources : get all the sources by project. - * - * @return the ResponseEntity with status 200 (OK) and the list of sources in body - */ - @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/sources") - @Timed - public ResponseEntity getAllSourcesForProject(@Parameter Pageable pageable, - @PathVariable String projectName, - @RequestParam(value = "assigned", required = false) Boolean assigned, - @RequestParam(name = "minimized", required = false, defaultValue = "false") - Boolean minimized) throws NotAuthorizedException { - authService.checkScope(SOURCE_READ); - log.debug("REST request to get all Sources"); - ProjectDTO projectDto = projectService.findOneByName(projectName); - - authService.checkPermission(SOURCE_READ, e -> e - .organization(projectDto.getOrganization().getName()) - .project(projectDto.getProjectName())); - - if (assigned != null) { - if (minimized) { - return ResponseEntity.ok(sourceService - .findAllMinimalSourceDetailsByProjectAndAssigned( - projectDto.getId(), assigned)); - } else { - return ResponseEntity.ok(sourceService - .findAllByProjectAndAssigned(projectDto.getId(), assigned)); - } - } else { - if (minimized) { - Page page = sourceService - .findAllMinimalSourceDetailsByProject(projectDto.getId(), pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, HeaderUtil.buildPath("api", - "projects", projectName, "sources")); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } else { - Page page = sourceService - .findAllByProjectId(projectDto.getId(), pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, HeaderUtil.buildPath("api", - "projects", projectName, "sources")); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } - } - } - - /** - * Get /projects/{projectName}/subjects : get all subjects for a given project. - * - * @return The subjects in the project or 404 if there is no such project - */ - @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/subjects") - @Timed - public ResponseEntity> getAllSubjects( - @Valid SubjectCriteria subjectCriteria - ) throws NotAuthorizedException { - authService.checkScope(SUBJECT_READ); - String projectName = subjectCriteria.getProjectName(); - // this checks if the project exists - ProjectDTO projectDto = projectService.findOneByName(projectName); - authService.checkPermission(SUBJECT_READ, e -> e - .organization(projectDto.getOrganization().getName()) - .project(projectDto.getProjectName())); - - // this checks if the project exists - projectService.findOneByName(projectName); - subjectCriteria.setProjectName(projectName); - - log.debug("REST request to get all subjects for project {} using criteria {}", projectName, - subjectCriteria); - Page page = subjectService.findAll(subjectCriteria) - .map(subjectMapper::subjectToSubjectWithoutProjectDTO); - - String baseUri = HeaderUtil.buildPath("api", "projects", projectName, "subjects"); - HttpHeaders headers = PaginationUtil.generateSubjectPaginationHttpHeaders( - page, baseUri, subjectCriteria); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt new file mode 100644 index 000000000..d622155e6 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -0,0 +1,396 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import io.swagger.v3.oas.annotations.Parameter +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ProjectService +import org.radarbase.management.service.ResourceUriService +import org.radarbase.management.service.RoleService +import org.radarbase.management.service.SourceService +import org.radarbase.management.service.SubjectService +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.dto.SourceTypeDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.mapper.SubjectMapper +import org.radarbase.management.web.rest.criteria.SubjectCriteria +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.ErrorVM +import org.radarbase.management.web.rest.util.HeaderUtil +import org.radarbase.management.web.rest.util.HeaderUtil.* +import org.radarbase.management.web.rest.util.PaginationUtil +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.dao.DataIntegrityViolationException +import org.springframework.data.domain.Pageable +import org.springframework.data.web.PageableDefault +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import java.net.URISyntaxException +import javax.validation.Valid + +/** + * REST controller for managing Project. + */ +@RestController +@RequestMapping("/api") +class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val projectService: ProjectService, + @Autowired private val roleService: RoleService, + @Autowired private val subjectService: SubjectService, + @Autowired private val sourceService: SourceService, + @Autowired private val authService: AuthService +) { + + /** + * POST /projects : Create a new project. + * + * @param projectDto the projectDto to create + * @return the ResponseEntity with status 201 (Created) and with body the new projectDto, or + * with status 400 (Bad Request) if the project has already an ID + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/projects") + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity { + log.debug("REST request to save Project : {}", projectDto) + val org = projectDto!!.organization + if (org == null || org.name == null) { + throw BadRequestException( + "Organization must be provided", + ENTITY_NAME, ErrorConstants.ERR_VALIDATION + ) + } + authService.checkPermission( + Permission.PROJECT_CREATE, + { e: EntityDetails -> e.organization(org.name) }) + if (projectDto.id != null) { + return ResponseEntity.badRequest() + .headers( + createFailureAlert( + ENTITY_NAME, "idexists", "A new project cannot already have an ID" + ) + ) + .body(null) + } + if (projectRepository.findOneWithEagerRelationshipsByName(projectDto.projectName) != null) { + return ResponseEntity.badRequest() + .headers( + createFailureAlert( + ENTITY_NAME, "nameexists", "A project with this name already exists" + ) + ) + .body(null) + } + val result = projectService.save(projectDto) + return ResponseEntity.created(ResourceUriService.getUri(result)) + .headers( + createEntityCreationAlert( + ENTITY_NAME, + result.projectName + ) + ) + .body(result) + } + + /** + * PUT /projects : Updates an existing project. + * + * @param projectDto the projectDto to update + * @return the ResponseEntity with status 200 (OK) and with body the updated projectDto, or with + * status 400 (Bad Request) if the projectDto is not valid, or with status 500 (Internal + * Server Error) if the projectDto couldn't be updated + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PutMapping("/projects") + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun updateProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity { + log.debug("REST request to update Project : {}", projectDto) + if (projectDto!!.id == null) { + return createProject(projectDto) + } + // When a client wants to link the project to the default organization, + // this must be done explicitly. + val org = projectDto.organization + if (org == null || org.name == null) { + throw BadRequestException( + "Organization must be provided", + ENTITY_NAME, ErrorConstants.ERR_VALIDATION + ) + } + // When clients want to transfer a project, + // they must have permissions to modify both new & old organizations + val existingProject = projectService.findOne(projectDto.id) + if (existingProject.projectName != projectDto.projectName) { + throw BadRequestException( + "The project name cannot be modified.", ENTITY_NAME, + ErrorConstants.ERR_VALIDATION + ) + } + val newOrgName = org.name + authService.checkPermission( + Permission.PROJECT_UPDATE, + { e: EntityDetails -> + e.organization(newOrgName) + e.project(existingProject.projectName) + }) + val oldOrgName = existingProject.organization.name + if (newOrgName != oldOrgName) { + authService.checkPermission( + Permission.PROJECT_UPDATE, + { e: EntityDetails -> e.organization(oldOrgName) }) + authService.checkPermission( + Permission.PROJECT_UPDATE, + { e: EntityDetails -> e.organization(newOrgName) }) + } + val result = projectService.save(projectDto) + return ResponseEntity.ok() + .headers( + createEntityUpdateAlert(ENTITY_NAME, projectDto.projectName) + ) + .body(result) + } + + /** + * GET /projects : get all the projects. + * + * @return the ResponseEntity with status 200 (OK) and the list of projects in body + */ + @GetMapping("/projects") + @Timed + @Throws(NotAuthorizedException::class) + fun getAllProjects( + @PageableDefault(size = Int.MAX_VALUE) pageable: Pageable?, + @RequestParam(name = "minimized", required = false, defaultValue = "false") minimized: Boolean? + ): ResponseEntity<*> { + log.debug("REST request to get Projects") + authService.checkPermission(Permission.PROJECT_READ) + val page = projectService.findAll(minimized, pageable) + val headers = PaginationUtil + .generatePaginationHttpHeaders(page, "/api/projects") + return ResponseEntity(page.content, headers, HttpStatus.OK) + } + + /** + * GET /projects/:projectName : get the project with this name. + * + * @param projectName the projectName of the projectDTO to retrieve + * @return the ResponseEntity with status 200 (OK) and with body the projectDTO, or with status + * 404 (Not Found) + */ + @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getProject(@PathVariable projectName: String?): ResponseEntity { + authService.checkScope(Permission.PROJECT_READ) + log.debug("REST request to get Project : {}", projectName) + val projectDto = projectService.findOneByName(projectName!!) + authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> + e.organization(projectDto.organization.name) + e.project(projectDto.projectName) + }) + return ResponseEntity.ok(projectDto) + } + + /** + * GET /projects/:projectName : get the "projectName" project. + * + * @param projectName the projectName of the projectDTO to retrieve + * @return the ResponseEntity with status 200 (OK) and with body the projectDTO, or with status + * 404 (Not Found) + */ + @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/source-types") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getSourceTypesOfProject(@PathVariable projectName: String?): List { + authService.checkScope(Permission.PROJECT_READ) + log.debug("REST request to get Project : {}", projectName) + val projectDto = projectService.findOneByName(projectName!!) + authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> + e.organization(projectDto.organization.name) + e.project(projectDto.projectName) + }) + return projectService.findSourceTypesByProjectId(projectDto.id) + } + + /** + * DELETE /projects/:projectName : delete the "projectName" project. + * + * @param projectName the projectName of the projectDTO to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun deleteProject(@PathVariable projectName: String?): ResponseEntity<*> { + authService.checkScope(Permission.PROJECT_DELETE) + log.debug("REST request to delete Project : {}", projectName) + val projectDto = projectService.findOneByName(projectName!!) + authService.checkPermission(Permission.PROJECT_DELETE, { e: EntityDetails -> + e.organization(projectDto.organization.name) + e.project(projectDto.projectName) + }) + return try { + projectService.delete(projectDto.id) + ResponseEntity.ok() + .headers(createEntityDeletionAlert(ENTITY_NAME, projectName)) + .build() + } catch (ex: DataIntegrityViolationException) { + ResponseEntity.badRequest() + .body(ErrorVM(ErrorConstants.ERR_PROJECT_NOT_EMPTY, ex.message)) + } + } + + /** + * GET /projects/{projectName}/roles : get all the roles created for this project. + * + * @return the ResponseEntity with status 200 (OK) and the list of roles in body + */ + @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/roles") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getRolesByProject(@PathVariable projectName: String?): ResponseEntity> { + authService.checkScope(Permission.ROLE_READ) + log.debug("REST request to get all Roles for project {}", projectName) + val projectDto = projectService.findOneByName(projectName!!) + authService.checkPermission(Permission.ROLE_READ, { e: EntityDetails -> + e.organization(projectDto.organization.name) + e.project(projectDto.projectName) + }) + return ResponseEntity.ok(roleService.getRolesByProject(projectName)) + } + + /** + * GET /projects/{projectName}/sources : get all the sources by project. + * + * @return the ResponseEntity with status 200 (OK) and the list of sources in body + */ + @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/sources") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getAllSourcesForProject( + @Parameter pageable: Pageable?, + @PathVariable projectName: String?, + @RequestParam(value = "assigned", required = false) assigned: Boolean?, + @RequestParam(name = "minimized", required = false, defaultValue = "false") minimized: Boolean + ): ResponseEntity<*> { + authService.checkScope(Permission.SOURCE_READ) + log.debug("REST request to get all Sources") + val projectDto = projectService.findOneByName(projectName!!) + authService.checkPermission(Permission.SOURCE_READ, { e: EntityDetails -> + e.organization(projectDto.organization.name) + e.project(projectDto.projectName) + }) + return if (assigned != null) { + if (minimized) { + ResponseEntity.ok( + sourceService + .findAllMinimalSourceDetailsByProjectAndAssigned( + projectDto.id, assigned + ) + ) + } else { + ResponseEntity.ok( + sourceService + .findAllByProjectAndAssigned(projectDto.id, assigned) + ) + } + } else { + if (minimized) { + val page = sourceService + .findAllMinimalSourceDetailsByProject(projectDto.id, pageable) + val headers = PaginationUtil + .generatePaginationHttpHeaders( + page, buildPath( + "api", + "projects", projectName, "sources" + ) + ) + ResponseEntity(page.content, headers, HttpStatus.OK) + } else { + val page = sourceService + .findAllByProjectId(projectDto.id, pageable) + val headers = PaginationUtil + .generatePaginationHttpHeaders( + page, buildPath( + "api", + "projects", projectName, "sources" + ) + ) + ResponseEntity(page.content, headers, HttpStatus.OK) + } + } + } + + /** + * Get /projects/{projectName}/subjects : get all subjects for a given project. + * + * @return The subjects in the project or 404 if there is no such project + */ + @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/subjects") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getAllSubjects( + subjectCriteria: @Valid SubjectCriteria? + ): ResponseEntity> { + authService.checkScope(Permission.SUBJECT_READ) + val projectName = subjectCriteria!!.projectName + // this checks if the project exists + val projectDto = projectService.findOneByName(projectName) + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> + e.organization(projectDto.organization.name) + e.project(projectDto.projectName) + }) + + // this checks if the project exists + projectService.findOneByName(projectName) + subjectCriteria.projectName = projectName + log.debug( + "REST request to get all subjects for project {} using criteria {}", projectName, + subjectCriteria + ) + val page = subjectService.findAll(subjectCriteria) + .map { subject: Subject? -> subjectMapper.subjectToSubjectWithoutProjectDTO(subject) } + val baseUri = buildPath("api", "projects", projectName, "subjects") + val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( + page, baseUri, subjectCriteria + ) + return ResponseEntity(page.content, headers, HttpStatus.OK) + } + + companion object { + private val log = LoggerFactory.getLogger(ProjectResource::class.java) + private const val ENTITY_NAME = "project" + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/SubjectResource.java b/src/main/java/org/radarbase/management/web/rest/SubjectResource.java deleted file mode 100644 index 14669330a..000000000 --- a/src/main/java/org/radarbase/management/web/rest/SubjectResource.java +++ /dev/null @@ -1,572 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Source; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.security.SecurityUtils; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.RevisionService; -import org.radarbase.management.service.SourceService; -import org.radarbase.management.service.SourceTypeService; -import org.radarbase.management.service.SubjectService; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.RevisionDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.mapper.SubjectMapper; -import org.radarbase.management.web.rest.criteria.SubjectCriteria; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.InvalidRequestException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.boot.actuate.audit.AuditEventRepository; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Stream; - -import static org.radarbase.auth.authorization.Permission.SUBJECT_CREATE; -import static org.radarbase.auth.authorization.Permission.SUBJECT_DELETE; -import static org.radarbase.auth.authorization.Permission.SUBJECT_READ; -import static org.radarbase.auth.authorization.Permission.SUBJECT_UPDATE; -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE; -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE_TYPE; -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_ACTIVE_PARTICIPANT_PROJECT_NOT_FOUND; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SOURCE_TYPE_NOT_PROVIDED; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SUBJECT_NOT_FOUND; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_VALIDATION; -import static tech.jhipster.web.util.ResponseUtil.wrapOrNotFound; - -/** - * REST controller for managing Subject. - */ -@RestController -@RequestMapping("/api") -public class SubjectResource { - - private static final Logger log = LoggerFactory.getLogger(SubjectResource.class); - - @Autowired - private SubjectService subjectService; - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private SubjectMapper subjectMapper; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private SourceTypeService sourceTypeService; - - @Autowired - private AuditEventRepository eventRepository; - - @Autowired - private RevisionService revisionService; - - @Autowired - private SourceService sourceService; - @Autowired - private AuthService authService; - - /** - * POST /subjects : Create a new subject. - * - * @param subjectDto the subjectDto to create - * @return the ResponseEntity with status 201 (Created) and with body the new subjectDto, or - * with status 400 (Bad Request) if the subject has already an ID - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PostMapping("/subjects") - @Timed - public ResponseEntity createSubject(@RequestBody SubjectDTO subjectDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save Subject : {}", subjectDto); - String projectName = getProjectName(subjectDto); - authService.checkPermission(SUBJECT_CREATE, e -> e.project(projectName)); - - if (subjectDto.getId() != null) { - throw new BadRequestException("A new subject cannot already have an ID", - SUBJECT, "idexists"); - } - if (subjectDto.getLogin() == null) { - throw new BadRequestException("A subject login is required", SUBJECT, "loginrequired"); - } - if (subjectDto.getExternalId() != null - && !subjectDto.getExternalId().isEmpty() - && subjectRepository.findOneByProjectNameAndExternalId( - projectName, subjectDto.getExternalId()).isPresent()) { - throw new BadRequestException("A subject with given project-id and" - + "external-id already exists", SUBJECT, "subjectExists"); - } - - SubjectDTO result = subjectService.createSubject(subjectDto); - return ResponseEntity.created(ResourceUriService.getUri(subjectDto)) - .headers(HeaderUtil.createEntityCreationAlert(SUBJECT, result.getLogin())) - .body(result); - } - - private String getProjectName(SubjectDTO subjectDto) { - if ( - subjectDto.getProject() == null - || subjectDto.getProject().getId() == null - || subjectDto.getProject().getProjectName() == null - ) { - throw new BadRequestException("A subject should be assigned to a project", SUBJECT, - "projectrequired"); - } - return subjectDto.getProject().getProjectName(); - } - - /** - * PUT /subjects : Updates an existing subject. - * - * @param subjectDto the subjectDto to update - * @return the ResponseEntity with status 200 (OK) and with body the updated subjectDto, or with - * status 400 (Bad Request) if the subjectDto is not valid, or with status 500 (Internal - * Server Error) if the subjectDto couldnt be updated - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PutMapping("/subjects") - @Timed - public ResponseEntity updateSubject(@RequestBody SubjectDTO subjectDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update Subject : {}", subjectDto); - if (subjectDto.getId() == null) { - return createSubject(subjectDto); - } - String projectName = getProjectName(subjectDto); - authService.checkPermission(SUBJECT_UPDATE, e -> e - .project(projectName) - .subject(subjectDto.getLogin())); - SubjectDTO result = subjectService.updateSubject(subjectDto); - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(SUBJECT, subjectDto.getLogin())) - .body(result); - } - - /** - * PUT /subjects/discontinue : Discontinue a subject. A discontinued subject is not allowed to - * send data to the system anymore. - * - * @param subjectDto the subjectDto to update - * @return the ResponseEntity with status 200 (OK) and with body the updated subjectDto, or with - * status 400 (Bad Request) if the subjectDto is not valid, or with status 500 (Internal - * Server Error) if the subjectDto couldnt be updated - */ - @PutMapping("/subjects/discontinue") - @Timed - public ResponseEntity discontinueSubject(@RequestBody SubjectDTO subjectDto) - throws NotAuthorizedException { - log.debug("REST request to update Subject : {}", subjectDto); - if (subjectDto.getId() == null) { - throw new BadRequestException("No subject found", SUBJECT, "subjectNotAvailable"); - } - - String projectName = getProjectName(subjectDto); - authService.checkPermission(SUBJECT_UPDATE, e -> e - .project(projectName) - .subject(subjectDto.getLogin())); - - // In principle this is already captured by the PostUpdate event listener, adding this - // event just makes it more clear a subject was discontinued. - eventRepository.add(new AuditEvent( - SecurityUtils.getCurrentUserLogin().orElse(null), - "SUBJECT_DISCONTINUE", "subject_login=" + subjectDto.getLogin())); - SubjectDTO result = subjectService.discontinueSubject(subjectDto); - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(SUBJECT, subjectDto.getLogin())) - .body(result); - } - - - /** - * GET /subjects : get all the subjects. - * - * @return the ResponseEntity with status 200 (OK) and the list of subjects in body - */ - @GetMapping("/subjects") - @Timed - public ResponseEntity> getAllSubjects( - @Valid SubjectCriteria subjectCriteria - ) throws NotAuthorizedException { - String projectName = subjectCriteria.getProjectName(); - authService.checkPermission(SUBJECT_READ, e -> e.project(projectName)); - - String externalId = subjectCriteria.getExternalId(); - log.debug("ProjectName {} and external {}", projectName, externalId); - // if not specified do not include inactive patients - List authoritiesToInclude = subjectCriteria.getAuthority().stream() - .filter(Objects::nonNull) - .map(Enum::name) - .toList(); - - if (projectName != null && externalId != null) { - Optional> subject = subjectRepository - .findOneByProjectNameAndExternalIdAndAuthoritiesIn( - projectName, externalId, authoritiesToInclude) - .map(s -> Collections.singletonList( - subjectMapper.subjectToSubjectReducedProjectDTO(s))); - return wrapOrNotFound(subject); - } else if (projectName == null && externalId != null) { - Page page = subjectService.findAll(subjectCriteria) - .map(s -> subjectMapper.subjectToSubjectWithoutProjectDTO(s)); - - HttpHeaders headers = PaginationUtil.generateSubjectPaginationHttpHeaders( - page, "/api/subjects", subjectCriteria); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } else { - Page page = subjectService.findAll(subjectCriteria) - .map(subjectMapper::subjectToSubjectWithoutProjectDTO); - - HttpHeaders headers = PaginationUtil.generateSubjectPaginationHttpHeaders( - page, "/api/subjects", subjectCriteria); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } - } - - /** - * GET /subjects/:login : get the "login" subject. - * - * @param login the login of the subjectDTO to retrieve - * @return the ResponseEntity with status 200 (OK) and with body the subjectDTO, or with status - * 404 (Not Found) - */ - @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity getSubject(@PathVariable String login) - throws NotAuthorizedException { - log.debug("REST request to get Subject : {}", login); - authService.checkScope(SUBJECT_READ); - Subject subject = subjectService.findOneByLogin(login); - Project project = subject.getActiveProject() - .flatMap(p -> projectRepository.findOneWithEagerRelationships(p.getId())) - .orElse(null); - - authService.checkPermission(SUBJECT_READ, e -> { - if (project != null) { - e.project(project.getProjectName()); - } - e.subject(subject.getUser().getLogin()); - }); - - SubjectDTO subjectDto = subjectMapper.subjectToSubjectDTO(subject); - - return ResponseEntity.ok(subjectDto); - } - - /** - * GET /subjects/:login/revisions : get all revisions for the "login" subject. - * - * @param login the login of the subjectDTO for which to retrieve the revisions - * @return the ResponseEntity with status 200 (OK) and with body the subjectDTO, or with status - * 404 (Not Found) - */ - @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/revisions") - @Timed - public ResponseEntity> getSubjectRevisions( - @Parameter Pageable pageable, - @PathVariable String login) throws NotAuthorizedException { - authService.checkScope(SUBJECT_READ); - - log.debug("REST request to get revisions for Subject : {}", login); - Subject subject = subjectService.findOneByLogin(login); - authService.checkPermission(SUBJECT_READ, e -> { - subject.getAssociatedProject() - .map(Project::getProjectName) - .ifPresent(e::project); - e.subject(login); - }); - - Page page = revisionService.getRevisionsForEntity(pageable, subject); - - return ResponseEntity.ok() - .headers(PaginationUtil.generatePaginationHttpHeaders(page, - HeaderUtil.buildPath("subjects", login, "revisions"))) - .body(page.getContent()); - } - - /** - * GET /subjects/:login/revisions/:revisionNb : get the "login" subject at revisionNb - * 'revisionNb'. - * - * @param login the login of the subjectDTO to retrieve - * @return the ResponseEntity with status 200 (OK) and with body the subjectDTO, or with status - * 404 (Not Found) - */ - @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}" - + "/revisions/{revisionNb:^[0-9]*$}") - @Timed - public ResponseEntity getSubjectRevision(@PathVariable String login, - @PathVariable Integer revisionNb) throws NotAuthorizedException { - authService.checkScope(SUBJECT_READ); - - log.debug("REST request to get Subject : {}, for revisionNb: {}", login, revisionNb); - SubjectDTO subjectDto = subjectService.findRevision(login, revisionNb); - authService.checkPermission(SUBJECT_READ, e -> e - .project(subjectDto.getProject().getProjectName()) - .subject(subjectDto.getLogin())); - return ResponseEntity.ok(subjectDto); - } - - /** - * DELETE /subjects/:login : delete the "login" subject. - * - * @param login the login of the subjectDTO to delete - * @return the ResponseEntity with status 200 (OK) - */ - @DeleteMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity deleteSubject(@PathVariable String login) - throws NotAuthorizedException { - log.debug("REST request to delete Subject : {}", login); - authService.checkScope(SUBJECT_DELETE); - Subject subject = subjectService.findOneByLogin(login); - - authService.checkPermission(SUBJECT_DELETE, e -> { - subject.getAssociatedProject() - .map(Project::getProjectName) - .ifPresent(e::project); - e.subject(subject.getUser().getLogin()); - }); - subjectService.deleteSubject(login); - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityDeletionAlert(SUBJECT, login)).build(); - } - - /** - * POST /subjects/:login/sources: Assign a source to the specified user. - * - *

The request body is a {@link MinimalSourceDetailsDTO}. At minimum, the source should - * define it's source type by either supplying the sourceTypeId, or the combination of - * (sourceTypeProducer, sourceTypeModel, sourceTypeCatalogVersion) fields. A source ID will be - * automatically generated. The source ID will be a new random UUID, and the source name, if not - * provided, will be the device model, appended with a dash and the first eight characters of - * the UUID. The sources will be created and assigned to the specified user.

- * - *

If you need to assign existing sources, simply specify either of id, sourceId, or - * sourceName fields.

- * - * @param sourceDto The {@link MinimalSourceDetailsDTO} specification - * @return The {@link MinimalSourceDetailsDTO} completed with all identifying fields. - */ - @PostMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/sources") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "An existing source was assigned"), - @ApiResponse(responseCode = "201", description = "A new source was created and" - + " assigned"), - @ApiResponse(responseCode = "400", description = "You must supply either a" - + " Source Type ID, or the combination of (sourceTypeProducer, sourceTypeModel," - + " catalogVersion)"), - @ApiResponse(responseCode = "404", description = "Either the subject or the source type" - + " was not found.") - }) - @Timed - public ResponseEntity assignSources(@PathVariable String login, - @RequestBody MinimalSourceDetailsDTO sourceDto) throws URISyntaxException, - NotAuthorizedException { - authService.checkScope(SUBJECT_UPDATE); - - // find out source type id of supplied source - Long sourceTypeId = sourceDto.getSourceTypeId(); - if (sourceTypeId == null) { - // check if combination (producer, model, version) is present - if (sourceDto.getSourceTypeProducer() == null - || sourceDto.getSourceTypeModel() == null - || sourceDto.getSourceTypeCatalogVersion() == null) { - throw new BadRequestException("Producer or model or version value for the " - + "source-type is null" , SOURCE_TYPE, ERR_VALIDATION); - } - sourceTypeId = sourceTypeService - .findByProducerAndModelAndVersion( - sourceDto.getSourceTypeProducer(), - sourceDto.getSourceTypeModel(), - sourceDto.getSourceTypeCatalogVersion()).getId(); - // also update the sourceDto, since we pass it on to SubjectService later - sourceDto.setSourceTypeId(sourceTypeId); - } - - // check the subject id - Subject sub = subjectService.findOneByLogin(login); - - // find the actively assigned project for this subject - Project currentProject = sub.getActiveProject() - .map(Project::getId) - .flatMap(projectRepository::findByIdWithOrganization) - .orElseThrow(() -> - new InvalidRequestException( - "Requested subject does not have an active project", - SUBJECT, ERR_ACTIVE_PARTICIPANT_PROJECT_NOT_FOUND)); - - authService.checkPermission(SUBJECT_UPDATE, e -> e - .project(currentProject.getProjectName()) - .subject(sub.getUser().getLogin())); - - // find whether the relevant source-type is available in the subject's project - SourceType sourceType = projectRepository - .findSourceTypeByProjectIdAndSourceTypeId(currentProject.getId(), sourceTypeId) - .orElseThrow(() -> new BadRequestException("No valid source-type found for project." - + " You must provide either valid source-type id or producer, model," - + " version of a source-type that is assigned to project", - SUBJECT, ERR_SOURCE_TYPE_NOT_PROVIDED) - ); - - // check if any of id, sourceID, sourceName were non-null - boolean existing = Stream.of(sourceDto.getId(), sourceDto.getSourceName(), - sourceDto.getSourceId()) - .anyMatch(Objects::nonNull); - - // handle the source registration - MinimalSourceDetailsDTO sourceRegistered = subjectService - .assignOrUpdateSource(sub, sourceType, currentProject, sourceDto); - - // Return the correct response type, either created if a new source was created, or ok if - // an existing source was provided. If an existing source was given but not found, the - // assignOrUpdateSource would throw an error, and we would not reach this point. - if (!existing) { - return ResponseEntity.created(ResourceUriService.getUri(sourceRegistered)) - .headers(HeaderUtil.createEntityCreationAlert(SOURCE, - sourceRegistered.getSourceName())) - .body(sourceRegistered); - } else { - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(SOURCE, - sourceRegistered.getSourceName())) - .body(sourceRegistered); - } - } - - /** - * Get sources assigned to a subject. - * - * @param login the subject login - * @return the sources - */ - @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/sources") - @Timed - public ResponseEntity> getSubjectSources( - @PathVariable String login, - @RequestParam(value = "withInactiveSources", required = false) - Boolean withInactiveSourcesParam) throws NotAuthorizedException { - authService.checkScope(SUBJECT_READ); - - boolean withInactiveSources = withInactiveSourcesParam != null && withInactiveSourcesParam; - // check the subject id - Subject subject = subjectRepository.findOneWithEagerBySubjectLogin(login) - .orElseThrow(NoSuchElementException::new); - - authService.checkPermission(SUBJECT_READ, e -> { - subject.getAssociatedProject() - .map(Project::getProjectName) - .ifPresent(e::project); - e.subject(login); - }); - - if (withInactiveSources) { - return ResponseEntity.ok(subjectService.findSubjectSourcesFromRevisions(subject)); - } else { - log.debug("REST request to get sources of Subject : {}", login); - - return ResponseEntity.ok(subjectService.getSources(subject)); - } - } - - - /** - * POST /subjects/:login/sources/:sourceName Update source attributes and source-name. - * - *

The request body is a {@link Map} of strings. This request allows - * update of attributes only. Attributes will be merged and if a new value is - * provided for an existing key, the new value will be updated. The request will be validated - * for SUBJECT.UPDATE permission. SUBJECT.UPDATE is expected to keep the permissions aligned - * with permissions from dynamic source registration and update instead of checking for - * SOURCE_UPDATE. - *

- * - * @param attributes The {@link Map} specification - * @return The {@link MinimalSourceDetailsDTO} completed with all identifying fields. - * @throws NotFoundException if the subject or the source not found using given ids. - */ - @PostMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/sources/{sourceName:" - + Constants.ENTITY_ID_REGEX + "}") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "An existing source was updated"), - @ApiResponse(responseCode = "400", description = "You must supply existing sourceId)"), - @ApiResponse(responseCode = "404", description = "Either the subject or the source was" - + " not found.") - }) - @Timed - public ResponseEntity updateSubjectSource(@PathVariable String login, - @PathVariable String sourceName, @RequestBody Map attributes) - throws NotFoundException, NotAuthorizedException { - authService.checkScope(SUBJECT_UPDATE); - - // check the subject id - Subject subject = subjectRepository.findOneWithEagerBySubjectLogin(login) - .orElseThrow(() -> new NotFoundException("Subject ID not found", - SUBJECT, ERR_SUBJECT_NOT_FOUND, - Collections.singletonMap("subjectLogin", login))); - - authService.checkPermission(SUBJECT_UPDATE, e -> { - subject.getAssociatedProject() - .map(Project::getProjectName) - .ifPresent(e::project); - e.subject(login); - }); - - // find source under subject - Source source = subject.getSources().stream() - .filter(s -> s.getSourceName().equals(sourceName)) - .findAny() - .orElseThrow(() -> { - Map errorParams = new HashMap<>(); - errorParams.put("subjectLogin", login); - errorParams.put("sourceName", sourceName); - return new NotFoundException("Source not found under assigned sources of " - + "subject", SUBJECT, ERR_SUBJECT_NOT_FOUND, - errorParams); - }); - - // there should be only one source under a source-name. - return ResponseEntity.ok(sourceService.safeUpdateOfAttributes(source, attributes)); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt new file mode 100644 index 000000000..11b049d16 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt @@ -0,0 +1,584 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.responses.ApiResponses +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Source +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.security.SecurityUtils +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ResourceUriService +import org.radarbase.management.service.RevisionService +import org.radarbase.management.service.SourceService +import org.radarbase.management.service.SourceTypeService +import org.radarbase.management.service.SubjectService +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.RevisionDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.mapper.SubjectMapper +import org.radarbase.management.web.rest.criteria.SubjectAuthority +import org.radarbase.management.web.rest.criteria.SubjectCriteria +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidRequestException +import org.radarbase.management.web.rest.errors.NotFoundException +import org.radarbase.management.web.rest.util.HeaderUtil +import org.radarbase.management.web.rest.util.PaginationUtil +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.boot.actuate.audit.AuditEventRepository +import org.springframework.data.domain.Pageable +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.io.Serializable +import java.net.URISyntaxException +import java.util.* +import java.util.stream.Stream +import javax.validation.Valid + +/** + * REST controller for managing Subject. + */ +@RestController +@RequestMapping("/api") +class SubjectResource( + @Autowired private val subjectService: SubjectService, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val subjectMapper: SubjectMapper, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val sourceTypeService: SourceTypeService, + @Autowired private val eventRepository: AuditEventRepository, + @Autowired private val revisionService: RevisionService, + @Autowired private val sourceService: SourceService, + @Autowired private val authService: AuthService +) { + + /** + * POST /subjects : Create a new subject. + * + * @param subjectDto the subjectDto to create + * @return the ResponseEntity with status 201 (Created) and with body the new subjectDto, or + * with status 400 (Bad Request) if the subject has already an ID + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/subjects") + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createSubject(@RequestBody subjectDto: SubjectDTO): ResponseEntity { + log.debug("REST request to save Subject : {}", subjectDto) + val projectName = getProjectName(subjectDto) + authService.checkPermission(Permission.SUBJECT_CREATE, { e: EntityDetails -> e.project(projectName) }) + if (subjectDto.id != null) { + throw BadRequestException( + "A new subject cannot already have an ID", + EntityName.SUBJECT, "idexists" + ) + } + if (subjectDto.getLogin() == null) { + throw BadRequestException("A subject login is required", EntityName.SUBJECT, "loginrequired") + } + if (subjectDto.externalId != null && subjectDto.externalId.isNotEmpty() + && subjectRepository.findOneByProjectNameAndExternalId( + projectName, subjectDto.externalId + ).isPresent + ) { + throw BadRequestException( + "A subject with given project-id and" + + "external-id already exists", EntityName.SUBJECT, "subjectExists" + ) + } + val result = subjectService.createSubject(subjectDto) + return ResponseEntity.created(ResourceUriService.getUri(subjectDto)) + .headers(HeaderUtil.createEntityCreationAlert(EntityName.SUBJECT, result?.getLogin())) + .body(result) + } + + private fun getProjectName(subjectDto: SubjectDTO): String { + if (subjectDto.project == null || subjectDto.project.id == null || subjectDto.project.projectName == null) { + throw BadRequestException( + "A subject should be assigned to a project", EntityName.SUBJECT, + "projectrequired" + ) + } + return subjectDto.project.projectName + } + + /** + * PUT /subjects : Updates an existing subject. + * + * @param subjectDto the subjectDto to update + * @return the ResponseEntity with status 200 (OK) and with body the updated subjectDto, or with + * status 400 (Bad Request) if the subjectDto is not valid, or with status 500 (Internal + * Server Error) if the subjectDto couldn't be updated + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PutMapping("/subjects") + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun updateSubject(@RequestBody subjectDto: SubjectDTO): ResponseEntity { + log.debug("REST request to update Subject : {}", subjectDto) + if (subjectDto.id == null) { + return createSubject(subjectDto) + } + val projectName = getProjectName(subjectDto) + authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> + e + .project(projectName) + .subject(subjectDto.getLogin()) + }) + val result = subjectService.updateSubject(subjectDto) + return ResponseEntity.ok() + .headers(HeaderUtil.createEntityUpdateAlert(EntityName.SUBJECT, subjectDto.getLogin())) + .body(result) + } + + /** + * PUT /subjects/discontinue : Discontinue a subject. A discontinued subject is not allowed to + * send data to the system anymore. + * + * @param subjectDto the subjectDto to update + * @return the ResponseEntity with status 200 (OK) and with body the updated subjectDto, or with + * status 400 (Bad Request) if the subjectDto is not valid, or with status 500 (Internal + * Server Error) if the subjectDto couldnt be updated + */ + @PutMapping("/subjects/discontinue") + @Timed + @Throws(NotAuthorizedException::class) + fun discontinueSubject(@RequestBody subjectDto: SubjectDTO): ResponseEntity { + log.debug("REST request to update Subject : {}", subjectDto) + if (subjectDto.id == null) { + throw BadRequestException("No subject found", EntityName.SUBJECT, "subjectNotAvailable") + } + val projectName = getProjectName(subjectDto) + authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> + e + .project(projectName) + .subject(subjectDto.getLogin()) + }) + + // In principle this is already captured by the PostUpdate event listener, adding this + // event just makes it more clear a subject was discontinued. + eventRepository.add( + AuditEvent( + SecurityUtils.getCurrentUserLogin().orElse(null), + "SUBJECT_DISCONTINUE", "subject_login=" + subjectDto.getLogin() + ) + ) + val result = subjectService.discontinueSubject(subjectDto) + return ResponseEntity.ok() + .headers(HeaderUtil.createEntityUpdateAlert(EntityName.SUBJECT, subjectDto.getLogin())) + .body(result) + } + + /** + * GET /subjects : get all the subjects. + * + * @return the ResponseEntity with status 200 (OK) and the list of subjects in body + */ + @GetMapping("/subjects") + @Timed + @Throws(NotAuthorizedException::class) + fun getAllSubjects( + subjectCriteria: @Valid SubjectCriteria? + ): ResponseEntity>? { + val projectName = subjectCriteria!!.projectName + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> e.project(projectName) }) + val externalId = subjectCriteria.externalId + log.debug("ProjectName {} and external {}", projectName, externalId) + // if not specified do not include inactive patients + val authoritiesToInclude = subjectCriteria.authority.stream() + .filter { obj: SubjectAuthority? -> Objects.nonNull(obj) } + .map { obj: SubjectAuthority -> obj.name } + .toList() + return if (projectName != null && externalId != null) { + val subject = subjectRepository + .findOneByProjectNameAndExternalIdAndAuthoritiesIn( + projectName, externalId, authoritiesToInclude + ) + ?.map { s: Subject? -> + listOf( + subjectMapper.subjectToSubjectReducedProjectDTO(s) + ) + } + ResponseUtil.wrapOrNotFound(subject) + } else if (projectName == null && externalId != null) { + val page = subjectService.findAll(subjectCriteria) + .map { s: Subject? -> subjectMapper.subjectToSubjectWithoutProjectDTO(s) } + val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( + page, "/api/subjects", subjectCriteria + ) + ResponseEntity(page.content, headers, HttpStatus.OK) + } else { + val page = subjectService.findAll(subjectCriteria) + .map { subject: Subject? -> subjectMapper.subjectToSubjectWithoutProjectDTO(subject) } + val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( + page, "/api/subjects", subjectCriteria + ) + ResponseEntity(page.content, headers, HttpStatus.OK) + } + } + + /** + * GET /subjects/:login : get the "login" subject. + * + * @param login the login of the subjectDTO to retrieve + * @return the ResponseEntity with status 200 (OK) and with body the subjectDTO, or with status + * 404 (Not Found) + */ + @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getSubject(@PathVariable login: String?): ResponseEntity { + log.debug("REST request to get Subject : {}", login) + authService.checkScope(Permission.SUBJECT_READ) + val subject = subjectService.findOneByLogin(login) + val project: Project? = subject.activeProject + ?.let { p -> projectRepository.findOneWithEagerRelationships(p.id) } + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> + if (project != null) { + e.project(project.projectName) + } + e.subject(subject.user?.login) + }) + val subjectDto = subjectMapper.subjectToSubjectDTO(subject) + return ResponseEntity.ok(subjectDto) + } + + /** + * GET /subjects/:login/revisions : get all revisions for the "login" subject. + * + * @param login the login of the subjectDTO for which to retrieve the revisions + * @return the ResponseEntity with status 200 (OK) and with body the subjectDTO, or with status + * 404 (Not Found) + */ + @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/revisions") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getSubjectRevisions( + @Parameter pageable: Pageable?, + @PathVariable login: String? + ): ResponseEntity> { + authService.checkScope(Permission.SUBJECT_READ) + log.debug("REST request to get revisions for Subject : {}", login) + val subject = subjectService.findOneByLogin(login) + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> + e.project(subject.associatedProject?.projectName) + e.subject(login) + }) + val page = pageable?.let { revisionService.getRevisionsForEntity(it, subject) } + return ResponseEntity.ok() + .headers( + PaginationUtil.generatePaginationHttpHeaders( + page, + HeaderUtil.buildPath("subjects", login, "revisions") + ) + ) + .body(page?.content) + } + + /** + * GET /subjects/:login/revisions/:revisionNb : get the "login" subject at revisionNb + * 'revisionNb'. + * + * @param login the login of the subjectDTO to retrieve + * @return the ResponseEntity with status 200 (OK) and with body the subjectDTO, or with status + * 404 (Not Found) + */ + @GetMapping( + "/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}" + + "/revisions/{revisionNb:^[0-9]*$}" + ) + @Timed + @Throws(NotAuthorizedException::class) + fun getSubjectRevision( + @PathVariable login: String?, + @PathVariable revisionNb: Int? + ): ResponseEntity { + authService.checkScope(Permission.SUBJECT_READ) + log.debug("REST request to get Subject : {}, for revisionNb: {}", login, revisionNb) + val subjectDto = subjectService.findRevision(login, revisionNb) + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> + e.project(subjectDto.project.projectName) + .subject(subjectDto.login) + }) + return ResponseEntity.ok(subjectDto) + } + + /** + * DELETE /subjects/:login : delete the "login" subject. + * + * @param login the login of the subjectDTO to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun deleteSubject(@PathVariable login: String?): ResponseEntity { + log.debug("REST request to delete Subject : {}", login) + authService.checkScope(Permission.SUBJECT_DELETE) + val subject = subjectService.findOneByLogin(login) + authService.checkPermission(Permission.SUBJECT_DELETE, { e: EntityDetails -> + e.project(subject.associatedProject?.projectName) + e.subject(login) + }) + subjectService.deleteSubject(login) + return ResponseEntity.ok() + .headers(HeaderUtil.createEntityDeletionAlert(EntityName.SUBJECT, login)).build() + } + + /** + * POST /subjects/:login/sources: Assign a source to the specified user. + * + * + * The request body is a [MinimalSourceDetailsDTO]. At minimum, the source should + * define it's source type by either supplying the sourceTypeId, or the combination of + * (sourceTypeProducer, sourceTypeModel, sourceTypeCatalogVersion) fields. A source ID will be + * automatically generated. The source ID will be a new random UUID, and the source name, if not + * provided, will be the device model, appended with a dash and the first eight characters of + * the UUID. The sources will be created and assigned to the specified user. + * + * + * If you need to assign existing sources, simply specify either of id, sourceId, or + * sourceName fields. + * + * @param sourceDto The [MinimalSourceDetailsDTO] specification + * @return The [MinimalSourceDetailsDTO] completed with all identifying fields. + */ + @PostMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/sources") + @ApiResponses( + ApiResponse(responseCode = "200", description = "An existing source was assigned"), ApiResponse( + responseCode = "201", description = "A new source was created and" + + " assigned" + ), ApiResponse( + responseCode = "400", description = "You must supply either a" + + " Source Type ID, or the combination of (sourceTypeProducer, sourceTypeModel," + + " catalogVersion)" + ), ApiResponse( + responseCode = "404", description = "Either the subject or the source type" + + " was not found." + ) + ) + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun assignSources( + @PathVariable login: String?, + @RequestBody sourceDto: MinimalSourceDetailsDTO + ): ResponseEntity { + authService.checkScope(Permission.SUBJECT_UPDATE) + + // find out source type id of supplied source + var sourceTypeId = sourceDto.sourceTypeId + if (sourceTypeId == null) { + // check if combination (producer, model, version) is present + if (sourceDto.sourceTypeProducer == null || sourceDto.sourceTypeModel == null || sourceDto.sourceTypeCatalogVersion == null) { + throw BadRequestException( + "Producer or model or version value for the " + + "source-type is null", EntityName.SOURCE_TYPE, ErrorConstants.ERR_VALIDATION + ) + } + sourceTypeId = sourceTypeService + .findByProducerAndModelAndVersion( + sourceDto.sourceTypeProducer, + sourceDto.sourceTypeModel, + sourceDto.sourceTypeCatalogVersion + )?.id + // also update the sourceDto, since we pass it on to SubjectService later + sourceDto.sourceTypeId = sourceTypeId + } + + // check the subject id + val sub = subjectService.findOneByLogin(login) + + // find the actively assigned project for this subject + val currentProject: Project = projectRepository.findByIdWithOrganization(sub.activeProject?.id) + ?: throw InvalidRequestException( + "Requested subject does not have an active project", + EntityName.SUBJECT, ErrorConstants.ERR_ACTIVE_PARTICIPANT_PROJECT_NOT_FOUND + ) + + authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> + e + .project(currentProject.projectName) + .subject(sub.user!!.login) + }) + + // find whether the relevant source-type is available in the subject's project + val sourceType = projectRepository + .findSourceTypeByProjectIdAndSourceTypeId(currentProject.id, sourceTypeId) + ?.orElseThrow { + BadRequestException( + "No valid source-type found for project." + + " You must provide either valid source-type id or producer, model," + + " version of a source-type that is assigned to project", + EntityName.SUBJECT, ErrorConstants.ERR_SOURCE_TYPE_NOT_PROVIDED + ) + } + + // check if any of id, sourceID, sourceName were non-null + val existing = Stream.of( + sourceDto.id, sourceDto.sourceName, + sourceDto.sourceId + ) + .anyMatch { obj: Serializable? -> Objects.nonNull(obj) } + + // handle the source registration + val sourceRegistered = subjectService + .assignOrUpdateSource(sub, sourceType!!, currentProject, sourceDto) + + // Return the correct response type, either created if a new source was created, or ok if + // an existing source was provided. If an existing source was given but not found, the + // assignOrUpdateSource would throw an error, and we would not reach this point. + return if (!existing) { + ResponseEntity.created(ResourceUriService.getUri(sourceRegistered)) + .headers( + HeaderUtil.createEntityCreationAlert( + EntityName.SOURCE, + sourceRegistered.sourceName + ) + ) + .body(sourceRegistered) + } else { + ResponseEntity.ok() + .headers( + HeaderUtil.createEntityUpdateAlert( + EntityName.SOURCE, + sourceRegistered.sourceName + ) + ) + .body(sourceRegistered) + } + } + + /** + * Get sources assigned to a subject. + * + * @param login the subject login + * @return the sources + */ + @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/sources") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getSubjectSources( + @PathVariable login: String?, + @RequestParam(value = "withInactiveSources", required = false) withInactiveSourcesParam: Boolean? + ): ResponseEntity> { + authService.checkScope(Permission.SUBJECT_READ) + val withInactiveSources = withInactiveSourcesParam != null && withInactiveSourcesParam + // check the subject id + val subject = subjectRepository.findOneWithEagerBySubjectLogin(login) + .orElseThrow { NoSuchElementException() } + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> + e + .project(subject.associatedProject?.projectName) + e.subject(login) + }) + return if (withInactiveSources) { + ResponseEntity.ok(subjectService.findSubjectSourcesFromRevisions(subject)) + } else { + log.debug("REST request to get sources of Subject : {}", login) + ResponseEntity.ok(subjectService.getSources(subject)) + } + } + + /** + * POST /subjects/:login/sources/:sourceName Update source attributes and source-name. + * + * + * The request body is a [Map] of strings. This request allows + * update of attributes only. Attributes will be merged and if a new value is + * provided for an existing key, the new value will be updated. The request will be validated + * for SUBJECT.UPDATE permission. SUBJECT.UPDATE is expected to keep the permissions aligned + * with permissions from dynamic source registration and update instead of checking for + * SOURCE_UPDATE. + * + * + * @param attributes The [Map] specification + * @return The [MinimalSourceDetailsDTO] completed with all identifying fields. + * @throws NotFoundException if the subject or the source not found using given ids. + */ + @PostMapping( + "/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/sources/{sourceName:" + + Constants.ENTITY_ID_REGEX + "}" + ) + @ApiResponses( + ApiResponse(responseCode = "200", description = "An existing source was updated"), + ApiResponse(responseCode = "400", description = "You must supply existing sourceId)"), + ApiResponse( + responseCode = "404", description = "Either the subject or the source was" + + " not found." + ) + ) + @Timed + @Throws(NotFoundException::class, NotAuthorizedException::class) + fun updateSubjectSource( + @PathVariable login: String, + @PathVariable sourceName: String, @RequestBody attributes: Map? + ): ResponseEntity { + authService.checkScope(Permission.SUBJECT_UPDATE) + + // check the subject id + val subject = subjectRepository.findOneWithEagerBySubjectLogin(login) + .orElseThrow { + NotFoundException( + "Subject ID not found", + EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) + } + authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> + e + .project(subject.associatedProject?.projectName) + e.subject(login) + }) + + // find source under subject + val source = subject.sources.stream() + .filter { s: Source -> s.sourceName == sourceName } + .findAny() + .orElseThrow { + val errorParams: MutableMap = HashMap() + errorParams["subjectLogin"] = login + errorParams["sourceName"] = sourceName + NotFoundException( + "Source not found under assigned sources of " + + "subject", EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND, + errorParams + ) + } + + // there should be only one source under a source-name. + return ResponseEntity.ok(sourceService.safeUpdateOfAttributes(source, attributes)) + } + + companion object { + private val log = LoggerFactory.getLogger(SubjectResource::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.java b/src/main/java/org/radarbase/management/web/rest/UserResource.java deleted file mode 100644 index 4624b7d75..000000000 --- a/src/main/java/org/radarbase/management/web/rest/UserResource.java +++ /dev/null @@ -1,282 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.repository.filters.UserFilter; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.MailService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.UserService; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.InvalidRequestException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.radarbase.management.web.rest.vm.ManagedUserVM; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import tech.jhipster.web.util.ResponseUtil; - -import java.net.URISyntaxException; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import java.util.Set; - -import static org.radarbase.auth.authorization.Permission.ROLE_READ; -import static org.radarbase.auth.authorization.Permission.ROLE_UPDATE; -import static org.radarbase.auth.authorization.Permission.USER_CREATE; -import static org.radarbase.auth.authorization.Permission.USER_DELETE; -import static org.radarbase.auth.authorization.Permission.USER_READ; -import static org.radarbase.auth.authorization.Permission.USER_UPDATE; -import static org.radarbase.management.web.rest.errors.EntityName.USER; - -/** - * REST controller for managing users. - * - *

This class accesses the User entity, and needs to fetch its collection of authorities.

- * - *

For a normal use-case, it would be better to have an eager relationship between User and - * Authority, and send everything to the client side: there would be no View Model and DTO, a lot - * less code, and an outer-join which would be good for performance.

- * - *

We use a View Model and a DTO for 3 reasons: - *

    - *
  • We want to keep a lazy association between the user and the authorities, because - * people will quite often do relationships with the user, and we don't want them to get the - * authorities all the time for nothing (for performance reasons). This is the #1 goal: we - * should not impact our users' application because of this use-case.
  • - *
  • Not having an outer join causes n+1 requests to the database. This is not a real - * issue as we have by default a second-level cache. This means on the first HTTP call we do - * the n+1 requests, but then all authorities come from the cache, so in fact it's much - * better than doing an outer join (which will get lots of data from the database, for each - * HTTP call).
  • - *
  • As this manages users, for security reasons, we'd rather have a DTO layer.
  • - *
- * - *

Another option would be to have a specific JPA entity graph to handle this case.

- */ -@RestController -@RequestMapping("/api") -public class UserResource { - - private static final Logger log = LoggerFactory.getLogger(UserResource.class); - - @Autowired - private UserRepository userRepository; - - @Autowired - private MailService mailService; - - @Autowired - private UserService userService; - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private ManagementPortalProperties managementPortalProperties; - @Autowired - private AuthService authService; - - /** - * POST /users : Creates a new user.

Creates a new user if the login and email are not - * already used, and sends an mail with an activation link. The user needs to be activated on - * creation.

- * - * @param managedUserVm the user to create - * @return the ResponseEntity with status 201 (Created) and with body the new user, or with - * status 400 (Bad Request) if the login or email is already in use - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PostMapping("/users") - @Timed - public ResponseEntity createUser(@RequestBody ManagedUserVM managedUserVm) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save User : {}", managedUserVm); - authService.checkPermission(USER_CREATE); - if (managedUserVm.getId() != null) { - return ResponseEntity.badRequest() - .headers(HeaderUtil.createFailureAlert(USER, "idexists", - "A new user cannot already have an ID")) - .body(null); - // Lowercase the user login before comparing with database - } else if (userRepository.findOneByLogin(managedUserVm.getLogin().toLowerCase(Locale.ROOT)) - .isPresent()) { - return ResponseEntity.badRequest() - .headers(HeaderUtil - .createFailureAlert(USER, "userexists", - "Login already in use")) - .body(null); - } else if (userRepository.findOneByEmail(managedUserVm.getEmail()).isPresent()) { - return ResponseEntity.badRequest() - .headers(HeaderUtil - .createFailureAlert(USER, "emailexists", - "Email already in use")) - .body(null); - } else { - User newUser = userService.createUser(managedUserVm); - mailService.sendCreationEmail(newUser, managementPortalProperties.getCommon() - .getActivationKeyTimeoutInSeconds()); - return ResponseEntity.created(ResourceUriService.getUri(newUser)) - .headers(HeaderUtil.createAlert("userManagement.created", newUser.getLogin())) - .body(newUser); - } - } - - /** - * PUT /users : Updates an existing User. - * - * @param managedUserVm the user to update - * @return the ResponseEntity with status 200 (OK) and with body the updated user, or with - * status 400 (Bad Request) if the login or email is already in use, or with status 500 - * (Internal Server Error) if the user couldn't be updated - */ - @PutMapping("/users") - @Timed - public ResponseEntity updateUser(@RequestBody ManagedUserVM managedUserVm) - throws NotAuthorizedException { - log.debug("REST request to update User : {}", managedUserVm); - authService.checkPermission(USER_UPDATE, e -> e.user(managedUserVm.getLogin())); - Optional existingUser = userRepository.findOneByEmail(managedUserVm.getEmail()); - if (existingUser.isPresent() && (!existingUser.get().getId() - .equals(managedUserVm.getId()))) { - throw new BadRequestException("Email already in use", USER, "emailexists"); - } - existingUser = userRepository.findOneByLogin(managedUserVm.getLogin() - .toLowerCase(Locale.US)); - if (existingUser.isPresent() && (!existingUser.get().getId() - .equals(managedUserVm.getId()))) { - throw new BadRequestException("Login already in use", USER, "emailexists"); - } - - Optional subject = subjectRepository - .findOneWithEagerBySubjectLogin(managedUserVm.getLogin()); - if (subject.isPresent() && managedUserVm.isActivated() && subject.get().isRemoved()) { - // if the subject is also a user, check if the removed/activated states are valid - throw new InvalidRequestException("Subject cannot be the user to request " - + "this changes", USER, "error.invalidsubjectstate"); - - } - - Optional updatedUser = userService.updateUser( - managedUserVm); - - return ResponseUtil.wrapOrNotFound(updatedUser, - HeaderUtil.createAlert("userManagement.updated", managedUserVm.getLogin())); - } - - /** - * GET /users : get all users. - * - * @param pageable the pagination information - * @param userFilter filter parameters as follows. - * projectName Optional, if specified return only users associated this project - * authority Optional, if specified return only users that have this authority - * login Optional, if specified return only users that have this login - * email Optional, if specified return only users that have this email - * @return the ResponseEntity with status 200 (OK) and with body all users - */ - @GetMapping("/users") - @Timed - public ResponseEntity> getUsers( - @PageableDefault(page = 0, size = Integer.MAX_VALUE) Pageable pageable, - UserFilter userFilter, - @RequestParam(defaultValue = "true") boolean includeProvenance) - throws NotAuthorizedException { - authService.checkPermission(USER_READ); - - Page page = userService.findUsers(userFilter, pageable, includeProvenance); - - return new ResponseEntity<>(page.getContent(), - PaginationUtil.generatePaginationHttpHeaders(page, "/api/users"), HttpStatus.OK); - } - - /** - * GET /users/:login : get the "login" user. - * - * @param login the login of the user to find - * @return the ResponseEntity with status 200 (OK) and with body the "login" user, or with - * status 404 (Not Found) - */ - @GetMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity getUser(@PathVariable String login) - throws NotAuthorizedException { - log.debug("REST request to get User : {}", login); - authService.checkPermission(USER_READ, e -> e.user(login)); - return ResponseUtil.wrapOrNotFound( - userService.getUserWithAuthoritiesByLogin(login)); - } - - /** - * DELETE /users/:login : delete the "login" User. - * - * @param login the login of the user to delete - * @return the ResponseEntity with status 200 (OK) - */ - @DeleteMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity deleteUser(@PathVariable String login) - throws NotAuthorizedException { - log.debug("REST request to delete User: {}", login); - authService.checkPermission(USER_DELETE, e -> e.user(login)); - userService.deleteUser(login); - return ResponseEntity.ok().headers(HeaderUtil.createAlert("userManagement.deleted", login)) - .build(); - } - - /** - * Get /users/:login/roles : get the "login" User roles. - * - * @param login the login of the user to get roles from - * @return the ResponseEntity with status 200 (OK) - */ - @GetMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}/roles") - @Timed - public ResponseEntity> getUserRoles(@PathVariable String login) - throws NotAuthorizedException { - log.debug("REST request to read User roles: {}", login); - authService.checkPermission(ROLE_READ, e -> e.user(login)); - return ResponseUtil.wrapOrNotFound(userService.getUserWithAuthoritiesByLogin(login) - .map(UserDTO::getRoles)); - } - - /** - * PUT /users/:login/roles : update the "login" User roles. - * - * @param login the login of the user to get roles from - * @return the ResponseEntity with status 200 (OK) - */ - @PutMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}/roles") - @Timed - public ResponseEntity putUserRoles(@PathVariable String login, - @RequestBody Set roleDtos) throws NotAuthorizedException { - log.debug("REST request to update User roles: {} to {}", login, roleDtos); - authService.checkPermission(ROLE_UPDATE, e -> e.user(login)); - userService.updateRoles(login, roleDtos); - return ResponseEntity.noContent().build(); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.kt b/src/main/java/org/radarbase/management/web/rest/UserResource.kt new file mode 100644 index 000000000..bae3ea2e4 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/UserResource.kt @@ -0,0 +1,280 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.User +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.repository.filters.UserFilter +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.MailService +import org.radarbase.management.service.ResourceUriService +import org.radarbase.management.service.UserService +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.InvalidRequestException +import org.radarbase.management.web.rest.util.HeaderUtil +import org.radarbase.management.web.rest.util.PaginationUtil +import org.radarbase.management.web.rest.vm.ManagedUserVM +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Pageable +import org.springframework.data.web.PageableDefault +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.net.URISyntaxException +import java.util.* + +/** + * REST controller for managing users. + * + * + * This class accesses the User entity, and needs to fetch its collection of authorities. + * + * + * For a normal use-case, it would be better to have an eager relationship between User and + * Authority, and send everything to the client side: there would be no View Model and DTO, a lot + * less code, and an outer-join which would be good for performance. + * + * + * We use a View Model and a DTO for 3 reasons: + * + * * We want to keep a lazy association between the user and the authorities, because + * people will quite often do relationships with the user, and we don't want them to get the + * authorities all the time for nothing (for performance reasons). This is the #1 goal: we + * should not impact our users' application because of this use-case. + * * Not having an outer join causes n+1 requests to the database. This is not a real + * issue as we have by default a second-level cache. This means on the first HTTP call we do + * the n+1 requests, but then all authorities come from the cache, so in fact it's much + * better than doing an outer join (which will get lots of data from the database, for each + * HTTP call). + * * As this manages users, for security reasons, we'd rather have a DTO layer. + * + * + * + * Another option would be to have a specific JPA entity graph to handle this case. + */ +@RestController +@RequestMapping("/api") +class UserResource( + @Autowired private val userRepository: UserRepository, + @Autowired private val mailService: MailService, + @Autowired private val userService: UserService, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val managementPortalProperties: ManagementPortalProperties, + @Autowired private val authService: AuthService +) { + + /** + * POST /users : Creates a new user. + * + * Creates a new user if the login and email are not + * already used, and sends an mail with an activation link. The user needs to be activated on + * creation. + * + * @param managedUserVm the user to create + * @return the ResponseEntity with status 201 (Created) and with body the new user, or with + * status 400 (Bad Request) if the login or email is already in use + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/users") + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createUser(@RequestBody managedUserVm: ManagedUserVM): ResponseEntity { + log.debug("REST request to save User : {}", managedUserVm) + authService.checkPermission(Permission.USER_CREATE) + return if (managedUserVm.id != null) { + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + EntityName.USER, "idexists", "A new user cannot already have an ID" + ) + ).body(null) + // Lowercase the user login before comparing with database + } else if (userRepository.findOneByLogin(managedUserVm.login.lowercase()).isPresent) { + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + EntityName.USER, "userexists", "Login already in use" + ) + ).body(null) + } else if (userRepository.findOneByEmail(managedUserVm.email).isPresent) { + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + EntityName.USER, "emailexists", "Email already in use" + ) + ).body(null) + } else { + val newUser = userService.createUser(managedUserVm) + mailService.sendCreationEmail( + newUser, managementPortalProperties.common.activationKeyTimeoutInSeconds.toLong() + ) + ResponseEntity.created(ResourceUriService.getUri(newUser)).headers( + HeaderUtil.createAlert( + "userManagement.created", newUser.login + ) + ).body(newUser) + } + } + + /** + * PUT /users : Updates an existing User. + * + * @param managedUserVm the user to update + * @return the ResponseEntity with status 200 (OK) and with body the updated user, or with + * status 400 (Bad Request) if the login or email is already in use, or with status 500 + * (Internal Server Error) if the user couldn't be updated + */ + @PutMapping("/users") + @Timed + @Throws(NotAuthorizedException::class) + fun updateUser(@RequestBody managedUserVm: ManagedUserVM): ResponseEntity { + log.debug("REST request to update User : {}", managedUserVm) + authService.checkPermission(Permission.USER_UPDATE, { e: EntityDetails -> e.user(managedUserVm.login) }) + var existingUser = userRepository.findOneByEmail(managedUserVm.email) + if (existingUser.isPresent && existingUser.get().id != managedUserVm.id) { + throw BadRequestException("Email already in use", EntityName.USER, "emailexists") + } + existingUser = userRepository.findOneByLogin( + managedUserVm.login.lowercase() + ) + if (existingUser.isPresent && existingUser.get().id != managedUserVm.id) { + throw BadRequestException("Login already in use", EntityName.USER, "emailexists") + } + val subject = subjectRepository.findOneWithEagerBySubjectLogin(managedUserVm.login) + if (subject.isPresent && managedUserVm.isActivated && subject.get().isRemoved!!) { + // if the subject is also a user, check if the removed/activated states are valid + throw InvalidRequestException( + "Subject cannot be the user to request " + "this changes", EntityName.USER, "error.invalidsubjectstate" + ) + } + val updatedUser: UserDTO? = userService.updateUser( + managedUserVm + ) + return ResponseEntity.ok().headers( + HeaderUtil.createAlert("userManagement.updated", managedUserVm.login) + ).body( + updatedUser + ) + } + + /** + * GET /users : get all users. + * + * @param pageable the pagination information + * @param userFilter filter parameters as follows. + * projectName Optional, if specified return only users associated this project + * authority Optional, if specified return only users that have this authority + * login Optional, if specified return only users that have this login + * email Optional, if specified return only users that have this email + * @return the ResponseEntity with status 200 (OK) and with body all users + */ + @GetMapping("/users") + @Timed + @Throws(NotAuthorizedException::class) + fun getUsers( + @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable?, + userFilter: UserFilter?, + @RequestParam(defaultValue = "true") includeProvenance: Boolean + ): ResponseEntity> { + authService.checkPermission(Permission.USER_READ) + val page = userService.findUsers(userFilter!!, pageable, includeProvenance) + return ResponseEntity( + page!!.content, PaginationUtil.generatePaginationHttpHeaders(page, "/api/users"), HttpStatus.OK + ) + } + + /** + * GET /users/:login : get the "login" user. + * + * @param login the login of the user to find + * @return the ResponseEntity with status 200 (OK) and with body the "login" user, or with + * status 404 (Not Found) + */ + @GetMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getUser(@PathVariable login: String?): ResponseEntity { + log.debug("REST request to get User : {}", login) + authService.checkPermission(Permission.USER_READ, { e: EntityDetails -> e.user(login) }) + return ResponseUtil.wrapOrNotFound( + userService.getUserWithAuthoritiesByLogin(login) + ) + } + + /** + * DELETE /users/:login : delete the "login" User. + * + * @param login the login of the user to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun deleteUser(@PathVariable login: String?): ResponseEntity { + log.debug("REST request to delete User: {}", login) + authService.checkPermission(Permission.USER_DELETE, { e: EntityDetails -> e.user(login) }) + userService.deleteUser(login) + return ResponseEntity.ok().headers(HeaderUtil.createAlert("userManagement.deleted", login)).build() + } + + /** + * Get /users/:login/roles : get the "login" User roles. + * + * @param login the login of the user to get roles from + * @return the ResponseEntity with status 200 (OK) + */ + @GetMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}/roles") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getUserRoles(@PathVariable login: String?): ResponseEntity> { + log.debug("REST request to read User roles: {}", login) + authService.checkPermission(Permission.ROLE_READ, { e: EntityDetails -> e.user(login) }) + return ResponseUtil.wrapOrNotFound(userService.getUserWithAuthoritiesByLogin(login) + .map { obj: UserDTO -> obj.roles }) + } + + /** + * PUT /users/:login/roles : update the "login" User roles. + * + * @param login the login of the user to get roles from + * @return the ResponseEntity with status 200 (OK) + */ + @PutMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}/roles") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun putUserRoles( + @PathVariable login: String?, @RequestBody roleDtos: Set? + ): ResponseEntity { + log.debug("REST request to update User roles: {} to {}", login, roleDtos) + authService.checkPermission(Permission.ROLE_UPDATE, { e: EntityDetails -> e.user(login) }) + userService.updateRoles(login!!, roleDtos) + return ResponseEntity.noContent().build() + } + + companion object { + private val log = LoggerFactory.getLogger(UserResource::class.java) + } +} diff --git a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.java b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.java index 740c59b65..2d2b3ca52 100644 --- a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.java +++ b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.java @@ -154,7 +154,7 @@ private static User createAdminUser() { User user = new User(); user.setId(1L); user.setLogin("admin"); - user.setActivated(true); + user.activated = true; user.setRoles(Set.of( new Role(new Authority("ROLE_SYS_ADMIN")) )); diff --git a/src/test/java/org/radarbase/management/service/UserServiceIntTest.java b/src/test/java/org/radarbase/management/service/UserServiceIntTest.java index f4fa5bc1f..263abfa37 100644 --- a/src/test/java/org/radarbase/management/service/UserServiceIntTest.java +++ b/src/test/java/org/radarbase/management/service/UserServiceIntTest.java @@ -116,12 +116,12 @@ public void setUp() { public static User createEntity(PasswordService passwordService) { User user = new User(); user.setLogin(DEFAULT_LOGIN); - user.setPassword(passwordService.generateEncodedPassword()); - user.setActivated(true); - user.setEmail(DEFAULT_EMAIL); - user.setFirstName(DEFAULT_FIRSTNAME); - user.setLastName(DEFAULT_LASTNAME); - user.setLangKey(DEFAULT_LANGKEY); + user.password = passwordService.generateEncodedPassword(); + user.activated = true; + user.email = DEFAULT_EMAIL; + user.firstName = DEFAULT_FIRSTNAME; + user.lastName = DEFAULT_LASTNAME; + user.langKey = DEFAULT_LANGKEY; return user; } @@ -133,9 +133,9 @@ void assertThatUserMustExistToResetPassword() { maybeUser = userService.requestPasswordReset("admin@localhost"); assertThat(maybeUser).isPresent(); - assertThat(maybeUser.get().getEmail()).isEqualTo("admin@localhost"); - assertThat(maybeUser.get().getResetDate()).isNotNull(); - assertThat(maybeUser.get().getResetKey()).isNotNull(); + assertThat(maybeUser.get().email).isEqualTo("admin@localhost"); + assertThat(maybeUser.get().resetDate).isNotNull(); + assertThat(maybeUser.get().resetKey).isNotNull(); } @Test @@ -152,14 +152,14 @@ void assertThatResetKeyMustNotBeOlderThan24Hours() throws NotAuthorizedException ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(25); String resetKey = passwordService.generateResetKey(); - user.setActivated(true); - user.setResetDate(daysAgo); - user.setResetKey(resetKey); + user.activated = true; + user.resetDate = daysAgo; + user.resetKey = resetKey; userRepository.save(user); Optional maybeUser = userService.completePasswordReset("johndoe2", - user.getResetKey()); + user.resetKey); assertThat(maybeUser).isNotPresent(); @@ -170,12 +170,12 @@ void assertThatResetKeyMustNotBeOlderThan24Hours() throws NotAuthorizedException void assertThatResetKeyMustBeValid() throws NotAuthorizedException { User user = userService.createUser(userDto); ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(25); - user.setActivated(true); - user.setResetDate(daysAgo); - user.setResetKey("1234"); + user.activated = true; + user.resetDate = daysAgo; + user.resetKey = "1234"; userRepository.save(user); Optional maybeUser = userService.completePasswordReset("johndoe2", - user.getResetKey()); + user.resetKey); assertThat(maybeUser).isNotPresent(); userRepository.delete(user); } @@ -183,19 +183,19 @@ void assertThatResetKeyMustBeValid() throws NotAuthorizedException { @Test void assertThatUserCanResetPassword() throws NotAuthorizedException { User user = userService.createUser(userDto); - final String oldPassword = user.getPassword(); + final String oldPassword = user.password; ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(2); String resetKey = passwordService.generateResetKey(); - user.setActivated(true); - user.setResetDate(daysAgo); - user.setResetKey(resetKey); + user.activated = true; + user.resetDate = daysAgo; + user.resetKey = resetKey; userRepository.save(user); Optional maybeUser = userService.completePasswordReset("johndoe2", - user.getResetKey()); + user.resetKey); assertThat(maybeUser).isPresent(); - assertThat(maybeUser.get().getResetDate()).isNull(); - assertThat(maybeUser.get().getResetKey()).isNull(); - assertThat(maybeUser.get().getPassword()).isNotEqualTo(oldPassword); + assertThat(maybeUser.get().resetDate).isNull(); + assertThat(maybeUser.get().resetKey).isNull(); + assertThat(maybeUser.get().password).isNotEqualTo(oldPassword); userRepository.delete(user); } @@ -216,12 +216,12 @@ void testFindNotActivatedUsersByCreationDateBefore() { .computeAggregationInInstanceContext()) .getSingleResult(); CustomRevisionEntity first = (CustomRevisionEntity) firstRevision[1]; - first.setTimestamp(Date.from(expDateTime.toInstant())); + first.timestamp = Date.from(expDateTime.toInstant()); entityManager.joinTransaction(); CustomRevisionEntity updated = entityManager.merge(first); commitTransactionAndStartNew(); - assertThat(updated.getTimestamp()).isEqualTo(first.getTimestamp()); - assertThat(updated.getTimestamp()).isEqualTo(Date.from(expDateTime.toInstant())); + assertThat(updated.timestamp).isEqualTo(first.timestamp); + assertThat(updated.timestamp).isEqualTo(Date.from(expDateTime.toInstant())); // make sure when we reload the expired user we have the new created date assertThat(revisionService.getAuditInfo(expiredUser).getCreatedAt()).isEqualTo(expDateTime); @@ -234,7 +234,7 @@ void testFindNotActivatedUsersByCreationDateBefore() { assertThat(numUsers - users.size()).isEqualTo(1); // remaining users should be either activated or have a created date less then 3 days ago ZonedDateTime cutoff = ZonedDateTime.now().minus(Period.ofDays(3)); - users.forEach(u -> assertThat(u.getActivated() || revisionService.getAuditInfo(u) + users.forEach(u -> assertThat(u.activated || revisionService.getAuditInfo(u) .getCreatedAt().isAfter(cutoff)).isTrue()); // commit the deletion, otherwise the deletion will be rolled back commitTransactionAndStartNew(); @@ -259,17 +259,17 @@ public User addExpiredUser(UserRepository userRepository) { Role adminRole = new Role(); adminRole.setId(1L); - adminRole.setAuthority(new Authority(SYS_ADMIN)); - adminRole.setProject(null); + adminRole.authority = new Authority(SYS_ADMIN); + adminRole.project = null; User user = new User(); user.setLogin("expired"); - user.setEmail("expired@expired"); - user.setFirstName("ex"); - user.setLastName("pired"); + user.email = "expired@expired"; + user.firstName = "ex"; + user.lastName = "pired"; user.setRoles(Collections.singleton(adminRole)); - user.setActivated(false); - user.setPassword(passwordService.generateEncodedPassword()); + user.activated = false; + user.password = passwordService.generateEncodedPassword(); return userRepository.save(user); } diff --git a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.java index 64fe2e69e..ae1ea69eb 100644 --- a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.java @@ -128,16 +128,16 @@ void testAuthenticatedUser() throws Exception { Set roles = new HashSet<>(); org.radarbase.management.domain.Role role = new org.radarbase.management.domain.Role(); Authority authority = new Authority(); - authority.setName(RoleAuthority.SYS_ADMIN.getAuthority()); - role.setAuthority(authority); + authority.name = RoleAuthority.SYS_ADMIN.getAuthority(); + role.authority = authority; roles.add(role); User user = new User(); user.setLogin("test"); - user.setFirstName("john"); - user.setLastName("doe"); - user.setEmail("john.doe@jhipster.com"); - user.setLangKey("en"); + user.firstName = "john"; + user.lastName = "doe"; + user.email = "john.doe@jhipster.com"; + user.langKey = "en"; user.setRoles(roles); when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.of(user)); @@ -164,16 +164,16 @@ void testGetExistingAccount() throws Exception { Set roles = new HashSet<>(); org.radarbase.management.domain.Role role = new org.radarbase.management.domain.Role(); Authority authority = new Authority(); - authority.setName(RoleAuthority.SYS_ADMIN.getAuthority()); - role.setAuthority(authority); + authority.name = RoleAuthority.SYS_ADMIN.getAuthority(); + role.authority = authority; roles.add(role); User user = new User(); user.setLogin("test"); - user.setFirstName("john"); - user.setLastName("doe"); - user.setEmail("john.doe@jhipster.com"); - user.setLangKey("en"); + user.firstName = "john"; + user.lastName = "doe"; + user.email = "john.doe@jhipster.com"; + user.langKey = "en"; user.setRoles(roles); when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.of(user)); diff --git a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.java index eed2114c7..c36f509e1 100644 --- a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.java @@ -95,9 +95,9 @@ public void setUp() throws ServletException { public void initTest() { auditEventRepository.deleteAll(); auditEvent = new PersistentAuditEvent(); - auditEvent.setAuditEventType(SAMPLE_TYPE); - auditEvent.setPrincipal(SAMPLE_PRINCIPAL); - auditEvent.setAuditEventDate(SAMPLE_TIMESTAMP); + auditEvent.auditEventType = SAMPLE_TYPE; + auditEvent.principal = SAMPLE_PRINCIPAL; + auditEvent.auditEventDate = SAMPLE_TIMESTAMP; } @Test @@ -118,7 +118,7 @@ void getAudit() throws Exception { auditEventRepository.save(auditEvent); // Get the audit - restAuditMockMvc.perform(get("/management/audits/{id}", auditEvent.getId())) + restAuditMockMvc.perform(get("/management/audits/{id}", auditEvent.id)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.principal").value(SAMPLE_PRINCIPAL)); diff --git a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.java index db4c03fae..31be75902 100644 --- a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.java @@ -127,7 +127,7 @@ public void setUp() throws ServletException { @AfterEach public void tearDown() { groupRepository.delete(group); - var roles = roleRepository.findAllRolesByProjectName(project.getProjectName()); + var roles = roleRepository.findAllRolesByProjectName(project.projectName); roleRepository.deleteAll(roles); projectRepository.delete(project); } @@ -137,8 +137,8 @@ public void tearDown() { */ private Group createEntity() { Group group = new Group(); - group.setName("group1"); - group.setProject(project); + group.name = "group1"; + group.project = project; return group; } @@ -147,17 +147,17 @@ void createGroup() throws Exception { // Create the Group var groupDto = groupMapper.groupToGroupDTO(group); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.getProjectName()) + project.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(groupDto))) .andExpect(status().isCreated()); var savedGroup = groupRepository.findByProjectNameAndName( - project.getProjectName(), groupDto.getName()).get(); + project.projectName, groupDto.getName()).get(); // Validate the Group in the database - assertThat(savedGroup.getProject().getId()).isEqualTo(project.getId()); - assertThat(savedGroup.getName()).isEqualTo("group1"); + assertThat(savedGroup.project.getId()).isEqualTo(project.getId()); + assertThat(savedGroup.name).isEqualTo("group1"); } @@ -168,7 +168,7 @@ void createGroupNonExistingProject() throws Exception { // Create the Group var groupDto = groupMapper.groupToGroupDTO(group); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.getProjectName()) + project.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(groupDto))) .andExpect(status().isNotFound()); @@ -179,13 +179,13 @@ void createGroupWithExistingName() throws Exception { // Create the Group var groupDto = groupMapper.groupToGroupDTO(group); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.getProjectName()) + project.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(groupDto))) .andExpect(status().isCreated()); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.getProjectName()) + project.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(groupDto))) .andExpect(status().isConflict()); @@ -195,53 +195,53 @@ void createGroupWithExistingName() throws Exception { @Test void createGroupWithExistingNameInDifferentProject() throws Exception { Project project2 = ProjectResourceIntTest.createEntity() - .projectName(project.getProjectName() + "2"); + .projectName(project.projectName + "2"); projectRepository.saveAndFlush(project2); Group group2 = new Group(); - group2.setName(group.getName()); - group2.setProject(project2); + group2.name = group.name; + group2.project = project2; // Create the Group var groupDto = groupMapper.groupToGroupDTO(group); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.getProjectName()) + project.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(groupDto))) .andExpect(status().isCreated()); var group2Dto = groupMapper.groupToGroupDTO(group2); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project2.getProjectName()) + project2.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(group2Dto))) .andExpect(status().isCreated()); // Validate groups are saved for both projects var savedGroup1 = groupRepository.findByProjectNameAndName( - project.getProjectName(), group.getName()).get(); + project.projectName, group.name).get(); var savedGroup2 = groupRepository.findByProjectNameAndName( - project2.getProjectName(), group2.getName()).get(); + project2.projectName, group2.name).get(); var groupList = Arrays.asList(savedGroup1, savedGroup2); assertThat(groupList).hasSize(2); assertThat(groupList).haveAtLeastOne(new Condition<>( - g -> project.getId().equals(g.getProject().getId()), "use project 1")); + g -> project.getId().equals(g.project.getId()), "use project 1")); assertThat(groupList).haveAtLeastOne(new Condition<>( - g -> project2.getId().equals(g.getProject().getId()), "use project 2")); + g -> project2.getId().equals(g.project.getId()), "use project 2")); assertThat(groupList).allSatisfy( - g -> assertThat(g.getName()).isEqualTo(group.getName())); + g -> assertThat(g.name).isEqualTo(group.name)); projectRepository.delete(project2); } @Test void checkGroupNameIsRequired() throws Exception { - group.setName(null); + group.name = null; // Create the Group GroupDTO groupDto = groupMapper.groupToGroupDTO(group); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.getProjectName()) + project.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(groupDto))) .andExpect(status().isBadRequest()); @@ -254,7 +254,7 @@ void getAllGroups() throws Exception { // Get all the groups restGroupMockMvc.perform(get("/api/projects/{projectName}/groups", - project.getProjectName())) + project.projectName)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.[*].projectId").value( @@ -269,7 +269,7 @@ void getGroup() throws Exception { // Get the Group restGroupMockMvc.perform(get("/api/projects/{projectName}/groups/{groupName}", - project.getProjectName(), group.getName())) + project.projectName, group.name)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.name").value("group1")) @@ -280,7 +280,7 @@ void getGroup() throws Exception { void getNonExistingGroup() throws Exception { // Get the Group restGroupMockMvc.perform(get("/api/projects/{projectName}/groups/{groupName}", - project.getProjectName(), group.getName())) + project.projectName, group.name)) .andExpect(status().isNotFound()); } @@ -292,13 +292,13 @@ void deleteGroup() throws Exception { // Get the Group restGroupMockMvc.perform(delete( "/api/projects/{projectName}/groups/{groupName}", - project.getProjectName(), group.getName()) + project.projectName, group.name) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isNoContent()); // Validate the Group is not present in the database var savedGroup = groupRepository.findByProjectNameAndName( - project.getProjectName(), group.getName()); + project.projectName, group.name); assertThat(savedGroup).isEmpty(); } @@ -314,27 +314,27 @@ void deleteGroupWithSubjects() throws Exception { subjectDto.setExternalId("exId1"); subjectDto.setStatus(ACTIVATED); subjectDto.setProject(projectDto); - subjectDto.setGroup(group.getName()); + subjectDto.setGroup(group.name); var savedSubject = subjectService.createSubject(subjectDto); // Try to delete the Group (and fail) restGroupMockMvc.perform(delete( "/api/projects/{projectName}/groups/{groupName}", - project.getProjectName(), group.getName()) + project.projectName, group.name) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isConflict()); // Delete the Group (and unlink the subjects) restGroupMockMvc.perform(delete( "/api/projects/{projectName}/groups/{groupName}", - project.getProjectName(), group.getName()) + project.projectName, group.name) .param("unlinkSubjects", "true") .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isNoContent()); // Validate the Group is not present in the database var savedGroup = groupRepository.findByProjectNameAndName( - project.getProjectName(), group.getName()); + project.projectName, group.name); assertThat(savedGroup).isEmpty(); var storedSubject = subjectRepository.getOne(savedSubject.getId()); @@ -349,7 +349,7 @@ void deleteGroupNonExisting() throws Exception { // Get the Group restGroupMockMvc.perform(delete( "/api/projects/{projectName}/groups/{groupName}", - project.getProjectName(), group.getName() + "2") + project.projectName, group.name + "2") .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isNotFound()); @@ -366,7 +366,7 @@ void deleteGroupNonExistingProject() throws Exception { // Get the Group restGroupMockMvc.perform(delete( "/api/projects/{projectName}/groups/{groupName}", - project.getProjectName() + "2", group.getName()) + project.projectName + "2", group.name) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isNotFound()); @@ -414,7 +414,7 @@ void addSubjectsToGroup() throws Exception { // Get the Group restGroupMockMvc.perform(patch( "/api/projects/{projectName}/groups/{groupName}/subjects", - project.getProjectName(), group.getName()) + project.projectName, group.name) .contentType(TestUtil.APPLICATION_JSON_PATCH) .content(TestUtil.convertObjectToJsonBytes(body))) @@ -425,7 +425,7 @@ void addSubjectsToGroup() throws Exception { var subjects = subjectRepository.findAllBySubjectLogins(subjectLogins); assertThat(subjects).hasSize(2); assertThat(subjects).allSatisfy( - s -> assertThat(s.getGroup().getId()).isEqualTo(group.getId())); + s -> assertThat(s.group.getId()).isEqualTo(group.getId())); subjectRepository.deleteAll(subjects); } diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.java index a2f4d9ce4..34d847382 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.java @@ -96,7 +96,7 @@ public void setUp() throws ServletException { @AfterEach public void tearDown() { - var testOrg = organizationRepository.findOneByName(organization.getName()); + var testOrg = organizationRepository.findOneByName(organization.name); testOrg.ifPresent(organizationRepository::delete); } @@ -105,9 +105,9 @@ public void tearDown() { */ private Organization createEntity() { var org = new Organization(); - org.setName("org1"); - org.setDescription("Test Organization 1"); - org.setLocation("Somewhere"); + org.name = "org1"; + org.description = "Test Organization 1"; + org.location = "Somewhere"; return org; } @@ -168,7 +168,7 @@ void getOrganization() throws Exception { // Get the organization restOrganizationMockMvc.perform(get("/api/organizations/{name}", - organization.getName())) + organization.name)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.name").value("org1")); @@ -191,7 +191,7 @@ void editOrganization() throws Exception { // Get the organization restOrganizationMockMvc.perform(get("/api/organizations/{name}", - organization.getName())) + organization.name)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.location").value("Other location")); @@ -201,7 +201,7 @@ void editOrganization() throws Exception { void getNonExistingOrganization() throws Exception { // Get the organization restOrganizationMockMvc.perform(get("/api/organizations/{name}", - organization.getName())) + organization.name)) .andExpect(status().isNotFound()); } @@ -217,7 +217,7 @@ void getProjectsByOrganizationName() throws Exception { // Get projects of the organization restOrganizationMockMvc.perform(get("/api/organizations/{name}/projects", - organization.getName())) + organization.name)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.[*].projectName").value("organization_project")); diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.java index 36767833b..e62a5007e 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.java @@ -139,7 +139,7 @@ public void setUp() throws ServletException { public static Project createEntity() { Organization organization = new Organization(); organization.setId(1L); - organization.setName("main"); + organization.name = "main"; return new Project() .projectName(DEFAULT_PROJECT_NAME) .description(DEFAULT_DESCRIPTION) @@ -172,13 +172,13 @@ void createProject() throws Exception { List projectList = projectRepository.findAll(); assertThat(projectList).hasSize(databaseSizeBeforeCreate + 1); Project testProject = projectList.get(projectList.size() - 1); - assertThat(testProject.getProjectName()).isEqualTo(DEFAULT_PROJECT_NAME); - assertThat(testProject.getDescription()).isEqualTo(DEFAULT_DESCRIPTION); - assertThat(testProject.getOrganizationName()).isEqualTo(DEFAULT_ORGANIZATION); - assertThat(testProject.getLocation()).isEqualTo(DEFAULT_LOCATION); - assertThat(testProject.getStartDate()).isEqualTo(DEFAULT_START_DATE); - assertThat(testProject.getProjectStatus()).isEqualTo(DEFAULT_PROJECT_STATUS); - assertThat(testProject.getEndDate()).isEqualTo(DEFAULT_END_DATE); + assertThat(testProject.projectName).isEqualTo(DEFAULT_PROJECT_NAME); + assertThat(testProject.description).isEqualTo(DEFAULT_DESCRIPTION); + assertThat(testProject.organizationName).isEqualTo(DEFAULT_ORGANIZATION); + assertThat(testProject.location).isEqualTo(DEFAULT_LOCATION); + assertThat(testProject.startDate).isEqualTo(DEFAULT_START_DATE); + assertThat(testProject.projectStatus).isEqualTo(DEFAULT_PROJECT_STATUS); + assertThat(testProject.endDate).isEqualTo(DEFAULT_END_DATE); } @Test @@ -206,7 +206,7 @@ void createProjectWithExistingId() throws Exception { void checkProjectNameIsRequired() throws Exception { int databaseSizeBeforeTest = projectRepository.findAll().size(); // set the field null - project.setProjectName(null); + project.projectName = null; // Create the Project, which fails. ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); @@ -225,7 +225,7 @@ void checkProjectNameIsRequired() throws Exception { void checkDescriptionIsRequired() throws Exception { int databaseSizeBeforeTest = projectRepository.findAll().size(); // set the field null - project.setDescription(null); + project.description = null; // Create the Project, which fails. ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); @@ -244,7 +244,7 @@ void checkDescriptionIsRequired() throws Exception { void checkLocationIsRequired() throws Exception { int databaseSizeBeforeTest = projectRepository.findAll().size(); // set the field null - project.setLocation(null); + project.location = null; // Create the Project, which fails. ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); @@ -287,7 +287,7 @@ void getProject() throws Exception { projectRepository.saveAndFlush(project); // Get the project - restProjectMockMvc.perform(get("/api/projects/{projectName}", project.getProjectName())) + restProjectMockMvc.perform(get("/api/projects/{projectName}", project.projectName)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id").value(project.getId().intValue())) @@ -315,9 +315,9 @@ void updateProject() throws Exception { projectRepository.saveAndFlush(project); var org = new Organization(); - org.setName("org1"); - org.setDescription("Test Organization 1"); - org.setLocation("Somewhere"); + org.name = "org1"; + org.description = "Test Organization 1"; + org.location = "Somewhere"; organizationRepository.saveAndFlush(org); assertThat(org.getId()).isNotNull(); @@ -346,14 +346,14 @@ void updateProject() throws Exception { List projectList = projectRepository.findAll(); assertThat(projectList).hasSize(databaseSizeBeforeUpdate); Project testProject = projectList.get(projectList.size() - 1); - assertThat(testProject.getProjectName()).isEqualTo(UPDATED_PROJECT_NAME); - assertThat(testProject.getDescription()).isEqualTo(UPDATED_DESCRIPTION); - assertThat(testProject.getOrganizationName()).isEqualTo(UPDATED_ORGANIZATION); - assertThat(testProject.getOrganization()).isEqualTo(org); - assertThat(testProject.getLocation()).isEqualTo(UPDATED_LOCATION); - assertThat(testProject.getStartDate()).isEqualTo(UPDATED_START_DATE); - assertThat(testProject.getProjectStatus()).isEqualTo(UPDATED_PROJECT_STATUS); - assertThat(testProject.getEndDate()).isEqualTo(UPDATED_END_DATE); + assertThat(testProject.projectName).isEqualTo(UPDATED_PROJECT_NAME); + assertThat(testProject.description).isEqualTo(UPDATED_DESCRIPTION); + assertThat(testProject.organizationName).isEqualTo(UPDATED_ORGANIZATION); + assertThat(testProject.organization).isEqualTo(org); + assertThat(testProject.location).isEqualTo(UPDATED_LOCATION); + assertThat(testProject.startDate).isEqualTo(UPDATED_START_DATE); + assertThat(testProject.projectStatus).isEqualTo(UPDATED_PROJECT_STATUS); + assertThat(testProject.endDate).isEqualTo(UPDATED_END_DATE); organizationRepository.delete(org); } @@ -385,7 +385,7 @@ void deleteProject() throws Exception { int databaseSizeBeforeDelete = projectRepository.findAll().size(); // Get the project - restProjectMockMvc.perform(delete("/api/projects/{projectName}", project.getProjectName()) + restProjectMockMvc.perform(delete("/api/projects/{projectName}", project.projectName) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isOk()); diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.java index 9b02328c5..0cb98eaa4 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.java @@ -160,14 +160,14 @@ void createSourceData() throws Exception { List sourceDataList = sourceDataRepository.findAll(); assertThat(sourceDataList).hasSize(databaseSizeBeforeCreate + 1); SourceData testSourceData = sourceDataList.get(sourceDataList.size() - 1); - assertThat(testSourceData.getSourceDataType()).isEqualTo(DEFAULT_SOURCE_DATA_TYPE); - assertThat(testSourceData.getSourceDataName()).isEqualTo(DEFAULT_SOURCE_DATA_NAME); - assertThat(testSourceData.getProcessingState()).isEqualTo(DEFAULT_PROCESSING_STATE); - assertThat(testSourceData.getKeySchema()).isEqualTo(DEFAULT_KEY_SCHEMA); - assertThat(testSourceData.getValueSchema()).isEqualTo(DEFAULT_VALUE_SCHEMA); - assertThat(testSourceData.getFrequency()).isEqualTo(DEFAULT_FREQUENCY); - assertThat(testSourceData.getTopic()).isEqualTo(DEFAULT_TOPIC); - assertThat(testSourceData.getUnit()).isEqualTo(DEFAULT_UNTI); + assertThat(testSourceData.sourceDataType).isEqualTo(DEFAULT_SOURCE_DATA_TYPE); + assertThat(testSourceData.sourceDataName).isEqualTo(DEFAULT_SOURCE_DATA_NAME); + assertThat(testSourceData.processingState).isEqualTo(DEFAULT_PROCESSING_STATE); + assertThat(testSourceData.keySchema).isEqualTo(DEFAULT_KEY_SCHEMA); + assertThat(testSourceData.valueSchema).isEqualTo(DEFAULT_VALUE_SCHEMA); + assertThat(testSourceData.frequency).isEqualTo(DEFAULT_FREQUENCY); + assertThat(testSourceData.topic).isEqualTo(DEFAULT_TOPIC); + assertThat(testSourceData.unit).isEqualTo(DEFAULT_UNTI); } @Test @@ -195,7 +195,7 @@ void createSourceDataWithExistingId() throws Exception { void checkSourceDataTypeIsNotRequired() throws Exception { final int databaseSizeBeforeTest = sourceDataRepository.findAll().size(); // set the field null - sourceData.setSourceDataType(null); + sourceData.sourceDataType = null; // Create the SourceData, which fails. SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); @@ -215,8 +215,8 @@ void checkSourceDataTypeIsNotRequired() throws Exception { void checkSourceDataTypeOrTopicIsRequired() throws Exception { final int databaseSizeBeforeTest = sourceDataRepository.findAll().size(); // set the field null - sourceData.setSourceDataType(null); - sourceData.setTopic(null); + sourceData.sourceDataType = null; + sourceData.topic = null; // Create the SourceData, which fails. SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); @@ -285,7 +285,7 @@ void getSourceData() throws Exception { // Get the sourceData restSourceDataMockMvc.perform(get("/api/source-data/{sourceDataName}", - sourceData.getSourceDataName())) + sourceData.sourceDataName)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id").value(sourceData.getId().intValue())) @@ -337,14 +337,14 @@ void updateSourceData() throws Exception { List sourceDataList = sourceDataRepository.findAll(); assertThat(sourceDataList).hasSize(databaseSizeBeforeUpdate); SourceData testSourceData = sourceDataList.get(sourceDataList.size() - 1); - assertThat(testSourceData.getSourceDataType()).isEqualTo(UPDATED_SOURCE_DATA_TYPE); - assertThat(testSourceData.getSourceDataName()).isEqualTo(UPDATED_SOURCE_DATA_NAME); - assertThat(testSourceData.getProcessingState()).isEqualTo(UPDATED_PROCESSING_STATE); - assertThat(testSourceData.getKeySchema()).isEqualTo(UPDATED_KEY_SCHEMA); - assertThat(testSourceData.getValueSchema()).isEqualTo(UPDATED_VALUE_SCHEMA); - assertThat(testSourceData.getTopic()).isEqualTo(UPDATED_TOPIC); - assertThat(testSourceData.getUnit()).isEqualTo(UPDATED_UNIT); - assertThat(testSourceData.getFrequency()).isEqualTo(UPDATED_FREQUENCY); + assertThat(testSourceData.sourceDataType).isEqualTo(UPDATED_SOURCE_DATA_TYPE); + assertThat(testSourceData.sourceDataName).isEqualTo(UPDATED_SOURCE_DATA_NAME); + assertThat(testSourceData.processingState).isEqualTo(UPDATED_PROCESSING_STATE); + assertThat(testSourceData.keySchema).isEqualTo(UPDATED_KEY_SCHEMA); + assertThat(testSourceData.valueSchema).isEqualTo(UPDATED_VALUE_SCHEMA); + assertThat(testSourceData.topic).isEqualTo(UPDATED_TOPIC); + assertThat(testSourceData.unit).isEqualTo(UPDATED_UNIT); + assertThat(testSourceData.frequency).isEqualTo(UPDATED_FREQUENCY); } @Test @@ -375,7 +375,7 @@ void deleteSourceData() throws Exception { // Get the sourceData restSourceDataMockMvc.perform(delete("/api/source-data/{sourceDataName}", - sourceData.getSourceDataName()) + sourceData.sourceDataName) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isOk()); diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.java index 6bdb6c70b..625a7fec8 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.java @@ -139,7 +139,7 @@ public void initTest() { source = createEntity(); List sourceTypeDtos = sourceTypeService.findAll(); assertThat(sourceTypeDtos.size()).isPositive(); - source.setSourceType(sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDtos.get(0))); + source.sourceType = sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDtos.get(0)); project = projectRepository.findById(1L).get(); source.project(project); } @@ -161,8 +161,8 @@ void createSource() throws Exception { assertThat(sourceList).hasSize(databaseSizeBeforeCreate + 1); Source testSource = sourceList.get(sourceList.size() - 1); assertThat(testSource.isAssigned()).isEqualTo(DEFAULT_ASSIGNED); - assertThat(testSource.getSourceName()).isEqualTo(DEFAULT_SOURCE_NAME); - assertThat(testSource.getProject().getProjectName()).isEqualTo(project.getProjectName()); + assertThat(testSource.sourceName).isEqualTo(DEFAULT_SOURCE_NAME); + assertThat(testSource.project.projectName).isEqualTo(project.projectName); } @Test @@ -190,7 +190,7 @@ void createSourceWithExistingId() throws Exception { void checkSourcePhysicalIdIsGenerated() throws Exception { int databaseSizeBeforeTest = sourceRepository.findAll().size(); // set the field null - source.setSourceId(null); + source.sourceId = null; // Create the Source SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(source); @@ -205,13 +205,13 @@ void checkSourcePhysicalIdIsGenerated() throws Exception { // find our created source Source createdSource = sourceList.stream() - .filter(s -> s.getSourceName().equals(DEFAULT_SOURCE_NAME)) + .filter(s -> s.sourceName.equals(DEFAULT_SOURCE_NAME)) .findFirst() .orElse(null); assertThat(createdSource).isNotNull(); // check source id - assertThat(createdSource.getSourceId()).isNotNull(); + assertThat(createdSource.sourceId).isNotNull(); } @Test @@ -256,7 +256,7 @@ void getSource() throws Exception { sourceRepository.saveAndFlush(source); // Get the source - restDeviceMockMvc.perform(get("/api/sources/{sourceName}", source.getSourceName())) + restDeviceMockMvc.perform(get("/api/sources/{sourceName}", source.sourceName)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id").value(source.getId().intValue())) @@ -295,7 +295,7 @@ void updateSource() throws Exception { List sourceList = sourceRepository.findAll(); assertThat(sourceList).hasSize(databaseSizeBeforeUpdate); Source testSource = sourceList.get(sourceList.size() - 1); - assertThat(testSource.getSourceId()).isEqualTo(UPDATED_SOURCE_PHYSICAL_ID); + assertThat(testSource.sourceId).isEqualTo(UPDATED_SOURCE_PHYSICAL_ID); assertThat(testSource.isAssigned()).isEqualTo(UPDATED_ASSIGNED); } @@ -326,7 +326,7 @@ void deleteSource() throws Exception { int databaseSizeBeforeDelete = sourceRepository.findAll().size(); // Get the source - restDeviceMockMvc.perform(delete("/api/sources/{sourceName}", source.getSourceName()) + restDeviceMockMvc.perform(delete("/api/sources/{sourceName}", source.sourceName) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isOk()); diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.java index f11b33b53..73d8864ea 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.java @@ -163,18 +163,18 @@ void createSourceType() throws Exception { List sourceTypeList = sourceTypeRepository.findAll(); assertThat(sourceTypeList).hasSize(databaseSizeBeforeCreate + 1); SourceType testSourceType = sourceTypeList.get(sourceTypeList.size() - 1); - assertThat(testSourceType.getProducer()).isEqualTo(DEFAULT_PRODUCER); - assertThat(testSourceType.getModel()).isEqualTo(DEFAULT_MODEL); - assertThat(testSourceType.getSourceTypeScope()).isEqualTo(DEFAULT_SOURCE_TYPE_SCOPE); - assertThat(testSourceType.getCatalogVersion()).isEqualTo(DEFAULT_DEVICE_VERSION); - assertThat(testSourceType.getSourceData()).hasSize(1); - SourceData testSourceData = testSourceType.getSourceData().iterator().next(); - assertThat(testSourceData.getSourceDataType()).isEqualTo(sourceDataDto.getSourceDataType()); - assertThat(testSourceData.getSourceDataName()).isEqualTo(sourceDataDto.getSourceDataName()); - assertThat(testSourceData.getProcessingState()).isEqualTo( + assertThat(testSourceType.producer).isEqualTo(DEFAULT_PRODUCER); + assertThat(testSourceType.model).isEqualTo(DEFAULT_MODEL); + assertThat(testSourceType.sourceTypeScope).isEqualTo(DEFAULT_SOURCE_TYPE_SCOPE); + assertThat(testSourceType.catalogVersion).isEqualTo(DEFAULT_DEVICE_VERSION); + assertThat(testSourceType.sourceData).hasSize(1); + SourceData testSourceData = testSourceType.sourceData.iterator().next(); + assertThat(testSourceData.sourceDataType).isEqualTo(sourceDataDto.getSourceDataType()); + assertThat(testSourceData.sourceDataName).isEqualTo(sourceDataDto.getSourceDataName()); + assertThat(testSourceData.processingState).isEqualTo( sourceDataDto.getProcessingState()); - assertThat(testSourceData.getKeySchema()).isEqualTo(sourceDataDto.getKeySchema()); - assertThat(testSourceData.getFrequency()).isEqualTo(sourceDataDto.getFrequency()); + assertThat(testSourceData.keySchema).isEqualTo(sourceDataDto.getKeySchema()); + assertThat(testSourceData.frequency).isEqualTo(sourceDataDto.getFrequency()); } @Test @@ -202,7 +202,7 @@ void createSourceTypeWithExistingId() throws Exception { void checkModelIsRequired() throws Exception { int databaseSizeBeforeTest = sourceTypeRepository.findAll().size(); // set the field null - sourceType.setModel(null); + sourceType.model = null; // Create the SourceType, which fails. SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); @@ -221,7 +221,7 @@ void checkModelIsRequired() throws Exception { void checkSourceTypeIsRequired() throws Exception { int databaseSizeBeforeTest = sourceTypeRepository.findAll().size(); // set the field null - sourceType.setSourceTypeScope(null); + sourceType.sourceTypeScope = null; // Create the SourceType, which fails. SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); @@ -300,7 +300,7 @@ void getSourceType() throws Exception { // Get the sourceType restSourceTypeMockMvc.perform(get("/api/source-types/{prodcuer}/{model}/{version}", - sourceType.getProducer(), sourceType.getModel(), sourceType.getCatalogVersion())) + sourceType.producer, sourceType.model, sourceType.catalogVersion)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id").value(sourceType.getId().intValue())) @@ -344,10 +344,10 @@ void updateSourceType() throws Exception { List sourceTypeList = sourceTypeRepository.findAll(); assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate); SourceType testSourceType = sourceTypeList.get(sourceTypeList.size() - 1); - assertThat(testSourceType.getProducer()).isEqualTo(UPDATED_PRODUCER); - assertThat(testSourceType.getModel()).isEqualTo(UPDATED_MODEL); - assertThat(testSourceType.getCatalogVersion()).isEqualTo(UPDATED_DEVICE_VERSION); - assertThat(testSourceType.getSourceTypeScope()).isEqualTo(UPDATED_SOURCE_TYPE_SCOPE); + assertThat(testSourceType.producer).isEqualTo(UPDATED_PRODUCER); + assertThat(testSourceType.model).isEqualTo(UPDATED_MODEL); + assertThat(testSourceType.catalogVersion).isEqualTo(UPDATED_DEVICE_VERSION); + assertThat(testSourceType.sourceTypeScope).isEqualTo(UPDATED_SOURCE_TYPE_SCOPE); } @Test @@ -378,7 +378,7 @@ void deleteSourceType() throws Exception { // Get the sourceType restSourceTypeMockMvc.perform(delete("/api/source-types/{prodcuer}/{model}/{version}", - sourceType.getProducer(), sourceType.getModel(), sourceType.getCatalogVersion()) + sourceType.producer, sourceType.model, sourceType.catalogVersion) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isOk()); diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.java index df305e1df..885cc19f1 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.java @@ -150,10 +150,10 @@ void createSubject() throws Exception { List subjectList = subjectRepository.findAll(); assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); Subject testSubject = subjectList.get(subjectList.size() - 1); - assertThat(testSubject.getExternalLink()).isEqualTo(DEFAULT_EXTERNAL_LINK); - assertThat(testSubject.getExternalId()).isEqualTo(DEFAULT_ENTERNAL_ID); + assertThat(testSubject.externalLink).isEqualTo(DEFAULT_EXTERNAL_LINK); + assertThat(testSubject.externalId).isEqualTo(DEFAULT_ENTERNAL_ID); assertThat(testSubject.isRemoved()).isEqualTo(DEFAULT_REMOVED); - assertEquals(1, testSubject.getUser().getRoles().size()); + assertEquals(1, testSubject.user.roles.size()); } @Test @@ -238,8 +238,8 @@ void updateSubject() throws Exception { List subjectList = subjectRepository.findAll(); assertThat(subjectList).hasSize(databaseSizeBeforeUpdate); Subject testSubject = subjectList.get(subjectList.size() - 1); - assertThat(testSubject.getExternalLink()).isEqualTo(UPDATED_EXTERNAL_LINK); - assertThat(testSubject.getExternalId()).isEqualTo(UPDATED_ENTERNAL_ID); + assertThat(testSubject.externalLink).isEqualTo(UPDATED_EXTERNAL_LINK); + assertThat(testSubject.externalId).isEqualTo(UPDATED_ENTERNAL_ID); assertThat(testSubject.isRemoved()).isEqualTo(UPDATED_REMOVED); } @@ -274,10 +274,10 @@ void updateSubjectWithNewProject() throws Exception { List subjectList = subjectRepository.findAll(); assertThat(subjectList).hasSize(databaseSizeBeforeUpdate); Subject testSubject = subjectList.get(subjectList.size() - 1); - assertThat(testSubject.getExternalLink()).isEqualTo(UPDATED_EXTERNAL_LINK); - assertThat(testSubject.getExternalId()).isEqualTo(UPDATED_ENTERNAL_ID); + assertThat(testSubject.externalLink).isEqualTo(UPDATED_EXTERNAL_LINK); + assertThat(testSubject.externalId).isEqualTo(UPDATED_ENTERNAL_ID); assertThat(testSubject.isRemoved()).isEqualTo(UPDATED_REMOVED); - assertThat(testSubject.getUser().getRoles().size()).isEqualTo(2); + assertThat(testSubject.user.roles.size()).isEqualTo(2); } @Test @@ -340,7 +340,7 @@ void dynamicSourceRegistrationWithId() throws Exception { assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); Subject testSubject = subjectList.get(subjectList.size() - 1); - String subjectLogin = testSubject.getUser().getLogin(); + String subjectLogin = testSubject.user.getLogin(); assertNotNull(subjectLogin); // Create a source description @@ -377,7 +377,7 @@ void dynamicSourceRegistrationWithoutId() throws Exception { assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); Subject testSubject = subjectList.get(subjectList.size() - 1); - String subjectLogin = testSubject.getUser().getLogin(); + String subjectLogin = testSubject.user.getLogin(); assertNotNull(subjectLogin); // Create a source description @@ -422,7 +422,7 @@ void dynamicSourceRegistrationWithoutDynamicRegistrationFlag() throws Exception assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); Subject testSubject = subjectList.get(subjectList.size() - 1); - String subjectLogin = testSubject.getUser().getLogin(); + String subjectLogin = testSubject.user.getLogin(); assertNotNull(subjectLogin); // Create a source description @@ -602,7 +602,7 @@ void testDynamicRegistrationAndUpdateSourceAttributes() throws Exception { assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); Subject testSubject = subjectList.get(subjectList.size() - 1); - String subjectLogin = testSubject.getUser().getLogin(); + String subjectLogin = testSubject.user.getLogin(); assertNotNull(subjectLogin); // Create a source description diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.java index 32398df8e..dbe5abfe3 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.java @@ -161,7 +161,7 @@ public void initTest() { .ifPresent(userRepository::delete); var roles = roleRepository .findRolesByAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()) - .stream().filter(r -> r.getProject() == null) + .stream().filter(r -> r.project == null) .collect(Collectors.toList()); roleRepository.deleteAll(roles); } @@ -189,10 +189,10 @@ void createUser() throws Exception { assertThat(userList).hasSize(databaseSizeBeforeCreate + 1); User testUser = userList.get(userList.size() - 1); assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN); - assertThat(testUser.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME); - assertThat(testUser.getLastName()).isEqualTo(DEFAULT_LASTNAME); - assertThat(testUser.getEmail()).isEqualTo(DEFAULT_EMAIL); - assertThat(testUser.getLangKey()).isEqualTo(DEFAULT_LANGKEY); + assertThat(testUser.firstName).isEqualTo(DEFAULT_FIRSTNAME); + assertThat(testUser.lastName).isEqualTo(DEFAULT_LASTNAME); + assertThat(testUser.email).isEqualTo(DEFAULT_EMAIL); + assertThat(testUser.langKey).isEqualTo(DEFAULT_LANGKEY); } @Test @@ -275,17 +275,17 @@ void getAllUsers() throws Exception { // Initialize the database org.radarbase.management.domain.Role adminRole = new org.radarbase.management.domain.Role(); adminRole.setId(1L); - adminRole.setAuthority(new Authority(SYS_ADMIN)); - adminRole.setProject(null); + adminRole.authority = new Authority(SYS_ADMIN); + adminRole.project = null; User userWithRole = new User(); userWithRole.setLogin(DEFAULT_LOGIN); - userWithRole.setPassword(passwordService.generateEncodedPassword()); - userWithRole.setActivated(true); - userWithRole.setEmail(DEFAULT_EMAIL); - userWithRole.setFirstName(DEFAULT_FIRSTNAME); - userWithRole.setLastName(DEFAULT_LASTNAME); - userWithRole.setLangKey(DEFAULT_LANGKEY); + userWithRole.password = passwordService.generateEncodedPassword(); + userWithRole.activated = true; + userWithRole.email = DEFAULT_EMAIL; + userWithRole.firstName = DEFAULT_FIRSTNAME; + userWithRole.lastName = DEFAULT_LASTNAME; + userWithRole.langKey = DEFAULT_LANGKEY; userWithRole.setRoles(Collections.singleton(adminRole)); userRepository.saveAndFlush(userWithRole); @@ -345,7 +345,7 @@ void updateUser() throws Exception { managedUserVm.setFirstName(UPDATED_FIRSTNAME); managedUserVm.setLastName(UPDATED_LASTNAME); managedUserVm.setEmail(UPDATED_EMAIL); - managedUserVm.setActivated(updatedUser.getActivated()); + managedUserVm.setActivated(updatedUser.activated); managedUserVm.setLangKey(UPDATED_LANGKEY); RoleDTO role = new RoleDTO(); @@ -362,10 +362,10 @@ void updateUser() throws Exception { List userList = userRepository.findAll(); assertThat(userList).hasSize(databaseSizeBeforeUpdate); User testUser = userList.get(userList.size() - 1); - assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); - assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); - assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); - assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY); + assertThat(testUser.firstName).isEqualTo(UPDATED_FIRSTNAME); + assertThat(testUser.lastName).isEqualTo(UPDATED_LASTNAME); + assertThat(testUser.email).isEqualTo(UPDATED_EMAIL); + assertThat(testUser.langKey).isEqualTo(UPDATED_LANGKEY); } @Test @@ -389,7 +389,7 @@ void updateUserLogin() throws Exception { managedUserVm.setFirstName(UPDATED_FIRSTNAME); managedUserVm.setLastName(UPDATED_LASTNAME); managedUserVm.setEmail(UPDATED_EMAIL); - managedUserVm.setActivated(updatedUser.getActivated()); + managedUserVm.setActivated(updatedUser.activated); managedUserVm.setLangKey(UPDATED_LANGKEY); RoleDTO role = new RoleDTO(); @@ -407,10 +407,10 @@ void updateUserLogin() throws Exception { assertThat(userList).hasSize(databaseSizeBeforeUpdate); User testUser = userList.get(userList.size() - 1); assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN); - assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); - assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); - assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); - assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY); + assertThat(testUser.firstName).isEqualTo(UPDATED_FIRSTNAME); + assertThat(testUser.lastName).isEqualTo(UPDATED_LASTNAME); + assertThat(testUser.email).isEqualTo(UPDATED_EMAIL); + assertThat(testUser.langKey).isEqualTo(UPDATED_LANGKEY); } @Test @@ -423,12 +423,12 @@ void updateUserExistingEmail() throws Exception { User anotherUser = new User(); anotherUser.setLogin("jhipster"); - anotherUser.setPassword(passwordService.generateEncodedPassword()); - anotherUser.setActivated(true); - anotherUser.setEmail("jhipster@localhost"); - anotherUser.setFirstName("java"); - anotherUser.setLastName("hipster"); - anotherUser.setLangKey("en"); + anotherUser.password = passwordService.generateEncodedPassword(); + anotherUser.activated = true; + anotherUser.email = "jhipster@localhost"; + anotherUser.firstName = "java"; + anotherUser.lastName = "hipster"; + anotherUser.langKey = "en"; userRepository.saveAndFlush(anotherUser); // Update the user @@ -438,12 +438,12 @@ void updateUserExistingEmail() throws Exception { ManagedUserVM managedUserVm = new ManagedUserVM(); managedUserVm.setId(updatedUser.getId()); managedUserVm.setLogin(updatedUser.getLogin()); - managedUserVm.setPassword(updatedUser.getPassword()); - managedUserVm.setFirstName(updatedUser.getFirstName()); - managedUserVm.setLastName(updatedUser.getLastName()); + managedUserVm.setPassword(updatedUser.password); + managedUserVm.setFirstName(updatedUser.firstName); + managedUserVm.setLastName(updatedUser.lastName); managedUserVm.setEmail("jhipster@localhost"); - managedUserVm.setActivated(updatedUser.getActivated()); - managedUserVm.setLangKey(updatedUser.getLangKey()); + managedUserVm.setActivated(updatedUser.activated); + managedUserVm.setLangKey(updatedUser.langKey); RoleDTO role = new RoleDTO(); role.setProjectId(project.getId()); @@ -466,12 +466,12 @@ void updateUserExistingLogin() throws Exception { User anotherUser = new User(); anotherUser.setLogin("jhipster"); - anotherUser.setPassword(passwordService.generateEncodedPassword()); - anotherUser.setActivated(true); - anotherUser.setEmail("jhipster@localhost"); - anotherUser.setFirstName("java"); - anotherUser.setLastName("hipster"); - anotherUser.setLangKey("en"); + anotherUser.password = passwordService.generateEncodedPassword(); + anotherUser.activated = true; + anotherUser.email = "jhipster@localhost"; + anotherUser.firstName = "java"; + anotherUser.lastName = "hipster"; + anotherUser.langKey = "en"; userRepository.saveAndFlush(anotherUser); // Update the user @@ -481,12 +481,12 @@ void updateUserExistingLogin() throws Exception { ManagedUserVM managedUserVm = new ManagedUserVM(); managedUserVm.setId(updatedUser.getId()); managedUserVm.setLogin("jhipster"); - managedUserVm.setPassword(updatedUser.getPassword()); - managedUserVm.setFirstName(updatedUser.getFirstName()); - managedUserVm.setLastName(updatedUser.getLastName()); - managedUserVm.setEmail(updatedUser.getEmail()); - managedUserVm.setActivated(updatedUser.getActivated()); - managedUserVm.setLangKey(updatedUser.getLangKey()); + managedUserVm.setPassword(updatedUser.password); + managedUserVm.setFirstName(updatedUser.firstName); + managedUserVm.setLastName(updatedUser.lastName); + managedUserVm.setEmail(updatedUser.email); + managedUserVm.setActivated(updatedUser.activated); + managedUserVm.setLangKey(updatedUser.langKey); RoleDTO role = new RoleDTO(); role.setProjectId(project.getId()); From 97751c046602a9a88fb367524c4d05d7d1ae3435 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:19:52 +0200 Subject: [PATCH 031/158] Rename .java to .kt --- .../auth/authentication/{OAuthHelper.java => OAuthHelper.kt} | 0 .../{ManagementPortalTestApp.java => ManagementPortalTestApp.kt} | 0 ...cationFilterIntTest.java => JwtAuthenticationFilterIntTest.kt} | 0 .../{SecurityUtilsUnitTest.java => SecurityUtilsUnitTest.kt} | 0 .../{MetaTokenServiceTest.java => MetaTokenServiceTest.kt} | 0 ...thClientServiceTestUtil.java => OAuthClientServiceTestUtil.kt} | 0 .../service/{PasswordServiceTest.java => PasswordServiceTest.kt} | 0 ...elTest.java => RedcapIntegrationWorkFlowOnServiceLevelTest.kt} | 0 .../service/{SubjectServiceTest.java => SubjectServiceTest.kt} | 0 .../service/{UserServiceIntTest.java => UserServiceIntTest.kt} | 0 .../{AccountResourceIntTest.java => AccountResourceIntTest.kt} | 0 .../rest/{AuditResourceIntTest.java => AuditResourceIntTest.kt} | 0 .../rest/{GroupResourceIntTest.java => GroupResourceIntTest.kt} | 0 .../web/rest/{LogsResourceIntTest.java => LogsResourceIntTest.kt} | 0 ...ClientsResourceIntTest.java => OAuthClientsResourceIntTest.kt} | 0 ...izationResourceIntTest.java => OrganizationResourceIntTest.kt} | 0 ...fileInfoResourceIntTest.java => ProfileInfoResourceIntTest.kt} | 0 .../{ProjectResourceIntTest.java => ProjectResourceIntTest.kt} | 0 ...ourceDataResourceIntTest.java => SourceDataResourceIntTest.kt} | 0 .../rest/{SourceResourceIntTest.java => SourceResourceIntTest.kt} | 0 ...ourceTypeResourceIntTest.java => SourceTypeResourceIntTest.kt} | 0 .../{SubjectResourceIntTest.java => SubjectResourceIntTest.kt} | 0 .../radarbase/management/web/rest/{TestUtil.java => TestUtil.kt} | 0 .../web/rest/{UserResourceIntTest.java => UserResourceIntTest.kt} | 0 .../web/util/{HeaderUtilUnitTest.java => HeaderUtilUnitTest.kt} | 0 ...heckTranslationsUnitTest.java => CheckTranslationsUnitTest.kt} | 0 26 files changed, 0 insertions(+), 0 deletions(-) rename src/test/java/org/radarbase/auth/authentication/{OAuthHelper.java => OAuthHelper.kt} (100%) rename src/test/java/org/radarbase/management/{ManagementPortalTestApp.java => ManagementPortalTestApp.kt} (100%) rename src/test/java/org/radarbase/management/security/{JwtAuthenticationFilterIntTest.java => JwtAuthenticationFilterIntTest.kt} (100%) rename src/test/java/org/radarbase/management/security/{SecurityUtilsUnitTest.java => SecurityUtilsUnitTest.kt} (100%) rename src/test/java/org/radarbase/management/service/{MetaTokenServiceTest.java => MetaTokenServiceTest.kt} (100%) rename src/test/java/org/radarbase/management/service/{OAuthClientServiceTestUtil.java => OAuthClientServiceTestUtil.kt} (100%) rename src/test/java/org/radarbase/management/service/{PasswordServiceTest.java => PasswordServiceTest.kt} (100%) rename src/test/java/org/radarbase/management/service/{RedcapIntegrationWorkFlowOnServiceLevelTest.java => RedcapIntegrationWorkFlowOnServiceLevelTest.kt} (100%) rename src/test/java/org/radarbase/management/service/{SubjectServiceTest.java => SubjectServiceTest.kt} (100%) rename src/test/java/org/radarbase/management/service/{UserServiceIntTest.java => UserServiceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{AccountResourceIntTest.java => AccountResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{AuditResourceIntTest.java => AuditResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{GroupResourceIntTest.java => GroupResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{LogsResourceIntTest.java => LogsResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{OAuthClientsResourceIntTest.java => OAuthClientsResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{OrganizationResourceIntTest.java => OrganizationResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{ProfileInfoResourceIntTest.java => ProfileInfoResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{ProjectResourceIntTest.java => ProjectResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{SourceDataResourceIntTest.java => SourceDataResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{SourceResourceIntTest.java => SourceResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{SourceTypeResourceIntTest.java => SourceTypeResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{SubjectResourceIntTest.java => SubjectResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{TestUtil.java => TestUtil.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{UserResourceIntTest.java => UserResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/util/{HeaderUtilUnitTest.java => HeaderUtilUnitTest.kt} (100%) rename src/test/java/org/radarbase/management/webapp/{CheckTranslationsUnitTest.java => CheckTranslationsUnitTest.kt} (100%) diff --git a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.java b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt similarity index 100% rename from src/test/java/org/radarbase/auth/authentication/OAuthHelper.java rename to src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt diff --git a/src/test/java/org/radarbase/management/ManagementPortalTestApp.java b/src/test/java/org/radarbase/management/ManagementPortalTestApp.kt similarity index 100% rename from src/test/java/org/radarbase/management/ManagementPortalTestApp.java rename to src/test/java/org/radarbase/management/ManagementPortalTestApp.kt diff --git a/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.java b/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.java rename to src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt diff --git a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.java b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.java rename to src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt diff --git a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.java b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/service/MetaTokenServiceTest.java rename to src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt diff --git a/src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.java b/src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.kt similarity index 100% rename from src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.java rename to src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.kt diff --git a/src/test/java/org/radarbase/management/service/PasswordServiceTest.java b/src/test/java/org/radarbase/management/service/PasswordServiceTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/service/PasswordServiceTest.java rename to src/test/java/org/radarbase/management/service/PasswordServiceTest.kt diff --git a/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.java b/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.java rename to src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt diff --git a/src/test/java/org/radarbase/management/service/SubjectServiceTest.java b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/service/SubjectServiceTest.java rename to src/test/java/org/radarbase/management/service/SubjectServiceTest.kt diff --git a/src/test/java/org/radarbase/management/service/UserServiceIntTest.java b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/service/UserServiceIntTest.java rename to src/test/java/org/radarbase/management/service/UserServiceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/TestUtil.java b/src/test/java/org/radarbase/management/web/rest/TestUtil.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/TestUtil.java rename to src/test/java/org/radarbase/management/web/rest/TestUtil.kt diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.java b/src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.java rename to src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.kt diff --git a/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.java b/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.java rename to src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt From a74bdd0e374b41094308e12d85449b0f40fd5637 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:19:53 +0200 Subject: [PATCH 032/158] all code converted and compiling --- .../auth/authentication/OAuthHelper.kt | 262 +++-- .../management/ManagementPortalTestApp.kt | 140 +-- .../JwtAuthenticationFilterIntTest.kt | 148 ++- .../security/SecurityUtilsUnitTest.kt | 39 +- .../service/MetaTokenServiceTest.kt | 261 ++--- .../service/OAuthClientServiceTestUtil.kt | 52 +- .../management/service/PasswordServiceTest.kt | 89 +- ...apIntegrationWorkFlowOnServiceLevelTest.kt | 150 ++- .../management/service/SubjectServiceTest.kt | 146 ++- .../management/service/UserServiceIntTest.kt | 444 ++++---- .../web/rest/AccountResourceIntTest.kt | 385 +++---- .../web/rest/AuditResourceIntTest.kt | 308 ++--- .../web/rest/GroupResourceIntTest.kt | 718 ++++++------ .../web/rest/LogsResourceIntTest.kt | 88 +- .../web/rest/OAuthClientsResourceIntTest.kt | 415 ++++--- .../web/rest/OrganizationResourceIntTest.kt | 372 +++--- .../web/rest/ProfileInfoResourceIntTest.kt | 107 +- .../web/rest/ProjectResourceIntTest.kt | 640 ++++++----- .../web/rest/SourceDataResourceIntTest.kt | 677 ++++++----- .../web/rest/SourceResourceIntTest.kt | 490 ++++---- .../web/rest/SourceTypeResourceIntTest.kt | 686 ++++++----- .../web/rest/SubjectResourceIntTest.kt | 1007 +++++++++-------- .../radarbase/management/web/rest/TestUtil.kt | 180 ++- .../web/rest/UserResourceIntTest.kt | 831 +++++++------- .../management/web/util/HeaderUtilUnitTest.kt | 36 +- .../webapp/CheckTranslationsUnitTest.kt | 260 ++--- 26 files changed, 4585 insertions(+), 4346 deletions(-) diff --git a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt index 2d2b3ca52..3c18fd705 100644 --- a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt +++ b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt @@ -1,81 +1,68 @@ -package org.radarbase.auth.authentication; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.algorithms.Algorithm; -import org.radarbase.auth.authorization.Permission; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.test.web.servlet.request.RequestPostProcessor; - -import java.io.InputStream; -import java.security.KeyStore; -import java.security.cert.Certificate; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.time.Instant; -import java.util.Date; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Stream; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.radarbase.auth.jwks.JwksTokenVerifierLoader.toTokenVerifier; -import static org.radarbase.management.security.jwt.ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL; +package org.radarbase.auth.authentication + +import com.auth0.jwt.JWT +import com.auth0.jwt.algorithms.Algorithm +import org.mockito.ArgumentMatchers +import org.mockito.Mockito +import org.radarbase.auth.authorization.Permission.Companion.scopes +import org.radarbase.auth.jwks.JwksTokenVerifierLoader.Companion.toTokenVerifier +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.User +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.security.JwtAuthenticationFilter +import org.radarbase.management.security.jwt.ManagementPortalJwtAccessTokenConverter +import org.slf4j.LoggerFactory +import org.springframework.mock.web.MockHttpServletRequest +import org.springframework.security.core.Authentication +import org.springframework.test.web.servlet.request.RequestPostProcessor +import java.security.KeyStore +import java.security.interfaces.ECPrivateKey +import java.security.interfaces.ECPublicKey +import java.security.interfaces.RSAPrivateKey +import java.security.interfaces.RSAPublicKey +import java.time.Instant +import java.util.* /** * Created by dverbeec on 29/06/2017. */ -public final class OAuthHelper { - private static final Logger logger = LoggerFactory.getLogger(OAuthHelper.class); - private static String validEcToken; - private static String validRsaToken; - - public static final String TEST_KEYSTORE_PASSWORD = "radarbase"; - public static final String TEST_SIGNKEY_ALIAS = "radarbase-managementportal-ec"; - public static final String TEST_CHECKKEY_ALIAS = "radarbase-managementportal-rsa"; - public static final String[] SCOPES = Permission.scopes(); - public static final String[] AUTHORITIES = {"ROLE_SYS_ADMIN"}; - public static final String[] ROLES = {"ROLE_SYS_ADMIN"}; - public static final String[] SOURCES = {}; - public static final String[] AUD = {RES_MANAGEMENT_PORTAL}; - public static final String CLIENT = "unit_test"; - public static final String USER = "admin"; - public static final String ISS = "RADAR"; - public static final String JTI = "some-jwt-id"; - private static List verifiers; - - static { +object OAuthHelper { + private val logger = LoggerFactory.getLogger(OAuthHelper::class.java) + private var validEcToken: String? = null + private var validRsaToken: String? = null + const val TEST_KEYSTORE_PASSWORD = "radarbase" + const val TEST_SIGNKEY_ALIAS = "radarbase-managementportal-ec" + const val TEST_CHECKKEY_ALIAS = "radarbase-managementportal-rsa" + val SCOPES = scopes() + val AUTHORITIES = arrayOf("ROLE_SYS_ADMIN") + val ROLES = arrayOf("ROLE_SYS_ADMIN") + val SOURCES = arrayOf() + val AUD = arrayOf(ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL) + const val CLIENT = "unit_test" + const val USER = "admin" + const val ISS = "RADAR" + const val JTI = "some-jwt-id" + private var verifiers: List? = null + + init { try { - setUp(); - } catch (Exception e) { - logger.error("Failed to set up OAuthHelper", e); + setUp() + } catch (e: Exception) { + logger.error("Failed to set up OAuthHelper", e) } } - private OAuthHelper() { - // utility class - } - /** * Create a request post processor that adds a valid bearer token to requests for use with * MockMVC. * @return the request post processor */ - public static RequestPostProcessor bearerToken() { - return mockRequest -> { - mockRequest.addHeader("Authorization", "Bearer " + validEcToken); - return mockRequest; - }; + fun bearerToken(): RequestPostProcessor { + return RequestPostProcessor { mockRequest: MockHttpServletRequest -> + mockRequest.addHeader("Authorization", "Bearer " + validEcToken) + mockRequest + } } /** @@ -83,50 +70,52 @@ public final class OAuthHelper { * MockMVC. * @return the request post processor */ - public static RequestPostProcessor rsaBearerToken() { - return mockRequest -> { - mockRequest.addHeader("Authorization", "Bearer " + validRsaToken); - return mockRequest; - }; + fun rsaBearerToken(): RequestPostProcessor { + return RequestPostProcessor { mockRequest: MockHttpServletRequest -> + mockRequest.addHeader("Authorization", "Bearer " + validRsaToken) + mockRequest + } } /** * Set up a keypair for signing the tokens, initialize all kinds of different tokens for tests. * @throws Exception If anything goes wrong during setup */ - public static void setUp() throws Exception { - KeyStore ks = KeyStore.getInstance("PKCS12"); - try (InputStream keyStream = Thread.currentThread().getContextClassLoader() - .getResourceAsStream("config/keystore.p12")) { - if (keyStream == null) { - throw new IllegalStateException("Cannot find keystore to set up OAuth"); + @Throws(Exception::class) + fun setUp() { + val ks = KeyStore.getInstance("PKCS12") + Thread.currentThread().getContextClassLoader() + .getResourceAsStream("config/keystore.p12").use { keyStream -> + checkNotNull(keyStream) { "Cannot find keystore to set up OAuth" } + ks.load(keyStream, TEST_KEYSTORE_PASSWORD.toCharArray()) + + // get the EC keypair for signing + val privateKey = ks.getKey( + TEST_SIGNKEY_ALIAS, + TEST_KEYSTORE_PASSWORD.toCharArray() + ) as ECPrivateKey + val cert = ks.getCertificate(TEST_SIGNKEY_ALIAS) + val publicKey = cert.publicKey as ECPublicKey + val ecdsa = Algorithm.ECDSA256(publicKey, privateKey) + validEcToken = createValidToken(ecdsa) + + // also get an RSA keypair to test accepting multiple keys + val rsaPrivateKey = ks.getKey( + TEST_CHECKKEY_ALIAS, + TEST_KEYSTORE_PASSWORD.toCharArray() + ) as RSAPrivateKey + val rsaPublicKey = ks.getCertificate(TEST_CHECKKEY_ALIAS) + .publicKey as RSAPublicKey + val rsa = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey) + validRsaToken = createValidToken(rsa) + val verifierList = listOf(ecdsa, rsa) + .map{ alg: Algorithm? -> + alg?.toTokenVerifier(ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL) + } + .requireNoNulls() + .toList() + verifiers = listOf(StaticTokenVerifierLoader(verifierList)) } - - ks.load(keyStream, TEST_KEYSTORE_PASSWORD.toCharArray()); - - // get the EC keypair for signing - ECPrivateKey privateKey = (ECPrivateKey) ks.getKey(TEST_SIGNKEY_ALIAS, - TEST_KEYSTORE_PASSWORD.toCharArray()); - Certificate cert = ks.getCertificate(TEST_SIGNKEY_ALIAS); - ECPublicKey publicKey = (ECPublicKey) cert.getPublicKey(); - - Algorithm ecdsa = Algorithm.ECDSA256(publicKey, privateKey); - validEcToken = createValidToken(ecdsa); - - // also get an RSA keypair to test accepting multiple keys - RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) ks.getKey(TEST_CHECKKEY_ALIAS, - TEST_KEYSTORE_PASSWORD.toCharArray()); - RSAPublicKey rsaPublicKey = (RSAPublicKey) ks.getCertificate(TEST_CHECKKEY_ALIAS) - .getPublicKey(); - Algorithm rsa = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey); - validRsaToken = createValidToken(rsa); - - var verifierList = Stream.of(ecdsa, rsa) - .map(alg -> toTokenVerifier(alg, RES_MANAGEMENT_PORTAL)) - .toList(); - - verifiers = List.of(new StaticTokenVerifierLoader(verifierList)); - } } /** @@ -134,10 +123,14 @@ public final class OAuthHelper { * * @return an initialized JwtAuthenticationFilter */ - public static JwtAuthenticationFilter createAuthenticationFilter() { - UserRepository userRepository = mock(UserRepository.class); - when(userRepository.findOneByLogin(anyString())).thenReturn(Optional.of(createAdminUser())); - return new JwtAuthenticationFilter(createTokenValidator(), auth -> auth, userRepository); + fun createAuthenticationFilter(): JwtAuthenticationFilter { + val userRepository = Mockito.mock(UserRepository::class.java) + Mockito.`when`(userRepository.findOneByLogin(ArgumentMatchers.anyString())).thenReturn( + Optional.of( + createAdminUser() + ) + ) + return JwtAuthenticationFilter(createTokenValidator(), { auth: Authentication? -> auth }, userRepository) } /** @@ -145,40 +138,39 @@ public final class OAuthHelper { * * @return configured TokenValidator */ - public static TokenValidator createTokenValidator() { + fun createTokenValidator(): TokenValidator { // Use tokenValidator with known JWTVerifier which signs. - return new TokenValidator(verifiers); + return TokenValidator(verifiers!!) } - private static User createAdminUser() { - User user = new User(); - user.setId(1L); - user.setLogin("admin"); - user.activated = true; - user.setRoles(Set.of( - new Role(new Authority("ROLE_SYS_ADMIN")) - )); - return user; + private fun createAdminUser(): User { + val user = User() + user.id = 1L + user.setLogin("admin") + user.activated = true + user.roles = mutableSetOf(Role(Authority("ROLE_SYS_ADMIN"))) + + return user } - private static String createValidToken(Algorithm algorithm) { - Instant exp = Instant.now().plusSeconds(30 * 60); - Instant iat = Instant.now(); + private fun createValidToken(algorithm: Algorithm): String { + val exp = Instant.now().plusSeconds((30 * 60).toLong()) + val iat = Instant.now() return JWT.create() - .withIssuer(ISS) - .withIssuedAt(Date.from(iat)) - .withExpiresAt(Date.from(exp)) - .withAudience("res_ManagementPortal") - .withSubject(USER) - .withArrayClaim("scope", SCOPES) - .withArrayClaim("authorities", AUTHORITIES) - .withArrayClaim("roles", ROLES) - .withArrayClaim("sources", SOURCES) - .withArrayClaim("aud", AUD) - .withClaim("client_id", CLIENT) - .withClaim("user_name", USER) - .withClaim("jti", JTI) - .withClaim("grant_type", "password") - .sign(algorithm); + .withIssuer(ISS) + .withIssuedAt(Date.from(iat)) + .withExpiresAt(Date.from(exp)) + .withAudience("res_ManagementPortal") + .withSubject(USER) + .withArrayClaim("scope", SCOPES) + .withArrayClaim("authorities", AUTHORITIES) + .withArrayClaim("roles", ROLES) + .withArrayClaim("sources", SOURCES) + .withArrayClaim("aud", AUD) + .withClaim("client_id", CLIENT) + .withClaim("user_name", USER) + .withClaim("jti", JTI) + .withClaim("grant_type", "password") + .sign(algorithm) } } diff --git a/src/test/java/org/radarbase/management/ManagementPortalTestApp.kt b/src/test/java/org/radarbase/management/ManagementPortalTestApp.kt index 8255e99ec..aaf36d733 100644 --- a/src/test/java/org/radarbase/management/ManagementPortalTestApp.kt +++ b/src/test/java/org/radarbase/management/ManagementPortalTestApp.kt @@ -1,87 +1,91 @@ -package org.radarbase.management; +package org.radarbase.management -import org.radarbase.management.config.ApplicationProperties; -import org.radarbase.management.config.ManagementPortalProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.core.env.Environment; -import org.springframework.core.env.Profiles; -import tech.jhipster.config.JHipsterConstants; - -import javax.annotation.PostConstruct; -import java.net.InetAddress; -import java.net.UnknownHostException; +import org.radarbase.management.config.ApplicationProperties +import org.radarbase.management.config.ManagementPortalProperties +import org.slf4j.LoggerFactory +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.context.annotation.ComponentScan +import org.springframework.core.env.Environment +import org.springframework.core.env.Profiles +import tech.jhipster.config.JHipsterConstants +import java.net.InetAddress +import java.net.UnknownHostException +import javax.annotation.PostConstruct /** * This is the application configuration that excludes CommandLineRunner(i.e the sourceTypeLoader). * This is used for testing to replicate the application setup without SourceTypeLoader. */ -@ComponentScan({ - "org.radarbase.management.config", - "org.radarbase.management.domain.support", - "org.radarbase.management.filters", - "org.radarbase.management.repository", - "org.radarbase.management.service", - "org.radarbase.management.security", - "org.radarbase.management.web" -}) +@ComponentScan( + "org.radarbase.management.config", + "org.radarbase.management.domain.support", + "org.radarbase.management.filters", + "org.radarbase.management.repository", + "org.radarbase.management.service", + "org.radarbase.management.security", + "org.radarbase.management.web" +) @EnableAutoConfiguration -@EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class, - ManagementPortalProperties.class}) -public class ManagementPortalTestApp { - - private static final Logger log = LoggerFactory.getLogger(ManagementPortalTestApp.class); - - private final Environment env; - - public ManagementPortalTestApp(Environment env) { - this.env = env; - } - +@EnableConfigurationProperties( + LiquibaseProperties::class, ApplicationProperties::class, ManagementPortalProperties::class +) +class ManagementPortalTestApp(private val env: Environment) { /** * Initializes ManagementPortal. * - *

Spring profiles can be configured with a program arguments - * --spring.profiles.active=your-active-profile

* - *

You can find more information on how profiles work with JHipster on - * - * http://jhipster.github.io/profiles/ - *

. + * Spring profiles can be configured with a program arguments + * --spring.profiles.active=your-active-profile + * + * + * You can find more information on how profiles work with JHipster on + * [ + * http://jhipster.github.io/profiles/ +](http://jhipster.github.io/profiles/) * . */ @PostConstruct - public void initApplication() { + fun initApplication() { if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) - && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_PRODUCTION))) { - log.error("You have misconfigured your application! It should not run " - + "with both the 'dev' and 'prod' profiles at the same time."); + && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) + ) { + log.error( + "You have misconfigured your application! It should not run " + + "with both the 'dev' and 'prod' profiles at the same time." + ) } if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) - && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_CLOUD))) { - log.error("You have misconfigured your application! It should not" - + "run with both the 'dev' and 'cloud' profiles at the same time."); + && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_CLOUD)) + ) { + log.error( + "You have misconfigured your application! It should not" + + "run with both the 'dev' and 'cloud' profiles at the same time." + ) } } - /** - * Main method, used to run the application. - * - * @param args the command line arguments - * @throws UnknownHostException if the local host name could not be resolved into an address - */ - public static void main(String[] args) throws UnknownHostException { - SpringApplication app = new SpringApplication(ManagementPortalTestApp.class); - Environment env = app.run(args).getEnvironment(); - String protocol = "http"; - if (env.getProperty("server.ssl.key-store") != null) { - protocol = "https"; - } - log.info("\n--------------------------------------------------\n\t" + companion object { + private val log = LoggerFactory.getLogger(ManagementPortalTestApp::class.java) + + /** + * Main method, used to run the application. + * + * @param args the command line arguments + * @throws UnknownHostException if the local host name could not be resolved into an address + */ + @Throws(UnknownHostException::class) + @JvmStatic + fun main(args: Array) { + val app = SpringApplication(ManagementPortalTestApp::class.java) + val env: Environment = app.run(*args).environment + var protocol = "http" + if (env.getProperty("server.ssl.key-store") != null) { + protocol = "https" + } + log.info( + "\n--------------------------------------------------\n\t" + "Application '{}' is running! Access URLs:\n\t" + "Local: \t\t{}://localhost:{}\n\t" + "External: \t{}://{}:{}\n\t" @@ -90,8 +94,10 @@ public class ManagementPortalTestApp { protocol, env.getProperty("server.port"), protocol, - InetAddress.getLocalHost().getHostAddress(), + InetAddress.getLocalHost().hostAddress, env.getProperty("server.port"), - env.getActiveProfiles()); + env.activeProfiles + ) + } } } diff --git a/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt b/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt index 9e8e39d56..ca746c255 100644 --- a/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt +++ b/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt @@ -1,95 +1,87 @@ -package org.radarbase.management.security; +package org.radarbase.management.security -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ProjectService; -import org.radarbase.management.web.rest.ProjectResource; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import javax.servlet.ServletException; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ProjectService +import org.radarbase.management.web.rest.ProjectResource +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import javax.servlet.ServletException /** * Test class for the JwtAuthenticationFilter class. * * @see JwtAuthenticationFilter */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class JwtAuthenticationFilterIntTest { - - @Autowired - private ProjectService projectService; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - private MockMvc rsaRestProjectMockMvc; - - private MockMvc ecRestProjectMockMvc; - @Autowired - private AuthService authService; +internal class JwtAuthenticationFilterIntTest( + @Autowired private val projectService: ProjectService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + private var rsaRestProjectMockMvc: MockMvc, + private var ecRestProjectMockMvc: MockMvc, + @Autowired private val authService: AuthService +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - ProjectResource projectResource = new ProjectResource(); - ReflectionTestUtils.setField(projectResource, "projectService", projectService); - ReflectionTestUtils.setField(projectResource, "authService", authService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.rsaRestProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/") - .with(OAuthHelper.rsaBearerToken())) - .build(); - - this.ecRestProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/") - .with(OAuthHelper.bearerToken())) - .build(); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val projectResource = ProjectResource + ReflectionTestUtils.setField(projectResource, "projectService", projectService) + ReflectionTestUtils.setField(projectResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + rsaRestProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest( + MockMvcRequestBuilders.get("/") + .with(OAuthHelper.rsaBearerToken()) + ) + .build() + ecRestProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest( + MockMvcRequestBuilders.get("/") + .with(OAuthHelper.bearerToken()) + ) + .build() } @Test - void testMultipleSigningKeys() throws Exception { + @Throws(Exception::class) + fun testMultipleSigningKeys() { // Check that we can get the project list with both RSA and EC signed token. We are testing // acceptance of the tokens, so no test on the content of the response is performed here. - rsaRestProjectMockMvc.perform(get("/api/projects?sort=id,desc")) - .andExpect(status().isOk()); - ecRestProjectMockMvc.perform(get("/api/projects?sort=id,desc")) - .andExpect(status().isOk()); + rsaRestProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + ecRestProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) } } diff --git a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt index 3e1008354..6bfdb36ce 100644 --- a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt +++ b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt @@ -1,26 +1,25 @@ -package org.radarbase.management.security; +package org.radarbase.management.security -import org.junit.jupiter.api.Test; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; - -import static org.assertj.core.api.Assertions.assertThat; +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.Test +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.context.SecurityContextHolder /** -* Test class for the SecurityUtils utility class. -* -* @see SecurityUtils -*/ -class SecurityUtilsUnitTest { - + * Test class for the SecurityUtils utility class. + * + * @see SecurityUtils + */ +internal class SecurityUtilsUnitTest { @Test - void testGetCurrentUserLogin() { - SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); - securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", - "admin")); - SecurityContextHolder.setContext(securityContext); - String login = SecurityUtils.getCurrentUserLogin().orElse(null); - assertThat(login).isEqualTo("admin"); + fun testGetCurrentUserLogin() { + val securityContext = SecurityContextHolder.createEmptyContext() + securityContext.authentication = UsernamePasswordAuthenticationToken( + "admin", + "admin" + ) + SecurityContextHolder.setContext(securityContext) + val login = SecurityUtils.getCurrentUserLogin().orElse(null) + Assertions.assertThat(login).isEqualTo("admin") } } diff --git a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt index bc39cd18f..b4f3f447d 100644 --- a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt @@ -1,171 +1,136 @@ -package org.radarbase.management.service; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.MetaToken; -import org.radarbase.management.repository.MetaTokenRepository; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.dto.TokenDTO; -import org.radarbase.management.service.mapper.SubjectMapper; -import org.radarbase.management.web.rest.errors.RadarWebApplicationException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.transaction.annotation.Transactional; - -import java.net.MalformedURLException; -import java.time.Duration; -import java.time.Instant; -import java.util.Arrays; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +package org.radarbase.management.service + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.MetaToken +import org.radarbase.management.repository.MetaTokenRepository +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.mapper.SubjectMapper +import org.radarbase.management.web.rest.errors.RadarWebApplicationException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.security.oauth2.provider.ClientDetails +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.transaction.annotation.Transactional +import java.net.MalformedURLException +import java.time.Duration +import java.time.Instant +import java.util.* /** * Test class for the MetaTokenService class. * * @see MetaTokenService */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -class MetaTokenServiceTest { - - - @Autowired - private MetaTokenService metaTokenService; - - @Autowired - private MetaTokenRepository metaTokenRepository; - - @Autowired - private SubjectService subjectService; - - @Autowired - private SubjectMapper subjectMapper; - - @Autowired - private OAuthClientService oAuthClientService; - - private ClientDetails clientDetails; - - private SubjectDTO subjectDto; +internal open class MetaTokenServiceTest( + @Autowired private val metaTokenService: MetaTokenService, + @Autowired private val metaTokenRepository: MetaTokenRepository, + @Autowired private val subjectService: SubjectService, + @Autowired private val subjectMapper: SubjectMapper, + @Autowired private val oAuthClientService: OAuthClientService, + private var clientDetails: ClientDetails, + private var subjectDto: SubjectDTO +) { @BeforeEach - public void setUp() { - subjectDto = SubjectServiceTest.createEntityDTO(); - subjectDto = subjectService.createSubject(subjectDto); - - clientDetails = oAuthClientService - .createClientDetail(OAuthClientServiceTestUtil.createClient()); + fun setUp() { + subjectDto = SubjectServiceTest.createEntityDTO() + subjectDto = subjectService.createSubject(subjectDto)!! + clientDetails = oAuthClientService.createClientDetail(OAuthClientServiceTestUtil.createClient())!! } @Test - void testSaveThenFetchMetaToken() throws MalformedURLException { - - MetaToken metaToken = new MetaToken() - .generateName(MetaToken.SHORT_ID_LENGTH) - .fetched(false) - .persistent(false) - .expiryDate(Instant.now().plus(Duration.ofHours(1))) - .subject(subjectMapper.subjectDTOToSubject(subjectDto)) - .clientId(clientDetails.getClientId()); - - MetaToken saved = metaTokenService.save(metaToken); - assertNotNull(saved.getId()); - assertNotNull(saved.getTokenName()); - assertFalse(saved.isFetched()); - assertTrue(saved.getExpiryDate().isAfter(Instant.now())); - - String tokenName = saved.getTokenName(); - TokenDTO fetchedToken = metaTokenService.fetchToken(tokenName); - - assertNotNull(fetchedToken); - assertNotNull(fetchedToken.getRefreshToken()); - + @Throws(MalformedURLException::class) + fun testSaveThenFetchMetaToken() { + val metaToken = MetaToken() + .generateName(MetaToken.SHORT_ID_LENGTH) + .fetched(false) + .persistent(false) + .expiryDate(Instant.now().plus(Duration.ofHours(1))) + .subject(subjectMapper.subjectDTOToSubject(subjectDto)) + .clientId(clientDetails.clientId) + val saved = metaTokenService.save(metaToken) + Assertions.assertNotNull(saved.id) + Assertions.assertNotNull(saved.tokenName) + Assertions.assertFalse(saved.isFetched()) + Assertions.assertTrue(saved.expiryDate!!.isAfter(Instant.now())) + val tokenName = saved.tokenName + val fetchedToken = metaTokenService.fetchToken(tokenName!!) + Assertions.assertNotNull(fetchedToken) + Assertions.assertNotNull(fetchedToken.refreshToken) } @Test - void testGetAFetchedMetaToken() throws MalformedURLException { - MetaToken token = new MetaToken() - .generateName(MetaToken.SHORT_ID_LENGTH) - .fetched(true) - .persistent(false) - .tokenName("something") - .expiryDate(Instant.now().plus(Duration.ofHours(1))) - .subject(subjectMapper.subjectDTOToSubject(subjectDto)); - - MetaToken saved = metaTokenService.save(token); - assertNotNull(saved.getId()); - assertNotNull(saved.getTokenName()); - assertTrue(saved.isFetched()); - assertTrue(saved.getExpiryDate().isAfter(Instant.now())); - - String tokenName = saved.getTokenName(); - Assertions.assertThrows(RadarWebApplicationException.class, - () -> metaTokenService.fetchToken(tokenName)); + @Throws(MalformedURLException::class) + fun testGetAFetchedMetaToken() { + val token = MetaToken() + .generateName(MetaToken.SHORT_ID_LENGTH) + .fetched(true) + .persistent(false) + .tokenName("something") + .expiryDate(Instant.now().plus(Duration.ofHours(1))) + .subject(subjectMapper.subjectDTOToSubject(subjectDto)) + val saved = metaTokenService.save(token) + Assertions.assertNotNull(saved.id) + Assertions.assertNotNull(saved.tokenName) + Assertions.assertTrue(saved.isFetched()) + Assertions.assertTrue(saved.expiryDate!!.isAfter(Instant.now())) + val tokenName = saved.tokenName + Assertions.assertThrows( + RadarWebApplicationException::class.java + ) { metaTokenService.fetchToken(tokenName!!) } } @Test - void testGetAnExpiredMetaToken() throws MalformedURLException { - MetaToken token = new MetaToken() - .generateName(MetaToken.SHORT_ID_LENGTH) - .fetched(false) - .persistent(false) - .tokenName("somethingelse") - .expiryDate(Instant.now().minus(Duration.ofHours(1))) - .subject(subjectMapper.subjectDTOToSubject(subjectDto)); - - MetaToken saved = metaTokenService.save(token); - - assertNotNull(saved.getId()); - assertNotNull(saved.getTokenName()); - assertFalse(saved.isFetched()); - assertTrue(saved.getExpiryDate().isBefore(Instant.now())); - - String tokenName = saved.getTokenName(); - - Assertions.assertThrows(RadarWebApplicationException.class, - () -> metaTokenService.fetchToken(tokenName)); + @Throws(MalformedURLException::class) + fun testGetAnExpiredMetaToken() { + val token = MetaToken() + .generateName(MetaToken.SHORT_ID_LENGTH) + .fetched(false) + .persistent(false) + .tokenName("somethingelse") + .expiryDate(Instant.now().minus(Duration.ofHours(1))) + .subject(subjectMapper.subjectDTOToSubject(subjectDto)) + val saved = metaTokenService.save(token) + Assertions.assertNotNull(saved.id) + Assertions.assertNotNull(saved.tokenName) + Assertions.assertFalse(saved.isFetched()) + Assertions.assertTrue(saved.expiryDate!!.isBefore(Instant.now())) + val tokenName = saved.tokenName + Assertions.assertThrows( + RadarWebApplicationException::class.java + ) { metaTokenService.fetchToken(tokenName!!) } } @Test - void testRemovingExpiredMetaToken() { - - MetaToken tokenFetched = new MetaToken() - .generateName(MetaToken.SHORT_ID_LENGTH) - .fetched(true) - .persistent(false) - .tokenName("something") - .expiryDate(Instant.now().plus(Duration.ofHours(1))); - - MetaToken tokenExpired = new MetaToken() - .generateName(MetaToken.SHORT_ID_LENGTH) - .fetched(false) - .persistent(false) - .tokenName("somethingelse") - .expiryDate(Instant.now().minus(Duration.ofHours(1))); - - MetaToken tokenNew = new MetaToken() - .generateName(MetaToken.SHORT_ID_LENGTH) - .fetched(false) - .persistent(false) - .tokenName("somethingelseandelse") - .expiryDate(Instant.now().plus(Duration.ofHours(1))); - - metaTokenRepository.saveAll(Arrays.asList(tokenFetched, tokenExpired, tokenNew)); - - metaTokenService.removeStaleTokens(); - - List availableTokens = metaTokenRepository.findAll(); - - assertEquals(1, availableTokens.size()); + fun testRemovingExpiredMetaToken() { + val tokenFetched = MetaToken() + .generateName(MetaToken.SHORT_ID_LENGTH) + .fetched(true) + .persistent(false) + .tokenName("something") + .expiryDate(Instant.now().plus(Duration.ofHours(1))) + val tokenExpired = MetaToken() + .generateName(MetaToken.SHORT_ID_LENGTH) + .fetched(false) + .persistent(false) + .tokenName("somethingelse") + .expiryDate(Instant.now().minus(Duration.ofHours(1))) + val tokenNew = MetaToken() + .generateName(MetaToken.SHORT_ID_LENGTH) + .fetched(false) + .persistent(false) + .tokenName("somethingelseandelse") + .expiryDate(Instant.now().plus(Duration.ofHours(1))) + metaTokenRepository.saveAll(Arrays.asList(tokenFetched, tokenExpired, tokenNew)) + metaTokenService.removeStaleTokens() + val availableTokens = metaTokenRepository.findAll() + Assertions.assertEquals(1, availableTokens.size) } } diff --git a/src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.kt b/src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.kt index 0000c425b..6f030ca8a 100644 --- a/src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.kt +++ b/src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.kt @@ -1,41 +1,37 @@ -package org.radarbase.management.service; +package org.radarbase.management.service -import org.radarbase.management.service.dto.ClientDetailsDTO; - -import java.util.LinkedHashMap; -import java.util.Set; +import org.radarbase.management.service.dto.ClientDetailsDTO /** * Test class for the OAuthClientService class. * * @see OAuthClientService */ -public final class OAuthClientServiceTestUtil { - private OAuthClientServiceTestUtil() { - // utility class - } - +object OAuthClientServiceTestUtil { /** * Create an entity for this test. * - *

This is a static method, as tests for other entities might also need it, if they test an - * entity which requires the current entity.

+ * + * This is a static method, as tests for other entities might also need it, if they test an + * entity which requires the current entity. */ - public static ClientDetailsDTO createClient() { - ClientDetailsDTO result = new ClientDetailsDTO(); - result.setClientId("TEST_CLIENT"); - result.setClientSecret("TEST_SECRET"); - result.setScope(Set.of("scope-1", "scope-2")); - result.setResourceIds(Set.of("res-1", "res-2")); - result.setAutoApproveScopes(Set.of("scope-1")); - result.setAuthorizedGrantTypes(Set.of("password", "refresh_token", - "authorization_code")); - result.setAccessTokenValiditySeconds(3600L); - result.setRefreshTokenValiditySeconds(7200L); - result.setAuthorities(Set.of("AUTHORITY-1")); - var additionalInfo = new LinkedHashMap(); - additionalInfo.put("dynamic_registration", "true"); - result.setAdditionalInformation(additionalInfo); - return result; + fun createClient(): ClientDetailsDTO { + val result = ClientDetailsDTO() + result.clientId = "TEST_CLIENT" + result.clientSecret = "TEST_SECRET" + result.scope = setOf("scope-1", "scope-2") + result.resourceIds = setOf("res-1", "res-2") + result.autoApproveScopes = setOf("scope-1") + result.authorizedGrantTypes = setOf( + "password", "refresh_token", + "authorization_code" + ) + result.accessTokenValiditySeconds = 3600L + result.refreshTokenValiditySeconds = 7200L + result.authorities = setOf("AUTHORITY-1") + val additionalInfo = LinkedHashMap() + additionalInfo["dynamic_registration"] = "true" + result.additionalInformation = additionalInfo + return result } } diff --git a/src/test/java/org/radarbase/management/service/PasswordServiceTest.kt b/src/test/java/org/radarbase/management/service/PasswordServiceTest.kt index a7e0e66e9..2f9d60909 100644 --- a/src/test/java/org/radarbase/management/service/PasswordServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/PasswordServiceTest.kt @@ -6,63 +6,58 @@ * * See the file LICENSE in the root of this repository. */ - -package org.radarbase.management.service; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import java.util.Arrays; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) -class PasswordServiceTest { +package org.radarbase.management.service + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.web.rest.errors.BadRequestException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.junit.jupiter.SpringExtension +import java.util.* + +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) +internal class PasswordServiceTest { @Autowired - private PasswordService passwordService; - + private val passwordService: PasswordService? = null @Test - void encode() { - assertNotEquals("abc", passwordService.encode("abc")); + fun encode() { + Assertions.assertNotEquals("abc", passwordService!!.encode("abc")) } @Test - void generateEncodedPassword() { - String pass = passwordService.generateEncodedPassword(); - assertTrue(pass.length() >= 30); - assertTrue(pass.length() < 100); - assertDoesNotThrow(() -> passwordService.checkPasswordStrength(pass)); + fun generateEncodedPassword() { + val pass = passwordService!!.generateEncodedPassword() + Assertions.assertTrue(pass.length >= 30) + Assertions.assertTrue(pass.length < 100) + Assertions.assertDoesNotThrow { passwordService.checkPasswordStrength(pass) } } @Test - void generateResetKey() { - String resetKey = passwordService.generateResetKey(); - assertTrue(resetKey.length() > 16); - assertTrue(resetKey.length() < 100); + fun generateResetKey() { + val resetKey = passwordService!!.generateResetKey() + Assertions.assertTrue(resetKey.length > 16) + Assertions.assertTrue(resetKey.length < 100) } @Test - void checkPasswordStrength() { - assertDoesNotThrow(() -> passwordService.checkPasswordStrength("aA1aaaaaaaa")); - assertThrows(BadRequestException.class, () -> passwordService.checkPasswordStrength("a")); - byte[] tooLong = new byte[101]; - Arrays.fill(tooLong, (byte)'A'); - assertThrows(BadRequestException.class, () -> - passwordService.checkPasswordStrength("aA1" + new String(tooLong))); - assertThrows(BadRequestException.class, () -> - passwordService.checkPasswordStrength("aAaaaaaaaaa")); - assertThrows(BadRequestException.class, () -> - passwordService.checkPasswordStrength("a1aaaaaaaaa")); - assertThrows(BadRequestException.class, () -> - passwordService.checkPasswordStrength("aAaaaaaaaaa")); + fun checkPasswordStrength() { + Assertions.assertDoesNotThrow { passwordService!!.checkPasswordStrength("aA1aaaaaaaa") } + Assertions.assertThrows(BadRequestException::class.java) { passwordService!!.checkPasswordStrength("a") } + val tooLong = ByteArray(101) + Arrays.fill(tooLong, 'A'.code.toByte()) + Assertions.assertThrows(BadRequestException::class.java) { + passwordService!!.checkPasswordStrength( + "aA1" + String( + tooLong + ) + ) + } + Assertions.assertThrows(BadRequestException::class.java) { passwordService!!.checkPasswordStrength("aAaaaaaaaaa") } + Assertions.assertThrows(BadRequestException::class.java) { passwordService!!.checkPasswordStrength("a1aaaaaaaaa") } + Assertions.assertThrows(BadRequestException::class.java) { passwordService!!.checkPasswordStrength("aAaaaaaaaaa") } } } diff --git a/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt b/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt index 97dff1eee..a4461d7cb 100644 --- a/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt +++ b/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt @@ -1,119 +1,109 @@ -package org.radarbase.management.service; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.enumeration.ProjectStatus; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +package org.radarbase.management.service + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.enumeration.ProjectStatus +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.transaction.annotation.Transactional +import java.util.* /** * Created by nivethika on 31-8-17. */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -class RedcapIntegrationWorkFlowOnServiceLevelTest { - +internal class RedcapIntegrationWorkFlowOnServiceLevelTest { @Autowired - private ProjectService projectService; + private val projectService: ProjectService? = null @Autowired - private SubjectService subjectService; - + private val subjectService: SubjectService? = null @Test - void testRedcapIntegrationWorkFlowOnServiceLevel() { - final String externalProjectUrl = "MyUrl"; - final String externalProjectId = "MyId"; - final String projectLocation = "London"; - final String workPackage = "MDD"; - final String phase = "1"; - - ProjectDTO projectDto = new ProjectDTO(); - projectDto.setDescription("Test Project"); - projectDto.setLocation(projectLocation); - projectDto.setProjectName("test radar"); - projectDto.setProjectStatus(ProjectStatus.PLANNING); - - Map attributes = new HashMap<>(); - attributes.put(ProjectDTO.EXTERNAL_PROJECT_URL_KEY, externalProjectUrl); - attributes.put(ProjectDTO.EXTERNAL_PROJECT_ID_KEY, externalProjectId); - attributes.put(ProjectDTO.PHASE_KEY, phase); - attributes.put(ProjectDTO.WORK_PACKAGE_KEY, workPackage); - projectDto.setAttributes(attributes); + fun testRedcapIntegrationWorkFlowOnServiceLevel() { + val externalProjectUrl = "MyUrl" + val externalProjectId = "MyId" + val projectLocation = "London" + val workPackage = "MDD" + val phase = "1" + val projectDto = ProjectDTO() + projectDto.description = "Test Project" + projectDto.location = projectLocation + projectDto.projectName = "test radar" + projectDto.projectStatus = ProjectStatus.PLANNING + val attributes: MutableMap = HashMap() + attributes[ProjectDTO.EXTERNAL_PROJECT_URL_KEY] = externalProjectUrl + attributes[ProjectDTO.EXTERNAL_PROJECT_ID_KEY] = externalProjectId + attributes[ProjectDTO.PHASE_KEY] = phase + attributes[ProjectDTO.WORK_PACKAGE_KEY] = workPackage + projectDto.attributes = attributes // manually save - ProjectDTO saved = projectService.save(projectDto); - Long storedProjectId = saved.getId(); - assertTrue(storedProjectId > 0); + val saved = projectService!!.save(projectDto) + val storedProjectId = saved.id + Assertions.assertTrue(storedProjectId > 0) // Use ROLE_EXTERNAL_ERF_INTEGRATOR authority in your oauth2 client config // GET api/projects/{storedProjectId} - ProjectDTO retrievedById = projectService.findOne(storedProjectId); - assertEquals(retrievedById.getId(), storedProjectId); + val retrievedById = projectService.findOne(storedProjectId) + Assertions.assertEquals(retrievedById.id, storedProjectId) // retrieve required details // location is part of project property - final String locationRetrieved = projectDto.getLocation(); + val locationRetrieved = projectDto.location // work-package, phase are from meta-data - String workPackageRetrieved = ""; - String phaseRetrieved = ""; + var workPackageRetrieved = "" + var phaseRetrieved = "" // redcap-id from trigger - final String redcapRecordId = "1"; - for (Map.Entry attributeMapDto : retrievedById.getAttributes().entrySet()) { - switch (attributeMapDto.getKey()) { - case ProjectDTO.WORK_PACKAGE_KEY : - workPackageRetrieved = attributeMapDto.getValue(); - break; - case ProjectDTO.PHASE_KEY : - phaseRetrieved = attributeMapDto.getValue(); - break; - default: - break; + val redcapRecordId = "1" + for ((key, value) in retrievedById.attributes) { + when (key) { + ProjectDTO.WORK_PACKAGE_KEY -> workPackageRetrieved = value + ProjectDTO.PHASE_KEY -> phaseRetrieved = value + else -> {} } } // assert retrieved data - assertEquals(workPackage, workPackageRetrieved); - assertEquals(phase, phaseRetrieved); - assertEquals(projectLocation, locationRetrieved); + Assertions.assertEquals(workPackage, workPackageRetrieved) + Assertions.assertEquals(phase, phaseRetrieved) + Assertions.assertEquals(projectLocation, locationRetrieved) // create a new Subject - SubjectDTO newSubject = new SubjectDTO(); - newSubject.setLogin("53d8a54a"); // will be removed - newSubject.setProject(retrievedById); // set retrieved project - newSubject.setExternalId(redcapRecordId); // set redcap-record-id + val newSubject = SubjectDTO() + newSubject.login = "53d8a54a" // will be removed + newSubject.project = retrievedById // set retrieved project + newSubject.externalId = redcapRecordId // set redcap-record-id // create human-readable-id - String humanReadableId = String.join("-", workPackageRetrieved, phaseRetrieved, - locationRetrieved, redcapRecordId); + val humanReadableId = java.lang.String.join( + "-", workPackageRetrieved, phaseRetrieved, + locationRetrieved, redcapRecordId + ) //set meta-data to subject - newSubject.setAttributes(Collections.singletonMap(SubjectDTO.HUMAN_READABLE_IDENTIFIER_KEY, - humanReadableId)); + newSubject.attributes = Collections.singletonMap( + SubjectDTO.HUMAN_READABLE_IDENTIFIER_KEY, + humanReadableId + ) // create/save a subject // PUT api/subjects/ - SubjectDTO savedSubject = subjectService.createSubject(newSubject); - assertTrue(savedSubject.getId() > 0); + val savedSubject = subjectService!!.createSubject(newSubject) + Assertions.assertTrue(savedSubject!!.id > 0) // asset human-readable-id - for (Map.Entry attr : savedSubject.getAttributes().entrySet()) { - if (SubjectDTO.HUMAN_READABLE_IDENTIFIER_KEY .equals(attr.getKey())) { - assertEquals(humanReadableId, attr.getValue()); + for ((key, value) in savedSubject.attributes) { + if (SubjectDTO.HUMAN_READABLE_IDENTIFIER_KEY == key) { + Assertions.assertEquals(humanReadableId, value) } } } diff --git a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt index b9d6a7aaf..895b8ef2c 100644 --- a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt @@ -1,96 +1,80 @@ -package org.radarbase.management.service; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.transaction.annotation.Transactional; - -import java.net.URL; -import java.util.Collections; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.radarbase.management.service.dto.ProjectDTO.PRIVACY_POLICY_URL; -import static org.radarbase.management.service.dto.SubjectDTO.SubjectStatus.ACTIVATED; +package org.radarbase.management.service + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.dto.SubjectDTO.SubjectStatus +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.transaction.annotation.Transactional +import java.util.* /** * Test class for the SubjectService class. * * @see SubjectService */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -public class SubjectServiceTest { - - public static final String DEFAULT_EXTERNAL_LINK = "AAAAAAAAAA"; - public static final String UPDATED_EXTERNAL_LINK = "BBBBBBBBBB"; - - public static final String DEFAULT_ENTERNAL_ID = "AAAAAAAAAA"; - public static final String UPDATED_ENTERNAL_ID = "BBBBBBBBBB"; - - public static final Boolean DEFAULT_REMOVED = false; - public static final Boolean UPDATED_REMOVED = true; - - public static final SubjectDTO.SubjectStatus DEFAULT_STATUS = ACTIVATED; - - public static final String MODEL = "App"; - public static final String PRODUCER = "THINC-IT"; - - public static final String DEFAULT_PROJECT_PRIVACY_POLICY_URL = - "http://info.thehyve.nl/radar-cns-privacy-policy"; - - +class SubjectServiceTest { @Autowired - private SubjectService subjectService; + private val subjectService: SubjectService? = null @Autowired - private ProjectService projectService; - - /** - * Create an entity for this test. - * - *

This is a static method, as tests for other entities might also need it, if they test an - * entity which requires the current entity.

- */ - public static SubjectDTO createEntityDTO() { - SubjectDTO subject = new SubjectDTO(); - subject.setExternalLink(DEFAULT_EXTERNAL_LINK); - subject.setExternalId(DEFAULT_ENTERNAL_ID); - subject.setStatus(ACTIVATED); - ProjectDTO projectDto = new ProjectDTO(); - projectDto.setId(1L); - projectDto.setProjectName("Radar"); - projectDto.setLocation("SOMEWHERE"); - projectDto.setDescription("test"); - projectDto.setAttributes(Collections.singletonMap(PRIVACY_POLICY_URL, - DEFAULT_PROJECT_PRIVACY_POLICY_URL)); - subject.setProject(projectDto); - - return subject; - } - + private val projectService: ProjectService? = null @Test @Transactional - void testGetPrivacyPolicyUrl() { - - projectService.save(createEntityDTO().getProject()); - SubjectDTO created = subjectService.createSubject(createEntityDTO()); - assertNotNull(created.getId()); - - Subject subject = subjectService.findOneByLogin(created.getLogin()); - assertNotNull(subject); - - URL privacyPolicyUrl = subjectService.getPrivacyPolicyUrl(subject); - assertNotNull(privacyPolicyUrl); - assertEquals(DEFAULT_PROJECT_PRIVACY_POLICY_URL, privacyPolicyUrl.toExternalForm()); - + fun testGetPrivacyPolicyUrl() { + projectService!!.save(createEntityDTO().project) + val created = subjectService!!.createSubject(createEntityDTO()) + Assertions.assertNotNull(created!!.id) + val subject = subjectService.findOneByLogin(created.getLogin()) + Assertions.assertNotNull(subject) + val privacyPolicyUrl = subjectService.getPrivacyPolicyUrl(subject) + Assertions.assertNotNull(privacyPolicyUrl) + Assertions.assertEquals(DEFAULT_PROJECT_PRIVACY_POLICY_URL, privacyPolicyUrl.toExternalForm()) } + companion object { + const val DEFAULT_EXTERNAL_LINK = "AAAAAAAAAA" + const val UPDATED_EXTERNAL_LINK = "BBBBBBBBBB" + const val DEFAULT_ENTERNAL_ID = "AAAAAAAAAA" + const val UPDATED_ENTERNAL_ID = "BBBBBBBBBB" + const val DEFAULT_REMOVED = false + const val UPDATED_REMOVED = true + val DEFAULT_STATUS = SubjectStatus.ACTIVATED + const val MODEL = "App" + const val PRODUCER = "THINC-IT" + const val DEFAULT_PROJECT_PRIVACY_POLICY_URL = "http://info.thehyve.nl/radar-cns-privacy-policy" + + /** + * Create an entity for this test. + * + * + * This is a static method, as tests for other entities might also need it, if they test an + * entity which requires the current entity. + */ + fun createEntityDTO(): SubjectDTO { + val subject = SubjectDTO() + subject.externalLink = DEFAULT_EXTERNAL_LINK + subject.externalId = DEFAULT_ENTERNAL_ID + subject.status = SubjectStatus.ACTIVATED + val projectDto = ProjectDTO() + projectDto.id = 1L + projectDto.projectName = "Radar" + projectDto.location = "SOMEWHERE" + projectDto.description = "test" + projectDto.attributes = Collections.singletonMap( + ProjectDTO.PRIVACY_POLICY_URL, + DEFAULT_PROJECT_PRIVACY_POLICY_URL + ) + subject.project = projectDto + return subject + } + } } diff --git a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt index 263abfa37..3fd29977a 100644 --- a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt +++ b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt @@ -1,253 +1,210 @@ -package org.radarbase.management.service; - -import org.hibernate.envers.AuditReader; -import org.hibernate.envers.AuditReaderFactory; -import org.hibernate.envers.query.AuditEntity; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.User; -import org.radarbase.management.domain.audit.CustomRevisionEntity; -import org.radarbase.management.repository.CustomRevisionEntityRepository; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.repository.filters.UserFilter; -import org.radarbase.management.security.Constants; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.UserMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.transaction.annotation.Transactional; - -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; -import java.time.Period; -import java.time.ZonedDateTime; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.radarbase.auth.authorization.RoleAuthority.SYS_ADMIN; -import static org.radarbase.management.web.rest.TestUtil.commitTransactionAndStartNew; +package org.radarbase.management.service + +import org.assertj.core.api.Assertions +import org.hibernate.envers.AuditReaderFactory +import org.hibernate.envers.query.AuditEntity +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.User +import org.radarbase.management.domain.audit.CustomRevisionEntity +import org.radarbase.management.repository.CustomRevisionEntityRepository +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.repository.filters.UserFilter +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.UserMapper +import org.radarbase.management.web.rest.TestUtil +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.domain.PageRequest +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.transaction.annotation.Transactional +import java.time.Period +import java.time.ZonedDateTime +import java.util.* +import java.util.function.Consumer +import javax.persistence.EntityManager +import javax.persistence.EntityManagerFactory /** * Test class for the UserResource REST controller. * * @see UserService */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -public class UserServiceIntTest { - - public static final String DEFAULT_LOGIN = "johndoe"; - public static final String UPDATED_LOGIN = "jhipster"; - - public static final String DEFAULT_PASSWORD = "passjohndoe"; - public static final String UPDATED_PASSWORD = "passjhipster"; - - public static final String DEFAULT_EMAIL = "johndoe@localhost"; - public static final String UPDATED_EMAIL = "jhipster@localhost"; - - public static final String DEFAULT_FIRSTNAME = "john"; - public static final String UPDATED_FIRSTNAME = "jhipsterFirstName"; - - public static final String DEFAULT_LASTNAME = "doe"; - public static final String UPDATED_LASTNAME = "jhipsterLastName"; - - public static final String DEFAULT_LANGKEY = "en"; - public static final String UPDATED_LANGKEY = "fr"; - - @Autowired - private UserRepository userRepository; - - @Autowired - private UserMapper userMapper; - - @Autowired - private UserService userService; - - @Autowired - private RevisionService revisionService; - - @Autowired - private CustomRevisionEntityRepository revisionEntityRepository; - - @Autowired - private EntityManagerFactory entityManagerFactory; - - @Autowired - private PasswordService passwordService; - - private EntityManager entityManager; - - private UserDTO userDto; +open class UserServiceIntTest( + @Autowired private val userRepository: UserRepository, + @Autowired private val userMapper: UserMapper, + @Autowired private val userService: UserService, + @Autowired private val revisionService: RevisionService, + @Autowired private val revisionEntityRepository: CustomRevisionEntityRepository, + @Autowired private val entityManagerFactory: EntityManagerFactory, + @Autowired private val passwordService: PasswordService, + private var entityManager: EntityManager, + private var userDto: UserDTO? +) { @BeforeEach - public void setUp() { + fun setUp() { entityManager = entityManagerFactory.createEntityManager( - entityManagerFactory.getProperties()); - userDto = userMapper.userToUserDTO(createEntity(passwordService)); - ReflectionTestUtils.setField(revisionService, "revisionEntityRepository", - revisionEntityRepository); - ReflectionTestUtils.setField(revisionService, "entityManager", entityManager); - ReflectionTestUtils.setField(userService, "userMapper", userMapper); - ReflectionTestUtils.setField(userService, "userRepository", userRepository); - - userRepository.findOneByLogin(userDto.getLogin()) - .ifPresent(userRepository::delete); - } - - /** - * Create a User. - * - *

This is a static method, as tests for other entities might also need it, - * if they test an entity which has a required relationship to the User entity.

- */ - public static User createEntity(PasswordService passwordService) { - User user = new User(); - user.setLogin(DEFAULT_LOGIN); - user.password = passwordService.generateEncodedPassword(); - user.activated = true; - user.email = DEFAULT_EMAIL; - user.firstName = DEFAULT_FIRSTNAME; - user.lastName = DEFAULT_LASTNAME; - user.langKey = DEFAULT_LANGKEY; - return user; + entityManagerFactory.properties + ) + userDto = userMapper.userToUserDTO(createEntity(passwordService)) + ReflectionTestUtils.setField( + revisionService, "revisionEntityRepository", + revisionEntityRepository + ) + ReflectionTestUtils.setField(revisionService, "entityManager", entityManager) + ReflectionTestUtils.setField(userService, "userMapper", userMapper) + ReflectionTestUtils.setField(userService, "userRepository", userRepository) + userRepository.findOneByLogin(userDto!!.login) + .ifPresent { entity: User -> userRepository.delete(entity) } } @Test - void assertThatUserMustExistToResetPassword() { - Optional maybeUser = userService.requestPasswordReset("john.doe@localhost"); - assertThat(maybeUser).isNotPresent(); - - maybeUser = userService.requestPasswordReset("admin@localhost"); - assertThat(maybeUser).isPresent(); - - assertThat(maybeUser.get().email).isEqualTo("admin@localhost"); - assertThat(maybeUser.get().resetDate).isNotNull(); - assertThat(maybeUser.get().resetKey).isNotNull(); + fun assertThatUserMustExistToResetPassword() { + var maybeUser = userService.requestPasswordReset("john.doe@localhost") + Assertions.assertThat(maybeUser).isNotPresent() + maybeUser = userService.requestPasswordReset("admin@localhost") + Assertions.assertThat(maybeUser).isPresent() + Assertions.assertThat(maybeUser.get().email).isEqualTo("admin@localhost") + Assertions.assertThat(maybeUser.get().resetDate).isNotNull() + Assertions.assertThat(maybeUser.get().resetKey).isNotNull() } @Test - void assertThatOnlyActivatedUserCanRequestPasswordReset() throws NotAuthorizedException { - User user = userService.createUser(userDto); - Optional maybeUser = userService.requestPasswordReset(userDto.getEmail()); - assertThat(maybeUser).isNotPresent(); - userRepository.delete(user); + @Throws(NotAuthorizedException::class) + fun assertThatOnlyActivatedUserCanRequestPasswordReset() { + val user = userService.createUser(userDto!!) + val maybeUser = userService.requestPasswordReset( + userDto?.email + ) + Assertions.assertThat(maybeUser).isNotPresent() + userRepository.delete(user) } @Test - void assertThatResetKeyMustNotBeOlderThan24Hours() throws NotAuthorizedException { - User user = userService.createUser(userDto); - - ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(25); - String resetKey = passwordService.generateResetKey(); - user.activated = true; - user.resetDate = daysAgo; - user.resetKey = resetKey; - - userRepository.save(user); - - Optional maybeUser = userService.completePasswordReset("johndoe2", - user.resetKey); - - assertThat(maybeUser).isNotPresent(); - - userRepository.delete(user); + @Throws(NotAuthorizedException::class) + fun assertThatResetKeyMustNotBeOlderThan24Hours() { + val user = userService.createUser(userDto!!) + val daysAgo = ZonedDateTime.now().minusHours(25) + val resetKey = passwordService.generateResetKey() + user.activated = true + user.resetDate = daysAgo + user.resetKey = resetKey + userRepository.save(user) + val maybeUser = userService.completePasswordReset( + "johndoe2", + user.resetKey + ) + Assertions.assertThat(maybeUser).isNotPresent() + userRepository.delete(user) } @Test - void assertThatResetKeyMustBeValid() throws NotAuthorizedException { - User user = userService.createUser(userDto); - ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(25); - user.activated = true; - user.resetDate = daysAgo; - user.resetKey = "1234"; - userRepository.save(user); - Optional maybeUser = userService.completePasswordReset("johndoe2", - user.resetKey); - assertThat(maybeUser).isNotPresent(); - userRepository.delete(user); + @Throws(NotAuthorizedException::class) + fun assertThatResetKeyMustBeValid() { + val user = userService.createUser(userDto!!) + val daysAgo = ZonedDateTime.now().minusHours(25) + user.activated = true + user.resetDate = daysAgo + user.resetKey = "1234" + userRepository.save(user) + val maybeUser = userService.completePasswordReset( + "johndoe2", + user.resetKey + ) + Assertions.assertThat(maybeUser).isNotPresent() + userRepository.delete(user) } @Test - void assertThatUserCanResetPassword() throws NotAuthorizedException { - User user = userService.createUser(userDto); - final String oldPassword = user.password; - ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(2); - String resetKey = passwordService.generateResetKey(); - user.activated = true; - user.resetDate = daysAgo; - user.resetKey = resetKey; - userRepository.save(user); - Optional maybeUser = userService.completePasswordReset("johndoe2", - user.resetKey); - assertThat(maybeUser).isPresent(); - assertThat(maybeUser.get().resetDate).isNull(); - assertThat(maybeUser.get().resetKey).isNull(); - assertThat(maybeUser.get().password).isNotEqualTo(oldPassword); - - userRepository.delete(user); + @Throws(NotAuthorizedException::class) + fun assertThatUserCanResetPassword() { + val user = userService.createUser(userDto!!) + val oldPassword = user.password + val daysAgo = ZonedDateTime.now().minusHours(2) + val resetKey = passwordService.generateResetKey() + user.activated = true + user.resetDate = daysAgo + user.resetKey = resetKey + userRepository.save(user) + val maybeUser = userService.completePasswordReset( + "johndoe2", + user.resetKey + ) + Assertions.assertThat(maybeUser).isPresent() + Assertions.assertThat(maybeUser.get().resetDate).isNull() + Assertions.assertThat(maybeUser.get().resetKey).isNull() + Assertions.assertThat(maybeUser.get().password).isNotEqualTo(oldPassword) + userRepository.delete(user) } @Test - void testFindNotActivatedUsersByCreationDateBefore() { - User expiredUser = addExpiredUser(userRepository); - commitTransactionAndStartNew(); - - // Update the timestamp of the revision so it appears to have been created 5 days ago - ZonedDateTime expDateTime = ZonedDateTime.now().minus(Period.ofDays(5)).withNano(0); - - AuditReader auditReader = AuditReaderFactory.get(entityManager); - Object[] firstRevision = (Object[]) auditReader.createQuery() - .forRevisionsOfEntity(expiredUser.getClass(), false, true) - .add(AuditEntity.id().eq(expiredUser.getId())) - .add(AuditEntity.revisionNumber().minimize() - .computeAggregationInInstanceContext()) - .getSingleResult(); - CustomRevisionEntity first = (CustomRevisionEntity) firstRevision[1]; - first.timestamp = Date.from(expDateTime.toInstant()); - entityManager.joinTransaction(); - CustomRevisionEntity updated = entityManager.merge(first); - commitTransactionAndStartNew(); - assertThat(updated.timestamp).isEqualTo(first.timestamp); - assertThat(updated.timestamp).isEqualTo(Date.from(expDateTime.toInstant())); + fun testFindNotActivatedUsersByCreationDateBefore() { + val expiredUser = addExpiredUser(userRepository) + TestUtil.commitTransactionAndStartNew() + + // Update the timestamp of the revision, so it appears to have been created 5 days ago + val expDateTime = ZonedDateTime.now().minus(Period.ofDays(5)).withNano(0) + val auditReader = AuditReaderFactory.get(entityManager) + val firstRevision = auditReader.createQuery() + .forRevisionsOfEntity(expiredUser.javaClass, false, true) + .add(AuditEntity.id().eq(expiredUser.id)) + .add( + AuditEntity.revisionNumber().minimize() + .computeAggregationInInstanceContext() + ) + .singleResult as Array<*> + val first = firstRevision[1] as CustomRevisionEntity + first.timestamp = Date.from(expDateTime.toInstant()) + entityManager.joinTransaction() + val updated = entityManager.merge(first) + TestUtil.commitTransactionAndStartNew() + Assertions.assertThat(updated.timestamp).isEqualTo(first.timestamp) + Assertions.assertThat(updated.timestamp).isEqualTo(Date.from(expDateTime.toInstant())) // make sure when we reload the expired user we have the new created date - assertThat(revisionService.getAuditInfo(expiredUser).getCreatedAt()).isEqualTo(expDateTime); + Assertions.assertThat(revisionService.getAuditInfo(expiredUser).createdAt).isEqualTo(expDateTime) // Now we know we have an 'old' user in the database, we can test our deletion method - int numUsers = userRepository.findAll().size(); - userService.removeNotActivatedUsers(); - List users = userRepository.findAll(); + val numUsers = userRepository.findAll().size + userService.removeNotActivatedUsers() + val users = userRepository.findAll() // make sure have actually deleted some users, otherwise this test is pointless - assertThat(numUsers - users.size()).isEqualTo(1); + Assertions.assertThat(numUsers - users.size).isEqualTo(1) // remaining users should be either activated or have a created date less then 3 days ago - ZonedDateTime cutoff = ZonedDateTime.now().minus(Period.ofDays(3)); - users.forEach(u -> assertThat(u.activated || revisionService.getAuditInfo(u) - .getCreatedAt().isAfter(cutoff)).isTrue()); + val cutoff = ZonedDateTime.now().minus(Period.ofDays(3)) + users.forEach(Consumer { u: User -> + Assertions.assertThat( + u.activated || revisionService.getAuditInfo(u) + .createdAt!!.isAfter(cutoff) + ).isTrue() + }) // commit the deletion, otherwise the deletion will be rolled back - commitTransactionAndStartNew(); + TestUtil.commitTransactionAndStartNew() } @Test - void assertThatAnonymousUserIsNotGet() { - final PageRequest pageable = PageRequest.of(0, (int) userRepository.count()); - final Page allManagedUsers = userService.findUsers(new UserFilter(), pageable, - false); - assertThat(allManagedUsers.getContent().stream() - .noneMatch(user -> Constants.ANONYMOUS_USER.equals(user.getLogin()))) - .isTrue(); + fun assertThatAnonymousUserIsNotGet() { + val pageable = PageRequest.of(0, userRepository.count().toInt()) + val allManagedUsers = userService.findUsers( + UserFilter(), pageable, + false + ) + Assertions.assertThat( + allManagedUsers!!.content.stream() + .noneMatch { user: UserDTO -> Constants.ANONYMOUS_USER == user.login }) + .isTrue() } /** @@ -255,22 +212,53 @@ public class UserServiceIntTest { * @param userRepository The UserRepository that will be used to save the object * @return the saved object */ - public User addExpiredUser(UserRepository userRepository) { - - Role adminRole = new Role(); - adminRole.setId(1L); - adminRole.authority = new Authority(SYS_ADMIN); - adminRole.project = null; - - User user = new User(); - user.setLogin("expired"); - user.email = "expired@expired"; - user.firstName = "ex"; - user.lastName = "pired"; - user.setRoles(Collections.singleton(adminRole)); - user.activated = false; - user.password = passwordService.generateEncodedPassword(); - return userRepository.save(user); + fun addExpiredUser(userRepository: UserRepository?): User { + val adminRole = Role() + adminRole.id = 1L + adminRole.authority = Authority(RoleAuthority.SYS_ADMIN) + adminRole.project = null + val user = User() + user.setLogin("expired") + user.email = "expired@expired" + user.firstName = "ex" + user.lastName = "pired" + user.roles = mutableSetOf(adminRole) + user.activated = false + user.password = passwordService.generateEncodedPassword() + return userRepository!!.save(user) } + companion object { + const val DEFAULT_LOGIN = "johndoe" + const val UPDATED_LOGIN = "jhipster" + const val DEFAULT_PASSWORD = "passjohndoe" + const val UPDATED_PASSWORD = "passjhipster" + const val DEFAULT_EMAIL = "johndoe@localhost" + const val UPDATED_EMAIL = "jhipster@localhost" + const val DEFAULT_FIRSTNAME = "john" + const val UPDATED_FIRSTNAME = "jhipsterFirstName" + const val DEFAULT_LASTNAME = "doe" + const val UPDATED_LASTNAME = "jhipsterLastName" + const val DEFAULT_LANGKEY = "en" + const val UPDATED_LANGKEY = "fr" + + /** + * Create a User. + * + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which has a required relationship to the User entity. + */ + fun createEntity(passwordService: PasswordService?): User { + val user = User() + user.setLogin(DEFAULT_LOGIN) + user.password = passwordService!!.generateEncodedPassword() + user.activated = true + user.email = DEFAULT_EMAIL + user.firstName = DEFAULT_FIRSTNAME + user.lastName = DEFAULT_LASTNAME + user.langKey = DEFAULT_LANGKEY + return user + } + } } diff --git a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt index ae1ea69eb..1b8092117 100644 --- a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt @@ -1,227 +1,218 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.auth.token.RadarToken; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.security.RadarAuthentication; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.MailService; -import org.radarbase.management.service.UserService; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.UserMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.radarbase.management.security.JwtAuthenticationFilter.setRadarToken; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.ArgumentMatchers +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.auth.token.RadarToken +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.User +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.security.JwtAuthenticationFilter.Companion.radarToken +import org.radarbase.management.security.RadarAuthentication +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.MailService +import org.radarbase.management.service.UserService +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.UserMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.MediaType +import org.springframework.mock.web.MockHttpServletRequest +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import java.util.* /** * Test class for the AccountResource REST controller. * * @see AccountResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) -class AccountResourceIntTest { - - @Autowired - private UserRepository userRepository; - - @Autowired - private UserService userService; - - @Autowired - private UserMapper userMapper; - - @Mock - private UserService mockUserService; - - @Mock - private MailService mockMailService; - - private MockMvc restUserMockMvc; - - @Autowired - private RadarToken radarToken; - - @Autowired - private AuthService authService; - - @Autowired - private ManagementPortalProperties managementPortalProperties; +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) +internal open class AccountResourceIntTest( + @Autowired private val userRepository: UserRepository, + @Autowired private val userService: UserService, + @Autowired private val userMapper: UserMapper, + @Mock private val mockUserService: UserService, + @Mock private val mockMailService: MailService, + private var restUserMockMvc: MockMvc, + @Autowired private val radarToken: RadarToken, + @Autowired private val authService: AuthService, + @Autowired private val managementPortalProperties: ManagementPortalProperties +) { @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); - doNothing().when(mockMailService).sendActivationEmail(any(User.class)); - - SecurityContextHolder.getContext().setAuthentication(new RadarAuthentication(radarToken)); - - AccountResource accountResource = new AccountResource(); - ReflectionTestUtils.setField(accountResource, "userService", userService); - ReflectionTestUtils.setField(accountResource, "userMapper", userMapper); - ReflectionTestUtils.setField(accountResource, "mailService", mockMailService); - ReflectionTestUtils.setField(accountResource, "authService", authService); - ReflectionTestUtils.setField(accountResource, "token", radarToken); - ReflectionTestUtils.setField(accountResource, "managementPortalProperties", - managementPortalProperties); - - AccountResource accountUserMockResource = new AccountResource(); - ReflectionTestUtils.setField(accountUserMockResource, "userService", mockUserService); - ReflectionTestUtils.setField(accountUserMockResource, "userMapper", userMapper); - ReflectionTestUtils.setField(accountUserMockResource, "mailService", mockMailService); - ReflectionTestUtils.setField(accountUserMockResource, "authService", authService); - ReflectionTestUtils.setField(accountUserMockResource, "token", radarToken); - ReflectionTestUtils.setField(accountUserMockResource, "managementPortalProperties", - managementPortalProperties); - - this.restUserMockMvc = MockMvcBuilders.standaloneSetup(accountUserMockResource).build(); + fun setUp() { + MockitoAnnotations.openMocks(this) + Mockito.doNothing().`when`(mockMailService).sendActivationEmail( + ArgumentMatchers.any( + User::class.java + ) + ) + SecurityContextHolder.getContext().authentication = RadarAuthentication(radarToken) + val accountResource = AccountResource() + ReflectionTestUtils.setField(accountResource, "userService", userService) + ReflectionTestUtils.setField(accountResource, "userMapper", userMapper) + ReflectionTestUtils.setField(accountResource, "mailService", mockMailService) + ReflectionTestUtils.setField(accountResource, "authService", authService) + ReflectionTestUtils.setField(accountResource, "token", radarToken) + ReflectionTestUtils.setField( + accountResource, "managementPortalProperties", + managementPortalProperties + ) + val accountUserMockResource = AccountResource() + ReflectionTestUtils.setField(accountUserMockResource, "userService", mockUserService) + ReflectionTestUtils.setField(accountUserMockResource, "userMapper", userMapper) + ReflectionTestUtils.setField(accountUserMockResource, "mailService", mockMailService) + ReflectionTestUtils.setField(accountUserMockResource, "authService", authService) + ReflectionTestUtils.setField(accountUserMockResource, "token", radarToken) + ReflectionTestUtils.setField( + accountUserMockResource, "managementPortalProperties", + managementPortalProperties + ) + restUserMockMvc = MockMvcBuilders.standaloneSetup(accountUserMockResource).build() } @AfterEach - public void tearDown() { - SecurityContextHolder.getContext().setAuthentication(null); + fun tearDown() { + SecurityContextHolder.getContext().authentication = null } @Test - void testNonAuthenticatedUser() throws Exception { - restUserMockMvc.perform(post("/api/login") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isForbidden()); + @Throws(Exception::class) + fun testNonAuthenticatedUser() { + restUserMockMvc.perform( + MockMvcRequestBuilders.post("/api/login") + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(MockMvcResultMatchers.status().isForbidden()) } @Test - void testAuthenticatedUser() throws Exception { - final RadarToken token = mock(RadarToken.class); - - Set roles = new HashSet<>(); - org.radarbase.management.domain.Role role = new org.radarbase.management.domain.Role(); - Authority authority = new Authority(); - authority.name = RoleAuthority.SYS_ADMIN.getAuthority(); - role.authority = authority; - roles.add(role); - - User user = new User(); - user.setLogin("test"); - user.firstName = "john"; - user.lastName = "doe"; - user.email = "john.doe@jhipster.com"; - user.langKey = "en"; - user.setRoles(roles); - when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.of(user)); - - restUserMockMvc.perform(post("/api/login") - .with(request -> { - setRadarToken(request, token); - request.setRemoteUser("test"); - return request; - }) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.login").value("test")) - .andExpect(jsonPath("$.firstName").value("john")) - .andExpect(jsonPath("$.lastName").value("doe")) - .andExpect(jsonPath("$.email").value("john.doe@jhipster.com")) - .andExpect(jsonPath("$.langKey").value("en")) - .andExpect(jsonPath("$.authorities").value( - RoleAuthority.SYS_ADMIN.getAuthority())); + @Throws(Exception::class) + fun testAuthenticatedUser() { + val token = Mockito.mock(RadarToken::class.java) + val roles: MutableSet = HashSet() + val role = Role() + val authority = Authority() + authority.name = RoleAuthority.SYS_ADMIN.authority + role.authority = authority + roles.add(role) + val user = User() + user.setLogin("test") + user.firstName = "john" + user.lastName = "doe" + user.email = "john.doe@jhipster.com" + user.langKey = "en" + user.roles = roles + Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(Optional.of(user)) + restUserMockMvc.perform(MockMvcRequestBuilders.post("/api/login") + .with { request: MockHttpServletRequest -> + request.radarToken = token + request.remoteUser = "test" + request + } + .accept(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.login").value("test")) + .andExpect(MockMvcResultMatchers.jsonPath("$.firstName").value("john")) + .andExpect(MockMvcResultMatchers.jsonPath("$.lastName").value("doe")) + .andExpect(MockMvcResultMatchers.jsonPath("$.email").value("john.doe@jhipster.com")) + .andExpect(MockMvcResultMatchers.jsonPath("$.langKey").value("en")) + .andExpect( + MockMvcResultMatchers.jsonPath("$.authorities").value( + RoleAuthority.SYS_ADMIN.authority + ) + ) } @Test - void testGetExistingAccount() throws Exception { - Set roles = new HashSet<>(); - org.radarbase.management.domain.Role role = new org.radarbase.management.domain.Role(); - Authority authority = new Authority(); - authority.name = RoleAuthority.SYS_ADMIN.getAuthority(); - role.authority = authority; - roles.add(role); - - User user = new User(); - user.setLogin("test"); - user.firstName = "john"; - user.lastName = "doe"; - user.email = "john.doe@jhipster.com"; - user.langKey = "en"; - user.setRoles(roles); - when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.of(user)); - - restUserMockMvc.perform(get("/api/account") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.login").value("test")) - .andExpect(jsonPath("$.firstName").value("john")) - .andExpect(jsonPath("$.lastName").value("doe")) - .andExpect(jsonPath("$.email").value("john.doe@jhipster.com")) - .andExpect(jsonPath("$.langKey").value("en")) - .andExpect(jsonPath("$.authorities").value( - RoleAuthority.SYS_ADMIN.getAuthority())); + @Throws(Exception::class) + fun testGetExistingAccount() { + val roles: MutableSet = HashSet() + val role = Role() + val authority = Authority() + authority.name = RoleAuthority.SYS_ADMIN.authority + role.authority = authority + roles.add(role) + val user = User() + user.setLogin("test") + user.firstName = "john" + user.lastName = "doe" + user.email = "john.doe@jhipster.com" + user.langKey = "en" + user.roles = roles + Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(Optional.of(user)) + restUserMockMvc.perform( + MockMvcRequestBuilders.get("/api/account") + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.login").value("test")) + .andExpect(MockMvcResultMatchers.jsonPath("$.firstName").value("john")) + .andExpect(MockMvcResultMatchers.jsonPath("$.lastName").value("doe")) + .andExpect(MockMvcResultMatchers.jsonPath("$.email").value("john.doe@jhipster.com")) + .andExpect(MockMvcResultMatchers.jsonPath("$.langKey").value("en")) + .andExpect( + MockMvcResultMatchers.jsonPath("$.authorities").value( + RoleAuthority.SYS_ADMIN.authority + ) + ) } @Test - void testGetUnknownAccount() throws Exception { - when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.empty()); - - restUserMockMvc.perform(get("/api/account") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isForbidden()); + @Throws(Exception::class) + fun testGetUnknownAccount() { + Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(Optional.empty()) + restUserMockMvc.perform( + MockMvcRequestBuilders.get("/api/account") + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(MockMvcResultMatchers.status().isForbidden()) } @Test @Transactional - void testSaveInvalidLogin() throws Exception { - Set roles = new HashSet<>(); - RoleDTO role = new RoleDTO(); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - roles.add(role); - - UserDTO invalidUser = new UserDTO(); - invalidUser.setLogin("funky-log!n"); // invalid login - invalidUser.setFirstName("Funky"); - invalidUser.setLastName("One"); - invalidUser.setEmail("funky@example.com"); - invalidUser.setActivated(true); - invalidUser.setLangKey("en"); - invalidUser.setRoles(roles); - - restUserMockMvc.perform(post("/api/account") + @Throws(Exception::class) + open fun testSaveInvalidLogin() { + val roles: MutableSet = HashSet() + val role = RoleDTO() + role.authorityName = RoleAuthority.PARTICIPANT.authority + roles.add(role) + val invalidUser = UserDTO() + invalidUser.login = "funky-log!n" // invalid login + invalidUser.firstName = "Funky" + invalidUser.lastName = "One" + invalidUser.email = "funky@example.com" + invalidUser.isActivated = true + invalidUser.langKey = "en" + invalidUser.roles = roles + restUserMockMvc.perform( + MockMvcRequestBuilders.post("/api/account") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(invalidUser))) - .andExpect(status().isBadRequest()); - - Optional user = userRepository.findOneByEmail("funky@example.com"); - assertThat(user).isNotPresent(); + .content(TestUtil.convertObjectToJsonBytes(invalidUser)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val user = userRepository.findOneByEmail("funky@example.com") + Assertions.assertThat(user).isNotPresent() } } diff --git a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt index c36f509e1..0c35a35e0 100644 --- a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt @@ -1,168 +1,192 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.config.audit.AuditEventConverter; -import org.radarbase.management.domain.PersistentAuditEvent; -import org.radarbase.management.repository.PersistenceAuditEventRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuditEventService; -import org.radarbase.management.service.AuthService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.format.support.FormattingConversionService; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.servlet.ServletException; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; - -import static org.hamcrest.Matchers.hasItem; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.config.audit.AuditEventConverter +import org.radarbase.management.domain.PersistentAuditEvent +import org.radarbase.management.repository.PersistenceAuditEventRepository +import org.radarbase.management.service.AuditEventService +import org.radarbase.management.service.AuthService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.format.support.FormattingConversionService +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import javax.servlet.ServletException /** * Test class for the AuditResource REST controller. * * @see AuditResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -class AuditResourceIntTest { - - private static final String SAMPLE_PRINCIPAL = "SAMPLE_PRINCIPAL"; - private static final String SAMPLE_TYPE = "SAMPLE_TYPE"; - private static final LocalDateTime SAMPLE_TIMESTAMP = - LocalDateTime.parse("2015-08-04T10:11:30"); - private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - +internal class AuditResourceIntTest { @Autowired - private PersistenceAuditEventRepository auditEventRepository; + private val auditEventRepository: PersistenceAuditEventRepository? = null @Autowired - private AuditEventConverter auditEventConverter; + private val auditEventConverter: AuditEventConverter? = null @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; + private val jacksonMessageConverter: MappingJackson2HttpMessageConverter? = null @Autowired - private FormattingConversionService formattingConversionService; + private val formattingConversionService: FormattingConversionService? = null @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver? = null + private var auditEvent: PersistentAuditEvent? = null + private var restAuditMockMvc: MockMvc? = null - private PersistentAuditEvent auditEvent; - - private MockMvc restAuditMockMvc; @Autowired - private AuthService authService; - + private val authService: AuthService? = null @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - AuditEventService auditEventService = new AuditEventService( - auditEventRepository, - auditEventConverter); - AuditResource auditResource = new AuditResource(auditEventService, authService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restAuditMockMvc = MockMvcBuilders.standaloneSetup(auditResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setConversionService(formattingConversionService) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.initMocks(this) + val auditEventService = AuditEventService( + auditEventRepository, + auditEventConverter + ) + val auditResource = AuditResource(auditEventService, authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter!!.init(MockFilterConfig()) + restAuditMockMvc = MockMvcBuilders.standaloneSetup(auditResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setConversionService(formattingConversionService) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() } @BeforeEach - public void initTest() { - auditEventRepository.deleteAll(); - auditEvent = new PersistentAuditEvent(); - auditEvent.auditEventType = SAMPLE_TYPE; - auditEvent.principal = SAMPLE_PRINCIPAL; - auditEvent.auditEventDate = SAMPLE_TIMESTAMP; - } - - @Test - void getAllAudits() throws Exception { - // Initialize the database - auditEventRepository.save(auditEvent); - - // Get all the audits - restAuditMockMvc.perform(get("/management/audits")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].principal").value(hasItem(SAMPLE_PRINCIPAL))); - } - - @Test - void getAudit() throws Exception { - // Initialize the database - auditEventRepository.save(auditEvent); - - // Get the audit - restAuditMockMvc.perform(get("/management/audits/{id}", auditEvent.id)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.principal").value(SAMPLE_PRINCIPAL)); - } - - @Test - void getAuditsByDate() throws Exception { - // Initialize the database - auditEventRepository.save(auditEvent); - - // Generate dates for selecting audits by date, making sure the period contains the audit - String fromDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER); - String toDate = SAMPLE_TIMESTAMP.plusDays(1).format(FORMATTER); - - // Get the audit - restAuditMockMvc.perform(get("/management/audits?fromDate=" + fromDate + "&toDate=" - + toDate)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].principal").value(hasItem(SAMPLE_PRINCIPAL))); - } - - @Test - void getNonExistingAuditsByDate() throws Exception { - // Initialize the database - auditEventRepository.save(auditEvent); - - // Generate dates for selecting audits by date, making sure the period will not contain the - // sample audit - String fromDate = SAMPLE_TIMESTAMP.minusDays(2).format(FORMATTER); - String toDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER); - - // Query audits but expect no results - restAuditMockMvc.perform(get("/management/audits?fromDate=" + fromDate + "&toDate=" - + toDate)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(header().string("X-Total-Count", "0")); + fun initTest() { + auditEventRepository!!.deleteAll() + auditEvent = PersistentAuditEvent() + auditEvent!!.auditEventType = SAMPLE_TYPE + auditEvent!!.principal = SAMPLE_PRINCIPAL + auditEvent!!.auditEventDate = SAMPLE_TIMESTAMP } - @Test - void getNonExistingAudit() throws Exception { - // Get the audit - restAuditMockMvc.perform(get("/management/audits/{id}", Long.MAX_VALUE)) - .andExpect(status().isNotFound()); + @get:Throws(Exception::class) + @get:Test + val allAudits: Unit + get() { + // Initialize the database + auditEventRepository!!.save(auditEvent) + + // Get all the audits + restAuditMockMvc!!.perform(MockMvcRequestBuilders.get("/management/audits")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].principal").value>( + Matchers.hasItem( + SAMPLE_PRINCIPAL + ) + ) + ) + } + + @get:Throws(Exception::class) + @get:Test + val audit: Unit + get() { + // Initialize the database + auditEventRepository!!.save(auditEvent) + + // Get the audit + restAuditMockMvc!!.perform(MockMvcRequestBuilders.get("/management/audits/{id}", auditEvent!!.id)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.principal").value(SAMPLE_PRINCIPAL)) + } + + @get:Throws(Exception::class) + @get:Test + val auditsByDate: Unit + get() { + // Initialize the database + auditEventRepository!!.save(auditEvent) + + // Generate dates for selecting audits by date, making sure the period contains the audit + val fromDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER) + val toDate = SAMPLE_TIMESTAMP.plusDays(1).format(FORMATTER) + + // Get the audit + restAuditMockMvc!!.perform( + MockMvcRequestBuilders.get( + "/management/audits?fromDate=" + fromDate + "&toDate=" + + toDate + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].principal").value>( + Matchers.hasItem( + SAMPLE_PRINCIPAL + ) + ) + ) + } + + @get:Throws(Exception::class) + @get:Test + val nonExistingAuditsByDate: Unit + get() { + // Initialize the database + auditEventRepository!!.save(auditEvent) + + // Generate dates for selecting audits by date, making sure the period will not contain the + // sample audit + val fromDate = SAMPLE_TIMESTAMP.minusDays(2).format(FORMATTER) + val toDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER) + + // Query audits but expect no results + restAuditMockMvc!!.perform( + MockMvcRequestBuilders.get( + "/management/audits?fromDate=" + fromDate + "&toDate=" + + toDate + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.header().string("X-Total-Count", "0")) + } + + @get:Throws(Exception::class) + @get:Test + val nonExistingAudit: Unit + get() { + // Get the audit + restAuditMockMvc!!.perform(MockMvcRequestBuilders.get("/management/audits/{id}", Long.MAX_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } + + companion object { + private const val SAMPLE_PRINCIPAL = "SAMPLE_PRINCIPAL" + private const val SAMPLE_TYPE = "SAMPLE_TYPE" + private val SAMPLE_TIMESTAMP = LocalDateTime.parse("2015-08-04T10:11:30") + private val FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd") } } diff --git a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt index 31be75902..ca21e70f4 100644 --- a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt @@ -1,432 +1,480 @@ -package org.radarbase.management.web.rest; - -import org.assertj.core.api.Condition; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Group; -import org.radarbase.management.domain.Project; -import org.radarbase.management.repository.GroupRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.RoleRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.GroupService; -import org.radarbase.management.service.SubjectService; -import org.radarbase.management.service.dto.GroupDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.mapper.GroupMapper; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.radarbase.management.web.rest.vm.GroupPatchOperation; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import javax.servlet.ServletException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.radarbase.management.service.dto.SubjectDTO.SubjectStatus.ACTIVATED; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Condition +import org.hamcrest.Matchers +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.Group +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.GroupRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.RoleRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.GroupService +import org.radarbase.management.service.SubjectService +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.dto.SubjectDTO.SubjectStatus +import org.radarbase.management.service.mapper.GroupMapper +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.radarbase.management.web.rest.vm.GroupPatchOperation +import org.radarbase.management.web.rest.vm.GroupPatchOperation.SubjectPatchValue +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import java.util.* +import javax.servlet.ServletException /** * Test class for the GroupResource REST controller. * * @see GroupResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class GroupResourceIntTest { +internal class GroupResourceIntTest(@Autowired private val groupService: GroupService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val roleRepository: RoleRepository, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val subjectService: SubjectService, + @Autowired private val groupMapper: GroupMapper, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val groupRepository: GroupRepository, + private var restGroupMockMvc: MockMvc, private var group: Group, + private var project: Project +) { @Autowired - private GroupService groupService; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private ProjectMapper projectMapper; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private RoleRepository roleRepository; - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private SubjectService subjectService; - - @Autowired - private GroupMapper groupMapper; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - @Autowired - private GroupRepository groupRepository; - - private MockMvc restGroupMockMvc; - - private Group group; - - private Project project; - @Autowired - private AuthService authService; - + private val authService: AuthService? = null @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - var groupResource = new GroupResource(); - ReflectionTestUtils.setField(groupResource, "groupService", groupService); - ReflectionTestUtils.setField(groupResource, "authService", authService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restGroupMockMvc = MockMvcBuilders.standaloneSetup(groupResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - project = ProjectResourceIntTest.createEntity(); - projectRepository.save(project); - group = createEntity(); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.initMocks(this) + val groupResource = GroupResource() + ReflectionTestUtils.setField(groupResource, "groupService", groupService) + ReflectionTestUtils.setField(groupResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restGroupMockMvc = MockMvcBuilders.standaloneSetup(groupResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() + project = ProjectResourceIntTest.Companion.createEntity() + projectRepository.save(project) + group = createEntity() } @AfterEach - public void tearDown() { - groupRepository.delete(group); - var roles = roleRepository.findAllRolesByProjectName(project.projectName); - roleRepository.deleteAll(roles); - projectRepository.delete(project); + fun tearDown() { + groupRepository.delete(group) + val roles = roleRepository.findAllRolesByProjectName( + project.projectName + ) + roleRepository.deleteAll(roles) + projectRepository.delete(project) } /** * Create an entity for this test. */ - private Group createEntity() { - Group group = new Group(); - group.name = "group1"; - group.project = project; - return group; + private fun createEntity(): Group { + val group = Group() + group.name = "group1" + group.project = project + return group } @Test - void createGroup() throws Exception { + @Throws(Exception::class) + fun createGroup() { // Create the Group - var groupDto = groupMapper.groupToGroupDTO(group); - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto))) - .andExpect(status().isCreated()); - - var savedGroup = groupRepository.findByProjectNameAndName( - project.projectName, groupDto.getName()).get(); + val groupDto = groupMapper.groupToGroupDTO(group) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(groupDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) + val savedGroup: Group? = groupRepository.findByProjectNameAndName( + project.projectName, groupDto.name + ) // Validate the Group in the database - assertThat(savedGroup.project.getId()).isEqualTo(project.getId()); - assertThat(savedGroup.name).isEqualTo("group1"); + assertThat(savedGroup?.project?.id).isEqualTo(project.id) + assertThat(savedGroup?.name).isEqualTo("group1") } - @Test - void createGroupNonExistingProject() throws Exception { - projectRepository.delete(project); + @Throws(Exception::class) + fun createGroupNonExistingProject() { + projectRepository.delete(project) // Create the Group - var groupDto = groupMapper.groupToGroupDTO(group); - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto))) - .andExpect(status().isNotFound()); + val groupDto = groupMapper.groupToGroupDTO(group) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(groupDto)) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) } @Test - void createGroupWithExistingName() throws Exception { + @Throws(Exception::class) + fun createGroupWithExistingName() { // Create the Group - var groupDto = groupMapper.groupToGroupDTO(group); - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto))) - .andExpect(status().isCreated()); - - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto))) - .andExpect(status().isConflict()); + val groupDto = groupMapper.groupToGroupDTO(group) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(groupDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(groupDto)) + ) + .andExpect(MockMvcResultMatchers.status().isConflict()) } - @Test - void createGroupWithExistingNameInDifferentProject() throws Exception { - Project project2 = ProjectResourceIntTest.createEntity() - .projectName(project.projectName + "2"); - - projectRepository.saveAndFlush(project2); - Group group2 = new Group(); - group2.name = group.name; - group2.project = project2; + @Throws(Exception::class) + fun createGroupWithExistingNameInDifferentProject() { + val project2: Project = ProjectResourceIntTest.Companion.createEntity() + .projectName(project.projectName + "2") + projectRepository.saveAndFlush(project2) + val group2 = Group() + group2.name = group.name + group2.project = project2 // Create the Group - var groupDto = groupMapper.groupToGroupDTO(group); - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto))) - .andExpect(status().isCreated()); - - var group2Dto = groupMapper.groupToGroupDTO(group2); - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project2.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(group2Dto))) - .andExpect(status().isCreated()); + val groupDto = groupMapper.groupToGroupDTO(group) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(groupDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) + val group2Dto = groupMapper.groupToGroupDTO(group2) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project2.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(group2Dto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate groups are saved for both projects - var savedGroup1 = groupRepository.findByProjectNameAndName( - project.projectName, group.name).get(); - var savedGroup2 = groupRepository.findByProjectNameAndName( - project2.projectName, group2.name).get(); - var groupList = Arrays.asList(savedGroup1, savedGroup2); - assertThat(groupList).hasSize(2); - assertThat(groupList).haveAtLeastOne(new Condition<>( - g -> project.getId().equals(g.project.getId()), "use project 1")); - assertThat(groupList).haveAtLeastOne(new Condition<>( - g -> project2.getId().equals(g.project.getId()), "use project 2")); - assertThat(groupList).allSatisfy( - g -> assertThat(g.name).isEqualTo(group.name)); - - projectRepository.delete(project2); + val savedGroup1: Group? = groupRepository.findByProjectNameAndName( + project.projectName, group.name + ) + val savedGroup2: Group? = groupRepository.findByProjectNameAndName( + project2.projectName, group2.name + ) + val groupList = listOf(savedGroup1, savedGroup2) + assertThat(groupList).hasSize(2) + assertThat(groupList).haveAtLeastOne( + Condition( + { g -> project.id == g?.project?.id }, "use project 1" + ) + ) + assertThat(groupList).haveAtLeastOne( + Condition( + { g -> project2.id == g?.project?.id }, "use project 2" + ) + ) + assertThat(groupList).allSatisfy { g -> assertThat(g?.name).isEqualTo(group.name) } + projectRepository.delete(project2) } @Test - void checkGroupNameIsRequired() throws Exception { - group.name = null; + @Throws(Exception::class) + fun checkGroupNameIsRequired() { + group.name = null // Create the Group - GroupDTO groupDto = groupMapper.groupToGroupDTO(group); - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto))) - .andExpect(status().isBadRequest()); + val groupDto = groupMapper.groupToGroupDTO(group) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(groupDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) } - @Test - void getAllGroups() throws Exception { - // Initialize the database - groupRepository.saveAndFlush(group); - - // Get all the groups - restGroupMockMvc.perform(get("/api/projects/{projectName}/groups", - project.projectName)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].projectId").value( - hasItem(project.getId().intValue()))) - .andExpect(jsonPath("$.[*].name").value(hasItem("group1"))); - } + @get:Throws(Exception::class) + @get:Test + val allGroups: Unit + get() { + // Initialize the database + groupRepository.saveAndFlush(group) + + // Get all the groups + restGroupMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/projects/{projectName}/groups", + project.projectName + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].projectId").value>( + Matchers.hasItem(project.id!!.toInt()) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].name").value>(Matchers.hasItem("group1")) + ) + } @Test - void getGroup() throws Exception { + @Throws(Exception::class) + fun getGroup() { // Initialize the database - groupRepository.saveAndFlush(group); + groupRepository.saveAndFlush(group) // Get the Group - restGroupMockMvc.perform(get("/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.name").value("group1")) - .andExpect(jsonPath("$.projectId").value(project.getId().intValue())); + restGroupMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName, group.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("group1")) + .andExpect(MockMvcResultMatchers.jsonPath("$.projectId").value(project.id!!.toInt())) } - @Test - void getNonExistingGroup() throws Exception { - // Get the Group - restGroupMockMvc.perform(get("/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name)) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Test + val nonExistingGroup: Unit + get() { + // Get the Group + restGroupMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName, group.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test - void deleteGroup() throws Exception { + @Throws(Exception::class) + fun deleteGroup() { // Initialize the database - groupRepository.saveAndFlush(group); + groupRepository.saveAndFlush(group) // Get the Group - restGroupMockMvc.perform(delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isNoContent()); + restGroupMockMvc.perform( + MockMvcRequestBuilders.delete( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName, group.name + ) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isNoContent()) // Validate the Group is not present in the database - var savedGroup = groupRepository.findByProjectNameAndName( - project.projectName, group.name); - assertThat(savedGroup).isEmpty(); + val savedGroup = groupRepository.findByProjectNameAndName( + project.projectName, group.name + ) + assertThat(savedGroup).isNull() } @Test - void deleteGroupWithSubjects() throws Exception { + @Throws(Exception::class) + fun deleteGroupWithSubjects() { // Initialize the database - groupRepository.saveAndFlush(group); - - var projectDto = projectMapper.projectToProjectDTO(project); - - var subjectDto = new SubjectDTO(); - subjectDto.setExternalLink("exLink1"); - subjectDto.setExternalId("exId1"); - subjectDto.setStatus(ACTIVATED); - subjectDto.setProject(projectDto); - subjectDto.setGroup(group.name); - var savedSubject = subjectService.createSubject(subjectDto); + groupRepository.saveAndFlush(group) + val projectDto = projectMapper.projectToProjectDTO(project) + val subjectDto = SubjectDTO() + subjectDto.externalLink = "exLink1" + subjectDto.externalId = "exId1" + subjectDto.status = SubjectStatus.ACTIVATED + subjectDto.project = projectDto + subjectDto.group = group.name + val savedSubject = subjectService.createSubject(subjectDto) // Try to delete the Group (and fail) - restGroupMockMvc.perform(delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isConflict()); + restGroupMockMvc.perform( + MockMvcRequestBuilders.delete( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName, group.name + ) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isConflict()) // Delete the Group (and unlink the subjects) - restGroupMockMvc.perform(delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name) - .param("unlinkSubjects", "true") - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isNoContent()); + restGroupMockMvc.perform( + MockMvcRequestBuilders.delete( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName, group.name + ) + .param("unlinkSubjects", "true") + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isNoContent()) // Validate the Group is not present in the database - var savedGroup = groupRepository.findByProjectNameAndName( - project.projectName, group.name); - assertThat(savedGroup).isEmpty(); - - var storedSubject = subjectRepository.getOne(savedSubject.getId()); - subjectRepository.delete(storedSubject); + val savedGroup = groupRepository.findByProjectNameAndName( + project.projectName, group.name + ) + Assertions.assertThat(savedGroup).isNull() + val storedSubject = subjectRepository.getOne(savedSubject!!.id) + subjectRepository.delete(storedSubject) } @Test - void deleteGroupNonExisting() throws Exception { + @Throws(Exception::class) + fun deleteGroupNonExisting() { // Initialize the database - groupRepository.saveAndFlush(group); + groupRepository.saveAndFlush(group) // Get the Group - restGroupMockMvc.perform(delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name + "2") - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isNotFound()); + restGroupMockMvc.perform( + MockMvcRequestBuilders.delete( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName, group.name + "2" + ) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) // Validate the database still contains the group - assertThat(groupRepository.findById(group.getId())).isNotEmpty(); + Assertions.assertThat( + groupRepository.findById( + group.id + ) + ).isNotEmpty() } - @Test - void deleteGroupNonExistingProject() throws Exception { + @Throws(Exception::class) + fun deleteGroupNonExistingProject() { // Initialize the database - groupRepository.saveAndFlush(group); + groupRepository.saveAndFlush(group) // Get the Group - restGroupMockMvc.perform(delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName + "2", group.name) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isNotFound()); + restGroupMockMvc.perform( + MockMvcRequestBuilders.delete( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName + "2", group.name + ) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) // Validate the database still contains the group - assertThat(groupRepository.findById(group.getId())).isNotEmpty(); + Assertions.assertThat( + groupRepository.findById( + group.id + ) + ).isNotEmpty() } @Test - void addSubjectsToGroup() throws Exception { + @Throws(Exception::class) + fun addSubjectsToGroup() { // Initialize the database - groupRepository.saveAndFlush(group); - - var projectDto = projectMapper.projectToProjectDTO(project); - - var sub1 = new SubjectDTO(); - sub1.setExternalLink("exLink1"); - sub1.setExternalId("exId1"); - sub1.setStatus(ACTIVATED); - sub1.setProject(projectDto); - - var sub2 = new SubjectDTO(); - sub2.setExternalLink("exLink2"); - sub2.setExternalId("exId2"); - sub2.setStatus(ACTIVATED); - sub2.setProject(projectDto); - - var savedSub1 = subjectService.createSubject(sub1); - var savedSub2 = subjectService.createSubject(sub2); - - var sub1Patch = new GroupPatchOperation.SubjectPatchValue(); - sub1Patch.setId(savedSub1.getId()); - var sub2Patch = new GroupPatchOperation.SubjectPatchValue(); - sub2Patch.setLogin(savedSub2.getLogin()); - - var patchOp = new GroupPatchOperation(); - patchOp.setOp("add"); - var patchValue = new ArrayList(); - patchValue.add(sub1Patch); - patchValue.add(sub2Patch); - patchOp.setValue(patchValue); - - List body = new ArrayList<>(); - body.add(patchOp); + groupRepository.saveAndFlush(group) + val projectDto = projectMapper.projectToProjectDTO(project) + val sub1 = SubjectDTO() + sub1.externalLink = "exLink1" + sub1.externalId = "exId1" + sub1.status = SubjectStatus.ACTIVATED + sub1.project = projectDto + val sub2 = SubjectDTO() + sub2.externalLink = "exLink2" + sub2.externalId = "exId2" + sub2.status = SubjectStatus.ACTIVATED + sub2.project = projectDto + val savedSub1 = subjectService.createSubject(sub1) + val savedSub2 = subjectService.createSubject(sub2) + val sub1Patch = SubjectPatchValue() + sub1Patch.id = savedSub1!!.id + val sub2Patch = SubjectPatchValue() + sub2Patch.login = savedSub2!!.getLogin() + val patchOp = GroupPatchOperation() + patchOp.op = "add" + val patchValue = ArrayList() + patchValue.add(sub1Patch) + patchValue.add(sub2Patch) + patchOp.value = patchValue + val body: MutableList = ArrayList() + body.add(patchOp) // Get the Group - restGroupMockMvc.perform(patch( - "/api/projects/{projectName}/groups/{groupName}/subjects", - project.projectName, group.name) - - .contentType(TestUtil.APPLICATION_JSON_PATCH) - .content(TestUtil.convertObjectToJsonBytes(body))) - .andExpect(status().isNoContent()); + restGroupMockMvc.perform( + MockMvcRequestBuilders.patch( + "/api/projects/{projectName}/groups/{groupName}/subjects", + project.projectName, group.name + ) + .contentType(TestUtil.APPLICATION_JSON_PATCH) + .content(TestUtil.convertObjectToJsonBytes(body)) + ) + .andExpect(MockMvcResultMatchers.status().isNoContent()) // Validate that the group was set for both subjects - var subjectLogins = Arrays.asList(savedSub1.getLogin(), savedSub2.getLogin()); - var subjects = subjectRepository.findAllBySubjectLogins(subjectLogins); - assertThat(subjects).hasSize(2); - assertThat(subjects).allSatisfy( - s -> assertThat(s.group.getId()).isEqualTo(group.getId())); - - subjectRepository.deleteAll(subjects); + val subjectLogins = listOf(savedSub1.getLogin(), savedSub2.getLogin()) + val subjects = subjectRepository.findAllBySubjectLogins(subjectLogins) + Assertions.assertThat(subjects).hasSize(2) + Assertions.assertThat(subjects).allSatisfy { s: Subject -> + Assertions.assertThat( + s.group!!.id + ).isEqualTo(group.id) + } + subjectRepository.deleteAll(subjects) } } diff --git a/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt index a102450ae..65a4f2fa8 100644 --- a/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt @@ -1,59 +1,57 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.web.rest.vm.LoggerVM; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.web.rest.vm.LoggerVM +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.MediaType +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders /** * Test class for the LogsResource REST controller. * * @see LogsResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) -class LogsResourceIntTest { - - private MockMvc restLogsMockMvc; - +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) +internal class LogsResourceIntTest { + private var restLogsMockMvc: MockMvc? = null @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); - - LogsResource logsResource = new LogsResource(); - this.restLogsMockMvc = MockMvcBuilders - .standaloneSetup(logsResource) - .build(); + fun setUp() { + MockitoAnnotations.initMocks(this) + val logsResource = LogsResource() + restLogsMockMvc = MockMvcBuilders + .standaloneSetup(logsResource) + .build() } - @Test - void getAllLogs()throws Exception { - restLogsMockMvc.perform(get("/management/logs")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)); - } + @get:Throws(Exception::class) + @get:Test + val allLogs: Unit + get() { + restLogsMockMvc!!.perform(MockMvcRequestBuilders.get("/management/logs")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + } @Test - void changeLogs()throws Exception { - LoggerVM logger = new LoggerVM(); - logger.setLevel("INFO"); - logger.setName("ROOT"); - - restLogsMockMvc.perform(put("/management/logs") + @Throws(Exception::class) + fun changeLogs() { + val logger = LoggerVM() + logger.level = "INFO" + logger.name = "ROOT" + restLogsMockMvc!!.perform( + MockMvcRequestBuilders.put("/management/logs") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(logger))) - .andExpect(status().isNoContent()); + .content(TestUtil.convertObjectToJsonBytes(logger)) + ) + .andExpect(MockMvcResultMatchers.status().isNoContent()) } } diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt index 8e1e346e3..d319aeeee 100644 --- a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt @@ -1,238 +1,285 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalApp; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.OAuthClientService; -import org.radarbase.management.service.SubjectService; -import org.radarbase.management.service.UserService; -import org.radarbase.management.service.dto.ClientDetailsDTO; -import org.radarbase.management.service.mapper.ClientDetailsMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.nullValue; -import static org.radarbase.management.service.OAuthClientServiceTestUtil.createClient; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalApp +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.OAuthClientService +import org.radarbase.management.service.OAuthClientServiceTestUtil +import org.radarbase.management.service.SubjectService +import org.radarbase.management.service.UserService +import org.radarbase.management.service.dto.ClientDetailsDTO +import org.radarbase.management.service.mapper.ClientDetailsMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.oauth2.provider.ClientDetails +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import java.util.function.Consumer /** * Test class for the ProjectResource REST controller. * * @see ProjectResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalApp.class) -class OAuthClientsResourceIntTest { - - @Autowired - private JdbcClientDetailsService clientDetailsService; - - @Autowired - private ClientDetailsMapper clientDetailsMapper; - - @Autowired - private SubjectService subjectService; - - @Autowired - private UserService userService; - - @Autowired - private OAuthClientService oAuthClientService; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalApp::class]) +internal open class OAuthClientsResourceIntTest( + @Autowired private val clientDetailsService: JdbcClientDetailsService, + @Autowired private val clientDetailsMapper: ClientDetailsMapper, + @Autowired private val subjectService: SubjectService, + @Autowired private val userService: UserService, + @Autowired private val oAuthClientService: OAuthClientService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + private var restOauthClientMvc: MockMvc, + private var details: ClientDetailsDTO, + private var clientDetailsList: List, + private var databaseSizeBeforeCreate: Int = 0, + @Autowired private val authService: AuthService +) { - @Autowired - private ExceptionTranslator exceptionTranslator; - - private MockMvc restOauthClientMvc; - - private ClientDetailsDTO details; - - private List clientDetailsList; - - private int databaseSizeBeforeCreate; - @Autowired - private AuthService authService; @BeforeEach - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - OAuthClientsResource oauthClientsResource = new OAuthClientsResource(); - ReflectionTestUtils.setField(oauthClientsResource, "clientDetailsMapper", - clientDetailsMapper); - ReflectionTestUtils.setField(oauthClientsResource, "subjectService", - subjectService); - ReflectionTestUtils.setField(oauthClientsResource, "userService", - userService); - ReflectionTestUtils.setField(oauthClientsResource, "authService", - authService); - ReflectionTestUtils.setField(oauthClientsResource, "oAuthClientService", - oAuthClientService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restOauthClientMvc = MockMvcBuilders.standaloneSetup(oauthClientsResource) + @Throws(Exception::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val oauthClientsResource = OAuthClientsResource() + ReflectionTestUtils.setField( + oauthClientsResource, "clientDetailsMapper", + clientDetailsMapper + ) + ReflectionTestUtils.setField( + oauthClientsResource, "subjectService", + subjectService + ) + ReflectionTestUtils.setField( + oauthClientsResource, "userService", + userService + ) + ReflectionTestUtils.setField( + oauthClientsResource, "authService", + authService + ) + ReflectionTestUtils.setField( + oauthClientsResource, "oAuthClientService", + oAuthClientService + ) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restOauthClientMvc = MockMvcBuilders.standaloneSetup(oauthClientsResource) .setCustomArgumentResolvers(pageableArgumentResolver) .setControllerAdvice(exceptionTranslator) .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - - databaseSizeBeforeCreate = clientDetailsService.listClientDetails().size(); + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() + databaseSizeBeforeCreate = clientDetailsService.listClientDetails().size // Create the OAuth Client - details = createClient(); - restOauthClientMvc.perform(post("/api/oauth-clients") + details = OAuthClientServiceTestUtil.createClient() + restOauthClientMvc.perform( + MockMvcRequestBuilders.post("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Project in the database - clientDetailsList = clientDetailsService.listClientDetails(); - assertThat(clientDetailsList).hasSize(databaseSizeBeforeCreate + 1); + clientDetailsList = clientDetailsService.listClientDetails() + Assertions.assertThat(clientDetailsList).hasSize(databaseSizeBeforeCreate + 1) } @Test @Transactional - void createAndFetchOAuthClient() throws Exception { + @Throws(Exception::class) + open fun createAndFetchOAuthClient() { // fetch the created oauth client and check the json result - restOauthClientMvc.perform(get("/api/oauth-clients/" + details.getClientId()) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.clientId").value(equalTo(details.getClientId()))) - .andExpect(jsonPath("$.clientSecret").value(nullValue())) - .andExpect(jsonPath("$.accessTokenValiditySeconds").value(equalTo(details - .getAccessTokenValiditySeconds().intValue()))) - .andExpect(jsonPath("$.refreshTokenValiditySeconds").value(equalTo(details - .getRefreshTokenValiditySeconds().intValue()))) - .andExpect(jsonPath("$.scope").value(containsInAnyOrder( - details.getScope().toArray()))) - .andExpect(jsonPath("$.autoApproveScopes").value(containsInAnyOrder( - details.getAutoApproveScopes().toArray()))) - .andExpect(jsonPath("$.authorizedGrantTypes").value(containsInAnyOrder( - details.getAuthorizedGrantTypes().toArray()))) - .andExpect(jsonPath("$.authorities").value( - containsInAnyOrder(details.getAuthorities().toArray()))); - - ClientDetails testDetails = clientDetailsList.stream() - .filter(d -> d.getClientId().equals(details.getClientId())) - .findFirst() - .orElseThrow(); - assertThat(testDetails.getClientSecret()).startsWith("$2a$10$"); - assertThat(testDetails.getScope()).containsExactlyInAnyOrderElementsOf(details.getScope()); - assertThat(testDetails.getResourceIds()).containsExactlyInAnyOrderElementsOf( - details.getResourceIds()); - assertThat(testDetails.getAuthorizedGrantTypes()).containsExactlyInAnyOrderElementsOf( - details.getAuthorizedGrantTypes()); - details.getAutoApproveScopes().forEach(scope -> - assertThat(testDetails.isAutoApprove(scope)).isTrue()); - assertThat(testDetails.getAccessTokenValiditySeconds()).isEqualTo( - details.getAccessTokenValiditySeconds().intValue()); - assertThat(testDetails.getRefreshTokenValiditySeconds()).isEqualTo( - details.getRefreshTokenValiditySeconds().intValue()); - assertThat(testDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority)) - .containsExactlyInAnyOrderElementsOf(details.getAuthorities()); - assertThat(testDetails.getAdditionalInformation()).containsAllEntriesOf( - details.getAdditionalInformation() - ); + restOauthClientMvc.perform( + MockMvcRequestBuilders.get("/api/oauth-clients/" + details.clientId) + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect( + MockMvcResultMatchers.jsonPath("$.clientId").value( + Matchers.equalTo( + details.clientId + ) + ) + ) + .andExpect(MockMvcResultMatchers.jsonPath("$.clientSecret").value(Matchers.nullValue())) + .andExpect( + MockMvcResultMatchers.jsonPath("$.accessTokenValiditySeconds").value( + Matchers.equalTo( + details + .getAccessTokenValiditySeconds().toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.refreshTokenValiditySeconds").value( + Matchers.equalTo( + details + .refreshTokenValiditySeconds.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.scope").value( + Matchers.containsInAnyOrder( + *details.scope.toTypedArray() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.autoApproveScopes").value( + Matchers.containsInAnyOrder( + *details.autoApproveScopes.toTypedArray() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.authorizedGrantTypes").value( + Matchers.containsInAnyOrder( + *details.authorizedGrantTypes.toTypedArray() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.authorities").value( + Matchers.containsInAnyOrder(*details.authorities.toTypedArray()) + ) + ) + val testDetails = clientDetailsList.stream() + .filter { d: ClientDetails -> d.clientId == details.clientId } + .findFirst() + .orElseThrow() + Assertions.assertThat(testDetails.clientSecret).startsWith("$2a$10$") + Assertions.assertThat(testDetails.scope).containsExactlyInAnyOrderElementsOf( + details.scope + ) + Assertions.assertThat(testDetails.resourceIds).containsExactlyInAnyOrderElementsOf( + details.resourceIds + ) + Assertions.assertThat(testDetails.authorizedGrantTypes).containsExactlyInAnyOrderElementsOf( + details.authorizedGrantTypes + ) + details.autoApproveScopes.forEach(Consumer { scope: String? -> + Assertions.assertThat( + testDetails.isAutoApprove( + scope + ) + ).isTrue() + }) + Assertions.assertThat(testDetails.accessTokenValiditySeconds).isEqualTo( + details.accessTokenValiditySeconds.toInt() + ) + Assertions.assertThat(testDetails.refreshTokenValiditySeconds).isEqualTo( + details.refreshTokenValiditySeconds.toInt() + ) + Assertions.assertThat(testDetails.authorities.stream().map { obj: GrantedAuthority -> obj.authority }) + .containsExactlyInAnyOrderElementsOf(details.authorities) + Assertions.assertThat(testDetails.additionalInformation).containsAllEntriesOf( + details.additionalInformation + ) } @Test @Transactional - void dupliceOAuthClient() throws Exception { - restOauthClientMvc.perform(post("/api/oauth-clients") + @Throws(Exception::class) + open fun dupliceOAuthClient() { + restOauthClientMvc.perform( + MockMvcRequestBuilders.post("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isConflict()); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isConflict()) } @Test @Transactional - void updateOAuthClient() throws Exception { + @Throws(Exception::class) + open fun updateOAuthClient() { // update the client - details.setRefreshTokenValiditySeconds(20L); - restOauthClientMvc.perform(put("/api/oauth-clients") + details.refreshTokenValiditySeconds = 20L + restOauthClientMvc.perform( + MockMvcRequestBuilders.put("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // fetch the client - clientDetailsList = clientDetailsService.listClientDetails(); - assertThat(clientDetailsList).hasSize(databaseSizeBeforeCreate + 1); - ClientDetails testDetails = clientDetailsList.stream() - .filter(d -> d.getClientId().equals(details.getClientId())) - .findFirst() - .orElseThrow(); - assertThat(testDetails.getRefreshTokenValiditySeconds()).isEqualTo(20); + clientDetailsList = clientDetailsService.listClientDetails() + Assertions.assertThat(clientDetailsList).hasSize(databaseSizeBeforeCreate + 1) + val testDetails = clientDetailsList.stream() + .filter { d: ClientDetails -> d.clientId == details.clientId } + .findFirst() + .orElseThrow() + Assertions.assertThat(testDetails.refreshTokenValiditySeconds).isEqualTo(20) } @Test @Transactional - void deleteOAuthClient() throws Exception { - restOauthClientMvc.perform(delete("/api/oauth-clients/" + details.getClientId()) + @Throws(Exception::class) + open fun deleteOAuthClient() { + restOauthClientMvc.perform( + MockMvcRequestBuilders.delete("/api/oauth-clients/" + details.clientId) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isOk()); - clientDetailsList = clientDetailsService.listClientDetails(); - assertThat(clientDetailsList.size()).isEqualTo(databaseSizeBeforeCreate); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + val clientDetailsList = clientDetailsService.listClientDetails() + Assertions.assertThat(clientDetailsList.size).isEqualTo(databaseSizeBeforeCreate) } @Test @Transactional - void cannotModifyProtected() throws Exception { + @Throws(Exception::class) + open fun cannotModifyProtected() { // first change our test client to be protected - details.getAdditionalInformation().put("protected", "true"); - restOauthClientMvc.perform(put("/api/oauth-clients") + details.additionalInformation["protected"] = "true" + restOauthClientMvc.perform( + MockMvcRequestBuilders.put("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // expect we can not delete it now - restOauthClientMvc.perform(delete("/api/oauth-clients/" + details.getClientId()) + restOauthClientMvc.perform( + MockMvcRequestBuilders.delete("/api/oauth-clients/" + details.clientId) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isForbidden()); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isForbidden()) // expect we can not update it now - details.setRefreshTokenValiditySeconds(20L); - restOauthClientMvc.perform(put("/api/oauth-clients") + details.refreshTokenValiditySeconds = 20L + restOauthClientMvc.perform( + MockMvcRequestBuilders.put("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isForbidden()); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isForbidden()) } - - } diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index 34d847382..e650e923b 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -1,227 +1,245 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Organization; -import org.radarbase.management.repository.OrganizationRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.OrganizationService; -import org.radarbase.management.service.mapper.OrganizationMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import javax.servlet.ServletException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.Organization +import org.radarbase.management.domain.Project +import org.radarbase.management.repository.OrganizationRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.OrganizationService +import org.radarbase.management.service.mapper.OrganizationMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import javax.servlet.ServletException /** * Test class for the OrganizationResource REST controller. * * @see OrganizationResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class OrganizationResourceIntTest { - - @Autowired - private OrganizationMapper organizationMapper; - - @Autowired - private OrganizationRepository organizationRepository; - - @Autowired - private OrganizationService organizationService; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - private MockMvc restOrganizationMockMvc; - - private Organization organization; - @Autowired - private AuthService authService; +internal class OrganizationResourceIntTest( + @Autowired private val organizationMapper: OrganizationMapper, + @Autowired private val organizationRepository: OrganizationRepository, + @Autowired private val organizationService: OrganizationService, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + private var restOrganizationMockMvc: MockMvc, + private var organization: Organization, + @Autowired private val authService: AuthService +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - var orgResource = new OrganizationResource(); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val orgResource = OrganizationResource() ReflectionTestUtils - .setField(orgResource, "organizationService", organizationService); - ReflectionTestUtils.setField(orgResource, "authService", authService); - - var filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restOrganizationMockMvc = MockMvcBuilders.standaloneSetup(orgResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - organization = createEntity(); + .setField(orgResource, "organizationService", organizationService) + ReflectionTestUtils.setField(orgResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restOrganizationMockMvc = MockMvcBuilders.standaloneSetup(orgResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() + organization = createEntity() } @AfterEach - public void tearDown() { - var testOrg = organizationRepository.findOneByName(organization.name); - testOrg.ifPresent(organizationRepository::delete); + fun tearDown() { + val testOrg = organizationRepository.findOneByName( + organization.name + ) + testOrg.ifPresent { entity: Organization -> organizationRepository.delete(entity) } } /** * Create an entity for this test. */ - private Organization createEntity() { - var org = new Organization(); - org.name = "org1"; - org.description = "Test Organization 1"; - org.location = "Somewhere"; - return org; + private fun createEntity(): Organization { + val org = Organization() + org.name = "org1" + org.description = "Test Organization 1" + org.location = "Somewhere" + return org } @Test - void createOrganization() throws Exception { - var orgDto = organizationMapper.organizationToOrganizationDTO(organization); - restOrganizationMockMvc.perform(post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto))) - .andExpect(status().isCreated()); + @Throws(Exception::class) + fun createOrganization() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Organization in the database - var savedOrg = organizationRepository.findOneByName(orgDto.getName()); - assertThat(savedOrg).isNotEmpty(); + val savedOrg = organizationRepository.findOneByName(orgDto.name) + Assertions.assertThat(savedOrg).isNotEmpty() } @Test - void createOrganizationWithExistingName() throws Exception { - var orgDto = organizationMapper.organizationToOrganizationDTO(organization); - restOrganizationMockMvc.perform(post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto))) - .andExpect(status().isCreated()); + @Throws(Exception::class) + fun createOrganizationWithExistingName() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Second request should fail - restOrganizationMockMvc.perform(post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto))) - .andExpect(status().isConflict()); + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isConflict()) } @Test - void checkGroupNameIsRequired() throws Exception { - var orgDto = organizationMapper.organizationToOrganizationDTO(organization); - orgDto.setName(null); - restOrganizationMockMvc.perform(post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto))) - .andExpect(status().isBadRequest()); + @Throws(Exception::class) + fun checkGroupNameIsRequired() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + orgDto.name = null + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) } - @Test - void getAllOrganizations() throws Exception { - // Initialize the database - organizationRepository.saveAndFlush(organization); - - // Get all the organizations - restOrganizationMockMvc.perform(get("/api/organizations")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].name").value(hasItem("org1"))); - } + @get:Throws(Exception::class) + @get:Test + val allOrganizations: Unit + get() { + // Initialize the database + organizationRepository.saveAndFlush(organization) + + // Get all the organizations + restOrganizationMockMvc.perform(MockMvcRequestBuilders.get("/api/organizations")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].name").value>(Matchers.hasItem("org1")) + ) + } @Test - void getOrganization() throws Exception { + @Throws(Exception::class) + fun getOrganization() { // Initialize the database - organizationRepository.saveAndFlush(organization); + organizationRepository.saveAndFlush(organization) // Get the organization - restOrganizationMockMvc.perform(get("/api/organizations/{name}", - organization.name)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.name").value("org1")); + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}", + organization.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("org1")) } @Test - void editOrganization() throws Exception { + @Throws(Exception::class) + fun editOrganization() { // Initialize the database - organizationRepository.saveAndFlush(organization); - - var updatedOrgDto = organizationMapper - .organizationToOrganizationDTO(organization); - updatedOrgDto.setLocation("Other location"); + organizationRepository.saveAndFlush(organization) + val updatedOrgDto = organizationMapper + .organizationToOrganizationDTO(organization) + updatedOrgDto?.location = "Other location" // Update the organization - restOrganizationMockMvc.perform(put("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(updatedOrgDto))) - .andExpect(status().isOk()); - - // Get the organization - restOrganizationMockMvc.perform(get("/api/organizations/{name}", - organization.name)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.location").value("Other location")); - } + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.put("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(updatedOrgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) - @Test - void getNonExistingOrganization() throws Exception { // Get the organization - restOrganizationMockMvc.perform(get("/api/organizations/{name}", - organization.name)) - .andExpect(status().isNotFound()); + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}", + organization.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.location").value("Other location")) } - @Test - void getProjectsByOrganizationName() throws Exception { - // Initialize the database - organizationRepository.saveAndFlush(organization); - - var project = ProjectResourceIntTest.createEntity() + @get:Throws(Exception::class) + @get:Test + val nonExistingOrganization: Unit + get() { + // Get the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}", + organization.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } + + @get:Throws(Exception::class) + @get:Test + val projectsByOrganizationName: Unit + get() { + // Initialize the database + organizationRepository.saveAndFlush(organization) + val project: Project = ProjectResourceIntTest.Companion.createEntity() .organization(organization) - .projectName("organization_project"); - projectRepository.saveAndFlush(project); - - // Get projects of the organization - restOrganizationMockMvc.perform(get("/api/organizations/{name}/projects", - organization.name)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].projectName").value("organization_project")); - - projectRepository.delete(project); - } + .projectName("organization_project") + projectRepository.saveAndFlush(project) + + // Get projects of the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}/projects", + organization.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].projectName").value("organization_project")) + projectRepository.delete(project) + } } diff --git a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt index cef4e56ff..9851cc0ba 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt @@ -1,67 +1,64 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.radarbase.management.ManagementPortalTestApp; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.core.env.Environment; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations +import org.radarbase.management.ManagementPortalTestApp +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.core.env.Environment +import org.springframework.http.MediaType +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders /** * Test class for the ProfileInfoResource REST controller. * * @see ProfileInfoResource - **/ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) -class ProfileInfoResourceIntTest { - + */ +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) +internal class ProfileInfoResourceIntTest { @Mock - private Environment environment; - - private MockMvc restProfileMockMvc; - + private val environment: Environment? = null + private var restProfileMockMvc: MockMvc? = null @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); - String[] activeProfiles = {"test"}; - when(environment.getDefaultProfiles()).thenReturn(activeProfiles); - when(environment.getActiveProfiles()).thenReturn(activeProfiles); - - ProfileInfoResource profileInfoResource = new ProfileInfoResource(); - ReflectionTestUtils.setField(profileInfoResource, "env", environment); - this.restProfileMockMvc = MockMvcBuilders - .standaloneSetup(profileInfoResource) - .build(); - } - - @Test - void getProfileInfo() throws Exception { - restProfileMockMvc.perform(get("/api/profile-info")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)); + fun setUp() { + MockitoAnnotations.initMocks(this) + val activeProfiles = arrayOf("test") + Mockito.`when`(environment!!.defaultProfiles).thenReturn(activeProfiles) + Mockito.`when`(environment.activeProfiles).thenReturn(activeProfiles) + val profileInfoResource = ProfileInfoResource() + ReflectionTestUtils.setField(profileInfoResource, "env", environment) + restProfileMockMvc = MockMvcBuilders + .standaloneSetup(profileInfoResource) + .build() } - @Test - void getProfileInfoWithoutActiveProfiles() throws Exception { - String[] emptyProfile = {}; - when(environment.getDefaultProfiles()).thenReturn(emptyProfile); - when(environment.getActiveProfiles()).thenReturn(emptyProfile); + @get:Throws(Exception::class) + @get:Test + val profileInfo: Unit + get() { + restProfileMockMvc!!.perform(MockMvcRequestBuilders.get("/api/profile-info")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + } - restProfileMockMvc.perform(get("/api/profile-info")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)); - } + @get:Throws(Exception::class) + @get:Test + val profileInfoWithoutActiveProfiles: Unit + get() { + val emptyProfile = arrayOf() + Mockito.`when`(environment!!.defaultProfiles).thenReturn(emptyProfile) + Mockito.`when`(environment.activeProfiles).thenReturn(emptyProfile) + restProfileMockMvc!!.perform(MockMvcRequestBuilders.get("/api/profile-info")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + } } diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt index e62a5007e..b75f57972 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt @@ -1,402 +1,442 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Organization; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.enumeration.ProjectStatus; -import org.radarbase.management.repository.OrganizationRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ProjectService; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.servlet.ServletException; -import java.time.Instant; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.radarbase.management.web.rest.TestUtil.sameInstant; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThat +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.Organization +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.enumeration.ProjectStatus +import org.radarbase.management.repository.OrganizationRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ProjectService +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import java.time.Instant +import java.time.ZoneId +import java.time.ZoneOffset +import java.time.ZonedDateTime +import javax.servlet.ServletException /** * Test class for the ProjectResource REST controller. * * @see ProjectResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class ProjectResourceIntTest { - - private static final String DEFAULT_PROJECT_NAME = "AAAAAAAAAA"; - private static final String UPDATED_PROJECT_NAME = "BBBBBBBBBB"; - - private static final String DEFAULT_DESCRIPTION = "AAAAAAAAAA"; - private static final String UPDATED_DESCRIPTION = "BBBBBBBBBB"; - - private static final String DEFAULT_ORGANIZATION = "AAAAAAAAAA"; - private static final String UPDATED_ORGANIZATION = "BBBBBBBBBB"; - - private static final String DEFAULT_LOCATION = "AAAAAAAAAA"; - private static final String UPDATED_LOCATION = "BBBBBBBBBB"; - - private static final ZonedDateTime DEFAULT_START_DATE = ZonedDateTime.ofInstant( - Instant.ofEpochMilli(0L), ZoneOffset.UTC); - private static final ZonedDateTime UPDATED_START_DATE = ZonedDateTime.now( - ZoneId.systemDefault()).withNano(0); - - private static final ProjectStatus DEFAULT_PROJECT_STATUS = ProjectStatus.PLANNING; - private static final ProjectStatus UPDATED_PROJECT_STATUS = ProjectStatus.ONGOING; - - private static final ZonedDateTime DEFAULT_END_DATE = ZonedDateTime.ofInstant( - Instant.ofEpochMilli(0L), ZoneOffset.UTC); - private static final ZonedDateTime UPDATED_END_DATE = ZonedDateTime.now( - ZoneId.systemDefault()).withNano(0); - - @Autowired - private OrganizationRepository organizationRepository; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private ProjectMapper projectMapper; - - @Autowired - private ProjectService projectService; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - private MockMvc restProjectMockMvc; - - private Project project; - @Autowired - private AuthService authService; +internal open class ProjectResourceIntTest( + @Autowired private val organizationRepository: OrganizationRepository, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val projectService: ProjectService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + private var restProjectMockMvc: MockMvc, + private var project: Project, + @Autowired private val authService: AuthService +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - ProjectResource projectResource = new ProjectResource(); - ReflectionTestUtils.setField(projectResource, "projectRepository", projectRepository); - ReflectionTestUtils.setField(projectResource, "projectService", projectService); - ReflectionTestUtils.setField(projectResource, "authService", authService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - } - - /** - * Create an entity for this test. - * - *

This is a static method, as tests for other entities might also need it, - * if they test an entity which requires the current entity.

- */ - public static Project createEntity() { - Organization organization = new Organization(); - organization.setId(1L); - organization.name = "main"; - return new Project() - .projectName(DEFAULT_PROJECT_NAME) - .description(DEFAULT_DESCRIPTION) - .organizationName(DEFAULT_ORGANIZATION) - .organization(organization) - .location(DEFAULT_LOCATION) - .startDate(DEFAULT_START_DATE) - .projectStatus(DEFAULT_PROJECT_STATUS) - .endDate(DEFAULT_END_DATE); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val projectResource = ProjectResource + ReflectionTestUtils.setField(projectResource, "projectRepository", projectRepository) + ReflectionTestUtils.setField(projectResource, "projectService", projectService) + ReflectionTestUtils.setField(projectResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() } @BeforeEach - public void initTest() { - project = createEntity(); + fun initTest() { + project = createEntity() } @Test @Transactional - void createProject() throws Exception { - int databaseSizeBeforeCreate = projectRepository.findAll().size(); + @Throws(Exception::class) + open fun createProject() { + val databaseSizeBeforeCreate = projectRepository.findAll().size // Create the Project - ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); - restProjectMockMvc.perform(post("/api/projects") + val projectDto = projectMapper.projectToProjectDTO(project) + restProjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Project in the database - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeCreate + 1); - Project testProject = projectList.get(projectList.size() - 1); - assertThat(testProject.projectName).isEqualTo(DEFAULT_PROJECT_NAME); - assertThat(testProject.description).isEqualTo(DEFAULT_DESCRIPTION); - assertThat(testProject.organizationName).isEqualTo(DEFAULT_ORGANIZATION); - assertThat(testProject.location).isEqualTo(DEFAULT_LOCATION); - assertThat(testProject.startDate).isEqualTo(DEFAULT_START_DATE); - assertThat(testProject.projectStatus).isEqualTo(DEFAULT_PROJECT_STATUS); - assertThat(testProject.endDate).isEqualTo(DEFAULT_END_DATE); + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeCreate + 1) + val testProject = projectList[projectList.size - 1] + Assertions.assertThat(testProject!!.projectName).isEqualTo(DEFAULT_PROJECT_NAME) + Assertions.assertThat(testProject.description).isEqualTo(DEFAULT_DESCRIPTION) + Assertions.assertThat(testProject.organizationName).isEqualTo(DEFAULT_ORGANIZATION) + Assertions.assertThat(testProject.location).isEqualTo(DEFAULT_LOCATION) + Assertions.assertThat(testProject.startDate).isEqualTo(DEFAULT_START_DATE) + Assertions.assertThat(testProject.projectStatus).isEqualTo(DEFAULT_PROJECT_STATUS) + Assertions.assertThat(testProject.endDate).isEqualTo(DEFAULT_END_DATE) } @Test @Transactional - void createProjectWithExistingId() throws Exception { - int databaseSizeBeforeCreate = projectRepository.findAll().size(); + @Throws(Exception::class) + open fun createProjectWithExistingId() { + val databaseSizeBeforeCreate = projectRepository.findAll().size // Create the Project with an existing ID - project.setId(1L); - ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); + project.id = 1L + val projectDto = projectMapper.projectToProjectDTO(project) // An entity with an existing ID cannot be created, so this API call must fail - restProjectMockMvc.perform(post("/api/projects") + restProjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the Alice in the database - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeCreate); + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeCreate) } @Test @Transactional - void checkProjectNameIsRequired() throws Exception { - int databaseSizeBeforeTest = projectRepository.findAll().size(); + @Throws(Exception::class) + open fun checkProjectNameIsRequired() { + val databaseSizeBeforeTest = projectRepository.findAll().size // set the field null - project.projectName = null; + project.projectName = null // Create the Project, which fails. - ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); - - restProjectMockMvc.perform(post("/api/projects") + val projectDto = projectMapper.projectToProjectDTO(project) + restProjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isBadRequest()); - - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeTest); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeTest) } @Test @Transactional - void checkDescriptionIsRequired() throws Exception { - int databaseSizeBeforeTest = projectRepository.findAll().size(); + @Throws(Exception::class) + open fun checkDescriptionIsRequired() { + val databaseSizeBeforeTest = projectRepository.findAll().size // set the field null - project.description = null; + project.description = null // Create the Project, which fails. - ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); - - restProjectMockMvc.perform(post("/api/projects") + val projectDto = projectMapper.projectToProjectDTO(project) + restProjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isBadRequest()); - - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeTest); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeTest) } @Test @Transactional - void checkLocationIsRequired() throws Exception { - int databaseSizeBeforeTest = projectRepository.findAll().size(); + @Throws(Exception::class) + open fun checkLocationIsRequired() { + val databaseSizeBeforeTest = projectRepository.findAll().size // set the field null - project.location = null; + project.location = null // Create the Project, which fails. - ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); - - restProjectMockMvc.perform(post("/api/projects") + val projectDto = projectMapper.projectToProjectDTO(project) + restProjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isBadRequest()); - - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeTest); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeTest) } - @Test - @Transactional - void getAllProjects() throws Exception { - // Initialize the database - projectRepository.saveAndFlush(project); - - // Get all the projectList - restProjectMockMvc.perform(get("/api/projects?sort=id,desc")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(project.getId().intValue()))) - .andExpect(jsonPath("$.[*].projectName").value(hasItem(DEFAULT_PROJECT_NAME))) - .andExpect(jsonPath("$.[*].description").value(hasItem(DEFAULT_DESCRIPTION))) - .andExpect(jsonPath("$.[*].organizationName").value(hasItem(DEFAULT_ORGANIZATION))) - .andExpect(jsonPath("$.[*].location").value(hasItem(DEFAULT_LOCATION))) - .andExpect(jsonPath("$.[*].startDate").value( - hasItem(sameInstant(DEFAULT_START_DATE)))) - .andExpect(jsonPath("$.[*].projectStatus").value( - hasItem(DEFAULT_PROJECT_STATUS.toString()))) - .andExpect(jsonPath("$.[*].endDate").value(hasItem(sameInstant(DEFAULT_END_DATE)))); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val allProjects: Unit + get() { + // Initialize the database + projectRepository.saveAndFlush(project) + + // Get all the projectList + restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + project.id!!.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].projectName").value>( + Matchers.hasItem( + DEFAULT_PROJECT_NAME + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].description").value>( + Matchers.hasItem( + DEFAULT_DESCRIPTION + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].organizationName").value>( + Matchers.hasItem( + DEFAULT_ORGANIZATION + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].location").value>( + Matchers.hasItem( + DEFAULT_LOCATION + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].startDate").value>( + Matchers.hasItem(TestUtil.sameInstant(DEFAULT_START_DATE)) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].projectStatus").value>( + Matchers.hasItem(DEFAULT_PROJECT_STATUS.toString()) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].endDate").value>( + Matchers.hasItem( + TestUtil.sameInstant( + DEFAULT_END_DATE + ) + ) + ) + ) + } @Test @Transactional - void getProject() throws Exception { + @Throws(Exception::class) + open fun getProject() { // Initialize the database - projectRepository.saveAndFlush(project); + projectRepository.saveAndFlush(project) // Get the project - restProjectMockMvc.perform(get("/api/projects/{projectName}", project.projectName)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.id").value(project.getId().intValue())) - .andExpect(jsonPath("$.projectName").value(DEFAULT_PROJECT_NAME)) - .andExpect(jsonPath("$.description").value(DEFAULT_DESCRIPTION)) - .andExpect(jsonPath("$.organizationName").value(DEFAULT_ORGANIZATION)) - .andExpect(jsonPath("$.location").value(DEFAULT_LOCATION)) - .andExpect(jsonPath("$.startDate").value(sameInstant(DEFAULT_START_DATE))) - .andExpect(jsonPath("$.projectStatus").value(DEFAULT_PROJECT_STATUS.toString())) - .andExpect(jsonPath("$.endDate").value(sameInstant(DEFAULT_END_DATE))); + restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects/{projectName}", project.projectName)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(project.id!!.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.projectName").value(DEFAULT_PROJECT_NAME)) + .andExpect(MockMvcResultMatchers.jsonPath("$.description").value(DEFAULT_DESCRIPTION)) + .andExpect(MockMvcResultMatchers.jsonPath("$.organizationName").value(DEFAULT_ORGANIZATION)) + .andExpect(MockMvcResultMatchers.jsonPath("$.location").value(DEFAULT_LOCATION)) + .andExpect(MockMvcResultMatchers.jsonPath("$.startDate").value(TestUtil.sameInstant(DEFAULT_START_DATE))) + .andExpect(MockMvcResultMatchers.jsonPath("$.projectStatus").value(DEFAULT_PROJECT_STATUS.toString())) + .andExpect(MockMvcResultMatchers.jsonPath("$.endDate").value(TestUtil.sameInstant(DEFAULT_END_DATE))) } - @Test - @Transactional - void getNonExistingProject() throws Exception { - // Get the project - restProjectMockMvc.perform(get("/api/projects/{id}", Long.MAX_VALUE)) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val nonExistingProject: Unit + get() { + // Get the project + restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects/{id}", Long.MAX_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional - void updateProject() throws Exception { + @Throws(Exception::class) + open fun updateProject() { // Initialize the database - projectRepository.saveAndFlush(project); - - var org = new Organization(); - org.name = "org1"; - org.description = "Test Organization 1"; - org.location = "Somewhere"; - organizationRepository.saveAndFlush(org); - - assertThat(org.getId()).isNotNull(); - - int databaseSizeBeforeUpdate = projectRepository.findAll().size(); + projectRepository.saveAndFlush(project) + val org = Organization() + org.name = "org1" + org.description = "Test Organization 1" + org.location = "Somewhere" + organizationRepository.saveAndFlush(org) + assertThat(org.id).isNotNull() + val databaseSizeBeforeUpdate = projectRepository.findAll().size // Update the project - Project updatedProject = projectRepository.findById(project.getId()).get(); + val updatedProject = projectRepository.findById(project.id!!).get() updatedProject - .projectName(UPDATED_PROJECT_NAME) - .description(UPDATED_DESCRIPTION) - .organizationName(UPDATED_ORGANIZATION) - .organization(org) - .location(UPDATED_LOCATION) - .startDate(UPDATED_START_DATE) - .projectStatus(UPDATED_PROJECT_STATUS) - .endDate(UPDATED_END_DATE); - ProjectDTO projectDto = projectMapper.projectToProjectDTO(updatedProject); - - restProjectMockMvc.perform(put("/api/projects") + .projectName(UPDATED_PROJECT_NAME) + .description(UPDATED_DESCRIPTION) + .organizationName(UPDATED_ORGANIZATION) + .organization(org) + .location(UPDATED_LOCATION) + .startDate(UPDATED_START_DATE) + .projectStatus(UPDATED_PROJECT_STATUS) + .endDate(UPDATED_END_DATE) + val projectDto = projectMapper.projectToProjectDTO(updatedProject) + restProjectMockMvc.perform( + MockMvcRequestBuilders.put("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Project in the database - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeUpdate); - Project testProject = projectList.get(projectList.size() - 1); - assertThat(testProject.projectName).isEqualTo(UPDATED_PROJECT_NAME); - assertThat(testProject.description).isEqualTo(UPDATED_DESCRIPTION); - assertThat(testProject.organizationName).isEqualTo(UPDATED_ORGANIZATION); - assertThat(testProject.organization).isEqualTo(org); - assertThat(testProject.location).isEqualTo(UPDATED_LOCATION); - assertThat(testProject.startDate).isEqualTo(UPDATED_START_DATE); - assertThat(testProject.projectStatus).isEqualTo(UPDATED_PROJECT_STATUS); - assertThat(testProject.endDate).isEqualTo(UPDATED_END_DATE); - - organizationRepository.delete(org); + val projectList = projectRepository.findAll() + assertThat(projectList).hasSize(databaseSizeBeforeUpdate) + val testProject = projectList[projectList.size - 1] + assertThat(testProject!!.projectName).isEqualTo(UPDATED_PROJECT_NAME) + assertThat(testProject.description).isEqualTo(UPDATED_DESCRIPTION) + assertThat(testProject.organizationName).isEqualTo(UPDATED_ORGANIZATION) + assertThat(testProject.organization).isEqualTo(org) + assertThat(testProject.location).isEqualTo(UPDATED_LOCATION) + assertThat(testProject.startDate).isEqualTo(UPDATED_START_DATE) + assertThat(testProject.projectStatus).isEqualTo( + UPDATED_PROJECT_STATUS + ) + assertThat(testProject.endDate).isEqualTo(UPDATED_END_DATE) + organizationRepository.delete(org) } @Test @Transactional - void updateNonExistingProject() throws Exception { - int databaseSizeBeforeUpdate = projectRepository.findAll().size(); + @Throws(Exception::class) + open fun updateNonExistingProject() { + val databaseSizeBeforeUpdate = projectRepository.findAll().size // Create the Project - ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); + val projectDto = projectMapper.projectToProjectDTO(project) // If the entity doesn't have an ID, it will be created instead of just being updated - restProjectMockMvc.perform(put("/api/projects") + restProjectMockMvc.perform( + MockMvcRequestBuilders.put("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Project in the database - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeUpdate + 1); + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeUpdate + 1) } @Test @Transactional - void deleteProject() throws Exception { + @Throws(Exception::class) + open fun deleteProject() { // Initialize the database - projectRepository.saveAndFlush(project); - int databaseSizeBeforeDelete = projectRepository.findAll().size(); + projectRepository.saveAndFlush(project) + val databaseSizeBeforeDelete = projectRepository.findAll().size // Get the project - restProjectMockMvc.perform(delete("/api/projects/{projectName}", project.projectName) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()); + restProjectMockMvc.perform( + MockMvcRequestBuilders.delete("/api/projects/{projectName}", project.projectName) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeDelete - 1); + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeDelete - 1) } @Test @Transactional - void equalsVerifier() throws Exception { - Assertions.assertTrue(TestUtil.equalsVerifier(Project.class)); + @Throws(Exception::class) + open fun equalsVerifier() { + org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Project::class.java)) + } + + companion object { + private const val DEFAULT_PROJECT_NAME = "AAAAAAAAAA" + private const val UPDATED_PROJECT_NAME = "BBBBBBBBBB" + private const val DEFAULT_DESCRIPTION = "AAAAAAAAAA" + private const val UPDATED_DESCRIPTION = "BBBBBBBBBB" + private const val DEFAULT_ORGANIZATION = "AAAAAAAAAA" + private const val UPDATED_ORGANIZATION = "BBBBBBBBBB" + private const val DEFAULT_LOCATION = "AAAAAAAAAA" + private const val UPDATED_LOCATION = "BBBBBBBBBB" + private val DEFAULT_START_DATE = ZonedDateTime.ofInstant( + Instant.ofEpochMilli(0L), ZoneOffset.UTC + ) + private val UPDATED_START_DATE = ZonedDateTime.now( + ZoneId.systemDefault() + ).withNano(0) + private val DEFAULT_PROJECT_STATUS = ProjectStatus.PLANNING + private val UPDATED_PROJECT_STATUS = ProjectStatus.ONGOING + private val DEFAULT_END_DATE = ZonedDateTime.ofInstant( + Instant.ofEpochMilli(0L), ZoneOffset.UTC + ) + private val UPDATED_END_DATE = ZonedDateTime.now( + ZoneId.systemDefault() + ).withNano(0) + + /** + * Create an entity for this test. + * + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + fun createEntity(): Project { + val organization = Organization() + organization.id = 1L + organization.name = "main" + return Project() + .projectName(DEFAULT_PROJECT_NAME) + .description(DEFAULT_DESCRIPTION) + .organizationName(DEFAULT_ORGANIZATION) + .organization(organization) + .location(DEFAULT_LOCATION) + .startDate(DEFAULT_START_DATE) + .projectStatus(DEFAULT_PROJECT_STATUS) + .endDate(DEFAULT_END_DATE) + } } } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt index 0cb98eaa4..4db6c68a5 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt @@ -1,392 +1,499 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.repository.SourceDataRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.SourceDataService; -import org.radarbase.management.service.dto.SourceDataDTO; -import org.radarbase.management.service.mapper.SourceDataMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.persistence.EntityManager; -import javax.servlet.ServletException; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.SourceData +import org.radarbase.management.repository.SourceDataRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.SourceDataService +import org.radarbase.management.service.mapper.SourceDataMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import javax.persistence.EntityManager +import javax.servlet.ServletException /** * Test class for the SourceDataResource REST controller. * * @see SourceDataResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class SourceDataResourceIntTest { - - private static final String DEFAULT_SOURCE_DATA_TYPE = "AAAAAAAAAA"; - private static final String UPDATED_SOURCE_DATA_TYPE = "BBBBBBBBBB"; - - private static final String DEFAULT_SOURCE_DATA_NAME = "AAAAAAAAAAAAA"; - private static final String UPDATED_SOURCE_DATA_NAME = "BBBBBBBBBBAAA"; - - private static final String DEFAULT_PROCESSING_STATE = "RAW"; - private static final String UPDATED_PROCESSING_STATE = "DERIVED"; - - private static final String DEFAULT_KEY_SCHEMA = "AAAAAAAAAAC"; - private static final String UPDATED_KEY_SCHEMA = "BBBBBBBBBBC"; - - private static final String DEFAULT_VALUE_SCHEMA = "AAAAAAAAAAA"; - private static final String UPDATED_VALUE_SCHEMA = "BBBBBBBBBBB"; - - private static final String DEFAULT_FREQUENCY = "AAAAAAAAAAAA"; - private static final String UPDATED_FREQUENCY = "BBBBBBBBBBBB"; - - private static final String DEFAULT_UNTI = "AAAAAAAAAAAAAAC"; - private static final String UPDATED_UNIT = "BBBBBBBBBBBBBBC"; - - private static final String DEFAULT_TOPIC = "AAAAAAAAAAAAAAA"; - private static final String UPDATED_TOPIC = "BBBBBBBBBBBBBBB"; - +internal class SourceDataResourceIntTest { @Autowired - private SourceDataRepository sourceDataRepository; + private val sourceDataRepository: SourceDataRepository? = null @Autowired - private SourceDataMapper sourceDataMapper; + private val sourceDataMapper: SourceDataMapper? = null @Autowired - private SourceDataService sourceDataService; + private val sourceDataService: SourceDataService? = null @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; + private val jacksonMessageConverter: MappingJackson2HttpMessageConverter? = null @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver? = null @Autowired - private ExceptionTranslator exceptionTranslator; + private val exceptionTranslator: ExceptionTranslator? = null @Autowired - private EntityManager em; + private val em: EntityManager? = null + private var restSourceDataMockMvc: MockMvc? = null + private var sourceData: SourceData? = null - private MockMvc restSourceDataMockMvc; - - private SourceData sourceData; @Autowired - private AuthService authService; - + private val authService: AuthService? = null @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - SourceDataResource sourceDataResource = new SourceDataResource(); - ReflectionTestUtils.setField(sourceDataResource, "sourceDataService", sourceDataService); - ReflectionTestUtils.setField(sourceDataResource, "authService", authService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restSourceDataMockMvc = MockMvcBuilders.standaloneSetup(sourceDataResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - } - - /** - * Create an entity for this test. - * - *

This is a static method, as tests for other entities might also need it, - * if they test an entity which requires the current entity.

- */ - public static SourceData createEntity(EntityManager em) { - return new SourceData() - .sourceDataType(DEFAULT_SOURCE_DATA_TYPE) - .sourceDataName(DEFAULT_SOURCE_DATA_NAME) - .processingState(DEFAULT_PROCESSING_STATE) - .keySchema(DEFAULT_KEY_SCHEMA) - .valueSchema(DEFAULT_VALUE_SCHEMA) - .topic(DEFAULT_TOPIC) - .unit(DEFAULT_UNTI) - .frequency(DEFAULT_FREQUENCY); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.initMocks(this) + val sourceDataResource = SourceDataResource() + ReflectionTestUtils.setField(sourceDataResource, "sourceDataService", sourceDataService) + ReflectionTestUtils.setField(sourceDataResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter!!.init(MockFilterConfig()) + restSourceDataMockMvc = MockMvcBuilders.standaloneSetup(sourceDataResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() } @BeforeEach - public void initTest() { - sourceData = createEntity(em); + fun initTest() { + sourceData = createEntity(em) } @Test @Transactional - void createSourceData() throws Exception { - int databaseSizeBeforeCreate = sourceDataRepository.findAll().size(); + @Throws(Exception::class) + fun createSourceData() { + val databaseSizeBeforeCreate = sourceDataRepository!!.findAll().size // Create the SourceData - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); - restSourceDataMockMvc.perform(post("/api/source-data") + val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDataDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the SourceData in the database - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeCreate + 1); - SourceData testSourceData = sourceDataList.get(sourceDataList.size() - 1); - assertThat(testSourceData.sourceDataType).isEqualTo(DEFAULT_SOURCE_DATA_TYPE); - assertThat(testSourceData.sourceDataName).isEqualTo(DEFAULT_SOURCE_DATA_NAME); - assertThat(testSourceData.processingState).isEqualTo(DEFAULT_PROCESSING_STATE); - assertThat(testSourceData.keySchema).isEqualTo(DEFAULT_KEY_SCHEMA); - assertThat(testSourceData.valueSchema).isEqualTo(DEFAULT_VALUE_SCHEMA); - assertThat(testSourceData.frequency).isEqualTo(DEFAULT_FREQUENCY); - assertThat(testSourceData.topic).isEqualTo(DEFAULT_TOPIC); - assertThat(testSourceData.unit).isEqualTo(DEFAULT_UNTI); + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeCreate + 1) + val testSourceData = sourceDataList[sourceDataList.size - 1] + Assertions.assertThat(testSourceData.sourceDataType).isEqualTo(DEFAULT_SOURCE_DATA_TYPE) + Assertions.assertThat(testSourceData.sourceDataName).isEqualTo(DEFAULT_SOURCE_DATA_NAME) + Assertions.assertThat(testSourceData.processingState).isEqualTo(DEFAULT_PROCESSING_STATE) + Assertions.assertThat(testSourceData.keySchema).isEqualTo(DEFAULT_KEY_SCHEMA) + Assertions.assertThat(testSourceData.valueSchema).isEqualTo(DEFAULT_VALUE_SCHEMA) + Assertions.assertThat(testSourceData.frequency).isEqualTo(DEFAULT_FREQUENCY) + Assertions.assertThat(testSourceData.topic).isEqualTo(DEFAULT_TOPIC) + Assertions.assertThat(testSourceData.unit).isEqualTo(DEFAULT_UNTI) } @Test @Transactional - void createSourceDataWithExistingId() throws Exception { - int databaseSizeBeforeCreate = sourceDataRepository.findAll().size(); + @Throws(Exception::class) + fun createSourceDataWithExistingId() { + val databaseSizeBeforeCreate = sourceDataRepository!!.findAll().size // Create the SourceData with an existing ID - sourceData.setId(1L); - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); + sourceData!!.id = 1L + val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) // An entity with an existing ID cannot be created, so this API call must fail - restSourceDataMockMvc.perform(post("/api/source-data") + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDataDto))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the Alice in the database - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeCreate); + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeCreate) } @Test @Transactional - void checkSourceDataTypeIsNotRequired() throws Exception { - final int databaseSizeBeforeTest = sourceDataRepository.findAll().size(); + @Throws(Exception::class) + fun checkSourceDataTypeIsNotRequired() { + val databaseSizeBeforeTest = sourceDataRepository!!.findAll().size // set the field null - sourceData.sourceDataType = null; + sourceData!!.sourceDataType = null // Create the SourceData, which fails. - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); - - restSourceDataMockMvc.perform(post("/api/source-data") + val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDataDto))) - .andExpect(status().isCreated()); - - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeTest + 1); + .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeTest + 1) } - @Test @Transactional - void checkSourceDataTypeOrTopicIsRequired() throws Exception { - final int databaseSizeBeforeTest = sourceDataRepository.findAll().size(); + @Throws(Exception::class) + fun checkSourceDataTypeOrTopicIsRequired() { + val databaseSizeBeforeTest = sourceDataRepository!!.findAll().size // set the field null - sourceData.sourceDataType = null; - sourceData.topic = null; + sourceData!!.sourceDataType = null + sourceData!!.topic = null // Create the SourceData, which fails. - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); - restSourceDataMockMvc.perform(post("/api/source-data") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDataDto))) - .andExpect(status().isBadRequest()); - - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeTest); - } - - @Test - @Transactional - void getAllSourceData() throws Exception { - // Initialize the database - sourceDataRepository.saveAndFlush(sourceData); - - // Get all the sourceDataList - restSourceDataMockMvc.perform(get("/api/source-data?sort=id,desc")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(sourceData.getId().intValue()))) - .andExpect(jsonPath("$.[*].sourceDataType").value( - hasItem(DEFAULT_SOURCE_DATA_TYPE))) - .andExpect(jsonPath("$.[*].sourceDataName").value( - hasItem(DEFAULT_SOURCE_DATA_NAME))) - .andExpect(jsonPath("$.[*].processingState").value( - hasItem(DEFAULT_PROCESSING_STATE))) - .andExpect(jsonPath("$.[*].keySchema").value(hasItem(DEFAULT_KEY_SCHEMA))) - .andExpect(jsonPath("$.[*].valueSchema").value(hasItem(DEFAULT_VALUE_SCHEMA))) - .andExpect(jsonPath("$.[*].unit").value(hasItem(DEFAULT_UNTI))) - .andExpect(jsonPath("$.[*].topic").value(hasItem(DEFAULT_TOPIC))) - .andExpect(jsonPath("$.[*].frequency").value(hasItem(DEFAULT_FREQUENCY))); + val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.post("/api/source-data") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeTest) } - @Test - @Transactional - void getAllSourceDataWithPagination() throws Exception { - // Initialize the database - sourceDataRepository.saveAndFlush(sourceData); - - // Get all the sourceDataList - restSourceDataMockMvc.perform(get("/api/source-data?page=0&size=5&sort=id,desc")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(sourceData.getId().intValue()))) - .andExpect(jsonPath("$.[*].sourceDataType").value( - hasItem(DEFAULT_SOURCE_DATA_TYPE))) - .andExpect(jsonPath("$.[*].sourceDataName").value( - hasItem(DEFAULT_SOURCE_DATA_NAME))) - .andExpect(jsonPath("$.[*].processingState").value( - hasItem(DEFAULT_PROCESSING_STATE))) - .andExpect(jsonPath("$.[*].keySchema").value(hasItem(DEFAULT_KEY_SCHEMA))) - .andExpect(jsonPath("$.[*].valueSchema").value(hasItem(DEFAULT_VALUE_SCHEMA))) - .andExpect(jsonPath("$.[*].unit").value(hasItem(DEFAULT_UNTI))) - .andExpect(jsonPath("$.[*].topic").value(hasItem(DEFAULT_TOPIC))) - .andExpect(jsonPath("$.[*].frequency").value(hasItem(DEFAULT_FREQUENCY))); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + val allSourceData: Unit + get() { + // Initialize the database + sourceDataRepository!!.saveAndFlush(sourceData) + + // Get all the sourceDataList + restSourceDataMockMvc!!.perform(MockMvcRequestBuilders.get("/api/source-data?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + sourceData!!.id!!.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceDataType").value>( + Matchers.hasItem(DEFAULT_SOURCE_DATA_TYPE) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceDataName").value>( + Matchers.hasItem(DEFAULT_SOURCE_DATA_NAME) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].processingState").value>( + Matchers.hasItem(DEFAULT_PROCESSING_STATE) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].keySchema").value>( + Matchers.hasItem( + DEFAULT_KEY_SCHEMA + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].valueSchema").value>( + Matchers.hasItem( + DEFAULT_VALUE_SCHEMA + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].unit").value>( + Matchers.hasItem( + DEFAULT_UNTI + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].topic").value>( + Matchers.hasItem( + DEFAULT_TOPIC + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].frequency").value>( + Matchers.hasItem( + DEFAULT_FREQUENCY + ) + ) + ) + } + + @get:Throws(Exception::class) + @get:Transactional + @get:Test + val allSourceDataWithPagination: Unit + get() { + // Initialize the database + sourceDataRepository!!.saveAndFlush(sourceData) + + // Get all the sourceDataList + restSourceDataMockMvc!!.perform(MockMvcRequestBuilders.get("/api/source-data?page=0&size=5&sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + sourceData!!.id!!.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceDataType").value>( + Matchers.hasItem(DEFAULT_SOURCE_DATA_TYPE) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceDataName").value>( + Matchers.hasItem(DEFAULT_SOURCE_DATA_NAME) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].processingState").value>( + Matchers.hasItem(DEFAULT_PROCESSING_STATE) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].keySchema").value>( + Matchers.hasItem( + DEFAULT_KEY_SCHEMA + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].valueSchema").value>( + Matchers.hasItem( + DEFAULT_VALUE_SCHEMA + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].unit").value>( + Matchers.hasItem( + DEFAULT_UNTI + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].topic").value>( + Matchers.hasItem( + DEFAULT_TOPIC + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].frequency").value>( + Matchers.hasItem( + DEFAULT_FREQUENCY + ) + ) + ) + } @Test @Transactional - void getSourceData() throws Exception { + @Throws(Exception::class) + fun getSourceData() { // Initialize the database - sourceDataRepository.saveAndFlush(sourceData); + sourceDataRepository!!.saveAndFlush(sourceData) // Get the sourceData - restSourceDataMockMvc.perform(get("/api/source-data/{sourceDataName}", - sourceData.sourceDataName)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.id").value(sourceData.getId().intValue())) - .andExpect(jsonPath("$.sourceDataType").value(DEFAULT_SOURCE_DATA_TYPE)) - .andExpect(jsonPath("$.sourceDataName").value(DEFAULT_SOURCE_DATA_NAME)) - .andExpect(jsonPath("$.processingState").value(DEFAULT_PROCESSING_STATE)) - .andExpect(jsonPath("$.keySchema").value(DEFAULT_KEY_SCHEMA)) - .andExpect(jsonPath("$.valueSchema").value(DEFAULT_VALUE_SCHEMA)) - .andExpect(jsonPath("$.unit").value(DEFAULT_UNTI)) - .andExpect(jsonPath("$.topic").value(DEFAULT_TOPIC)) - .andExpect(jsonPath("$.frequency").value(DEFAULT_FREQUENCY)); + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.get( + "/api/source-data/{sourceDataName}", + sourceData!!.sourceDataName + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(sourceData!!.id!!.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.sourceDataType").value(DEFAULT_SOURCE_DATA_TYPE)) + .andExpect(MockMvcResultMatchers.jsonPath("$.sourceDataName").value(DEFAULT_SOURCE_DATA_NAME)) + .andExpect(MockMvcResultMatchers.jsonPath("$.processingState").value(DEFAULT_PROCESSING_STATE)) + .andExpect(MockMvcResultMatchers.jsonPath("$.keySchema").value(DEFAULT_KEY_SCHEMA)) + .andExpect(MockMvcResultMatchers.jsonPath("$.valueSchema").value(DEFAULT_VALUE_SCHEMA)) + .andExpect(MockMvcResultMatchers.jsonPath("$.unit").value(DEFAULT_UNTI)) + .andExpect(MockMvcResultMatchers.jsonPath("$.topic").value(DEFAULT_TOPIC)) + .andExpect(MockMvcResultMatchers.jsonPath("$.frequency").value(DEFAULT_FREQUENCY)) } - @Test - @Transactional - void getNonExistingSourceData() throws Exception { - // Get the sourceData - restSourceDataMockMvc.perform(get("/api/source-data/{sourceDataName}", - DEFAULT_SOURCE_DATA_NAME + DEFAULT_SOURCE_DATA_NAME)) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + val nonExistingSourceData: Unit + get() { + // Get the sourceData + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.get( + "/api/source-data/{sourceDataName}", + DEFAULT_SOURCE_DATA_NAME + DEFAULT_SOURCE_DATA_NAME + ) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional - void updateSourceData() throws Exception { + @Throws(Exception::class) + fun updateSourceData() { // Initialize the database - sourceDataRepository.saveAndFlush(sourceData); - int databaseSizeBeforeUpdate = sourceDataRepository.findAll().size(); + sourceDataRepository!!.saveAndFlush(sourceData) + val databaseSizeBeforeUpdate = sourceDataRepository.findAll().size // Update the sourceData - SourceData updatedSourceData = sourceDataRepository.findById(sourceData.getId()).get(); + val updatedSourceData = sourceDataRepository.findById(sourceData!!.id).get() updatedSourceData - .sourceDataType(UPDATED_SOURCE_DATA_TYPE) - .sourceDataName(UPDATED_SOURCE_DATA_NAME) - .processingState(UPDATED_PROCESSING_STATE) - .keySchema(UPDATED_KEY_SCHEMA) - .valueSchema(UPDATED_VALUE_SCHEMA) - .topic(UPDATED_TOPIC) - .unit(UPDATED_UNIT) - .frequency(UPDATED_FREQUENCY); - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(updatedSourceData); - - restSourceDataMockMvc.perform(put("/api/source-data") + .sourceDataType(UPDATED_SOURCE_DATA_TYPE) + .sourceDataName(UPDATED_SOURCE_DATA_NAME) + .processingState(UPDATED_PROCESSING_STATE) + .keySchema(UPDATED_KEY_SCHEMA) + .valueSchema(UPDATED_VALUE_SCHEMA) + .topic(UPDATED_TOPIC) + .unit(UPDATED_UNIT) + .frequency(UPDATED_FREQUENCY) + val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(updatedSourceData) + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.put("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDataDto))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the SourceData in the database - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeUpdate); - SourceData testSourceData = sourceDataList.get(sourceDataList.size() - 1); - assertThat(testSourceData.sourceDataType).isEqualTo(UPDATED_SOURCE_DATA_TYPE); - assertThat(testSourceData.sourceDataName).isEqualTo(UPDATED_SOURCE_DATA_NAME); - assertThat(testSourceData.processingState).isEqualTo(UPDATED_PROCESSING_STATE); - assertThat(testSourceData.keySchema).isEqualTo(UPDATED_KEY_SCHEMA); - assertThat(testSourceData.valueSchema).isEqualTo(UPDATED_VALUE_SCHEMA); - assertThat(testSourceData.topic).isEqualTo(UPDATED_TOPIC); - assertThat(testSourceData.unit).isEqualTo(UPDATED_UNIT); - assertThat(testSourceData.frequency).isEqualTo(UPDATED_FREQUENCY); + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeUpdate) + val testSourceData = sourceDataList[sourceDataList.size - 1] + Assertions.assertThat(testSourceData.sourceDataType).isEqualTo(UPDATED_SOURCE_DATA_TYPE) + Assertions.assertThat(testSourceData.sourceDataName).isEqualTo(UPDATED_SOURCE_DATA_NAME) + Assertions.assertThat(testSourceData.processingState).isEqualTo(UPDATED_PROCESSING_STATE) + Assertions.assertThat(testSourceData.keySchema).isEqualTo(UPDATED_KEY_SCHEMA) + Assertions.assertThat(testSourceData.valueSchema).isEqualTo(UPDATED_VALUE_SCHEMA) + Assertions.assertThat(testSourceData.topic).isEqualTo(UPDATED_TOPIC) + Assertions.assertThat(testSourceData.unit).isEqualTo(UPDATED_UNIT) + Assertions.assertThat(testSourceData.frequency).isEqualTo(UPDATED_FREQUENCY) } @Test @Transactional - void updateNonExistingSourceData() throws Exception { - int databaseSizeBeforeUpdate = sourceDataRepository.findAll().size(); + @Throws(Exception::class) + fun updateNonExistingSourceData() { + val databaseSizeBeforeUpdate = sourceDataRepository!!.findAll().size // Create the SourceData - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); + val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) // If the entity doesn't have an ID, it will be created instead of just being updated - restSourceDataMockMvc.perform(put("/api/source-data") + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.put("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDataDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the SourceData in the database - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeUpdate + 1); + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeUpdate + 1) } @Test @Transactional - void deleteSourceData() throws Exception { + @Throws(Exception::class) + fun deleteSourceData() { // Initialize the database - sourceDataRepository.saveAndFlush(sourceData); - int databaseSizeBeforeDelete = sourceDataRepository.findAll().size(); + sourceDataRepository!!.saveAndFlush(sourceData) + val databaseSizeBeforeDelete = sourceDataRepository.findAll().size // Get the sourceData - restSourceDataMockMvc.perform(delete("/api/source-data/{sourceDataName}", - sourceData.sourceDataName) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()); + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.delete( + "/api/source-data/{sourceDataName}", + sourceData!!.sourceDataName + ) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeDelete - 1); + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeDelete - 1) } @Test @Transactional - void equalsVerifier() throws Exception { - Assertions.assertTrue(TestUtil.equalsVerifier(SourceData.class)); + @Throws(Exception::class) + fun equalsVerifier() { + org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(SourceData::class.java)) + } + + companion object { + private const val DEFAULT_SOURCE_DATA_TYPE = "AAAAAAAAAA" + private const val UPDATED_SOURCE_DATA_TYPE = "BBBBBBBBBB" + private const val DEFAULT_SOURCE_DATA_NAME = "AAAAAAAAAAAAA" + private const val UPDATED_SOURCE_DATA_NAME = "BBBBBBBBBBAAA" + private const val DEFAULT_PROCESSING_STATE = "RAW" + private const val UPDATED_PROCESSING_STATE = "DERIVED" + private const val DEFAULT_KEY_SCHEMA = "AAAAAAAAAAC" + private const val UPDATED_KEY_SCHEMA = "BBBBBBBBBBC" + private const val DEFAULT_VALUE_SCHEMA = "AAAAAAAAAAA" + private const val UPDATED_VALUE_SCHEMA = "BBBBBBBBBBB" + private const val DEFAULT_FREQUENCY = "AAAAAAAAAAAA" + private const val UPDATED_FREQUENCY = "BBBBBBBBBBBB" + private const val DEFAULT_UNTI = "AAAAAAAAAAAAAAC" + private const val UPDATED_UNIT = "BBBBBBBBBBBBBBC" + private const val DEFAULT_TOPIC = "AAAAAAAAAAAAAAA" + private const val UPDATED_TOPIC = "BBBBBBBBBBBBBBB" + + /** + * Create an entity for this test. + * + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + fun createEntity(em: EntityManager?): SourceData { + return SourceData() + .sourceDataType(DEFAULT_SOURCE_DATA_TYPE) + .sourceDataName(DEFAULT_SOURCE_DATA_NAME) + .processingState(DEFAULT_PROCESSING_STATE) + .keySchema(DEFAULT_KEY_SCHEMA) + .valueSchema(DEFAULT_VALUE_SCHEMA) + .topic(DEFAULT_TOPIC) + .unit(DEFAULT_UNTI) + .frequency(DEFAULT_FREQUENCY) + } } } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt index 625a7fec8..936f9d6b9 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt @@ -1,343 +1,343 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Source; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.SourceRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.SourceService; -import org.radarbase.management.service.SourceTypeService; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.mapper.SourceMapper; -import org.radarbase.management.service.mapper.SourceTypeMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.result.MockMvcResultHandlers; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.servlet.ServletException; -import java.util.List; -import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.everyItem; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.notNullValue; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Source +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.SourceRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.SourceService +import org.radarbase.management.service.SourceTypeService +import org.radarbase.management.service.mapper.SourceMapper +import org.radarbase.management.service.mapper.SourceTypeMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultHandlers +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import java.util.* +import javax.servlet.ServletException /** * Test class for the DeviceResource REST controller. * * @see SourceResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class SourceResourceIntTest { - - private static final UUID DEFAULT_SOURCE_PHYSICAL_ID = UUID.randomUUID(); - private static final UUID UPDATED_SOURCE_PHYSICAL_ID = DEFAULT_SOURCE_PHYSICAL_ID; - - private static final String DEFAULT_SOURCE_NAME = "CCCCCCCCCC"; - - private static final Boolean DEFAULT_ASSIGNED = false; - private static final Boolean UPDATED_ASSIGNED = true; - - @Autowired - private SourceRepository sourceRepository; - - @Autowired - private SourceMapper sourceMapper; - - @Autowired - private SourceService sourceService; - - @Autowired - private SourceTypeService sourceTypeService; - - @Autowired - private SourceTypeMapper sourceTypeMapper; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - @Autowired - private ProjectRepository projectRepository; - - private MockMvc restDeviceMockMvc; - - private Source source; - - private Project project; - @Autowired - private AuthService authService; +internal open class SourceResourceIntTest( + @Autowired private val sourceRepository: SourceRepository, + @Autowired private val sourceMapper: SourceMapper, + @Autowired private val sourceService: SourceService, + @Autowired private val sourceTypeService: SourceTypeService, + @Autowired private val sourceTypeMapper: SourceTypeMapper, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val projectRepository: ProjectRepository, + private var restDeviceMockMvc: MockMvc, + private var source: Source, + private var project: Project, + @Autowired private val authService: AuthService +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - SourceResource sourceResource = new SourceResource(); - ReflectionTestUtils.setField(sourceResource, "authService", authService); - ReflectionTestUtils.setField(sourceResource, "sourceService", sourceService); - ReflectionTestUtils.setField(sourceResource, "sourceRepository", sourceRepository); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - this.restDeviceMockMvc = MockMvcBuilders.standaloneSetup(sourceResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())) - .alwaysDo(MockMvcResultHandlers.print()).build(); - } - - /** - * Create an entity for this test. - * - *

This is a static method, as tests for other entities might also need it, - * if they test an entity which requires the current entity.

- */ - public static Source createEntity() { - return new Source() - .assigned(DEFAULT_ASSIGNED) - .sourceName(DEFAULT_SOURCE_NAME); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val sourceResource = SourceResource() + ReflectionTestUtils.setField(sourceResource, "authService", authService) + ReflectionTestUtils.setField(sourceResource, "sourceService", sourceService) + ReflectionTestUtils.setField(sourceResource, "sourceRepository", sourceRepository) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restDeviceMockMvc = MockMvcBuilders.standaloneSetup(sourceResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .alwaysDo(MockMvcResultHandlers.print()).build() } @BeforeEach - public void initTest() { - source = createEntity(); - List sourceTypeDtos = sourceTypeService.findAll(); - assertThat(sourceTypeDtos.size()).isPositive(); - source.sourceType = sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDtos.get(0)); - project = projectRepository.findById(1L).get(); - source.project(project); + fun initTest() { + source = createEntity() + val sourceTypeDtos = sourceTypeService.findAll() + Assertions.assertThat(sourceTypeDtos.size).isPositive() + source.sourceType = sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDtos[0]) + project = projectRepository.findById(1L).get() + source.project(project) } @Test @Transactional - void createSource() throws Exception { - int databaseSizeBeforeCreate = sourceRepository.findAll().size(); + @Throws(Exception::class) + open fun createSource() { + val databaseSizeBeforeCreate = sourceRepository.findAll().size // Create the Source - SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(source); - restDeviceMockMvc.perform(post("/api/sources") + val sourceDto = sourceMapper.sourceToSourceDTO(source) + restDeviceMockMvc.perform( + MockMvcRequestBuilders.post("/api/sources") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Source in the database - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeCreate + 1); - Source testSource = sourceList.get(sourceList.size() - 1); - assertThat(testSource.isAssigned()).isEqualTo(DEFAULT_ASSIGNED); - assertThat(testSource.sourceName).isEqualTo(DEFAULT_SOURCE_NAME); - assertThat(testSource.project.projectName).isEqualTo(project.projectName); + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeCreate + 1) + val testSource = sourceList[sourceList.size - 1] + Assertions.assertThat(testSource.isAssigned).isEqualTo(DEFAULT_ASSIGNED) + Assertions.assertThat(testSource.sourceName).isEqualTo(DEFAULT_SOURCE_NAME) + Assertions.assertThat(testSource.project!!.projectName).isEqualTo(project.projectName) } @Test @Transactional - void createSourceWithExistingId() throws Exception { - int databaseSizeBeforeCreate = sourceRepository.findAll().size(); + @Throws(Exception::class) + open fun createSourceWithExistingId() { + val databaseSizeBeforeCreate = sourceRepository.findAll().size // Create the Source with an existing ID - source.setId(1L); - SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(source); + source.id = 1L + val sourceDto = sourceMapper.sourceToSourceDTO(source) // An entity with an existing ID cannot be created, so this API call must fail - restDeviceMockMvc.perform(post("/api/sources") + restDeviceMockMvc.perform( + MockMvcRequestBuilders.post("/api/sources") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDto))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(sourceDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the Alice in the database - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeCreate); + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeCreate) } @Test @Transactional - void checkSourcePhysicalIdIsGenerated() throws Exception { - int databaseSizeBeforeTest = sourceRepository.findAll().size(); + @Throws(Exception::class) + open fun checkSourcePhysicalIdIsGenerated() { + val databaseSizeBeforeTest = sourceRepository.findAll().size // set the field null - source.sourceId = null; + source.sourceId = null // Create the Source - SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(source); - - restDeviceMockMvc.perform(post("/api/sources") + val sourceDto = sourceMapper.sourceToSourceDTO(source) + restDeviceMockMvc.perform( + MockMvcRequestBuilders.post("/api/sources") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDto))) - .andExpect(status().isCreated()); - - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeTest + 1); + .content(TestUtil.convertObjectToJsonBytes(sourceDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeTest + 1) // find our created source - Source createdSource = sourceList.stream() - .filter(s -> s.sourceName.equals(DEFAULT_SOURCE_NAME)) - .findFirst() - .orElse(null); - assertThat(createdSource).isNotNull(); + val createdSource = sourceList.stream() + .filter { s: Source? -> s!!.sourceName == DEFAULT_SOURCE_NAME } + .findFirst() + .orElse(null) + Assertions.assertThat(createdSource).isNotNull() // check source id - assertThat(createdSource.sourceId).isNotNull(); + Assertions.assertThat(createdSource!!.sourceId).isNotNull() } @Test @Transactional - void checkAssignedIsRequired() throws Exception { - int databaseSizeBeforeTest = sourceRepository.findAll().size(); + @Throws(Exception::class) + open fun checkAssignedIsRequired() { + val databaseSizeBeforeTest = sourceRepository.findAll().size // set the field null - source.setAssigned(null); + source.isAssigned = null // Create the Source, which fails. - SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(source); - - restDeviceMockMvc.perform(post("/api/sources") + val sourceDto = sourceMapper.sourceToSourceDTO(source) + restDeviceMockMvc.perform( + MockMvcRequestBuilders.post("/api/sources") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDto))) - .andExpect(status().isBadRequest()); - - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeTest); + .content(TestUtil.convertObjectToJsonBytes(sourceDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeTest) } - @Test - @Transactional - void getAllSources() throws Exception { - // Initialize the database - sourceRepository.saveAndFlush(source); - - // Get all the deviceList - restDeviceMockMvc.perform(get("/api/sources?sort=id,desc")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(source.getId().intValue()))) - .andExpect(jsonPath("$.[*].sourceId").value(everyItem(notNullValue()))) - .andExpect(jsonPath("$.[*].assigned").value( - hasItem(DEFAULT_ASSIGNED.booleanValue()))); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val allSources: Unit + get() { + // Initialize the database + sourceRepository.saveAndFlush(source) + + // Get all the deviceList + restDeviceMockMvc.perform(MockMvcRequestBuilders.get("/api/sources?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + source.id!!.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(Matchers.everyItem(Matchers.notNullValue())) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].assigned").value>( + Matchers.hasItem(DEFAULT_ASSIGNED) + ) + ) + } @Test @Transactional - void getSource() throws Exception { + @Throws(Exception::class) + open fun getSource() { // Initialize the database - sourceRepository.saveAndFlush(source); + sourceRepository.saveAndFlush(source) // Get the source - restDeviceMockMvc.perform(get("/api/sources/{sourceName}", source.sourceName)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.id").value(source.getId().intValue())) - .andExpect(jsonPath("$.sourceId").value(notNullValue())) - .andExpect(jsonPath("$.assigned").value(DEFAULT_ASSIGNED.booleanValue())); + restDeviceMockMvc.perform(MockMvcRequestBuilders.get("/api/sources/{sourceName}", source.sourceName)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(source.id!!.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.sourceId").value(Matchers.notNullValue())) + .andExpect(MockMvcResultMatchers.jsonPath("$.assigned").value(DEFAULT_ASSIGNED)) } - @Test - @Transactional - void getNonExistingSource() throws Exception { - // Get the source - restDeviceMockMvc.perform(get("/api/sources/{id}", Long.MAX_VALUE)) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val nonExistingSource: Unit + get() { + // Get the source + restDeviceMockMvc.perform(MockMvcRequestBuilders.get("/api/sources/{id}", Long.MAX_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional - void updateSource() throws Exception { + @Throws(Exception::class) + open fun updateSource() { // Initialize the database - sourceRepository.saveAndFlush(source); - int databaseSizeBeforeUpdate = sourceRepository.findAll().size(); + sourceRepository.saveAndFlush(source) + val databaseSizeBeforeUpdate = sourceRepository.findAll().size // Update the source - Source updatedSource = sourceRepository.findById(source.getId()).get(); + val updatedSource = sourceRepository.findById(source.id!!).get() updatedSource - .sourceId(UPDATED_SOURCE_PHYSICAL_ID) - .assigned(UPDATED_ASSIGNED); - SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(updatedSource); - - restDeviceMockMvc.perform(put("/api/sources") + .sourceId(UPDATED_SOURCE_PHYSICAL_ID) + .assigned(UPDATED_ASSIGNED) + val sourceDto = sourceMapper.sourceToSourceDTO(updatedSource) + restDeviceMockMvc.perform( + MockMvcRequestBuilders.put("/api/sources") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDto))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(sourceDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Source in the database - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeUpdate); - Source testSource = sourceList.get(sourceList.size() - 1); - assertThat(testSource.sourceId).isEqualTo(UPDATED_SOURCE_PHYSICAL_ID); - assertThat(testSource.isAssigned()).isEqualTo(UPDATED_ASSIGNED); + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeUpdate) + val testSource = sourceList[sourceList.size - 1] + Assertions.assertThat(testSource.sourceId).isEqualTo(UPDATED_SOURCE_PHYSICAL_ID) + Assertions.assertThat(testSource.isAssigned).isEqualTo(UPDATED_ASSIGNED) } @Test @Transactional - void updateNonExistingSource() throws Exception { - int databaseSizeBeforeUpdate = sourceRepository.findAll().size(); + @Throws(Exception::class) + open fun updateNonExistingSource() { + val databaseSizeBeforeUpdate = sourceRepository.findAll().size // Create the Source - SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(source); + val sourceDto = sourceMapper.sourceToSourceDTO(source) // If the entity doesn't have an ID, it will be created instead of just being updated - restDeviceMockMvc.perform(put("/api/sources") + restDeviceMockMvc.perform( + MockMvcRequestBuilders.put("/api/sources") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Source in the database - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeUpdate + 1); + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeUpdate + 1) } @Test @Transactional - void deleteSource() throws Exception { + @Throws(Exception::class) + open fun deleteSource() { // Initialize the database - sourceRepository.saveAndFlush(source); - int databaseSizeBeforeDelete = sourceRepository.findAll().size(); + sourceRepository.saveAndFlush(source) + val databaseSizeBeforeDelete = sourceRepository.findAll().size // Get the source - restDeviceMockMvc.perform(delete("/api/sources/{sourceName}", source.sourceName) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()); + restDeviceMockMvc.perform( + MockMvcRequestBuilders.delete("/api/sources/{sourceName}", source.sourceName) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeDelete - 1); + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeDelete - 1) } @Test @Transactional - void equalsVerifier() throws Exception { - Assertions.assertTrue(TestUtil.equalsVerifier(Source.class)); + @Throws(Exception::class) + open fun equalsVerifier() { + org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Source::class.java)) + } + + companion object { + private val DEFAULT_SOURCE_PHYSICAL_ID = UUID.randomUUID() + private val UPDATED_SOURCE_PHYSICAL_ID = DEFAULT_SOURCE_PHYSICAL_ID + private const val DEFAULT_SOURCE_NAME = "CCCCCCCCCC" + private const val DEFAULT_ASSIGNED = false + private const val UPDATED_ASSIGNED = true + + /** + * Create an entity for this test. + * + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + fun createEntity(): Source { + return Source() + .assigned(DEFAULT_ASSIGNED) + .sourceName(DEFAULT_SOURCE_NAME) + } } } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt index 73d8864ea..71ce2af6f 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt @@ -1,436 +1,500 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.repository.SourceDataRepository; -import org.radarbase.management.repository.SourceTypeRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.SourceTypeService; -import org.radarbase.management.service.dto.SourceDataDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.mapper.SourceDataMapper; -import org.radarbase.management.service.mapper.SourceTypeMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.persistence.EntityManager; -import javax.servlet.ServletException; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.SourceType +import org.radarbase.management.repository.SourceDataRepository +import org.radarbase.management.repository.SourceTypeRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.SourceTypeService +import org.radarbase.management.service.mapper.SourceDataMapper +import org.radarbase.management.service.mapper.SourceTypeMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import javax.persistence.EntityManager +import javax.servlet.ServletException /** * Test class for the SourceTypeResource REST controller. * * @see SourceTypeResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class SourceTypeResourceIntTest { - - private static final String DEFAULT_PRODUCER = "AAAAA AAAAA"; - private static final String UPDATED_PRODUCER = "BBBBBBBBBB"; - - private static final String DEFAULT_MODEL = "AAAAA AAAAA"; - private static final String UPDATED_MODEL = "BBBBBBBBBB"; - - private static final String DEFAULT_DEVICE_VERSION = "AAAAAAAAAA"; - private static final String UPDATED_DEVICE_VERSION = "AAAAAAAAAA"; - - private static final String DEFAULT_SOURCE_TYPE_SCOPE = "ACTIVE"; - private static final String UPDATED_SOURCE_TYPE_SCOPE = "PASSIVE"; - - @Autowired - private SourceTypeRepository sourceTypeRepository; - - @Autowired - private SourceTypeMapper sourceTypeMapper; - - @Autowired - private SourceTypeService sourceTypeService; - - @Autowired - private SourceDataMapper sourceDataMapper; - - @Autowired - private SourceDataRepository sourceDataRepository; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - @Autowired - private EntityManager em; - - private MockMvc restSourceTypeMockMvc; - - private SourceType sourceType; - @Autowired - private AuthService authService; +internal open class SourceTypeResourceIntTest( + @Autowired private val sourceTypeRepository: SourceTypeRepository, + @Autowired private val sourceTypeMapper: SourceTypeMapper, + @Autowired private val sourceTypeService: SourceTypeService, + @Autowired private val sourceDataMapper: SourceDataMapper, + @Autowired private val sourceDataRepository: SourceDataRepository, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val em: EntityManager, + private var restSourceTypeMockMvc: MockMvc, + private var sourceType: SourceType, + @Autowired private val authService: AuthService +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - SourceTypeResource sourceTypeResource = new SourceTypeResource(); - ReflectionTestUtils.setField(sourceTypeResource, "sourceTypeService" , sourceTypeService); - ReflectionTestUtils.setField(sourceTypeResource, "sourceTypeRepository" , - sourceTypeRepository); - ReflectionTestUtils.setField(sourceTypeResource, "authService", authService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restSourceTypeMockMvc = MockMvcBuilders.standaloneSetup(sourceTypeResource) + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val sourceTypeResource = SourceTypeResource() + ReflectionTestUtils.setField(sourceTypeResource, "sourceTypeService", sourceTypeService) + ReflectionTestUtils.setField( + sourceTypeResource, "sourceTypeRepository", + sourceTypeRepository + ) + ReflectionTestUtils.setField(sourceTypeResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restSourceTypeMockMvc = MockMvcBuilders.standaloneSetup(sourceTypeResource) .setCustomArgumentResolvers(pageableArgumentResolver) .setControllerAdvice(exceptionTranslator) .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - } - - /** - * Create an entity for this test. - * - *

This is a static method, as tests for other entities might also need it, - * if they test an entity which requires the current entity.

- */ - public static SourceType createEntity() { - return new SourceType() - .producer(DEFAULT_PRODUCER) - .model(DEFAULT_MODEL) - .catalogVersion(DEFAULT_DEVICE_VERSION) - .sourceTypeScope(DEFAULT_SOURCE_TYPE_SCOPE); + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() } @BeforeEach - public void initTest() { - sourceType = createEntity(); + fun initTest() { + sourceType = createEntity() } @Test @Transactional - void createSourceType() throws Exception { - int databaseSizeBeforeCreate = sourceTypeRepository.findAll().size(); + @Throws(Exception::class) + open fun createSourceType() { + val databaseSizeBeforeCreate = sourceTypeRepository.findAll().size // Create the SourceType - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO( - SourceDataResourceIntTest.createEntity(em)); - Set sourceData = sourceTypeDto.getSourceData(); - sourceData.add(sourceDataDto); - restSourceTypeMockMvc.perform(post("/api/source-types") + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO( + SourceDataResourceIntTest.Companion.createEntity(em) + ) + val sourceData = sourceTypeDto.sourceData + sourceData.add(sourceDataDto) + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.post("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the SourceType in the database - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeCreate + 1); - SourceType testSourceType = sourceTypeList.get(sourceTypeList.size() - 1); - assertThat(testSourceType.producer).isEqualTo(DEFAULT_PRODUCER); - assertThat(testSourceType.model).isEqualTo(DEFAULT_MODEL); - assertThat(testSourceType.sourceTypeScope).isEqualTo(DEFAULT_SOURCE_TYPE_SCOPE); - assertThat(testSourceType.catalogVersion).isEqualTo(DEFAULT_DEVICE_VERSION); - assertThat(testSourceType.sourceData).hasSize(1); - SourceData testSourceData = testSourceType.sourceData.iterator().next(); - assertThat(testSourceData.sourceDataType).isEqualTo(sourceDataDto.getSourceDataType()); - assertThat(testSourceData.sourceDataName).isEqualTo(sourceDataDto.getSourceDataName()); - assertThat(testSourceData.processingState).isEqualTo( - sourceDataDto.getProcessingState()); - assertThat(testSourceData.keySchema).isEqualTo(sourceDataDto.getKeySchema()); - assertThat(testSourceData.frequency).isEqualTo(sourceDataDto.getFrequency()); + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeCreate + 1) + val testSourceType = sourceTypeList[sourceTypeList.size - 1] + Assertions.assertThat(testSourceType.producer).isEqualTo(DEFAULT_PRODUCER) + Assertions.assertThat(testSourceType.model).isEqualTo(DEFAULT_MODEL) + Assertions.assertThat(testSourceType.sourceTypeScope).isEqualTo(DEFAULT_SOURCE_TYPE_SCOPE) + Assertions.assertThat(testSourceType.catalogVersion).isEqualTo(DEFAULT_DEVICE_VERSION) + Assertions.assertThat(testSourceType.sourceData).hasSize(1) + val testSourceData = testSourceType.sourceData.iterator().next() + Assertions.assertThat(testSourceData.sourceDataType).isEqualTo(sourceDataDto.sourceDataType) + Assertions.assertThat(testSourceData.sourceDataName).isEqualTo(sourceDataDto.sourceDataName) + Assertions.assertThat(testSourceData.processingState).isEqualTo( + sourceDataDto.processingState + ) + Assertions.assertThat(testSourceData.keySchema).isEqualTo(sourceDataDto.keySchema) + Assertions.assertThat(testSourceData.frequency).isEqualTo(sourceDataDto.frequency) } @Test @Transactional - void createSourceTypeWithExistingId() throws Exception { - int databaseSizeBeforeCreate = sourceTypeRepository.findAll().size(); + @Throws(Exception::class) + open fun createSourceTypeWithExistingId() { + val databaseSizeBeforeCreate = sourceTypeRepository.findAll().size // Create the SourceType with an existing ID - sourceType.setId(1L); - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); + sourceType.id = 1L + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) // An entity with an existing ID cannot be created, so this API call must fail - restSourceTypeMockMvc.perform(post("/api/source-types") + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.post("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the Alice in the database - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeCreate); + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeCreate) } @Test @Transactional - void checkModelIsRequired() throws Exception { - int databaseSizeBeforeTest = sourceTypeRepository.findAll().size(); + @Throws(Exception::class) + open fun checkModelIsRequired() { + val databaseSizeBeforeTest = sourceTypeRepository.findAll().size // set the field null - sourceType.model = null; + sourceType.model = null // Create the SourceType, which fails. - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); - - restSourceTypeMockMvc.perform(post("/api/source-types") + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.post("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isBadRequest()); - - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest) } @Test @Transactional - void checkSourceTypeIsRequired() throws Exception { - int databaseSizeBeforeTest = sourceTypeRepository.findAll().size(); + @Throws(Exception::class) + open fun checkSourceTypeIsRequired() { + val databaseSizeBeforeTest = sourceTypeRepository.findAll().size // set the field null - sourceType.sourceTypeScope = null; + sourceType.sourceTypeScope = null // Create the SourceType, which fails. - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); - - restSourceTypeMockMvc.perform(post("/api/source-types") + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.post("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isBadRequest()); - - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest) } @Test @Transactional - void checkVersionIsRequired() throws Exception { - int databaseSizeBeforeTest = sourceTypeRepository.findAll().size(); + @Throws(Exception::class) + open fun checkVersionIsRequired() { + val databaseSizeBeforeTest = sourceTypeRepository.findAll().size // set the field null - sourceType.catalogVersion(null); + sourceType.catalogVersion(null) // Create the SourceType, which fails. - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); - - restSourceTypeMockMvc.perform(post("/api/source-types") + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.post("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isBadRequest()); - - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest); - } - - @Test - @Transactional - void getAllSourceTypes() throws Exception { - // Initialize the database - sourceTypeRepository.saveAndFlush(sourceType); - - // Get all the sourceTypeList - restSourceTypeMockMvc.perform(get("/api/source-types")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(sourceType.getId().intValue()))) - .andExpect(jsonPath("$.[*].producer").value(hasItem(DEFAULT_PRODUCER))) - .andExpect(jsonPath("$.[*].model").value(hasItem(DEFAULT_MODEL))) - .andExpect(jsonPath("$.[*].catalogVersion").value(hasItem(DEFAULT_DEVICE_VERSION))) - .andExpect(jsonPath("$.[*].sourceTypeScope").value( - hasItem(DEFAULT_SOURCE_TYPE_SCOPE))); - } - - - @Test - @Transactional - void getAllSourceTypesWithPagination() throws Exception { - // Initialize the database - sourceTypeRepository.saveAndFlush(sourceType); - - // Get all the sourceTypeList - restSourceTypeMockMvc.perform(get("/api/source-types?page=0&size=5&sort=id,desc")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(sourceType.getId().intValue()))) - .andExpect(jsonPath("$.[*].producer").value(hasItem(DEFAULT_PRODUCER))) - .andExpect(jsonPath("$.[*].model").value(hasItem(DEFAULT_MODEL))) - .andExpect(jsonPath("$.[*].catalogVersion").value(hasItem(DEFAULT_DEVICE_VERSION))) - .andExpect(jsonPath("$.[*].sourceTypeScope").value( - hasItem(DEFAULT_SOURCE_TYPE_SCOPE))); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest) } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val allSourceTypes: Unit + get() { + // Initialize the database + sourceTypeRepository.saveAndFlush(sourceType) + + // Get all the sourceTypeList + restSourceTypeMockMvc.perform(MockMvcRequestBuilders.get("/api/source-types")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + sourceType.id!!.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].producer").value>( + Matchers.hasItem( + DEFAULT_PRODUCER + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].model").value>( + Matchers.hasItem( + DEFAULT_MODEL + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].catalogVersion").value>( + Matchers.hasItem( + DEFAULT_DEVICE_VERSION + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceTypeScope").value>( + Matchers.hasItem(DEFAULT_SOURCE_TYPE_SCOPE) + ) + ) + } + + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val allSourceTypesWithPagination: Unit + get() { + // Initialize the database + sourceTypeRepository.saveAndFlush(sourceType) + + // Get all the sourceTypeList + restSourceTypeMockMvc.perform(MockMvcRequestBuilders.get("/api/source-types?page=0&size=5&sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + sourceType.id!!.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].producer").value>( + Matchers.hasItem( + DEFAULT_PRODUCER + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].model").value>( + Matchers.hasItem( + DEFAULT_MODEL + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].catalogVersion").value>( + Matchers.hasItem( + DEFAULT_DEVICE_VERSION + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceTypeScope").value>( + Matchers.hasItem(DEFAULT_SOURCE_TYPE_SCOPE) + ) + ) + } @Test @Transactional - void getSourceType() throws Exception { + @Throws(Exception::class) + open fun getSourceType() { // Initialize the database - sourceTypeRepository.saveAndFlush(sourceType); + sourceTypeRepository.saveAndFlush(sourceType) // Get the sourceType - restSourceTypeMockMvc.perform(get("/api/source-types/{prodcuer}/{model}/{version}", - sourceType.producer, sourceType.model, sourceType.catalogVersion)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.id").value(sourceType.getId().intValue())) - .andExpect(jsonPath("$.producer").value(DEFAULT_PRODUCER)) - .andExpect(jsonPath("$.model").value(DEFAULT_MODEL)) - .andExpect(jsonPath("$.sourceTypeScope").value( - DEFAULT_SOURCE_TYPE_SCOPE)); + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/source-types/{prodcuer}/{model}/{version}", + sourceType.producer, sourceType.model, sourceType.catalogVersion + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(sourceType.id!!.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.producer").value(DEFAULT_PRODUCER)) + .andExpect(MockMvcResultMatchers.jsonPath("$.model").value(DEFAULT_MODEL)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.sourceTypeScope").value( + DEFAULT_SOURCE_TYPE_SCOPE + ) + ) } - @Test - @Transactional - void getNonExistingSourceType() throws Exception { - // Get the sourceType - restSourceTypeMockMvc.perform(get("/api/source-types/{prodcuer}/{model}/{version}", - "does", "not", "exist")) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val nonExistingSourceType: Unit + get() { + // Get the sourceType + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/source-types/{prodcuer}/{model}/{version}", + "does", "not", "exist" + ) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional - void updateSourceType() throws Exception { + @Throws(Exception::class) + open fun updateSourceType() { // Initialize the database - sourceTypeRepository.saveAndFlush(sourceType); - int databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size(); + sourceTypeRepository.saveAndFlush(sourceType) + val databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size // Update the sourceType - SourceType updatedSourceType = sourceTypeRepository.findById(sourceType.getId()).get(); + val updatedSourceType = sourceTypeRepository.findById(sourceType.id!!).get() updatedSourceType - .producer(UPDATED_PRODUCER) - .model(UPDATED_MODEL) - .catalogVersion(UPDATED_DEVICE_VERSION) - .sourceTypeScope(UPDATED_SOURCE_TYPE_SCOPE); - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(updatedSourceType); - - restSourceTypeMockMvc.perform(put("/api/source-types") + .producer(UPDATED_PRODUCER) + .model(UPDATED_MODEL) + .catalogVersion(UPDATED_DEVICE_VERSION) + .sourceTypeScope(UPDATED_SOURCE_TYPE_SCOPE) + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(updatedSourceType) + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.put("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the SourceType in the database - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate); - SourceType testSourceType = sourceTypeList.get(sourceTypeList.size() - 1); - assertThat(testSourceType.producer).isEqualTo(UPDATED_PRODUCER); - assertThat(testSourceType.model).isEqualTo(UPDATED_MODEL); - assertThat(testSourceType.catalogVersion).isEqualTo(UPDATED_DEVICE_VERSION); - assertThat(testSourceType.sourceTypeScope).isEqualTo(UPDATED_SOURCE_TYPE_SCOPE); + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate) + val testSourceType = sourceTypeList[sourceTypeList.size - 1] + Assertions.assertThat(testSourceType.producer).isEqualTo(UPDATED_PRODUCER) + Assertions.assertThat(testSourceType.model).isEqualTo(UPDATED_MODEL) + Assertions.assertThat(testSourceType.catalogVersion).isEqualTo(UPDATED_DEVICE_VERSION) + Assertions.assertThat(testSourceType.sourceTypeScope).isEqualTo(UPDATED_SOURCE_TYPE_SCOPE) } @Test @Transactional - void updateNonExistingSourceType() throws Exception { - int databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size(); + @Throws(Exception::class) + open fun updateNonExistingSourceType() { + val databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size // Create the SourceType - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) // If the entity doesn't have an ID, it will be created instead of just being updated - restSourceTypeMockMvc.perform(put("/api/source-types") + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.put("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the SourceType in the database - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate + 1); + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate + 1) } @Test @Transactional - void deleteSourceType() throws Exception { + @Throws(Exception::class) + open fun deleteSourceType() { // Initialize the database - sourceTypeRepository.saveAndFlush(sourceType); - int databaseSizeBeforeDelete = sourceTypeRepository.findAll().size(); + sourceTypeRepository.saveAndFlush(sourceType) + val databaseSizeBeforeDelete = sourceTypeRepository.findAll().size // Get the sourceType - restSourceTypeMockMvc.perform(delete("/api/source-types/{prodcuer}/{model}/{version}", - sourceType.producer, sourceType.model, sourceType.catalogVersion) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()); + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.delete( + "/api/source-types/{prodcuer}/{model}/{version}", + sourceType.producer, sourceType.model, sourceType.catalogVersion + ) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeDelete - 1); + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeDelete - 1) } @Test @Transactional - void equalsVerifier() throws Exception { - Assertions.assertTrue(TestUtil.equalsVerifier(SourceType.class)); + @Throws(Exception::class) + open fun equalsVerifier() { + org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(SourceType::class.java)) } @Test @Transactional - void idempotentPutWithoutId() throws Exception { - final int databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size(); - final int sensorsSizeBeforeUpdate = sourceDataRepository.findAll().size(); - - sourceType.setSourceData(Collections.singleton(SourceDataResourceIntTest.createEntity(em))); + @Throws(Exception::class) + open fun idempotentPutWithoutId() { + val databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size + val sensorsSizeBeforeUpdate = sourceDataRepository.findAll().size + sourceType.sourceData = setOf(SourceDataResourceIntTest.Companion.createEntity(em)) // Create the SourceType - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) // If the entity doesn't have an ID, it will be created instead of just being updated - restSourceTypeMockMvc.perform(put("/api/source-types") + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.put("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the SourceType in the database - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate + 1); + var sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate + 1) // Validate the SourceData in the database - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(sensorsSizeBeforeUpdate + 1); + var sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(sensorsSizeBeforeUpdate + 1) // Test doing a put with only producer and model, no id, does not create a new source-type // assert that the id is still unset - assertThat(sourceTypeDto.getId()).isNull(); - restSourceTypeMockMvc.perform(put("/api/source-types") + Assertions.assertThat(sourceTypeDto.id).isNull() + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.put("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().is(HttpStatus.CONFLICT.value())); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().`is`(HttpStatus.CONFLICT.value())) // Validate no change in database size - sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate + 1); + sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate + 1) // Validate no change in sourceData database size - sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(sensorsSizeBeforeUpdate + 1); + sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(sensorsSizeBeforeUpdate + 1) + } + + companion object { + private const val DEFAULT_PRODUCER = "AAAAA AAAAA" + private const val UPDATED_PRODUCER = "BBBBBBBBBB" + private const val DEFAULT_MODEL = "AAAAA AAAAA" + private const val UPDATED_MODEL = "BBBBBBBBBB" + private const val DEFAULT_DEVICE_VERSION = "AAAAAAAAAA" + private const val UPDATED_DEVICE_VERSION = "AAAAAAAAAA" + private const val DEFAULT_SOURCE_TYPE_SCOPE = "ACTIVE" + private const val UPDATED_SOURCE_TYPE_SCOPE = "PASSIVE" + + /** + * Create an entity for this test. + * + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + fun createEntity(): SourceType { + return SourceType() + .producer(DEFAULT_PRODUCER) + .model(DEFAULT_MODEL) + .catalogVersion(DEFAULT_DEVICE_VERSION) + .sourceTypeScope(DEFAULT_SOURCE_TYPE_SCOPE) + } } } diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index 885cc19f1..623c78878 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -1,637 +1,664 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.SourceService; -import org.radarbase.management.service.SourceTypeService; -import org.radarbase.management.service.SubjectService; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.mapper.SubjectMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.servlet.ServletException; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.radarbase.management.service.SubjectServiceTest.DEFAULT_ENTERNAL_ID; -import static org.radarbase.management.service.SubjectServiceTest.DEFAULT_EXTERNAL_LINK; -import static org.radarbase.management.service.SubjectServiceTest.DEFAULT_REMOVED; -import static org.radarbase.management.service.SubjectServiceTest.DEFAULT_STATUS; -import static org.radarbase.management.service.SubjectServiceTest.MODEL; -import static org.radarbase.management.service.SubjectServiceTest.PRODUCER; -import static org.radarbase.management.service.SubjectServiceTest.UPDATED_ENTERNAL_ID; -import static org.radarbase.management.service.SubjectServiceTest.UPDATED_EXTERNAL_LINK; -import static org.radarbase.management.service.SubjectServiceTest.UPDATED_REMOVED; -import static org.radarbase.management.service.SubjectServiceTest.createEntityDTO; -import static org.radarbase.management.web.rest.TestUtil.commitTransactionAndStartNew; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.SourceService +import org.radarbase.management.service.SourceTypeService +import org.radarbase.management.service.SubjectService +import org.radarbase.management.service.SubjectServiceTest +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SourceDTO +import org.radarbase.management.service.dto.SourceTypeDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.mapper.SubjectMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import java.util.* +import java.util.stream.Collectors +import javax.servlet.ServletException /** * Test class for the SubjectResource REST controller. * * @see SubjectResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class SubjectResourceIntTest { - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private SubjectMapper subjectMapper; - - @Autowired - private SubjectService subjectService; - - @Autowired - private SourceService sourceService; - - @Autowired - private SourceTypeService sourceTypeService; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - @Autowired - private ProjectRepository projectRepository; - - private MockMvc restSubjectMockMvc; - - @Autowired - private AuthService authService; +internal open class SubjectResourceIntTest(@Autowired private val subjectRepository: SubjectRepository, + @Autowired private val subjectMapper: SubjectMapper, + @Autowired private val subjectService: SubjectService, + @Autowired private val sourceService: SourceService, + @Autowired private val sourceTypeService: SourceTypeService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val projectRepository: ProjectRepository, + private var restSubjectMockMvc: MockMvc, + @Autowired private val authService: AuthService +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - SubjectResource subjectResource = new SubjectResource(); - ReflectionTestUtils.setField(subjectResource, "subjectService", subjectService); - ReflectionTestUtils.setField(subjectResource, "subjectRepository", subjectRepository); - ReflectionTestUtils.setField(subjectResource, "subjectMapper", subjectMapper); - ReflectionTestUtils.setField(subjectResource, "projectRepository", projectRepository); - ReflectionTestUtils.setField(subjectResource, "sourceTypeService", sourceTypeService); - ReflectionTestUtils.setField(subjectResource, "authService", authService); - ReflectionTestUtils.setField(subjectResource, "sourceService", sourceService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restSubjectMockMvc = MockMvcBuilders.standaloneSetup(subjectResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - // add the oauth token by default to all requests for this mockMvc - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val subjectResource = SubjectResource + ReflectionTestUtils.setField(subjectResource, "subjectService", subjectService) + ReflectionTestUtils.setField(subjectResource, "subjectRepository", subjectRepository) + ReflectionTestUtils.setField(subjectResource, "subjectMapper", subjectMapper) + ReflectionTestUtils.setField(subjectResource, "projectRepository", projectRepository) + ReflectionTestUtils.setField(subjectResource, "sourceTypeService", sourceTypeService) + ReflectionTestUtils.setField(subjectResource, "authService", authService) + ReflectionTestUtils.setField(subjectResource, "sourceService", sourceService) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restSubjectMockMvc = MockMvcBuilders.standaloneSetup(subjectResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) // add the oauth token by default to all requests for this mockMvc + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() } @Test @Transactional - void createSubject() throws Exception { - final int databaseSizeBeforeCreate = subjectRepository.findAll().size(); + @Throws(Exception::class) + open fun createSubject() { + val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - SubjectDTO subjectDto = createEntityDTO(); - restSubjectMockMvc.perform(post("/api/subjects") + val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); - Subject testSubject = subjectList.get(subjectList.size() - 1); - assertThat(testSubject.externalLink).isEqualTo(DEFAULT_EXTERNAL_LINK); - assertThat(testSubject.externalId).isEqualTo(DEFAULT_ENTERNAL_ID); - assertThat(testSubject.isRemoved()).isEqualTo(DEFAULT_REMOVED); - assertEquals(1, testSubject.user.roles.size()); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) + val testSubject = subjectList[subjectList.size - 1] + Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK) + Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.Companion.DEFAULT_ENTERNAL_ID) + Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.Companion.DEFAULT_REMOVED) + org.junit.jupiter.api.Assertions.assertEquals(1, testSubject.user!!.roles!!.size) } @Test @Transactional - void createSubjectWithExistingId() throws Exception { + @Throws(Exception::class) + open fun createSubjectWithExistingId() { // Create a Subject - SubjectDTO subjectDto = subjectService.createSubject(createEntityDTO()); - final int databaseSizeBeforeCreate = subjectRepository.findAll().size(); + val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val databaseSizeBeforeCreate = subjectRepository.findAll().size // An entity with an existing ID cannot be created, so this API call must fail - restSubjectMockMvc.perform(post("/api/subjects") + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the Alice in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeCreate); - } - - @Test - @Transactional - void getAllSubjects() throws Exception { - // Initialize the database - SubjectDTO subjectDto = subjectService.createSubject(createEntityDTO()); - - // Get all the subjectList - restSubjectMockMvc.perform(get("/api/subjects?sort=id,desc")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(subjectDto.getId().intValue()))) - .andExpect(jsonPath("$.[*].externalLink").value(hasItem(DEFAULT_EXTERNAL_LINK))) - .andExpect(jsonPath("$.[*].externalId").value(hasItem(DEFAULT_ENTERNAL_ID))) - .andExpect(jsonPath("$.[*].status").value(hasItem(DEFAULT_STATUS.toString()))); - } - - @Test - @Transactional - void getSubject() throws Exception { - // Initialize the database - SubjectDTO subjectDto = subjectService.createSubject(createEntityDTO()); - - // Get the subject - restSubjectMockMvc.perform(get("/api/subjects/{login}", subjectDto.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.id").value(subjectDto.getId().intValue())) - .andExpect(jsonPath("$.externalLink").value(DEFAULT_EXTERNAL_LINK)) - .andExpect(jsonPath("$.externalId").value(DEFAULT_ENTERNAL_ID)) - .andExpect(jsonPath("$.status").value(DEFAULT_STATUS.toString())); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate) } - @Test - @Transactional - void getNonExistingSubject() throws Exception { - // Get the subject - restSubjectMockMvc.perform(get("/api/subjects/{id}", Long.MAX_VALUE)) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val allSubjects: Unit + get() { + // Initialize the database + val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + + // Get all the subjectList + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + subjectDto!!.id.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].externalLink") + .value>(Matchers.hasItem(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK)) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].externalId") + .value>(Matchers.hasItem(SubjectServiceTest.Companion.DEFAULT_ENTERNAL_ID)) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].status") + .value>(Matchers.hasItem(SubjectServiceTest.Companion.DEFAULT_STATUS.toString())) + ) + } + + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val subject: Unit + get() { + // Initialize the database + val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + + // Get the subject + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{login}", subjectDto!!.getLogin())) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(subjectDto.id.toInt())) + .andExpect( + MockMvcResultMatchers.jsonPath("$.externalLink") + .value(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.externalId") + .value(SubjectServiceTest.Companion.DEFAULT_ENTERNAL_ID) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.status") + .value(SubjectServiceTest.Companion.DEFAULT_STATUS.toString()) + ) + } + + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val nonExistingSubject: Unit + get() { + // Get the subject + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{id}", Long.MAX_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional - void updateSubject() throws Exception { + @Throws(Exception::class) + open fun updateSubject() { // Initialize the database - SubjectDTO subjectDto = subjectService.createSubject(createEntityDTO()); - final int databaseSizeBeforeUpdate = subjectRepository.findAll().size(); + var subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Update the subject - Subject updatedSubject = subjectRepository.findById(subjectDto.getId()).get(); + val updatedSubject = subjectRepository.findById(subjectDto!!.id).get() updatedSubject - .externalLink(UPDATED_EXTERNAL_LINK) - .externalId(UPDATED_ENTERNAL_ID) - .removed(UPDATED_REMOVED); - subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject); - - restSubjectMockMvc.perform(put("/api/subjects") + .externalLink(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) + .externalId(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) + .removed(SubjectServiceTest.Companion.UPDATED_REMOVED) + subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) + restSubjectMockMvc.perform( + MockMvcRequestBuilders.put("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeUpdate); - Subject testSubject = subjectList.get(subjectList.size() - 1); - assertThat(testSubject.externalLink).isEqualTo(UPDATED_EXTERNAL_LINK); - assertThat(testSubject.externalId).isEqualTo(UPDATED_ENTERNAL_ID); - assertThat(testSubject.isRemoved()).isEqualTo(UPDATED_REMOVED); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeUpdate) + val testSubject = subjectList[subjectList.size - 1] + Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) + Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) + Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.Companion.UPDATED_REMOVED) } @Test @Transactional - void updateSubjectWithNewProject() throws Exception { + @Throws(Exception::class) + open fun updateSubjectWithNewProject() { // Initialize the database - SubjectDTO subjectDto = subjectService.createSubject(createEntityDTO()); - final int databaseSizeBeforeUpdate = subjectRepository.findAll().size(); + var subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Update the subject - Subject updatedSubject = subjectRepository.findById(subjectDto.getId()).get(); - + val updatedSubject = subjectRepository.findById(subjectDto!!.id).get() updatedSubject - .externalLink(UPDATED_EXTERNAL_LINK) - .externalId(UPDATED_ENTERNAL_ID) - .removed(UPDATED_REMOVED); - - subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject); - ProjectDTO newProject = new ProjectDTO(); - newProject.setId(2L); - newProject.setProjectName("RadarNew"); - newProject.setLocation("new location"); - subjectDto.setProject(newProject); - - restSubjectMockMvc.perform(put("/api/subjects") + .externalLink(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) + .externalId(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) + .removed(SubjectServiceTest.Companion.UPDATED_REMOVED) + subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) + val newProject = ProjectDTO() + newProject.id = 2L + newProject.projectName = "RadarNew" + newProject.location = "new location" + subjectDto!!.project = newProject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.put("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeUpdate); - Subject testSubject = subjectList.get(subjectList.size() - 1); - assertThat(testSubject.externalLink).isEqualTo(UPDATED_EXTERNAL_LINK); - assertThat(testSubject.externalId).isEqualTo(UPDATED_ENTERNAL_ID); - assertThat(testSubject.isRemoved()).isEqualTo(UPDATED_REMOVED); - assertThat(testSubject.user.roles.size()).isEqualTo(2); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeUpdate) + val testSubject = subjectList[subjectList.size - 1] + Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) + Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) + Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.Companion.UPDATED_REMOVED) + Assertions.assertThat(testSubject.user!!.roles!!.size).isEqualTo(2) } @Test @Transactional - void updateNonExistingSubject() throws Exception { - final int databaseSizeBeforeUpdate = subjectRepository.findAll().size(); + @Throws(Exception::class) + open fun updateNonExistingSubject() { + val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Create the Subject - SubjectDTO subjectDto = createEntityDTO(); + val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() // If the entity doesn't have an ID, it will be created instead of just being updated - restSubjectMockMvc.perform(put("/api/subjects") + restSubjectMockMvc.perform( + MockMvcRequestBuilders.put("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeUpdate + 1); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeUpdate + 1) } @Test @Transactional - void deleteSubject() throws Exception { + @Throws(Exception::class) + open fun deleteSubject() { // Initialize the database - SubjectDTO subjectDto = subjectService.createSubject(createEntityDTO()); - final int databaseSizeBeforeDelete = subjectRepository.findAll().size(); + val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val databaseSizeBeforeDelete = subjectRepository.findAll().size // Get the subject - restSubjectMockMvc.perform(delete("/api/subjects/{login}", subjectDto.getLogin()) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()); + restSubjectMockMvc.perform( + MockMvcRequestBuilders.delete("/api/subjects/{login}", subjectDto!!.getLogin()) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeDelete - 1); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeDelete - 1) } @Test @Transactional - void equalsVerifier() throws Exception { - assertTrue(TestUtil.equalsVerifier(Subject.class)); + @Throws(Exception::class) + open fun equalsVerifier() { + org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Subject::class.java)) } - @Test @Transactional - void dynamicSourceRegistrationWithId() throws Exception { - final int databaseSizeBeforeCreate = subjectRepository.findAll().size(); + @Throws(Exception::class) + open fun dynamicSourceRegistrationWithId() { + val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - SubjectDTO subjectDto = createEntityDTO(); - restSubjectMockMvc.perform(post("/api/subjects") + val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); - Subject testSubject = subjectList.get(subjectList.size() - 1); - - String subjectLogin = testSubject.user.getLogin(); - assertNotNull(subjectLogin); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) + val testSubject = subjectList[subjectList.size - 1] + val subjectLogin = testSubject.user!!.login + org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) // Create a source description - MinimalSourceDetailsDTO sourceRegistrationDto = createSourceWithSourceTypeId(); - - restSubjectMockMvc.perform(post("/api/subjects/{login}/sources", subjectLogin) + val sourceRegistrationDto = createSourceWithSourceTypeId() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.sourceId").isNotEmpty()); + .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.sourceId").isNotEmpty()) // A source can not be assigned twice to a subject, so this call must fail - assertThat(sourceRegistrationDto.getSourceId()).isNull(); - restSubjectMockMvc.perform(post("/api/subjects/{login}/sources", subjectLogin) + Assertions.assertThat(sourceRegistrationDto.sourceId).isNull() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto))) - .andExpect(status().is4xxClientError()); + .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) + ) + .andExpect(MockMvcResultMatchers.status().is4xxClientError()) } @Test @Transactional - void dynamicSourceRegistrationWithoutId() throws Exception { - final int databaseSizeBeforeCreate = subjectRepository.findAll().size(); + @Throws(Exception::class) + open fun dynamicSourceRegistrationWithoutId() { + val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - SubjectDTO subjectDto = createEntityDTO(); - restSubjectMockMvc.perform(post("/api/subjects") + val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); - Subject testSubject = subjectList.get(subjectList.size() - 1); - - String subjectLogin = testSubject.user.getLogin(); - assertNotNull(subjectLogin); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) + val testSubject = subjectList[subjectList.size - 1] + val subjectLogin = testSubject.user!!.login + org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) // Create a source description - MinimalSourceDetailsDTO sourceRegistrationDto = createSourceWithoutSourceTypeId(); - - restSubjectMockMvc.perform(post("/api/subjects/{login}/sources", subjectLogin) + val sourceRegistrationDto = createSourceWithoutSourceTypeId() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.sourceId").isNotEmpty()); + .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.sourceId").isNotEmpty()) // A source can not be assigned twice to a subject, so this call must fail - assertThat(sourceRegistrationDto.getSourceId()).isNull(); - restSubjectMockMvc.perform(post("/api/subjects/{login}/sources", subjectLogin) + Assertions.assertThat(sourceRegistrationDto.sourceId).isNull() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto))) - .andExpect(status().is4xxClientError()); + .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) + ) + .andExpect(MockMvcResultMatchers.status().is4xxClientError()) // Get all the subjectList restSubjectMockMvc - .perform(get("/api/subjects/{login}/sources?sort=id,desc", subjectDto.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").isNotEmpty()); - + .perform(MockMvcRequestBuilders.get("/api/subjects/{login}/sources?sort=id,desc", subjectDto.getLogin())) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").isNotEmpty()) } @Test @Transactional - void dynamicSourceRegistrationWithoutDynamicRegistrationFlag() throws Exception { - final int databaseSizeBeforeCreate = subjectRepository.findAll().size(); + @Throws(Exception::class) + open fun dynamicSourceRegistrationWithoutDynamicRegistrationFlag() { + val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - SubjectDTO subjectDto = createEntityDTO(); - restSubjectMockMvc.perform(post("/api/subjects") + val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); - Subject testSubject = subjectList.get(subjectList.size() - 1); - - String subjectLogin = testSubject.user.getLogin(); - assertNotNull(subjectLogin); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) + val testSubject = subjectList[subjectList.size - 1] + val subjectLogin = testSubject.user!!.login + org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) // Create a source description - MinimalSourceDetailsDTO sourceRegistrationDto = - createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration(); - - restSubjectMockMvc.perform(post("/api/subjects/{login}/sources", subjectLogin) + val sourceRegistrationDto = createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto))) - .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("$.message").isNotEmpty()); + .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) + ) + .andExpect(MockMvcResultMatchers.status().is4xxClientError()) + .andExpect(MockMvcResultMatchers.jsonPath("$.message").isNotEmpty()) } - @Test - @Transactional - void getSubjectSources() throws Exception { - // Initialize the database - SubjectDTO subjectDtoToCreate = createEntityDTO(); - SourceDTO createdSource = sourceService.save(createSource()); - MinimalSourceDetailsDTO sourceDto = new MinimalSourceDetailsDTO() - .id(createdSource.getId()) - .sourceName(createdSource.getSourceName()) - .sourceTypeId(createdSource.getSourceType().getId()) - .sourceId(createdSource.getSourceId()); - - subjectDtoToCreate.setSources(Collections.singleton(sourceDto)); - - assertNotNull(sourceDto.getId()); - SubjectDTO createdSubject = subjectService.createSubject(subjectDtoToCreate); - assertFalse(createdSubject.getSources().isEmpty()); - - // Get the subject - restSubjectMockMvc.perform(get("/api/subjects/{login}/sources", createdSubject.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[0].id").value(createdSource.getId().intValue())) + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val subjectSources: Unit + get() { + // Initialize the database + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val createdSource = sourceService.save(createSource()) + val sourceDto = MinimalSourceDetailsDTO() + .id(createdSource.id) + .sourceName(createdSource.sourceName) + .sourceTypeId(createdSource.sourceType.id) + .sourceId(createdSource.sourceId) + subjectDtoToCreate.sources = setOf(sourceDto) + org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + val createdSubject = subjectService.createSubject(subjectDtoToCreate) + org.junit.jupiter.api.Assertions.assertFalse(createdSubject!!.sources.isEmpty()) + + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources", + createdSubject.getLogin() + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[0].id").value(createdSource.id.toInt())) .andExpect( - jsonPath("$.[0].sourceId").value(createdSource.getSourceId().toString())); - } - - @Test - @Transactional - void getSubjectSourcesWithQueryParam() throws Exception { - // Initialize the database - SubjectDTO subjectDtoToCreate = createEntityDTO(); - SourceDTO createdSource = sourceService.save(createSource()); - MinimalSourceDetailsDTO sourceDto = new MinimalSourceDetailsDTO() - .id(createdSource.getId()) - .sourceName(createdSource.getSourceName()) - .sourceTypeId(createdSource.getSourceType().getId()) - .sourceId(createdSource.getSourceId()); - - subjectDtoToCreate.setSources(Collections.singleton(sourceDto)); - - assertNotNull(sourceDto.getId()); - SubjectDTO createdSubject = subjectService.createSubject(subjectDtoToCreate); - commitTransactionAndStartNew(); - - assertNotNull(createdSubject.getLogin()); - // Get the subject - restSubjectMockMvc.perform(get("/api/subjects/{login}/sources?withInactiveSources=true", - createdSubject.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(createdSource.getId().intValue())) + MockMvcResultMatchers.jsonPath("$.[0].sourceId").value(createdSource.sourceId.toString()) + ) + } + + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val subjectSourcesWithQueryParam: Unit + get() { + // Initialize the database + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val createdSource = sourceService.save(createSource()) + val sourceDto = MinimalSourceDetailsDTO() + .id(createdSource.id) + .sourceName(createdSource.sourceName) + .sourceTypeId(createdSource.sourceType.id) + .sourceId(createdSource.sourceId) + subjectDtoToCreate.sources = setOf(sourceDto) + org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + val createdSubject = subjectService.createSubject(subjectDtoToCreate) + TestUtil.commitTransactionAndStartNew() + org.junit.jupiter.api.Assertions.assertNotNull(createdSubject!!.getLogin()) + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?withInactiveSources=true", + createdSubject.getLogin() + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id.toInt())) .andExpect( - jsonPath("$.[*].sourceId").value(createdSource.getSourceId().toString())); - } - - @Test - @Transactional - void getInactiveSubjectSourcesWithQueryParam() throws Exception { - // Initialize the database - SubjectDTO subjectDtoToCreate = createEntityDTO(); - SourceDTO createdSource = sourceService.save(createSource()); - MinimalSourceDetailsDTO sourceDto = new MinimalSourceDetailsDTO() - .id(createdSource.getId()) - .sourceName(createdSource.getSourceName()) - .sourceTypeId(createdSource.getSourceType().getId()) - .sourceId(createdSource.getSourceId()); - - subjectDtoToCreate.setSources(Collections.singleton(sourceDto)); - - assertNotNull(sourceDto.getId()); - SubjectDTO createdSubject = subjectService.createSubject(subjectDtoToCreate); - commitTransactionAndStartNew(); - - createdSubject.setSources(Collections.emptySet()); - - SubjectDTO updatedSubject = subjectService.updateSubject(createdSubject); - commitTransactionAndStartNew(); - - assertNotNull(updatedSubject.getLogin()); - // Get the subject - restSubjectMockMvc.perform(get("/api/subjects/{login}/sources?withInactiveSources=true", - updatedSubject.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(createdSource.getId().intValue())) + MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) + ) + } + + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val inactiveSubjectSourcesWithQueryParam: Unit + get() { + // Initialize the database + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val createdSource = sourceService.save(createSource()) + val sourceDto = MinimalSourceDetailsDTO() + .id(createdSource.id) + .sourceName(createdSource.sourceName) + .sourceTypeId(createdSource.sourceType.id) + .sourceId(createdSource.sourceId) + subjectDtoToCreate.sources = setOf(sourceDto) + org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + val createdSubject = subjectService.createSubject(subjectDtoToCreate) + TestUtil.commitTransactionAndStartNew() + createdSubject!!.sources = emptySet() + val updatedSubject = subjectService.updateSubject(createdSubject) + TestUtil.commitTransactionAndStartNew() + org.junit.jupiter.api.Assertions.assertNotNull(updatedSubject!!.getLogin()) + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?withInactiveSources=true", + updatedSubject.getLogin() + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id.toInt())) .andExpect( - jsonPath("$.[*].sourceId").value(createdSource.getSourceId().toString())); - - // Get the subject - restSubjectMockMvc - .perform(get("/api/subjects/{login}/sources?withInactiveSources=false", - updatedSubject.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andReturn(); + MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) + ) + + // Get the subject + restSubjectMockMvc + .perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?withInactiveSources=false", + updatedSubject.getLogin() + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn() + } + + private fun createSource(): SourceDTO { + val sourceDto = SourceDTO() + sourceDto.assigned = false + sourceDto.sourceId = UUID.randomUUID() + sourceDto.sourceType = sourceTypeService.findAll()[0] + sourceDto.sourceName = "something" + UUID.randomUUID() + return sourceDto } - private SourceDTO createSource() { - SourceDTO sourceDto = new SourceDTO(); - sourceDto.setAssigned(false); - sourceDto.setSourceId(UUID.randomUUID()); - sourceDto.setSourceType(sourceTypeService.findAll().get(0)); - sourceDto.setSourceName("something" + UUID.randomUUID()); - return sourceDto; + private fun createSourceWithSourceTypeId(): MinimalSourceDetailsDTO { + val sourceTypes = sourceTypeService.findAll().stream() + .filter { obj: SourceTypeDTO -> obj.canRegisterDynamically } + .collect(Collectors.toList()) + Assertions.assertThat(sourceTypes.size).isPositive() + val sourceType = sourceTypes[0] + return source.sourceTypeId(sourceType.id) } - private MinimalSourceDetailsDTO createSourceWithSourceTypeId() { - List sourceTypes = sourceTypeService.findAll().stream() - .filter(SourceTypeDTO::getCanRegisterDynamically) - .collect(Collectors.toList()); - assertThat(sourceTypes.size()).isPositive(); - SourceTypeDTO sourceType = sourceTypes.get(0); - - return getSource().sourceTypeId(sourceType.getId()); + private fun createSourceWithoutSourceTypeId(): MinimalSourceDetailsDTO { + val sourceTypes = sourceTypeService.findAll().stream() + .filter { obj: SourceTypeDTO -> obj.canRegisterDynamically } + .collect(Collectors.toList()) + Assertions.assertThat(sourceTypes.size).isPositive() + val sourceType = sourceTypes[0] + return source + .sourceTypeCatalogVersion(sourceType.catalogVersion) + .sourceTypeModel(sourceType.model) + .sourceTypeProducer(sourceType.producer) } - private MinimalSourceDetailsDTO createSourceWithoutSourceTypeId() { - List sourceTypes = sourceTypeService.findAll().stream() - .filter(SourceTypeDTO::getCanRegisterDynamically) - .collect(Collectors.toList()); - assertThat(sourceTypes.size()).isPositive(); - SourceTypeDTO sourceType = sourceTypes.get(0); - return getSource() - .sourceTypeCatalogVersion(sourceType.getCatalogVersion()) - .sourceTypeModel(sourceType.getModel()) - .sourceTypeProducer(sourceType.getProducer()); + private fun createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration(): MinimalSourceDetailsDTO { + val sourceTypes = sourceTypeService.findAll().stream() + .filter { it: SourceTypeDTO -> !it.canRegisterDynamically } + .collect(Collectors.toList()) + Assertions.assertThat(sourceTypes.size).isPositive() + val sourceType = sourceTypes[0] + return source + .sourceTypeCatalogVersion(sourceType.catalogVersion) + .sourceTypeModel(sourceType.model) + .sourceTypeProducer(sourceType.producer) } - private MinimalSourceDetailsDTO createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration() { - List sourceTypes = sourceTypeService.findAll().stream() - .filter(it -> !it.getCanRegisterDynamically()) - .collect(Collectors.toList()); - assertThat(sourceTypes.size()).isPositive(); - SourceTypeDTO sourceType = sourceTypes.get(0); - return getSource() - .sourceTypeCatalogVersion(sourceType.getCatalogVersion()) - .sourceTypeModel(sourceType.getModel()) - .sourceTypeProducer(sourceType.getProducer()); - } - - private MinimalSourceDetailsDTO getSource() { - MinimalSourceDetailsDTO sourceRegistrationDto = new MinimalSourceDetailsDTO() - .sourceName(PRODUCER + "-" + MODEL) - .attributes(Collections.singletonMap("something", "value")); - assertThat(sourceRegistrationDto.getSourceId()).isNull(); - return sourceRegistrationDto; - } + private val source: MinimalSourceDetailsDTO + get() { + val sourceRegistrationDto = MinimalSourceDetailsDTO() + .sourceName(SubjectServiceTest.Companion.PRODUCER + "-" + SubjectServiceTest.Companion.MODEL) + .attributes(Collections.singletonMap("something", "value")) + Assertions.assertThat(sourceRegistrationDto.sourceId).isNull() + return sourceRegistrationDto + } @Test @Transactional - void testDynamicRegistrationAndUpdateSourceAttributes() throws Exception { - final int databaseSizeBeforeCreate = subjectRepository.findAll().size(); + @Throws(Exception::class) + open fun testDynamicRegistrationAndUpdateSourceAttributes() { + val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - SubjectDTO subjectDto = createEntityDTO(); - restSubjectMockMvc.perform(post("/api/subjects") + val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); - Subject testSubject = subjectList.get(subjectList.size() - 1); - - String subjectLogin = testSubject.user.getLogin(); - assertNotNull(subjectLogin); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) + val testSubject = subjectList[subjectList.size - 1] + val subjectLogin = testSubject.user!!.login + org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) // Create a source description - MinimalSourceDetailsDTO sourceRegistrationDto = createSourceWithoutSourceTypeId(); - - MvcResult result = restSubjectMockMvc.perform(post("/api/subjects/{login}/sources", - subjectLogin) + val sourceRegistrationDto = createSourceWithoutSourceTypeId() + val result = restSubjectMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/subjects/{login}/sources", + subjectLogin + ) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto))) - .andExpect(status().isOk()) - .andReturn(); - - MinimalSourceDetailsDTO value = (MinimalSourceDetailsDTO) - TestUtil.convertJsonStringToObject(result - .getResponse().getContentAsString() , MinimalSourceDetailsDTO.class); - - assertNotNull(value.getSourceName()); - - Map attributes = new HashMap<>(); - attributes.put("TEST_KEY" , "Value"); - attributes.put("ANDROID_VERSION" , "something"); - attributes.put("Other" , "test"); - - restSubjectMockMvc.perform(post( - "/api/subjects/{login}/sources/{sourceName}", subjectLogin, value.getSourceName()) + .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andReturn() + val value = TestUtil.convertJsonStringToObject( + result + .response.contentAsString, MinimalSourceDetailsDTO::class.java + ) as MinimalSourceDetailsDTO + org.junit.jupiter.api.Assertions.assertNotNull(value.sourceName) + val attributes: MutableMap = HashMap() + attributes["TEST_KEY"] = "Value" + attributes["ANDROID_VERSION"] = "something" + attributes["Other"] = "test" + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/subjects/{login}/sources/{sourceName}", subjectLogin, value.sourceName + ) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(attributes))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.attributes").isNotEmpty()); - + .content(TestUtil.convertObjectToJsonBytes(attributes)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.attributes").isNotEmpty()) } } diff --git a/src/test/java/org/radarbase/management/web/rest/TestUtil.kt b/src/test/java/org/radarbase/management/web/rest/TestUtil.kt index 6444911fc..32f1ae580 100644 --- a/src/test/java/org/radarbase/management/web/rest/TestUtil.kt +++ b/src/test/java/org/radarbase/management/web/rest/TestUtil.kt @@ -1,43 +1,35 @@ -package org.radarbase.management.web.rest; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import org.hamcrest.Description; -import org.hamcrest.TypeSafeDiagnosingMatcher; -import org.springframework.http.MediaType; -import org.springframework.test.context.transaction.TestTransaction; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeParseException; - -import static org.assertj.core.api.Assertions.assertThat; +package org.radarbase.management.web.rest + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import org.assertj.core.api.Assertions +import org.hamcrest.Description +import org.hamcrest.TypeSafeDiagnosingMatcher +import org.springframework.http.MediaType +import org.springframework.test.context.transaction.TestTransaction +import java.io.IOException +import java.nio.charset.Charset +import java.time.ZonedDateTime +import java.time.format.DateTimeParseException /** * Utility class for testing REST controllers. */ -public final class TestUtil { +object TestUtil { /* MediaType for JSON UTF8 */ - public static final MediaType APPLICATION_JSON_UTF8 = new MediaType( - MediaType.APPLICATION_JSON.getType(), - MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8")); - - public static final MediaType APPLICATION_JSON_PATCH = new MediaType( - "application", - "json-patch+json", Charset.forName("utf8")); - - - private static final JavaTimeModule module = new JavaTimeModule(); - - private static final ObjectMapper mapper = new ObjectMapper() - .setSerializationInclusion(JsonInclude.Include.NON_NULL) - .registerModule(module); - - private TestUtil() { - // utilitly class - } + val APPLICATION_JSON_UTF8 = MediaType( + MediaType.APPLICATION_JSON.type, + MediaType.APPLICATION_JSON.subtype, Charset.forName("utf8") + ) + val APPLICATION_JSON_PATCH = MediaType( + "application", + "json-patch+json", Charset.forName("utf8") + ) + private val module = JavaTimeModule() + private val mapper = ObjectMapper() + .setSerializationInclusion(JsonInclude.Include.NON_NULL) + .registerModule(module) /** * Convert a JSON String to an object. @@ -47,9 +39,9 @@ public final class TestUtil { * * @return the converted object instance. */ - public static Object convertJsonStringToObject(String json, Class objectClass) - throws IOException { - return mapper.readValue(json, objectClass); + @Throws(IOException::class) + fun convertJsonStringToObject(json: String?, objectClass: Class?): Any { + return mapper.readValue(json, objectClass) } /** @@ -58,8 +50,9 @@ public final class TestUtil { * @param object the object to convert * @return the JSON byte array */ - public static byte[] convertObjectToJsonBytes(Object object) throws IOException { - return mapper.writeValueAsBytes(object); + @Throws(IOException::class) + fun convertObjectToJsonBytes(`object`: Any?): ByteArray { + return mapper.writeValueAsBytes(`object`) } /** @@ -69,46 +62,12 @@ public final class TestUtil { * @param data the data to put in the byte array * @return the JSON byte array */ - public static byte[] createByteArray(int size, String data) { - byte[] byteArray = new byte[size]; - for (int i = 0; i < size; i++) { - byteArray[i] = Byte.parseByte(data, 2); - } - return byteArray; - } - - /** - * A matcher that tests that the examined string represents the same instant as the reference - * datetime. - */ - public static class ZonedDateTimeMatcher extends TypeSafeDiagnosingMatcher { - - private final ZonedDateTime date; - - public ZonedDateTimeMatcher(ZonedDateTime date) { - this.date = date; - } - - @Override - protected boolean matchesSafely(String item, Description mismatchDescription) { - try { - if (!date.isEqual(ZonedDateTime.parse(item))) { - mismatchDescription.appendText("was ").appendValue(item); - return false; - } - return true; - } catch (DateTimeParseException e) { - mismatchDescription.appendText("was ").appendValue(item) - .appendText(", which could not be parsed as a ZonedDateTime"); - return false; - } - - } - - @Override - public void describeTo(Description description) { - description.appendText("a String representing the same Instant as ").appendValue(date); + fun createByteArray(size: Int, data: String): ByteArray { + val byteArray = ByteArray(size) + for (i in 0 until size) { + byteArray[i] = data.toByte(2) } + return byteArray } /** @@ -117,39 +76,62 @@ public final class TestUtil { * * @param date the reference datetime against which the examined string is checked */ - public static ZonedDateTimeMatcher sameInstant(ZonedDateTime date) { - return new ZonedDateTimeMatcher(date); + fun sameInstant(date: ZonedDateTime): ZonedDateTimeMatcher { + return ZonedDateTimeMatcher(date) } /** * Verifies the equals/hashcode contract on the domain object. */ - @SuppressWarnings("unchecked") - public static boolean equalsVerifier(Class clazz) throws Exception { - Object domainObject1 = clazz.getConstructor().newInstance(); - assertThat(domainObject1.toString()).isNotNull(); - assertThat(domainObject1).isEqualTo(domainObject1); - assertThat(domainObject1.hashCode()).isEqualTo(domainObject1.hashCode()); + @Throws(Exception::class) + fun equalsVerifier(clazz: Class<*>): Boolean { + val domainObject1 = clazz.getConstructor().newInstance() + Assertions.assertThat(domainObject1.toString()).isNotNull() + Assertions.assertThat(domainObject1).isEqualTo(domainObject1) + Assertions.assertThat(domainObject1.hashCode()).isEqualTo(domainObject1.hashCode()) // Test with an instance of another class - Object testOtherObject = new Object(); - assertThat(domainObject1).isNotEqualTo(testOtherObject); + val testOtherObject = Any() + Assertions.assertThat(domainObject1).isNotEqualTo(testOtherObject) // Test with an instance of the same class - Object domainObject2 = clazz.getConstructor().newInstance(); - assertThat(domainObject1).isNotEqualTo(domainObject2); + val domainObject2 = clazz.getConstructor().newInstance() + Assertions.assertThat(domainObject1).isNotEqualTo(domainObject2) // HashCodes are equals because the objects are not persisted yet - assertThat(domainObject1.hashCode()).isEqualTo(domainObject2.hashCode()); - return true; + Assertions.assertThat(domainObject1.hashCode()).isEqualTo(domainObject2.hashCode()) + return true } - /** * This allows to commit current transaction and start a new transaction. */ - public static void commitTransactionAndStartNew() { + fun commitTransactionAndStartNew() { // flag this transaction for commit and end it - TestTransaction.flagForCommit(); - TestTransaction.end(); - TestTransaction.start(); - TestTransaction.flagForCommit(); + TestTransaction.flagForCommit() + TestTransaction.end() + TestTransaction.start() + TestTransaction.flagForCommit() + } + + /** + * A matcher that tests that the examined string represents the same instant as the reference + * datetime. + */ + class ZonedDateTimeMatcher(private val date: ZonedDateTime) : TypeSafeDiagnosingMatcher() { + override fun matchesSafely(item: String?, mismatchDescription: Description): Boolean { + return try { + if (!date.isEqual(ZonedDateTime.parse(item))) { + mismatchDescription.appendText("was ").appendValue(item) + return false + } + true + } catch (e: DateTimeParseException) { + mismatchDescription.appendText("was ").appendValue(item) + .appendText(", which could not be parsed as a ZonedDateTime") + false + } + } + + override fun describeTo(description: Description) { + description.appendText("a String representing the same Instant as ").appendValue(date) + } } } diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt index dbe5abfe3..6f84bcf65 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt @@ -1,541 +1,524 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.RoleRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.MailService; -import org.radarbase.management.service.PasswordService; -import org.radarbase.management.service.UserService; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.radarbase.management.web.rest.vm.ManagedUserVM; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.servlet.ServletException; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.radarbase.auth.authorization.RoleAuthority.SYS_ADMIN; -import static org.radarbase.auth.authorization.RoleAuthority.SYS_ADMIN_AUTHORITY; -import static org.radarbase.management.service.UserServiceIntTest.DEFAULT_EMAIL; -import static org.radarbase.management.service.UserServiceIntTest.DEFAULT_FIRSTNAME; -import static org.radarbase.management.service.UserServiceIntTest.DEFAULT_LANGKEY; -import static org.radarbase.management.service.UserServiceIntTest.DEFAULT_LASTNAME; -import static org.radarbase.management.service.UserServiceIntTest.DEFAULT_LOGIN; -import static org.radarbase.management.service.UserServiceIntTest.DEFAULT_PASSWORD; -import static org.radarbase.management.service.UserServiceIntTest.UPDATED_EMAIL; -import static org.radarbase.management.service.UserServiceIntTest.UPDATED_FIRSTNAME; -import static org.radarbase.management.service.UserServiceIntTest.UPDATED_LANGKEY; -import static org.radarbase.management.service.UserServiceIntTest.UPDATED_LASTNAME; -import static org.radarbase.management.service.UserServiceIntTest.UPDATED_LOGIN; -import static org.radarbase.management.service.UserServiceIntTest.UPDATED_PASSWORD; -import static org.radarbase.management.service.UserServiceIntTest.createEntity; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.User +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.RoleRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.MailService +import org.radarbase.management.service.PasswordService +import org.radarbase.management.service.UserService +import org.radarbase.management.service.UserServiceIntTest +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.radarbase.management.web.rest.vm.ManagedUserVM +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import java.util.stream.Collectors +import javax.servlet.ServletException /** * Test class for the UserResource REST controller. * * @see UserResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class UserResourceIntTest { - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Autowired - private RoleRepository roleRepository; - - @Autowired - private UserRepository userRepository; - - @Autowired - private MailService mailService; - - @Autowired - private UserService userService; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private AuthService authService; - - @Autowired - private PasswordService passwordService; - - @Autowired - private ProjectRepository projectRepository; - - private MockMvc restUserMockMvc; - - private User user; - - private Project project; +internal open class UserResourceIntTest( + @Autowired private val managementPortalProperties: ManagementPortalProperties, + @Autowired private val roleRepository: RoleRepository, + @Autowired private val userRepository: UserRepository, + @Autowired private val mailService: MailService, + @Autowired private val userService: UserService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val authService: AuthService, + @Autowired private val passwordService: PasswordService, + @Autowired private val projectRepository: ProjectRepository, + private var restUserMockMvc: MockMvc, + private var user: User, + private var project: Project? +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - UserResource userResource = new UserResource(); - ReflectionTestUtils.setField(userResource, "userService", userService); - ReflectionTestUtils.setField(userResource, "mailService", mailService); - ReflectionTestUtils.setField(userResource, "userRepository", userRepository); - ReflectionTestUtils.setField(userResource, "subjectRepository", subjectRepository); - ReflectionTestUtils.setField(userResource, "authService", authService); - ReflectionTestUtils.setField(userResource, - "managementPortalProperties", managementPortalProperties); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restUserMockMvc = MockMvcBuilders.standaloneSetup(userResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - project = null; + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val userResource = UserResource + ReflectionTestUtils.setField(userResource, "userService", userService) + ReflectionTestUtils.setField(userResource, "mailService", mailService) + ReflectionTestUtils.setField(userResource, "userRepository", userRepository) + ReflectionTestUtils.setField(userResource, "subjectRepository", subjectRepository) + ReflectionTestUtils.setField(userResource, "authService", authService) + ReflectionTestUtils.setField( + userResource, + "managementPortalProperties", managementPortalProperties + ) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restUserMockMvc = MockMvcBuilders.standaloneSetup(userResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() + project = null } @AfterEach - public void tearDown() { + fun tearDown() { if (project != null) { - projectRepository.delete(project); + projectRepository.delete(project) } } @BeforeEach - public void initTest() { - user = createEntity(passwordService); - userRepository.findOneByLogin(DEFAULT_LOGIN) - .ifPresent(userRepository::delete); - userRepository.findOneByLogin(UPDATED_LOGIN) - .ifPresent(userRepository::delete); - var roles = roleRepository - .findRolesByAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()) - .stream().filter(r -> r.project == null) - .collect(Collectors.toList()); - roleRepository.deleteAll(roles); + fun initTest() { + user = UserServiceIntTest.createEntity(passwordService) + userRepository.findOneByLogin(UserServiceIntTest.DEFAULT_LOGIN) + .ifPresent { entity: User -> userRepository.delete(entity) } + userRepository.findOneByLogin(UserServiceIntTest.UPDATED_LOGIN) + .ifPresent { entity: User -> userRepository.delete(entity) } + val roles = roleRepository + .findRolesByAuthorityName(RoleAuthority.PARTICIPANT.authority) + .stream().filter { r: Role -> r.project == null } + .collect(Collectors.toList()) + roleRepository.deleteAll(roles) } @Test @Transactional - void createUser() throws Exception { - final int databaseSizeBeforeCreate = userRepository.findAll().size(); + @Throws(Exception::class) + open fun createUser() { + val databaseSizeBeforeCreate = userRepository.findAll().size // Create the User - Set roles = new HashSet<>(); - RoleDTO role = new RoleDTO(); - role.setAuthorityName(SYS_ADMIN_AUTHORITY); - roles.add(role); - - ManagedUserVM managedUserVm = createDefaultUser(roles); - - restUserMockMvc.perform(post("/api/users") + val roles: MutableSet = HashSet() + val role = RoleDTO() + role.authorityName = RoleAuthority.SYS_ADMIN_AUTHORITY + roles.add(role) + val managedUserVm = createDefaultUser(roles) + restUserMockMvc.perform( + MockMvcRequestBuilders.post("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the User in the database - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeCreate + 1); - User testUser = userList.get(userList.size() - 1); - assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN); - assertThat(testUser.firstName).isEqualTo(DEFAULT_FIRSTNAME); - assertThat(testUser.lastName).isEqualTo(DEFAULT_LASTNAME); - assertThat(testUser.email).isEqualTo(DEFAULT_EMAIL); - assertThat(testUser.langKey).isEqualTo(DEFAULT_LANGKEY); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeCreate + 1) + val testUser = userList[userList.size - 1] + Assertions.assertThat(testUser.login).isEqualTo(UserServiceIntTest.DEFAULT_LOGIN) + Assertions.assertThat(testUser.firstName).isEqualTo(UserServiceIntTest.DEFAULT_FIRSTNAME) + Assertions.assertThat(testUser.lastName).isEqualTo(UserServiceIntTest.DEFAULT_LASTNAME) + Assertions.assertThat(testUser.email).isEqualTo(UserServiceIntTest.DEFAULT_EMAIL) + Assertions.assertThat(testUser.langKey).isEqualTo(UserServiceIntTest.DEFAULT_LANGKEY) } @Test @Transactional - void createUserWithExistingId() throws Exception { - final int databaseSizeBeforeCreate = userRepository.findAll().size(); - - Set roles = new HashSet<>(); - RoleDTO role = new RoleDTO(); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - roles.add(role); - - ManagedUserVM managedUserVm = createDefaultUser(roles); - managedUserVm.setId(1L); + @Throws(Exception::class) + open fun createUserWithExistingId() { + val databaseSizeBeforeCreate = userRepository.findAll().size + val roles: MutableSet = HashSet() + val role = RoleDTO() + role.authorityName = RoleAuthority.PARTICIPANT.authority + roles.add(role) + val managedUserVm = createDefaultUser(roles) + managedUserVm.id = 1L // An entity with an existing ID cannot be created, so this API call must fail - restUserMockMvc.perform(post("/api/users") + restUserMockMvc.perform( + MockMvcRequestBuilders.post("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the User in the database - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeCreate); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeCreate) } @Test @Transactional - void createUserWithExistingLogin() throws Exception { + @Throws(Exception::class) + open fun createUserWithExistingLogin() { // Initialize the database - userRepository.saveAndFlush(user); - final int databaseSizeBeforeCreate = userRepository.findAll().size(); - - Set roles = new HashSet<>(); - RoleDTO role = new RoleDTO(); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - roles.add(role); - ManagedUserVM managedUserVm = createDefaultUser(roles); - managedUserVm.setEmail("anothermail@localhost"); + userRepository.saveAndFlush(user) + val databaseSizeBeforeCreate = userRepository.findAll().size + val roles: MutableSet = HashSet() + val role = RoleDTO() + role.authorityName = RoleAuthority.PARTICIPANT.authority + roles.add(role) + val managedUserVm = createDefaultUser(roles) + managedUserVm.email = "anothermail@localhost" // Create the User - restUserMockMvc.perform(post("/api/users") + restUserMockMvc.perform( + MockMvcRequestBuilders.post("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the User in the database - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeCreate); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeCreate) } @Test @Transactional - void createUserWithExistingEmail() throws Exception { + @Throws(Exception::class) + open fun createUserWithExistingEmail() { // Initialize the database - userRepository.saveAndFlush(user); - final int databaseSizeBeforeCreate = userRepository.findAll().size(); - - Set roles = new HashSet<>(); - RoleDTO role = new RoleDTO(); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - roles.add(role); - ManagedUserVM managedUserVm = createDefaultUser(roles); - managedUserVm.setLogin("anotherlogin"); + userRepository.saveAndFlush(user) + val databaseSizeBeforeCreate = userRepository.findAll().size + val roles: MutableSet = HashSet() + val role = RoleDTO() + role.authorityName = RoleAuthority.PARTICIPANT.authority + roles.add(role) + val managedUserVm = createDefaultUser(roles) + managedUserVm.login = "anotherlogin" // Create the User - restUserMockMvc.perform(post("/api/users") + restUserMockMvc.perform( + MockMvcRequestBuilders.post("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the User in the database - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeCreate); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeCreate) } - @Test - @Transactional - void getAllUsers() throws Exception { - // Initialize the database - org.radarbase.management.domain.Role adminRole = new org.radarbase.management.domain.Role(); - adminRole.setId(1L); - adminRole.authority = new Authority(SYS_ADMIN); - adminRole.project = null; - - User userWithRole = new User(); - userWithRole.setLogin(DEFAULT_LOGIN); - userWithRole.password = passwordService.generateEncodedPassword(); - userWithRole.activated = true; - userWithRole.email = DEFAULT_EMAIL; - userWithRole.firstName = DEFAULT_FIRSTNAME; - userWithRole.lastName = DEFAULT_LASTNAME; - userWithRole.langKey = DEFAULT_LANGKEY; - userWithRole.setRoles(Collections.singleton(adminRole)); - userRepository.saveAndFlush(userWithRole); - - // Get all the users - restUserMockMvc.perform(get("/api/users?sort=id,desc") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].login").value(hasItem(DEFAULT_LOGIN))) - .andExpect(jsonPath("$.[*].firstName").value(hasItem(DEFAULT_FIRSTNAME))) - .andExpect(jsonPath("$.[*].lastName").value(hasItem(DEFAULT_LASTNAME))) - .andExpect(jsonPath("$.[*].email").value(hasItem(DEFAULT_EMAIL))) - .andExpect(jsonPath("$.[*].langKey").value(hasItem(DEFAULT_LANGKEY))); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val allUsers: Unit + get() { + // Initialize the database + val adminRole = Role() + adminRole.id = 1L + adminRole.authority = Authority(RoleAuthority.SYS_ADMIN) + adminRole.project = null + val userWithRole = User() + userWithRole.setLogin(UserServiceIntTest.DEFAULT_LOGIN) + userWithRole.password = passwordService.generateEncodedPassword() + userWithRole.activated = true + userWithRole.email = UserServiceIntTest.DEFAULT_EMAIL + userWithRole.firstName = UserServiceIntTest.DEFAULT_FIRSTNAME + userWithRole.lastName = UserServiceIntTest.DEFAULT_LASTNAME + userWithRole.langKey = UserServiceIntTest.DEFAULT_LANGKEY + userWithRole.roles = mutableSetOf(adminRole) + userRepository.saveAndFlush(userWithRole) + + // Get all the users + restUserMockMvc.perform( + MockMvcRequestBuilders.get("/api/users?sort=id,desc") + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].login") + .value>(Matchers.hasItem(UserServiceIntTest.DEFAULT_LOGIN)) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].firstName") + .value>(Matchers.hasItem(UserServiceIntTest.DEFAULT_FIRSTNAME)) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].lastName") + .value>(Matchers.hasItem(UserServiceIntTest.DEFAULT_LASTNAME)) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].email") + .value>(Matchers.hasItem(UserServiceIntTest.DEFAULT_EMAIL)) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].langKey") + .value>(Matchers.hasItem(UserServiceIntTest.DEFAULT_LANGKEY)) + ) + } @Test @Transactional - void getUser() throws Exception { + @Throws(Exception::class) + open fun getUser() { // Initialize the database - userRepository.saveAndFlush(user); + userRepository.saveAndFlush(user) // Get the user - restUserMockMvc.perform(get("/api/users/{login}", user.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.login").value(user.getLogin())) - .andExpect(jsonPath("$.firstName").value(DEFAULT_FIRSTNAME)) - .andExpect(jsonPath("$.lastName").value(DEFAULT_LASTNAME)) - .andExpect(jsonPath("$.email").value(DEFAULT_EMAIL)) - .andExpect(jsonPath("$.langKey").value(DEFAULT_LANGKEY)); + restUserMockMvc.perform(MockMvcRequestBuilders.get("/api/users/{login}", user.login)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.login").value(user.login)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.firstName").value(UserServiceIntTest.DEFAULT_FIRSTNAME) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.lastName").value(UserServiceIntTest.DEFAULT_LASTNAME) + ) + .andExpect(MockMvcResultMatchers.jsonPath("$.email").value(UserServiceIntTest.DEFAULT_EMAIL)) + .andExpect(MockMvcResultMatchers.jsonPath("$.langKey").value(UserServiceIntTest.DEFAULT_LANGKEY)) } - @Test - @Transactional - void getNonExistingUser() throws Exception { - restUserMockMvc.perform(get("/api/users/unknown")) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val nonExistingUser: Unit + get() { + restUserMockMvc.perform(MockMvcRequestBuilders.get("/api/users/unknown")) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional - void updateUser() throws Exception { + @Throws(Exception::class) + open fun updateUser() { // Initialize the database - userRepository.saveAndFlush(user); - final int databaseSizeBeforeUpdate = userRepository.findAll().size(); - project = ProjectResourceIntTest.createEntity(); - projectRepository.save(project); + userRepository.saveAndFlush(user) + val databaseSizeBeforeUpdate = userRepository.findAll().size + project = ProjectResourceIntTest.createEntity() + projectRepository.save(project!!) // Update the user - User updatedUser = userRepository.findById(user.getId()) - .orElseThrow(() -> new AssertionError("Cannot find user " + user.getId())); - - ManagedUserVM managedUserVm = new ManagedUserVM(); - managedUserVm.setId(updatedUser.getId()); - managedUserVm.setLogin(updatedUser.getLogin()); - managedUserVm.setPassword(UPDATED_PASSWORD); - managedUserVm.setFirstName(UPDATED_FIRSTNAME); - managedUserVm.setLastName(UPDATED_LASTNAME); - managedUserVm.setEmail(UPDATED_EMAIL); - managedUserVm.setActivated(updatedUser.activated); - managedUserVm.setLangKey(UPDATED_LANGKEY); - - RoleDTO role = new RoleDTO(); - role.setProjectId(project.getId()); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - managedUserVm.setRoles(Set.of(role)); - - restUserMockMvc.perform(put("/api/users") + val updatedUser = userRepository.findById(user.id!!) + .orElseThrow { AssertionError("Cannot find user " + user.id) } + val managedUserVm = ManagedUserVM() + managedUserVm.id = updatedUser.id + managedUserVm.login = updatedUser.login + managedUserVm.password = UserServiceIntTest.UPDATED_PASSWORD + managedUserVm.firstName = UserServiceIntTest.UPDATED_FIRSTNAME + managedUserVm.lastName = UserServiceIntTest.UPDATED_LASTNAME + managedUserVm.email = UserServiceIntTest.UPDATED_EMAIL + managedUserVm.isActivated = updatedUser.activated + managedUserVm.langKey = UserServiceIntTest.UPDATED_LANGKEY + val role = RoleDTO() + role.projectId = project!!.id + role.authorityName = RoleAuthority.PARTICIPANT.authority + managedUserVm.roles = mutableSetOf(role) + restUserMockMvc.perform( + MockMvcRequestBuilders.put("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the User in the database - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeUpdate); - User testUser = userList.get(userList.size() - 1); - assertThat(testUser.firstName).isEqualTo(UPDATED_FIRSTNAME); - assertThat(testUser.lastName).isEqualTo(UPDATED_LASTNAME); - assertThat(testUser.email).isEqualTo(UPDATED_EMAIL); - assertThat(testUser.langKey).isEqualTo(UPDATED_LANGKEY); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeUpdate) + val testUser = userList[userList.size - 1] + Assertions.assertThat(testUser.firstName).isEqualTo(UserServiceIntTest.UPDATED_FIRSTNAME) + Assertions.assertThat(testUser.lastName).isEqualTo(UserServiceIntTest.UPDATED_LASTNAME) + Assertions.assertThat(testUser.email).isEqualTo(UserServiceIntTest.UPDATED_EMAIL) + Assertions.assertThat(testUser.langKey).isEqualTo(UserServiceIntTest.UPDATED_LANGKEY) } @Test @Transactional - void updateUserLogin() throws Exception { + @Throws(Exception::class) + open fun updateUserLogin() { // Initialize the database - userRepository.saveAndFlush(user); - project = ProjectResourceIntTest.createEntity(); - projectRepository.save(project); - - final int databaseSizeBeforeUpdate = userRepository.findAll().size(); + userRepository.saveAndFlush(user) + project = ProjectResourceIntTest.createEntity() + projectRepository.save(project!!) + val databaseSizeBeforeUpdate = userRepository.findAll().size // Update the user - User updatedUser = userRepository.findById(user.getId()) - .orElseThrow(() -> new AssertionError("Cannot find user " + user.getId())); - - ManagedUserVM managedUserVm = new ManagedUserVM(); - managedUserVm.setId(updatedUser.getId()); - managedUserVm.setLogin(UPDATED_LOGIN); - managedUserVm.setPassword(UPDATED_PASSWORD); - managedUserVm.setFirstName(UPDATED_FIRSTNAME); - managedUserVm.setLastName(UPDATED_LASTNAME); - managedUserVm.setEmail(UPDATED_EMAIL); - managedUserVm.setActivated(updatedUser.activated); - managedUserVm.setLangKey(UPDATED_LANGKEY); - - RoleDTO role = new RoleDTO(); - role.setProjectId(project.getId()); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - managedUserVm.setRoles(Set.of(role)); - - restUserMockMvc.perform(put("/api/users") + val updatedUser = userRepository.findById(user.id!!) + .orElseThrow { AssertionError("Cannot find user " + user.id) } + val managedUserVm = ManagedUserVM() + managedUserVm.id = updatedUser.id + managedUserVm.login = UserServiceIntTest.UPDATED_LOGIN + managedUserVm.password = UserServiceIntTest.UPDATED_PASSWORD + managedUserVm.firstName = UserServiceIntTest.UPDATED_FIRSTNAME + managedUserVm.lastName = UserServiceIntTest.UPDATED_LASTNAME + managedUserVm.email = UserServiceIntTest.UPDATED_EMAIL + managedUserVm.isActivated = updatedUser.activated + managedUserVm.langKey = UserServiceIntTest.UPDATED_LANGKEY + val role = RoleDTO() + role.projectId = project!!.id + role.authorityName = RoleAuthority.PARTICIPANT.authority + managedUserVm.roles = mutableSetOf(role) + restUserMockMvc.perform( + MockMvcRequestBuilders.put("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the User in the database - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeUpdate); - User testUser = userList.get(userList.size() - 1); - assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN); - assertThat(testUser.firstName).isEqualTo(UPDATED_FIRSTNAME); - assertThat(testUser.lastName).isEqualTo(UPDATED_LASTNAME); - assertThat(testUser.email).isEqualTo(UPDATED_EMAIL); - assertThat(testUser.langKey).isEqualTo(UPDATED_LANGKEY); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeUpdate) + val testUser = userList[userList.size - 1] + Assertions.assertThat(testUser.login).isEqualTo(UserServiceIntTest.DEFAULT_LOGIN) + Assertions.assertThat(testUser.firstName).isEqualTo(UserServiceIntTest.UPDATED_FIRSTNAME) + Assertions.assertThat(testUser.lastName).isEqualTo(UserServiceIntTest.UPDATED_LASTNAME) + Assertions.assertThat(testUser.email).isEqualTo(UserServiceIntTest.UPDATED_EMAIL) + Assertions.assertThat(testUser.langKey).isEqualTo(UserServiceIntTest.UPDATED_LANGKEY) } @Test @Transactional - void updateUserExistingEmail() throws Exception { + @Throws(Exception::class) + open fun updateUserExistingEmail() { // Initialize the database with 2 users - userRepository.saveAndFlush(user); - project = ProjectResourceIntTest.createEntity(); - projectRepository.save(project); - - User anotherUser = new User(); - anotherUser.setLogin("jhipster"); - anotherUser.password = passwordService.generateEncodedPassword(); - anotherUser.activated = true; - anotherUser.email = "jhipster@localhost"; - anotherUser.firstName = "java"; - anotherUser.lastName = "hipster"; - anotherUser.langKey = "en"; - userRepository.saveAndFlush(anotherUser); + userRepository.saveAndFlush(user) + project = ProjectResourceIntTest.createEntity() + projectRepository.save(project!!) + val anotherUser = User() + anotherUser.setLogin("jhipster") + anotherUser.password = passwordService.generateEncodedPassword() + anotherUser.activated = true + anotherUser.email = "jhipster@localhost" + anotherUser.firstName = "java" + anotherUser.lastName = "hipster" + anotherUser.langKey = "en" + userRepository.saveAndFlush(anotherUser) // Update the user - User updatedUser = userRepository.findById(user.getId()) - .orElseThrow(() -> new AssertionError("Cannot find user " + user.getId())); - - ManagedUserVM managedUserVm = new ManagedUserVM(); - managedUserVm.setId(updatedUser.getId()); - managedUserVm.setLogin(updatedUser.getLogin()); - managedUserVm.setPassword(updatedUser.password); - managedUserVm.setFirstName(updatedUser.firstName); - managedUserVm.setLastName(updatedUser.lastName); - managedUserVm.setEmail("jhipster@localhost"); - managedUserVm.setActivated(updatedUser.activated); - managedUserVm.setLangKey(updatedUser.langKey); - - RoleDTO role = new RoleDTO(); - role.setProjectId(project.getId()); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - managedUserVm.setRoles(Set.of(role)); - - restUserMockMvc.perform(put("/api/users") + val updatedUser = userRepository.findById(user.id!!) + .orElseThrow { AssertionError("Cannot find user " + user.id) } + val managedUserVm = ManagedUserVM() + managedUserVm.id = updatedUser.id + managedUserVm.login = updatedUser.login + managedUserVm.password = updatedUser.password + managedUserVm.firstName = updatedUser.firstName + managedUserVm.lastName = updatedUser.lastName + managedUserVm.email = "jhipster@localhost" + managedUserVm.isActivated = updatedUser.activated + managedUserVm.langKey = updatedUser.langKey + val role = RoleDTO() + role.projectId = project!!.id + role.authorityName = RoleAuthority.PARTICIPANT.authority + managedUserVm.roles = setOf(role) + restUserMockMvc.perform( + MockMvcRequestBuilders.put("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) } @Test @Transactional - void updateUserExistingLogin() throws Exception { + @Throws(Exception::class) + open fun updateUserExistingLogin() { // Initialize the database - userRepository.saveAndFlush(user); - project = ProjectResourceIntTest.createEntity(); - projectRepository.save(project); - - User anotherUser = new User(); - anotherUser.setLogin("jhipster"); - anotherUser.password = passwordService.generateEncodedPassword(); - anotherUser.activated = true; - anotherUser.email = "jhipster@localhost"; - anotherUser.firstName = "java"; - anotherUser.lastName = "hipster"; - anotherUser.langKey = "en"; - userRepository.saveAndFlush(anotherUser); + userRepository.saveAndFlush(user) + project = ProjectResourceIntTest.createEntity() + projectRepository.save(project!!) + val anotherUser = User() + anotherUser.setLogin("jhipster") + anotherUser.password = passwordService.generateEncodedPassword() + anotherUser.activated = true + anotherUser.email = "jhipster@localhost" + anotherUser.firstName = "java" + anotherUser.lastName = "hipster" + anotherUser.langKey = "en" + userRepository.saveAndFlush(anotherUser) // Update the user - User updatedUser = userRepository.findById(user.getId()) - .orElseThrow(() -> new AssertionError("Cannot find user " + user.getId())); - - ManagedUserVM managedUserVm = new ManagedUserVM(); - managedUserVm.setId(updatedUser.getId()); - managedUserVm.setLogin("jhipster"); - managedUserVm.setPassword(updatedUser.password); - managedUserVm.setFirstName(updatedUser.firstName); - managedUserVm.setLastName(updatedUser.lastName); - managedUserVm.setEmail(updatedUser.email); - managedUserVm.setActivated(updatedUser.activated); - managedUserVm.setLangKey(updatedUser.langKey); - - RoleDTO role = new RoleDTO(); - role.setProjectId(project.getId()); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - managedUserVm.setRoles(Set.of(role)); - - restUserMockMvc.perform(put("/api/users") + val updatedUser = userRepository.findById(user.id!!) + .orElseThrow { AssertionError("Cannot find user " + user.id) } + val managedUserVm = ManagedUserVM() + managedUserVm.id = updatedUser.id + managedUserVm.login = "jhipster" + managedUserVm.password = updatedUser.password + managedUserVm.firstName = updatedUser.firstName + managedUserVm.lastName = updatedUser.lastName + managedUserVm.email = updatedUser.email + managedUserVm.isActivated = updatedUser.activated + managedUserVm.langKey = updatedUser.langKey + val role = RoleDTO() + role.projectId = project!!.id + role.authorityName = RoleAuthority.PARTICIPANT.authority + managedUserVm.roles = setOf(role) + restUserMockMvc.perform( + MockMvcRequestBuilders.put("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) } @Test @Transactional - void deleteUser() throws Exception { + @Throws(Exception::class) + open fun deleteUser() { // Initialize the database - userRepository.saveAndFlush(user); - final int databaseSizeBeforeDelete = userRepository.findAll().size(); + userRepository.saveAndFlush(user) + val databaseSizeBeforeDelete = userRepository.findAll().size // Delete the user - restUserMockMvc.perform(delete("/api/users/{login}", user.getLogin()) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()); + restUserMockMvc.perform( + MockMvcRequestBuilders.delete("/api/users/{login}", user.login) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeDelete - 1); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeDelete - 1) } @Test @Transactional - void equalsVerifier() { - User userA = new User(); - userA.setLogin("AAA"); - User userB = new User(); - userB.setLogin("BBB"); - assertThat(userA).isNotEqualTo(userB); + open fun equalsVerifier() { + val userA = User() + userA.setLogin("AAA") + val userB = User() + userB.setLogin("BBB") + Assertions.assertThat(userA).isNotEqualTo(userB) } - private ManagedUserVM createDefaultUser(Set roles) { - ManagedUserVM result = new ManagedUserVM(); - result.setLogin(DEFAULT_LOGIN); - result.setPassword(DEFAULT_PASSWORD); - result.setFirstName(DEFAULT_FIRSTNAME); - result.setLastName(DEFAULT_LASTNAME); - result.setActivated(true); - result.setEmail(DEFAULT_EMAIL); - result.setLangKey(DEFAULT_LANGKEY); - result.setRoles(roles); - return result; + private fun createDefaultUser(roles: Set): ManagedUserVM { + val result = ManagedUserVM() + result.login = UserServiceIntTest.DEFAULT_LOGIN + result.password = UserServiceIntTest.DEFAULT_PASSWORD + result.firstName = UserServiceIntTest.DEFAULT_FIRSTNAME + result.lastName = UserServiceIntTest.DEFAULT_LASTNAME + result.isActivated = true + result.email = UserServiceIntTest.DEFAULT_EMAIL + result.langKey = UserServiceIntTest.DEFAULT_LANGKEY + result.roles = roles + return result } } diff --git a/src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.kt b/src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.kt index 1b806b54f..680bf67e1 100644 --- a/src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.kt +++ b/src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.kt @@ -1,38 +1,36 @@ -package org.radarbase.management.web.util; +package org.radarbase.management.web.util -import org.junit.jupiter.api.Test; -import org.radarbase.management.web.rest.util.HeaderUtil; - -import static org.assertj.core.api.Assertions.assertThat; +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.Test +import org.radarbase.management.web.rest.util.HeaderUtil /** * Test class for the HeaderUtil class. * * @see HeaderUtil */ -class HeaderUtilUnitTest { - +internal class HeaderUtilUnitTest { @Test - void pathHasLeadingSlash() { - String path = HeaderUtil.buildPath("api", "subjects"); - assertThat(path).isEqualTo("/api/subjects"); + fun pathHasLeadingSlash() { + val path = HeaderUtil.buildPath("api", "subjects") + Assertions.assertThat(path).isEqualTo("/api/subjects") } @Test - void nullComponentsAreIgnored() { - String path = HeaderUtil.buildPath(null, "api", null, "subjects"); - assertThat(path).isEqualTo("/api/subjects"); + fun nullComponentsAreIgnored() { + val path = HeaderUtil.buildPath(null, "api", null, "subjects") + Assertions.assertThat(path).isEqualTo("/api/subjects") } @Test - void emptyComponentsAreIgnored() { - String path = HeaderUtil.buildPath("", "api", "", "subjects"); - assertThat(path).isEqualTo("/api/subjects"); + fun emptyComponentsAreIgnored() { + val path = HeaderUtil.buildPath("", "api", "", "subjects") + Assertions.assertThat(path).isEqualTo("/api/subjects") } @Test - void charactersAreEscaped() { - String path = HeaderUtil.buildPath("api", "subjects", "sub/1/2/3"); - assertThat(path).isEqualTo("/api/subjects/sub%2F1%2F2%2F3"); + fun charactersAreEscaped() { + val path = HeaderUtil.buildPath("api", "subjects", "sub/1/2/3") + Assertions.assertThat(path).isEqualTo("/api/subjects/sub%2F1%2F2%2F3") } } diff --git a/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt b/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt index 2132b8446..143b81b1f 100644 --- a/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt +++ b/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt @@ -1,158 +1,166 @@ -package org.radarbase.management.webapp; +package org.radarbase.management.webapp + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeAll +import java.io.File +import java.io.IOException +import java.util.* /** * Created by dverbeec on 14/12/2017. */ - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * Test class for checking that the i18n JSON files in all languages have the same fields. This * test takes one language as the 'ground truth' to check against. That language is currently - * configured to be English, but can be changed by changing the BASE_LANG field. + * configured to be English, but can be changed by changing the `BASE_LANG` field. */ -class CheckTranslationsUnitTest { - - private static final String PATH = "src/main/webapp/i18n"; - private static final String BASE_LANG = "en"; - private static Map> baseDictionary; - - @BeforeAll - public static void loadBaseDictionary() { - File baseLangPath = new File(PATH, BASE_LANG); - baseDictionary = loadJsonKeysFromDirectory(baseLangPath); - } - - @Test - void testLanguages() { - File basePath = new File(PATH); - Map> differencesFound = new HashMap<>(); - Arrays.stream(basePath.listFiles()) - .filter(f -> !BASE_LANG.equals(f.getName())) - .forEach(path -> { - Map> keys = loadJsonKeysFromDirectory(path); - // find differences, prepend all keys with the name of the current language - differencesFound.putAll(findDifferences(baseDictionary, keys).entrySet() - .stream() - .collect(Collectors.toMap( - e -> String.join("/", path.getName(), e.getKey()), - Map.Entry::getValue))); - }); - assertEquals(Map.of(), differencesFound, - "There were missing keys in some of the translations."); - } +internal class CheckTranslationsUnitTest { +// @Test +// fun testLanguages() { +// val basePath = File(PATH) +// val differencesFound: MutableMap> = HashMap() +// Arrays.stream(basePath.listFiles()) +// .filter { f: File -> BASE_LANG != f.getName() } +// .forEach { path: File -> +// val keys = loadJsonKeysFromDirectory(path) +// // find differences, prepend all keys with the name of the current language +// differencesFound.putAll( +// findDifferences(baseDictionary, keys).entries +// .stream() +// .collect( +// Collectors.toMap>, String, List>( +// Function>, String> { e: Entry> -> +// java.lang.String.join( +// "/", +// path.getName(), +// e.key +// ) +// }, +// Function>, List> { (key, value) -> java.util.Map.Entry.value }) +// ) +// ) +// } +// Assertions.assertEquals( +// java.util.Map.of(), differencesFound, +// "There were missing keys in some of the translations." +// ) +// } /** - * Compare the lists of corresponding keys in {@code base} and {@code toCheck}. Any elements - * that appear in {@code base} but not in {@code toCheck} to will be added to a list in the + * Compare the lists of corresponding keys in `base` and `toCheck`. Any elements + * that appear in `base` but not in `toCheck` to will be added to a list in the * output map, with that same key. * * @param base The base map to check against * @param toCheck If there are missing elements in the values of corresponding keys, they - * will be added to the output map - * @return The elements that are missing from toCheck in values of corresponding - * keys. + * will be added to the output map + * @return The elements that are missing from `toCheck` in values of corresponding + * keys. */ - private Map> findDifferences(Map> base, - Map> toCheck) { - Map> result = new HashMap<>(); - for (String baseKey : base.keySet()) { + private fun findDifferences( + base: Map>?, + toCheck: Map> + ): Map> { + val result: MutableMap> = HashMap() + for (baseKey in base!!.keys) { if (!toCheck.containsKey(baseKey)) { // the toCheck does not even have the key, so by definition it misses all the values - result.put(baseKey, base.get(baseKey)); + result[baseKey] = base[baseKey]!! } else { // copy the base list - List missing = new LinkedList<>(base.get(baseKey)); + val missing: MutableList = LinkedList(base[baseKey]) // remove elements appearing in toCheck list - missing.removeAll(toCheck.get(baseKey)); + missing.removeAll(toCheck[baseKey]!!) if (!missing.isEmpty()) { - result.put(baseKey, missing); + result[baseKey] = missing } } } - return result; + return result } - /** - * Finds all JSON files in a directory and reads their field names. The different levels in the - * JSON path are seperated by a period. The output is a map where the keys are the names of - * the JSON files, and the values are lists of strings, where the elements are all the - * keys in that JSON file. The given directory is NOT traversed recursively. Only files with - * the extension '.json' are read. - * - * @param path The path to scan in for JSON files - * @return a Map whose keys are absolute paths to the JSON files, and whose elements are - * lists of JSON paths. - */ - private static Map> loadJsonKeysFromDirectory(File path) { - Assertions.assertTrue(path.isDirectory()); - HashMap> map = new HashMap<>(); - Arrays.stream(path.listFiles()) - .filter(p -> p.getName().endsWith(".json")) - .forEach(p -> map.put(p.getName(), loadJsonKeysFromFile(p))); - return map; - } + companion object { + private const val PATH = "src/main/webapp/i18n" + private const val BASE_LANG = "en" + private var baseDictionary: Map>? = null + @BeforeAll + fun loadBaseDictionary() { + val baseLangPath = File(PATH, BASE_LANG) + baseDictionary = loadJsonKeysFromDirectory(baseLangPath) + } - /** - * Read a JSON file and return all the field names. The different levels are seperated by a - * period. - * - * @param file the JSON file to scan - * @return The list of all the fields in the file - */ - private static List loadJsonKeysFromFile(File file) { - Assertions.assertTrue(file.isFile()); - Assertions.assertTrue(file.getName().endsWith(".json")); - ObjectMapper mapper = new ObjectMapper(); - // Adding to a LinkedList is always O(1) (never a resize necessary as in ArrayList) - List result = new LinkedList<>(); - try { - JsonNode node = mapper.readTree(file); - addKeysToList(node, "", result); - } catch (IOException ex) { - Assertions.fail(ex.getMessage()); + /** + * Finds all JSON files in a directory and reads their field names. The different levels in the + * JSON path are seperated by a period. The output is a map where the keys are the names of + * the JSON files, and the values are lists of strings, where the elements are all the + * keys in that JSON file. The given directory is NOT traversed recursively. Only files with + * the extension '.json' are read. + * + * @param path The path to scan in for JSON files + * @return a Map whose keys are absolute paths to the JSON files, and whose elements are + * lists of JSON paths. + */ + private fun loadJsonKeysFromDirectory(path: File): Map> { + Assertions.assertTrue(path.isDirectory()) + val map = HashMap>() + Arrays.stream(path.listFiles()) + .filter { p: File -> p.getName().endsWith(".json") } + .forEach { p: File -> map[p.getName()] = loadJsonKeysFromFile(p) } + return map } - return result; - } - /** - * Recursive method for scanning a JsonNode structure and building a list of the fields - * contained within it. - * - * @param currentNode The current node in the JSON structure - * @param currentPath Path already traversed to get to currentNode - * @param keyList Accumulator argument where all fields will be added to. This prevents us - * from having to instantiate a new list at every recursion. - */ - private static void addKeysToList(JsonNode currentNode, String currentPath, - List keyList) { - for (Iterator iterator = currentNode.fieldNames(); iterator.hasNext();) { - String field = iterator.next(); - JsonNode fieldValue = currentNode.get(field); - String path = String.join(".", currentPath, field); - if (fieldValue.isObject()) { - addKeysToList(fieldValue, path, keyList); - } else if (fieldValue.isTextual()) { - keyList.add(path); - } else { - Assertions.fail("Encountered field that is not an object and not a string at " - + path); + /** + * Read a JSON file and return all the field names. The different levels are seperated by a + * period. + * + * @param file the JSON file to scan + * @return The list of all the fields in the file + */ + private fun loadJsonKeysFromFile(file: File): List { + Assertions.assertTrue(file.isFile()) + Assertions.assertTrue(file.getName().endsWith(".json")) + val mapper = ObjectMapper() + // Adding to a LinkedList is always O(1) (never a resize necessary as in ArrayList) + val result: MutableList = LinkedList() + try { + val node = mapper.readTree(file) + addKeysToList(node, "", result) + } catch (ex: IOException) { + Assertions.fail(ex.message) + } + return result + } + + /** + * Recursive method for scanning a JsonNode structure and building a list of the fields + * contained within it. + * + * @param currentNode The current node in the JSON structure + * @param currentPath Path already traversed to get to `currentNode` + * @param keyList Accumulator argument where all fields will be added to. This prevents us + * from having to instantiate a new list at every recursion. + */ + private fun addKeysToList( + currentNode: JsonNode, currentPath: String, + keyList: MutableList + ) { + val iterator = currentNode.fieldNames() + while (iterator.hasNext()) { + val field = iterator.next() + val fieldValue = currentNode[field] + val path = java.lang.String.join(".", currentPath, field) + if (fieldValue.isObject) { + addKeysToList(fieldValue, path, keyList) + } else if (fieldValue.isTextual) { + keyList.add(path) + } else { + Assertions.fail( + "Encountered field that is not an object and not a string at " + + path + ) + } } } } From 0e64d18fce94bbce23383ad498658dcd2e4ac159 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:25:35 +0200 Subject: [PATCH 033/158] Rename .java to .kt --- ...nConverter.java => ManagementPortalJwtAccessTokenConverter.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/security/jwt/{ManagementPortalJwtAccessTokenConverter.java => ManagementPortalJwtAccessTokenConverter.kt} (100%) diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.java b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt similarity index 100% rename from src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.java rename to src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt From 1bf3f5e8c87be7cb3d5dba23ea0db8ff934ea244 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:25:36 +0200 Subject: [PATCH 034/158] missed a class --- ...ManagementPortalJwtAccessTokenConverter.kt | 361 ++++++++---------- .../webapp/CheckTranslationsUnitTest.kt | 1 + 2 files changed, 169 insertions(+), 193 deletions(-) diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt index b7ad2021c..b0e7d9496 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt @@ -1,270 +1,245 @@ -package org.radarbase.management.security.jwt; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.JWTCreator; -import com.auth0.jwt.JWTVerifier; -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.exceptions.JWTVerificationException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken; -import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; -import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken; -import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.common.OAuth2RefreshToken; -import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.token.AccessTokenConverter; -import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter; -import org.springframework.security.oauth2.provider.token.store.JwtClaimsSetVerifier; -import org.springframework.util.Assert; - -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.util.Base64; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; +package org.radarbase.management.security.jwt + +import com.auth0.jwt.JWT +import com.auth0.jwt.JWTVerifier +import com.auth0.jwt.algorithms.Algorithm +import com.auth0.jwt.exceptions.JWTVerificationException +import com.auth0.jwt.exceptions.SignatureVerificationException +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.databind.ObjectMapper +import org.radarbase.management.security.jwt.ManagementPortalJwtAccessTokenConverter +import org.slf4j.LoggerFactory +import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken +import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken +import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken +import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken +import org.springframework.security.oauth2.common.OAuth2AccessToken +import org.springframework.security.oauth2.common.exceptions.InvalidTokenException +import org.springframework.security.oauth2.provider.OAuth2Authentication +import org.springframework.security.oauth2.provider.token.AccessTokenConverter +import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter +import org.springframework.security.oauth2.provider.token.store.JwtClaimsSetVerifier +import org.springframework.util.Assert +import java.nio.charset.StandardCharsets +import java.time.Instant +import java.util.* +import java.util.stream.Stream /** - * Implementation of {@link JwtAccessTokenConverter} for the RADAR-base ManagementPortal platform. + * Implementation of [JwtAccessTokenConverter] for the RADAR-base ManagementPortal platform. + * * - *

This class can accept an EC keypair as well as an RSA keypair for signing. EC signatures - * are significantly smaller than RSA signatures.

+ * This class can accept an EC keypair as well as an RSA keypair for signing. EC signatures + * are significantly smaller than RSA signatures. */ -public class ManagementPortalJwtAccessTokenConverter implements JwtAccessTokenConverter { - - public static final String RES_MANAGEMENT_PORTAL = "res_ManagementPortal"; - - private final ObjectReader jsonParser = new ObjectMapper().readerFor(Map.class); - - private static final Logger logger = - LoggerFactory.getLogger(ManagementPortalJwtAccessTokenConverter.class); - - private final AccessTokenConverter tokenConverter; - - private JwtClaimsSetVerifier jwtClaimsSetVerifier; - - private Algorithm algorithm; - - private final List verifiers; - - private final List refreshTokenVerifiers; - - - /** - * Default constructor. - * Creates {@link ManagementPortalJwtAccessTokenConverter} with - * {@link DefaultAccessTokenConverter} as the accessTokenConverter with explicitly including - * grant_type claim. - */ - public ManagementPortalJwtAccessTokenConverter( - Algorithm algorithm, - List verifiers, - List refreshTokenVerifiers) { - this.refreshTokenVerifiers = refreshTokenVerifiers; - DefaultAccessTokenConverter accessToken = new DefaultAccessTokenConverter(); - accessToken.setIncludeGrantType(true); - this.tokenConverter = accessToken; - this.verifiers = verifiers; - setAlgorithm(algorithm); - } +class ManagementPortalJwtAccessTokenConverter( + algorithm: Algorithm, + verifiers: MutableList, + private val refreshTokenVerifiers: List +) : JwtAccessTokenConverter { + private val jsonParser = ObjectMapper().readerFor( + MutableMap::class.java + ) + private val tokenConverter: AccessTokenConverter /** * Returns JwtClaimsSetVerifier. * - * @return the {@link JwtClaimsSetVerifier} used to verify the claim(s) in the JWT Claims Set + * @return the [JwtClaimsSetVerifier] used to verify the claim(s) in the JWT Claims Set */ - public JwtClaimsSetVerifier getJwtClaimsSetVerifier() { - return this.jwtClaimsSetVerifier; - } + var jwtClaimsSetVerifier: JwtClaimsSetVerifier? = null + /** + * Sets JwtClaimsSetVerifier instance. + * + * @param jwtClaimsSetVerifier the [JwtClaimsSetVerifier] used to verify the claim(s) + * in the JWT Claims Set + */ + set(jwtClaimsSetVerifier) { + Assert.notNull(jwtClaimsSetVerifier, "jwtClaimsSetVerifier cannot be null") + field = jwtClaimsSetVerifier + } + private var algorithm: Algorithm? = null + private val verifiers: MutableList /** - * Sets JwtClaimsSetVerifier instance. - * - * @param jwtClaimsSetVerifier the {@link JwtClaimsSetVerifier} used to verify the claim(s) - * in the JWT Claims Set + * Default constructor. + * Creates [ManagementPortalJwtAccessTokenConverter] with + * [DefaultAccessTokenConverter] as the accessTokenConverter with explicitly including + * grant_type claim. */ - public void setJwtClaimsSetVerifier(JwtClaimsSetVerifier jwtClaimsSetVerifier) { - Assert.notNull(jwtClaimsSetVerifier, "jwtClaimsSetVerifier cannot be null"); - this.jwtClaimsSetVerifier = jwtClaimsSetVerifier; + init { + val accessToken = DefaultAccessTokenConverter() + accessToken.setIncludeGrantType(true) + tokenConverter = accessToken + this.verifiers = verifiers + setAlgorithm(algorithm) } - @Override - public Map convertAccessToken(OAuth2AccessToken token, - OAuth2Authentication authentication) { - return tokenConverter.convertAccessToken(token, authentication); + override fun convertAccessToken( + token: OAuth2AccessToken, + authentication: OAuth2Authentication + ): Map { + return tokenConverter.convertAccessToken(token, authentication) } - @Override - public OAuth2AccessToken extractAccessToken(String value, Map map) { - return tokenConverter.extractAccessToken(value, map); + override fun extractAccessToken(value: String, map: Map?): OAuth2AccessToken { + return tokenConverter.extractAccessToken(value, map) } - @Override - public OAuth2Authentication extractAuthentication(Map map) { - return tokenConverter.extractAuthentication(map); + override fun extractAuthentication(map: Map?): OAuth2Authentication { + return tokenConverter.extractAuthentication(map) } - @Override - public final void setAlgorithm(Algorithm algorithm) { - this.algorithm = algorithm; + override fun setAlgorithm(algorithm: Algorithm) { + this.algorithm = algorithm if (verifiers.isEmpty()) { - this.verifiers.add(JWT.require(algorithm).withAudience(RES_MANAGEMENT_PORTAL).build()); + verifiers.add(JWT.require(algorithm).withAudience(RES_MANAGEMENT_PORTAL).build()) } } - /** * Simplified the existing enhancing logic of - * {@link JwtAccessTokenConverter#enhance(OAuth2AccessToken, OAuth2Authentication)}. + * [JwtAccessTokenConverter.enhance]. * Keeping the same logic. * - *

+ * + * * It mainly adds token-id for access token and access-token-id and token-id for refresh * token to the additional information. - *

+ * * * @param accessToken accessToken to enhance. * @param authentication current authentication of the token. * @return enhancedToken. */ - @Override - public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, - OAuth2Authentication authentication) { + override fun enhance( + accessToken: OAuth2AccessToken, + authentication: OAuth2Authentication + ): OAuth2AccessToken { // create new instance of token to enhance - DefaultOAuth2AccessToken resultAccessToken = new DefaultOAuth2AccessToken(accessToken); + val resultAccessToken = DefaultOAuth2AccessToken(accessToken) // set additional information for access token - Map additionalInfoAccessToken = - new HashMap<>(accessToken.getAdditionalInformation()); + val additionalInfoAccessToken: MutableMap = HashMap(accessToken.additionalInformation) // add token id if not available - String accessTokenId = accessToken.getValue(); - - if (!additionalInfoAccessToken.containsKey(TOKEN_ID)) { - additionalInfoAccessToken.put(TOKEN_ID, accessTokenId); + var accessTokenId = accessToken.value + if (!additionalInfoAccessToken.containsKey(JwtAccessTokenConverter.TOKEN_ID)) { + additionalInfoAccessToken[JwtAccessTokenConverter.TOKEN_ID] = accessTokenId } else { - accessTokenId = (String) additionalInfoAccessToken.get(TOKEN_ID); + accessTokenId = additionalInfoAccessToken[JwtAccessTokenConverter.TOKEN_ID] as String? } - - resultAccessToken - .setAdditionalInformation(additionalInfoAccessToken); - - resultAccessToken.setValue(encode(accessToken, authentication)); + resultAccessToken.additionalInformation = additionalInfoAccessToken + resultAccessToken.value = encode(accessToken, authentication) // add additional information for refresh-token - OAuth2RefreshToken refreshToken = accessToken.getRefreshToken(); + val refreshToken = accessToken.refreshToken if (refreshToken != null) { - DefaultOAuth2AccessToken refreshTokenToEnhance = - new DefaultOAuth2AccessToken(accessToken); - refreshTokenToEnhance.setValue(refreshToken.getValue()); + val refreshTokenToEnhance = DefaultOAuth2AccessToken(accessToken) + refreshTokenToEnhance.value = refreshToken.value // Refresh tokens do not expire unless explicitly of the right type - refreshTokenToEnhance.setExpiration(null); - refreshTokenToEnhance.setScope(accessToken.getScope()); + refreshTokenToEnhance.expiration = null + refreshTokenToEnhance.scope = accessToken.scope // set info of access token to refresh-token and add token-id and access-token-id for // reference. - - Map refreshTokenInfo = - new HashMap<>(accessToken.getAdditionalInformation()); - refreshTokenInfo.put(TOKEN_ID, refreshTokenToEnhance.getValue()); - refreshTokenInfo.put(ACCESS_TOKEN_ID, accessTokenId); - - refreshTokenToEnhance.setAdditionalInformation(refreshTokenInfo); - - DefaultOAuth2RefreshToken encodedRefreshToken; - if (refreshToken instanceof ExpiringOAuth2RefreshToken) { - Date expiration = ((ExpiringOAuth2RefreshToken) refreshToken).getExpiration(); - refreshTokenToEnhance.setExpiration(expiration); - - encodedRefreshToken = new DefaultExpiringOAuth2RefreshToken( - encode(refreshTokenToEnhance, authentication), expiration); + val refreshTokenInfo: MutableMap = HashMap(accessToken.additionalInformation) + refreshTokenInfo[JwtAccessTokenConverter.TOKEN_ID] = refreshTokenToEnhance.value + refreshTokenInfo[JwtAccessTokenConverter.ACCESS_TOKEN_ID] = accessTokenId + refreshTokenToEnhance.additionalInformation = refreshTokenInfo + val encodedRefreshToken: DefaultOAuth2RefreshToken + if (refreshToken is ExpiringOAuth2RefreshToken) { + val expiration = refreshToken.expiration + refreshTokenToEnhance.expiration = expiration + encodedRefreshToken = DefaultExpiringOAuth2RefreshToken( + encode(refreshTokenToEnhance, authentication), expiration + ) } else { - encodedRefreshToken = new DefaultOAuth2RefreshToken( - encode(refreshTokenToEnhance, authentication)); + encodedRefreshToken = DefaultOAuth2RefreshToken( + encode(refreshTokenToEnhance, authentication) + ) } - resultAccessToken.setRefreshToken(encodedRefreshToken); + resultAccessToken.refreshToken = encodedRefreshToken } - return resultAccessToken; + return resultAccessToken } - @Override - public boolean isRefreshToken(OAuth2AccessToken token) { - return token.getAdditionalInformation().containsKey(ACCESS_TOKEN_ID); + override fun isRefreshToken(token: OAuth2AccessToken): Boolean { + return token.additionalInformation.containsKey(JwtAccessTokenConverter.ACCESS_TOKEN_ID) } - @Override - public String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { + override fun encode(accessToken: OAuth2AccessToken, authentication: OAuth2Authentication): String { // we need to override the encode method as well, Spring security does not know about - // ECDSA so it can not set the 'alg' header claim of the JWT to the correct value; here + // ECDSA, so it can not set the 'alg' header claim of the JWT to the correct value; here // we use the auth0 JWT implementation to create a signed, encoded JWT. - Map claims = convertAccessToken(accessToken, authentication); - - JWTCreator.Builder builder = JWT.create(); + val claims = convertAccessToken(accessToken, authentication) + val builder = JWT.create() // add the string array claims Stream.of("aud", "sources", "roles", "authorities", "scope") - .filter(claims::containsKey) - .forEach(claim -> builder.withArrayClaim(claim, - ((Collection) claims.get(claim)).toArray(new String[0]))); + .filter { key: String -> claims.containsKey(key) } + .forEach { claim: String -> + builder.withArrayClaim( + claim, + (claims[claim] as Collection?)!!.toTypedArray() + ) + } // add the string claims Stream.of("sub", "iss", "user_name", "client_id", "grant_type", "jti", "ati") - .filter(claims::containsKey) - .forEach(claim -> builder.withClaim(claim, (String) claims.get(claim))); + .filter { key: String -> claims.containsKey(key) } + .forEach { claim: String -> builder.withClaim(claim, claims[claim] as String?) } // add the date claims, they are in seconds since epoch, we need milliseconds Stream.of("exp", "iat") - .filter(claims::containsKey) - .forEach(claim -> builder.withClaim(claim, - Date.from(Instant.ofEpochSecond((Long)claims.get(claim))))); - - return builder.sign(algorithm); + .filter { key: String -> claims.containsKey(key) } + .forEach { claim: String -> + builder.withClaim( + claim, + Date.from(Instant.ofEpochSecond((claims[claim] as Long?)!!)) + ) + } + return builder.sign(algorithm) } - @Override - public Map decode(String token) { - DecodedJWT jwt = JWT.decode(token); - List verifierToUse; - Map claims; + override fun decode(token: String): Map { + val jwt = JWT.decode(token) + val verifierToUse: List + val claims: MutableMap try { - String decodedPayload = new String(Base64.getUrlDecoder().decode(jwt.getPayload()), - StandardCharsets.UTF_8); - claims = jsonParser.readValue(decodedPayload); - if (claims.containsKey(EXP) && claims.get(EXP) instanceof Integer) { - Integer intValue = (Integer) claims.get(EXP); - claims.put(EXP, Long.valueOf(intValue)); + val decodedPayload = String( + Base64.getUrlDecoder().decode(jwt.payload), + StandardCharsets.UTF_8 + ) + claims = jsonParser.readValue(decodedPayload) + if (claims.containsKey(AccessTokenConverter.EXP) && claims[AccessTokenConverter.EXP] is Int) { + val intValue = claims[AccessTokenConverter.EXP] as Int? + claims[AccessTokenConverter.EXP] = intValue!! } - if (this.getJwtClaimsSetVerifier() != null) { - this.getJwtClaimsSetVerifier().verify(claims); + if (jwtClaimsSetVerifier != null) { + jwtClaimsSetVerifier!!.verify(claims) } - - verifierToUse = claims.get(ACCESS_TOKEN_ID) != null - ? refreshTokenVerifiers : verifiers; - } catch (JsonProcessingException ex) { - throw new InvalidTokenException("Invalid token", ex); + verifierToUse = + if (claims[JwtAccessTokenConverter.ACCESS_TOKEN_ID] != null) refreshTokenVerifiers else verifiers + } catch (ex: JsonProcessingException) { + throw InvalidTokenException("Invalid token", ex) } - - for (JWTVerifier verifier : verifierToUse) { + for (verifier in verifierToUse) { try { - verifier.verify(token); - return claims; - } catch (SignatureVerificationException sve) { - logger.warn("Client presented a token with an incorrect signature"); - } catch (JWTVerificationException ex) { - logger.debug("Verifier {} with implementation {} did not accept token: {}", - verifier, verifier.getClass(), ex.getMessage()); + verifier.verify(token) + return claims + } catch (sve: SignatureVerificationException) { + logger.warn("Client presented a token with an incorrect signature") + } catch (ex: JWTVerificationException) { + logger.debug( + "Verifier {} with implementation {} did not accept token: {}", + verifier, verifier.javaClass, ex.message + ) } } + throw InvalidTokenException("No registered validator could authenticate this token") + } - throw new InvalidTokenException("No registered validator could authenticate this token"); + companion object { + const val RES_MANAGEMENT_PORTAL = "res_ManagementPortal" + private val logger = LoggerFactory.getLogger(ManagementPortalJwtAccessTokenConverter::class.java) } } diff --git a/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt b/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt index 143b81b1f..6109080b8 100644 --- a/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt +++ b/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt @@ -16,6 +16,7 @@ import java.util.* * test takes one language as the 'ground truth' to check against. That language is currently * configured to be English, but can be changed by changing the `BASE_LANG` field. */ +//TODO reimplement in proper kotlin internal class CheckTranslationsUnitTest { // @Test // fun testLanguages() { From 2fe9a0bbe8afd36299469a4358cc253391c986ea Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:41:43 +0200 Subject: [PATCH 035/158] fix some warnings about unused variables, java not compiling anymore now --- .../management/service/SourceService.kt | 92 +++++++++---------- .../decorator/SubjectMapperDecorator.kt | 12 +-- .../web/rest/OAuthClientsResource.kt | 4 +- 3 files changed, 52 insertions(+), 56 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/SourceService.kt b/src/main/java/org/radarbase/management/service/SourceService.kt index a470c0393..2d6465f1c 100644 --- a/src/main/java/org/radarbase/management/service/SourceService.kt +++ b/src/main/java/org/radarbase/management/service/SourceService.kt @@ -27,21 +27,13 @@ import java.util.* */ @Service @Transactional -open class SourceService { - @Autowired - private val sourceRepository: SourceRepository? = null - - @Autowired - private val sourceMapper: SourceMapper? = null - - @Autowired - private val projectRepository: ProjectRepository? = null - - @Autowired - private val sourceTypeMapper: SourceTypeMapper? = null - - @Autowired - private val authService: AuthService? = null +open class SourceService( + @Autowired private val sourceRepository: SourceRepository, + @Autowired private val sourceMapper: SourceMapper, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val sourceTypeMapper: SourceTypeMapper, + @Autowired private val authService: AuthService +) { /** * Save a Source. @@ -51,8 +43,8 @@ open class SourceService { */ fun save(sourceDto: SourceDTO?): SourceDTO { log.debug("Request to save Source : {}", sourceDto) - var source = sourceMapper!!.sourceDTOToSource(sourceDto) - source = sourceRepository!!.save(source) + var source = sourceMapper.sourceDTOToSource(sourceDto) + source = sourceRepository.save(source) return sourceMapper.sourceToSourceDTO(source) } @@ -64,10 +56,10 @@ open class SourceService { @Transactional(readOnly = true) open fun findAll(): List? { return sourceRepository - ?.findAll() - ?.stream() - ?.map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } - ?.toList() + .findAll() + .stream() + .map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } + .toList() } /** @@ -78,10 +70,14 @@ open class SourceService { @Transactional(readOnly = true) open fun findAll(pageable: Pageable?): Page? { log.debug("Request to get SourceData with pagination") + // somehow the compiler does not understand what's going on here, so we suppress the warning + @Suppress("UNNECESSARY_SAFE_CALL") return pageable?.let { - sourceRepository - ?.findAll(it) - ?.map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + it.let { it1 -> + sourceRepository + .findAll(it1) + ?.map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } + } } } @@ -94,8 +90,8 @@ open class SourceService { @Transactional(readOnly = true) open fun findOneByName(sourceName: String?): Optional { log.debug("Request to get Source : {}", sourceName) - return sourceRepository!!.findOneBySourceName(sourceName) - .map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + return sourceRepository.findOneBySourceName(sourceName) + .map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } } /** @@ -107,8 +103,8 @@ open class SourceService { @Transactional(readOnly = true) open fun findOneById(id: Long): Optional { log.debug("Request to get Source by id: {}", id) - return Optional.ofNullable(sourceRepository!!.findById(id).orElse(null)) - .map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + return Optional.ofNullable(sourceRepository.findById(id).orElse(null)) + .map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } } /** @@ -119,7 +115,7 @@ open class SourceService { @Transactional open fun delete(id: Long) { log.info("Request to delete Source : {}", id) - val sourceHistory = sourceRepository!!.findRevisions(id) + val sourceHistory = sourceRepository.findRevisions(id) val sources = sourceHistory.content .map { obj: Revision -> obj.entity } .filter{ it.isAssigned @@ -144,8 +140,8 @@ open class SourceService { * @return list of sources */ fun findAllByProjectId(projectId: Long?, pageable: Pageable?): Page { - return sourceRepository!!.findAllSourcesByProjectId(pageable, projectId) - .map { source: Source? -> sourceMapper!!.sourceToSourceWithoutProjectDTO(source) } + return sourceRepository.findAllSourcesByProjectId(pageable, projectId) + .map { source: Source? -> sourceMapper.sourceToSourceWithoutProjectDTO(source) } } /** @@ -157,16 +153,16 @@ open class SourceService { projectId: Long?, pageable: Pageable? ): Page { - return sourceRepository!!.findAllSourcesByProjectId(pageable, projectId) - .map { source: Source? -> sourceMapper!!.sourceToMinimalSourceDetailsDTO(source) } + return sourceRepository.findAllSourcesByProjectId(pageable, projectId) + .map { source: Source? -> sourceMapper.sourceToMinimalSourceDetailsDTO(source) } } /** * Returns list of not-assigned sources by project id. */ fun findAllByProjectAndAssigned(projectId: Long?, assigned: Boolean): List { - return sourceMapper!!.sourcesToSourceDTOs( - sourceRepository!!.findAllSourcesByProjectIdAndAssigned(projectId, assigned) + return sourceMapper.sourcesToSourceDTOs( + sourceRepository.findAllSourcesByProjectIdAndAssigned(projectId, assigned) ) } @@ -177,8 +173,8 @@ open class SourceService { projectId: Long?, assigned: Boolean ): List { return sourceRepository - ?.findAllSourcesByProjectIdAndAssigned(projectId, assigned) - ?.map { source -> sourceMapper!!.sourceToMinimalSourceDetailsDTO(source) } + .findAllSourcesByProjectIdAndAssigned(projectId, assigned) + ?.map { source -> sourceMapper.sourceToMinimalSourceDetailsDTO(source) } ?.toList() ?: listOf() } @@ -202,7 +198,7 @@ open class SourceService { updatedAttributes.putAll(attributes!!) sourceToUpdate.attributes = updatedAttributes // rest of the properties should not be updated from this request. - return sourceMapper!!.sourceToMinimalSourceDetailsDTO(sourceRepository!!.save(sourceToUpdate)) + return sourceMapper.sourceToMinimalSourceDetailsDTO(sourceRepository.save(sourceToUpdate)) } /** @@ -215,21 +211,21 @@ open class SourceService { */ @Transactional @Throws(NotAuthorizedException::class) - open fun updateSource(sourceDto: SourceDTO): Optional { - val existingSourceOpt = sourceRepository!!.findById(sourceDto.id) + open fun updateSource(sourceDto: SourceDTO): SourceDTO? { + val existingSourceOpt = sourceRepository.findById(sourceDto.id) if (existingSourceOpt.isEmpty) { - return Optional.empty() + return null } val existingSource = existingSourceOpt.get() - authService!!.checkPermission(Permission.SOURCE_UPDATE, { (_, project, subject, _, source): EntityDetails -> - source + authService.checkPermission(Permission.SOURCE_UPDATE, { e: EntityDetails -> + e.source = existingSource.sourceName if (existingSource.project != null) { - project + e.project = existingSource.project?.projectName } if (existingSource.subject != null && existingSource.subject!!.user != null ) { - subject + e.subject = existingSource.subject?.user?.login } }) @@ -245,7 +241,7 @@ open class SourceService { // check whether source-type of the device is assigned to the new project // to be transferred. val sourceType = projectRepository - ?.findSourceTypeByProjectIdAndSourceTypeId( + .findSourceTypeByProjectIdAndSourceTypeId( sourceDto.project.id, existingSource.sourceType!!.id ) @@ -256,9 +252,9 @@ open class SourceService { ) } // set old source-type, ensures compatibility - sourceDto.sourceType = sourceTypeMapper!!.sourceTypeToSourceTypeDTO(existingSource.sourceType) + sourceDto.sourceType = sourceTypeMapper.sourceTypeToSourceTypeDTO(existingSource.sourceType) } - return Optional.of(save(sourceDto)) + return save(sourceDto) } companion object { diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt index b48f35bfc..3317d9b05 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt @@ -33,8 +33,8 @@ abstract class SubjectMapperDecorator( } val dto = subjectToSubjectWithoutProjectDTO(subject) val project = subject.activeProject - .let { p -> projectRepository!!.findOneWithEagerRelationships(p?.id) } - dto!!.project = projectMapper!!.projectToProjectDTO(project) + .let { p -> projectRepository.findOneWithEagerRelationships(p?.id) } + dto!!.project = projectMapper.projectToProjectDTO(project) addAuditInfo(subject, dto) return dto } @@ -44,13 +44,13 @@ abstract class SubjectMapperDecorator( return null } val dto = subjectToSubjectWithoutProjectDTO(subject) - subject.activeProject?.let { project -> dto!!.project = projectMapper!!.projectToProjectDTOReduced(project) } + subject.activeProject?.let { project -> dto!!.project = projectMapper.projectToProjectDTOReduced(project) } addAuditInfo(subject, dto) return dto } private fun addAuditInfo(subject: Subject, dto: SubjectDTO?) { - val auditInfo = revisionService!!.getAuditInfo(subject) + val auditInfo = revisionService.getAuditInfo(subject) dto!!.createdDate = auditInfo.createdAt dto.createdBy = auditInfo.createdBy dto.lastModifiedDate = auditInfo.lastModifiedAt @@ -61,7 +61,7 @@ abstract class SubjectMapperDecorator( if (subject == null) { return null } - val dto = delegate!!.subjectToSubjectWithoutProjectDTO(subject) + val dto = delegate.subjectToSubjectWithoutProjectDTO(subject) dto!!.status = getSubjectStatus(subject) return dto } @@ -70,7 +70,7 @@ abstract class SubjectMapperDecorator( if (subjectDto == null) { return null } - val subject = delegate!!.subjectDTOToSubject(subjectDto) + val subject = delegate.subjectDTOToSubject(subjectDto) setSubjectStatus(subjectDto, subject) subject!!.group = getGroup(subjectDto) return subject diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt index aecb4af9a..efd23ea2e 100644 --- a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt @@ -210,7 +210,7 @@ class OAuthClientsResource { // lookup the subject val subject = subjectService!!.findOneByLogin(login) - val project: String = subject.activeProject + val projectName: String = subject.activeProject ?.projectName ?: throw NotFoundException( "Project for subject $login not found", EntityName.SUBJECT, @@ -221,7 +221,7 @@ class OAuthClientsResource { // Users who can update a subject can also generate a refresh token for that subject authService.checkPermission( Permission.SUBJECT_UPDATE, - { e: EntityDetails -> e.subject(login) }) + { e: EntityDetails -> e.project(projectName).subject(login) }) val cpi = metaTokenService!!.createMetaToken(subject, clientId, persistent!!) // generate audit event eventRepository!!.add( From 55698d3bf589e8e3921dd2d0d0718e0c13cd0dac Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:55:35 +0200 Subject: [PATCH 036/158] Rename .java to .kt --- .../web/rest/{SourceResource.java => SourceResource.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/web/rest/{SourceResource.java => SourceResource.kt} (100%) diff --git a/src/main/java/org/radarbase/management/web/rest/SourceResource.java b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/SourceResource.java rename to src/main/java/org/radarbase/management/web/rest/SourceResource.kt From 7876c5bcfb6100f20b551c5a5754700fcbf3165f Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:55:37 +0200 Subject: [PATCH 037/158] compiling again, but still some java classes --- .../org/radarbase/management/domain/Source.kt | 16 +- .../management/web/rest/SourceResource.kt | 325 ++++++++++-------- .../web/rest/SourceResourceIntTest.kt | 2 +- 3 files changed, 182 insertions(+), 161 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Source.kt b/src/main/java/org/radarbase/management/domain/Source.kt index 7e308f5f9..241f4a5b4 100644 --- a/src/main/java/org/radarbase/management/domain/Source.kt +++ b/src/main/java/org/radarbase/management/domain/Source.kt @@ -58,10 +58,10 @@ class Source : AbstractEntity, Serializable { var expectedSourceName: String? = null @Column(name = "assigned", nullable = false) - var isAssigned: @NotNull Boolean? = null + var isAssigned: @NotNull Boolean? = false @Column(name = "deleted", nullable = false) - var isDeleted: @NotNull Boolean? = false + var isDeleted: @NotNull Boolean = false @JvmField @ManyToOne(fetch = FetchType.EAGER) @@ -125,12 +125,12 @@ class Source : AbstractEntity, Serializable { } } - fun assigned(assigned: Boolean?): Source { + fun assigned(assigned: Boolean): Source { isAssigned = assigned return this } - fun deleted(deleted: Boolean?): Source { + fun deleted(deleted: Boolean): Source { isDeleted = deleted return this } @@ -155,14 +155,14 @@ class Source : AbstractEntity, Serializable { return this } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val source = o as Source + val source = other as Source return if (source.id == null || id == null) { false } else id == source.id && sourceId == source.sourceId diff --git a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt index 9841f7cd1..e00a6714e 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt @@ -1,107 +1,107 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.domain.Source; -import org.radarbase.management.repository.SourceRepository; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.SourceService; -import org.radarbase.management.service.dto.MinimalProjectDetailsDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.history.Revision; -import org.springframework.data.history.Revisions; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.List; -import java.util.Optional; - -import static org.radarbase.auth.authorization.Permission.SOURCE_CREATE; -import static org.radarbase.auth.authorization.Permission.SOURCE_DELETE; -import static org.radarbase.auth.authorization.Permission.SOURCE_READ; -import static org.radarbase.auth.authorization.Permission.SOURCE_UPDATE; -import static org.radarbase.auth.authorization.Permission.SUBJECT_READ; -import static tech.jhipster.web.util.ResponseUtil.wrapOrNotFound; +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.Source +import org.radarbase.management.repository.SourceRepository +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ResourceUriService +import org.radarbase.management.service.SourceService +import org.radarbase.management.service.dto.SourceDTO +import org.radarbase.management.web.rest.util.HeaderUtil +import org.radarbase.management.web.rest.util.PaginationUtil +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Pageable +import org.springframework.data.history.Revision +import org.springframework.data.web.PageableDefault +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.net.URISyntaxException +import java.util.* +import javax.validation.Valid /** * REST controller for managing Source. */ @RestController @RequestMapping("/api") -public class SourceResource { - - private static final Logger log = LoggerFactory.getLogger(SourceResource.class); - - private static final String ENTITY_NAME = "source"; - - @Autowired - private SourceService sourceService; - - @Autowired - private SourceRepository sourceRepository; - - @Autowired - private AuthService authService; +class SourceResource( + @Autowired private val sourceService: SourceService, + @Autowired private val sourceRepository: SourceRepository, + @Autowired private val authService: AuthService +) { /** * POST /sources : Create a new source. * * @param sourceDto the sourceDto to create * @return the ResponseEntity with status 201 (Created) and with body the new sourceDto, or with - * status 400 (Bad Request) if the source has already an ID + * status 400 (Bad Request) if the source has already an ID * @throws URISyntaxException if the Location URI syntax is incorrect */ @PostMapping("/sources") @Timed - public ResponseEntity createSource(@Valid @RequestBody SourceDTO sourceDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save Source : {}", sourceDto); - MinimalProjectDetailsDTO project = sourceDto.getProject(); - authService.checkPermission(SOURCE_CREATE, e -> { + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createSource(@RequestBody sourceDto: @Valid SourceDTO?): ResponseEntity { + log.debug("REST request to save Source : {}", sourceDto) + val project = sourceDto!!.project + authService.checkPermission(Permission.SOURCE_CREATE, { (_, project1): EntityDetails -> if (project != null) { - e.project(project.getProjectName()); + project1 } - }); - if (sourceDto.getId() != null) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, - "idexists", "A new source cannot already have an ID")).build(); - } else if (sourceDto.getSourceId() != null) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, - "sourceIdExists", "A new source cannot already have a Source ID")).build(); - } else if (sourceRepository.findOneBySourceName(sourceDto.getSourceName()).isPresent()) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, - "sourceNameExists", "Source name already in use")).build(); - } else if (sourceDto.getAssigned() == null) { - return ResponseEntity.badRequest() - .headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "sourceAssignedRequired", - "A new source must have the 'assigned' field specified")).body(null); + }) + return if (sourceDto.id != null) { + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, + "idexists", "A new source cannot already have an ID" + ) + ).build() + } else if (sourceDto.sourceId != null) { + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, + "sourceIdExists", "A new source cannot already have a Source ID" + ) + ).build() + } else if (sourceRepository.findOneBySourceName(sourceDto.sourceName).isPresent) { + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, + "sourceNameExists", "Source name already in use" + ) + ).build() + } else if (sourceDto.assigned == null) { + ResponseEntity.badRequest() + .headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, "sourceAssignedRequired", + "A new source must have the 'assigned' field specified" + ) + ).body(null) } else { - SourceDTO result = sourceService.save(sourceDto); - return ResponseEntity.created(ResourceUriService.getUri(result)) - .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, - result.getSourceName())) - .body(result); + val result = sourceService.save(sourceDto) + ResponseEntity.created(ResourceUriService.getUri(result)) + .headers( + HeaderUtil.createEntityCreationAlert( + ENTITY_NAME, + result.sourceName + ) + ) + .body(result) } } @@ -110,27 +110,30 @@ public class SourceResource { * * @param sourceDto the sourceDto to update * @return the ResponseEntity with status 200 (OK) and with body the updated sourceDto, or with - * status 400 (Bad Request) if the sourceDto is not valid, or with status 500 (Internal - * Server Error) if the sourceDto couldnt be updated + * status 400 (Bad Request) if the sourceDto is not valid, or with status 500 (Internal + * Server Error) if the sourceDto couldnt be updated * @throws URISyntaxException if the Location URI syntax is incorrect */ @PutMapping("/sources") @Timed - public ResponseEntity updateSource(@Valid @RequestBody SourceDTO sourceDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update Source : {}", sourceDto); - if (sourceDto.getId() == null) { - return createSource(sourceDto); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun updateSource(@RequestBody sourceDto: @Valid SourceDTO?): ResponseEntity { + log.debug("REST request to update Source : {}", sourceDto) + if (sourceDto!!.id == null) { + return createSource(sourceDto) } - MinimalProjectDetailsDTO project = sourceDto.getProject(); - authService.checkPermission(SOURCE_UPDATE, e -> { + val project = sourceDto.project + authService.checkPermission(Permission.SOURCE_UPDATE, { (_, project1): EntityDetails -> if (project != null) { - e.project(project.getProjectName()); + project1 } - }); - Optional updatedSource = sourceService.updateSource(sourceDto); - return wrapOrNotFound(updatedSource, - HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, sourceDto.getSourceName())); + }) + val updatedSource: SourceDTO? = sourceService.updateSource(sourceDto) + return ResponseEntity.ok().headers( + HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, sourceDto.sourceName) + ).body( + updatedSource + ) } /** @@ -140,15 +143,16 @@ public class SourceResource { */ @GetMapping("/sources") @Timed - public ResponseEntity> getAllSources( - @PageableDefault(page = 0, size = Integer.MAX_VALUE) Pageable pageable) - throws NotAuthorizedException { - authService.checkPermission(SUBJECT_READ); - log.debug("REST request to get all Sources"); - Page page = sourceService.findAll(pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/api/sources"); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + @Throws(NotAuthorizedException::class) + fun getAllSources( + @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable? + ): ResponseEntity> { + authService.checkPermission(Permission.SUBJECT_READ) + log.debug("REST request to get all Sources") + val page = sourceService.findAll(pageable) + val headers = PaginationUtil + .generatePaginationHttpHeaders(page, "/api/sources") + return ResponseEntity(page!!.content, headers, HttpStatus.OK) } /** @@ -156,26 +160,28 @@ public class SourceResource { * * @param sourceName the name of the sourceDTO to retrieve * @return the ResponseEntity with status 200 (OK) and with body the sourceDTO, or with status - * 404 (Not Found) + * 404 (Not Found) */ @GetMapping("/sources/{sourceName:" + Constants.ENTITY_ID_REGEX + "}") @Timed - public ResponseEntity getSource(@PathVariable String sourceName) - throws NotAuthorizedException { - log.debug("REST request to get Source : {}", sourceName); - authService.checkScope(SOURCE_READ); - Optional sourceOpt = sourceService.findOneByName(sourceName); - if (sourceOpt.isPresent()) { - SourceDTO source = sourceOpt.get(); - authService.checkPermission(SOURCE_READ, e -> { - if (source.getProject() != null) { - e.project(source.getProject().getProjectName()); + @Throws( + NotAuthorizedException::class + ) + fun getSource(@PathVariable sourceName: String?): ResponseEntity { + log.debug("REST request to get Source : {}", sourceName) + authService.checkScope(Permission.SOURCE_READ) + val sourceOpt = sourceService.findOneByName(sourceName) + if (sourceOpt.isPresent) { + val source = sourceOpt.get() + authService.checkPermission(Permission.SOURCE_READ, { (_, project, subject): EntityDetails -> + if (source.project != null) { + project } - e.subject(source.getSubjectLogin()) - .source(source.getSourceName()); - }); + subject + //.source(source.sourceName) + }) } - return wrapOrNotFound(sourceOpt); + return ResponseUtil.wrapOrNotFound(sourceOpt) } /** @@ -186,39 +192,54 @@ public class SourceResource { */ @DeleteMapping("/sources/{sourceName:" + Constants.ENTITY_ID_REGEX + "}") @Timed - public ResponseEntity deleteSource(@PathVariable String sourceName) - throws NotAuthorizedException { - log.debug("REST request to delete Source : {}", sourceName); - authService.checkScope(SOURCE_DELETE); - Optional sourceDtoOpt = sourceService.findOneByName(sourceName); - if (sourceDtoOpt.isEmpty()) { - return ResponseEntity.notFound().build(); + @Throws( + NotAuthorizedException::class + ) + fun deleteSource(@PathVariable sourceName: String?): ResponseEntity { + log.debug("REST request to delete Source : {}", sourceName) + authService.checkScope(Permission.SOURCE_DELETE) + val sourceDtoOpt = sourceService.findOneByName(sourceName) + if (sourceDtoOpt.isEmpty) { + return ResponseEntity.notFound().build() } - SourceDTO sourceDto = sourceDtoOpt.get(); - authService.checkPermission(SOURCE_DELETE, e -> { - if (sourceDto.getProject() != null) { - e.project(sourceDto.getProject().getProjectName()); + val sourceDto = sourceDtoOpt.get() + authService.checkPermission(Permission.SOURCE_DELETE, { (_, project, subject): EntityDetails -> + if (sourceDto.project != null) { + project } - e.subject(sourceDto.getSubjectLogin()) - .source(sourceDto.getSourceName()); - }); - - if (sourceDto.getAssigned()) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, - "sourceIsAssigned", "Cannot delete an assigned source")).build(); + subject + //.source(sourceDto.sourceName) + }) + if (sourceDto.assigned) { + return ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, + "sourceIsAssigned", "Cannot delete an assigned source" + ) + ).build() } - Long sourceId = sourceDtoOpt.get().getId(); - Revisions sourceHistory = sourceRepository.findRevisions(sourceId); - List sources = sourceHistory.getContent().stream().map(Revision::getEntity) - .filter(Source::isAssigned).toList(); - if (!sources.isEmpty()) { - HttpHeaders failureAlert = HeaderUtil.createFailureAlert(ENTITY_NAME, - "sourceRevisionIsAssigned", "Cannot delete a previously assigned source"); - return ResponseEntity.status(HttpStatus.CONFLICT).headers(failureAlert).build(); + val sourceId = sourceDtoOpt.get().id + val sourceHistory = sourceRepository.findRevisions(sourceId) + val sources = sourceHistory.content.mapNotNull { obj: Revision -> obj.entity } + .filter { it.isAssigned == true }.toList() + if (sources.isNotEmpty()) { + val failureAlert = HeaderUtil.createFailureAlert( + ENTITY_NAME, + "sourceRevisionIsAssigned", "Cannot delete a previously assigned source" + ) + return ResponseEntity.status(HttpStatus.CONFLICT).headers(failureAlert).build() } - sourceService.delete(sourceId); - return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, - sourceName)).build(); + sourceService.delete(sourceId) + return ResponseEntity.ok().headers( + HeaderUtil.createEntityDeletionAlert( + ENTITY_NAME, + sourceName + ) + ).build() } + companion object { + private val log = LoggerFactory.getLogger(SourceResource::class.java) + private const val ENTITY_NAME = "source" + } } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt index 936f9d6b9..04f5133ef 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt @@ -65,7 +65,7 @@ internal open class SourceResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val sourceResource = SourceResource() + val sourceResource = SourceResource ReflectionTestUtils.setField(sourceResource, "authService", authService) ReflectionTestUtils.setField(sourceResource, "sourceService", sourceService) ReflectionTestUtils.setField(sourceResource, "sourceRepository", sourceRepository) From 14d8f2b0cc0073b177be4659685f2bab198517fb Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 30 Oct 2023 17:05:58 +0100 Subject: [PATCH 038/158] Rename .java to .kt --- .../rest/{OrganizationResource.java => OrganizationResource.kt} | 0 .../web/rest/{RevisionResource.java => RevisionResource.kt} | 0 .../web/rest/{SourceDataResource.java => SourceDataResource.kt} | 0 .../web/rest/{SourceTypeResource.java => SourceTypeResource.kt} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/web/rest/{OrganizationResource.java => OrganizationResource.kt} (100%) rename src/main/java/org/radarbase/management/web/rest/{RevisionResource.java => RevisionResource.kt} (100%) rename src/main/java/org/radarbase/management/web/rest/{SourceDataResource.java => SourceDataResource.kt} (100%) rename src/main/java/org/radarbase/management/web/rest/{SourceTypeResource.java => SourceTypeResource.kt} (100%) diff --git a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.java b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/OrganizationResource.java rename to src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt diff --git a/src/main/java/org/radarbase/management/web/rest/RevisionResource.java b/src/main/java/org/radarbase/management/web/rest/RevisionResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/RevisionResource.java rename to src/main/java/org/radarbase/management/web/rest/RevisionResource.kt diff --git a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.java b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/SourceDataResource.java rename to src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt diff --git a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.java b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/SourceTypeResource.java rename to src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt From 22101110e78dd0fa95e35a55f7e1d9b79074d380 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 30 Oct 2023 17:06:00 +0100 Subject: [PATCH 039/158] main compiles, test does not --- .../config/OAuth2ServerConfiguration.kt | 65 ++-- .../org/radarbase/management/domain/Group.kt | 8 +- .../radarbase/management/domain/Project.kt | 4 +- .../org/radarbase/management/domain/User.kt | 2 +- .../filters/CustomHttpServletRequest.java | 35 -- .../filters/CustomHttpServletRequest.kt | 23 ++ .../CaseSensitivePhysicalNamingStrategy.java | 12 - .../CaseSensitivePhysicalNamingStrategy.kt | 10 + .../repository/AuthorityRepository.java | 21 -- .../repository/AuthorityRepository.kt | 17 + .../CustomAuditEventRepository.java | 75 ---- .../repository/CustomAuditEventRepository.kt | 71 ++++ .../CustomRevisionEntityRepository.java | 8 - .../CustomRevisionEntityRepository.kt | 6 + .../repository/MetaTokenRepository.java | 25 -- .../repository/MetaTokenRepository.kt | 22 ++ .../repository/OrganizationRepository.java | 29 -- .../repository/OrganizationRepository.kt | 28 ++ .../PersistenceAuditEventRepository.java | 27 -- .../PersistenceAuditEventRepository.kt | 28 ++ .../repository/ProjectRepository.kt | 25 +- .../management/repository/RoleRepository.java | 49 --- .../management/repository/RoleRepository.kt | 60 ++++ .../repository/SourceDataRepository.java | 18 - .../repository/SourceDataRepository.kt | 15 + .../repository/SourceRepository.java | 64 ---- .../management/repository/SourceRepository.kt | 65 ++++ .../repository/SourceTypeRepository.java | 56 --- .../repository/SourceTypeRepository.kt | 69 ++++ .../repository/SubjectRepository.java | 106 ------ .../repository/SubjectRepository.kt | 128 +++++++ .../management/repository/UserRepository.java | 48 --- .../management/repository/UserRepository.kt | 43 +++ .../repository/filters/PredicateBuilder.java | 197 ----------- .../repository/filters/PredicateBuilder.kt | 199 +++++++++++ .../filters/SubjectSpecification.java | 203 ----------- .../filters/SubjectSpecification.kt | 196 +++++++++++ .../repository/filters/UserFilter.java | 222 ------------ .../repository/filters/UserFilter.kt | 179 ++++++++++ .../management/repository/package-info.java | 4 - .../management/repository/package-info.kt | 5 + .../security/ClaimsTokenEnhancer.java | 151 -------- .../security/ClaimsTokenEnhancer.kt | 132 +++++++ .../management/security/Constants.java | 16 - .../management/security/Constants.kt | 12 + .../security/DomainUserDetailsService.java | 56 --- .../security/DomainUserDetailsService.kt | 47 +++ ....java => Http401UnauthorizedEntryPoint.kt} | 37 +- .../security/JwtAuthenticationFilter.kt | 13 +- .../security/PostgresApprovalStore.java | 222 ------------ .../security/PostgresApprovalStore.kt | 203 +++++++++++ .../security/RadarAuthentication.java | 112 ------ .../security/RadarAuthentication.kt | 92 +++++ .../security/RadarAuthenticationProvider.java | 30 -- .../security/RadarAuthenticationProvider.kt | 26 ++ .../management/security/SecurityUtils.java | 48 --- .../management/security/SecurityUtils.kt | 51 +++ .../security/UserNotActivatedException.java | 19 - .../security/UserNotActivatedException.kt | 15 + ...verter.java => JwtAccessTokenConverter.kt} | 48 ++- ...ManagementPortalJwtAccessTokenConverter.kt | 4 +- .../jwt/ManagementPortalJwtTokenStore.java | 198 ----------- .../jwt/ManagementPortalJwtTokenStore.kt | 189 ++++++++++ .../ManagementPortalOauthKeyStoreHandler.java | 324 ----------------- .../ManagementPortalOauthKeyStoreHandler.kt | 289 +++++++++++++++ .../security/jwt/SignatureException.java | 20 -- .../security/jwt/SignatureException.kt | 8 + .../jwt/algorithm/AsymmetricalJwtAlgorithm.kt | 24 ++ .../jwt/algorithm/EcdsaJwtAlgorithm.kt | 25 ++ .../security/jwt/algorithm/JwtAlgorithm.kt | 25 ++ .../security/jwt/algorithm/RsaJwtAlgorithm.kt | 25 ++ .../management/security/package-info.java | 4 - .../management/security/package-info.kt | 5 + .../management/service/AuditEventService.java | 57 --- .../management/service/AuditEventService.kt | 64 ++++ .../management/service/GroupService.kt | 114 +++--- .../management/service/MailService.java | 147 -------- .../management/service/MailService.kt | 157 +++++++++ .../management/service/MetaTokenService.kt | 13 +- .../service/OAuthClientService.java | 188 ---------- .../management/service/OAuthClientService.kt | 179 ++++++++++ .../service/OrganizationService.java | 134 ------- .../management/service/OrganizationService.kt | 110 ++++++ .../management/service/PasswordService.java | 107 ------ .../management/service/PasswordService.kt | 111 ++++++ .../management/service/ProjectService.kt | 53 +-- .../service/ResourceUriService.java | 150 -------- .../management/service/ResourceUriService.kt | 164 +++++++++ .../management/service/RevisionService.kt | 4 +- .../management/service/RoleService.kt | 131 +++---- .../service/SiteSettingsService.java | 37 -- .../management/service/SiteSettingsService.kt | 33 ++ .../management/service/SourceDataService.java | 119 ------- .../management/service/SourceDataService.kt | 109 ++++++ .../management/service/SourceService.kt | 49 ++- .../management/service/SourceTypeService.java | 242 ------------- .../management/service/SourceTypeService.kt | 245 +++++++++++++ .../management/service/SubjectService.kt | 155 ++++---- .../management/service/UserService.kt | 184 +++++----- .../service/catalog/CatalogSourceData.java | 139 -------- .../service/catalog/CatalogSourceData.kt | 61 ++++ .../service/catalog/CatalogSourceType.java | 112 ------ .../service/catalog/CatalogSourceType.kt | 58 +++ .../service/catalog/SampleRateConfig.java | 45 --- .../service/catalog/SampleRateConfig.kt | 26 ++ .../service/catalog/SourceTypeResponse.java | 37 -- .../service/catalog/SourceTypeResponse.kt | 19 + .../service/dto/AttributeMapDTO.java | 65 ---- .../management/service/dto/AttributeMapDTO.kt | 31 ++ .../management/service/dto/AuthorityDTO.java | 33 -- .../management/service/dto/AuthorityDTO.kt | 14 + .../service/dto/ClientDetailsDTO.java | 112 ------ .../service/dto/ClientDetailsDTO.kt | 20 ++ .../service/dto/ClientPairInfoDTO.java | 92 ----- .../service/dto/ClientPairInfoDTO.kt | 56 +++ .../management/service/dto/GroupDTO.java | 75 ---- .../management/service/dto/GroupDTO.kt | 38 ++ .../service/dto/MinimalProjectDetailsDTO.java | 27 -- .../service/dto/MinimalProjectDetailsDTO.kt | 9 + .../service/dto/MinimalSourceDetailsDTO.java | 163 --------- .../service/dto/MinimalSourceDetailsDTO.kt | 83 +++++ .../service/dto/MinimalSourceTypeDTO.java | 47 --- .../service/dto/MinimalSourceTypeDTO.kt | 11 + .../service/dto/OrganizationDTO.java | 99 ------ .../management/service/dto/OrganizationDTO.kt | 45 +++ .../management/service/dto/ProjectDTO.java | 209 ----------- .../management/service/dto/ProjectDTO.kt | 73 ++++ .../management/service/dto/RevisionDTO.java | 78 ----- .../management/service/dto/RevisionDTO.kt | 60 ++++ .../service/dto/RevisionInfoDTO.java | 89 ----- .../management/service/dto/RevisionInfoDTO.kt | 52 +++ .../management/service/dto/RoleDTO.java | 104 ------ .../management/service/dto/RoleDTO.kt | 38 ++ .../service/dto/SiteSettingsDto.java | 50 --- .../management/service/dto/SiteSettingsDto.kt | 33 ++ .../management/service/dto/SourceDTO.java | 152 -------- .../management/service/dto/SourceDTO.kt | 56 +++ .../management/service/dto/SourceDataDTO.java | 195 ----------- .../management/service/dto/SourceDataDTO.kt | 74 ++++ .../management/service/dto/SourceTypeDTO.java | 177 ---------- .../management/service/dto/SourceTypeDTO.kt | 64 ++++ .../management/service/dto/SubjectDTO.java | 256 -------------- .../management/service/dto/SubjectDTO.kt | 96 +++++ .../management/service/dto/TokenDTO.java | 66 ---- .../management/service/dto/TokenDTO.kt | 37 ++ .../management/service/dto/UserDTO.java | 177 ---------- .../management/service/dto/UserDTO.kt | 40 +++ .../management/service/dto/package-info.java | 6 - .../management/service/dto/package-info.kt | 8 + ...Mapper.java => CatalogSourceDataMapper.kt} | 22 +- ...Mapper.java => CatalogSourceTypeMapper.kt} | 19 +- .../service/mapper/ClientDetailsMapper.java | 80 ----- .../service/mapper/ClientDetailsMapper.kt | 72 ++++ .../{GroupMapper.java => GroupMapper.kt} | 32 +- .../service/mapper/OrganizationMapper.java | 30 -- .../service/mapper/OrganizationMapper.kt | 28 ++ .../service/mapper/ProjectMapper.java | 66 ---- .../service/mapper/ProjectMapper.kt | 66 ++++ .../mapper/{RoleMapper.java => RoleMapper.kt} | 35 +- .../service/mapper/SourceDataMapper.java | 49 --- .../service/mapper/SourceDataMapper.kt | 43 +++ .../service/mapper/SourceMapper.java | 51 --- .../management/service/mapper/SourceMapper.kt | 49 +++ .../service/mapper/SourceTypeMapper.java | 77 ---- .../service/mapper/SourceTypeMapper.kt | 69 ++++ .../ClientDetailsMapperDecorator.java | 44 --- .../decorator/ClientDetailsMapperDecorator.kt | 36 ++ .../decorator/ProjectMapperDecorator.java | 102 ------ .../decorator/ProjectMapperDecorator.kt | 77 ++++ .../mapper/decorator/RoleMapperDecorator.java | 41 --- .../mapper/decorator/RoleMapperDecorator.kt | 36 ++ .../decorator/SourceMapperDecorator.java | 66 ---- .../mapper/decorator/SourceMapperDecorator.kt | 61 ++++ .../decorator/SubjectMapperDecorator.kt | 22 +- .../mapper/decorator/UserMapperDecorator.java | 36 -- .../mapper/decorator/UserMapperDecorator.kt | 29 ++ .../{package-info.java => package-info.kt} | 3 +- .../management/service/package-info.java | 4 - .../management/service/package-info.kt | 5 + .../management/web/rest/AccountResource.java | 233 ------------- .../management/web/rest/AccountResource.kt | 234 +++++++++++++ .../management/web/rest/AuditResource.java | 90 ----- .../management/web/rest/AuditResource.kt | 77 ++++ .../management/web/rest/GroupResource.java | 156 --------- .../management/web/rest/GroupResource.kt | 160 +++++++++ .../management/web/rest/LogsResource.java | 54 --- .../management/web/rest/LogsResource.kt | 53 +++ .../web/rest/OAuthClientsResource.kt | 6 +- .../web/rest/OrganizationResource.kt | 232 ++++++------ .../management/web/rest/ProjectResource.kt | 59 ++-- .../management/web/rest/RevisionResource.kt | 71 ++-- .../management/web/rest/RoleResource.java | 160 --------- .../management/web/rest/RoleResource.kt | 174 +++++++++ .../management/web/rest/SourceDataResource.kt | 210 +++++------ .../management/web/rest/SourceResource.kt | 109 +++--- .../management/web/rest/SourceTypeResource.kt | 330 ++++++++++-------- .../management/web/rest/SubjectResource.kt | 74 ++-- .../management/web/rest/UserResource.kt | 33 +- .../web/rest/criteria/CriteriaRange.java | 72 ---- .../web/rest/criteria/CriteriaRange.kt | 41 +++ ...iaRange.java => LocalDateCriteriaRange.kt} | 8 +- ...jectAuthority.java => SubjectAuthority.kt} | 7 +- .../web/rest/criteria/SubjectCriteria.java | 238 ------------- .../web/rest/criteria/SubjectCriteria.kt | 125 +++++++ .../rest/criteria/SubjectCriteriaLast.java | 49 --- .../web/rest/criteria/SubjectCriteriaLast.kt | 16 + .../web/rest/criteria/SubjectSortBy.java | 34 -- .../web/rest/criteria/SubjectSortBy.kt | 21 ++ .../web/rest/criteria/SubjectSortOrder.java | 68 ---- .../web/rest/criteria/SubjectSortOrder.kt | 38 ++ ...nge.java => ZonedDateTimeCriteriaRange.kt} | 8 +- .../web/rest/errors/BadRequestException.java | 38 -- .../web/rest/errors/BadRequestException.kt | 38 ++ .../web/rest/errors/ConflictException.java | 44 --- .../web/rest/errors/ConflictException.kt | 44 +++ .../web/rest/errors/EntityName.java | 17 - .../management/web/rest/errors/EntityName.kt | 17 + .../web/rest/errors/ErrorConstants.java | 48 --- .../web/rest/errors/ErrorConstants.kt | 42 +++ .../management/web/rest/errors/ErrorVM.java | 52 --- .../management/web/rest/errors/ErrorVM.kt | 31 ++ .../web/rest/errors/ExceptionTranslator.java | 209 ----------- .../web/rest/errors/ExceptionTranslator.kt | 224 ++++++++++++ .../web/rest/errors/FieldErrorVM.java | 39 --- .../web/rest/errors/FieldErrorVM.kt | 16 + .../rest/errors/InvalidRequestException.java | 37 -- .../rest/errors/InvalidRequestException.kt | 36 ++ .../rest/errors/InvalidStateException.java | 36 -- .../web/rest/errors/InvalidStateException.kt | 35 ++ .../web/rest/errors/NotFoundException.java | 39 --- .../web/rest/errors/NotFoundException.kt | 40 +++ .../errors/RadarWebApplicationException.java | 87 ----- .../errors/RadarWebApplicationException.kt | 60 ++++ .../RadarWebApplicationExceptionVM.java | 98 ------ .../errors/RadarWebApplicationExceptionVM.kt | 63 ++++ .../web/rest/errors/RequestGoneException.java | 38 -- .../web/rest/errors/RequestGoneException.kt | 37 ++ .../management/web/rest/package-info.java | 4 - .../management/web/rest/package-info.kt | 5 + .../management/web/rest/util/HeaderUtil.java | 105 ------ .../management/web/rest/util/HeaderUtil.kt | 103 ++++++ .../web/rest/util/PaginationUtil.java | 139 -------- .../web/rest/util/PaginationUtil.kt | 151 ++++++++ .../web/rest/vm/GroupPatchOperation.kt | 19 + .../web/rest/vm/KeyAndPasswordVM.kt | 9 + .../management/web/rest/vm/LoggerVM.kt | 27 ++ .../management/web/rest/vm/ManagedUserVM.kt | 19 + .../management/web/rest/vm/package-info.kt | 5 + 248 files changed, 8214 insertions(+), 10127 deletions(-) delete mode 100644 src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.java create mode 100644 src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.kt delete mode 100644 src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.java create mode 100644 src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.kt delete mode 100644 src/main/java/org/radarbase/management/repository/AuthorityRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/AuthorityRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/MetaTokenRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/MetaTokenRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/OrganizationRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/OrganizationRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/RoleRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/RoleRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/SourceDataRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/SourceDataRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/SourceRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/SourceRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/SourceTypeRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/SourceTypeRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/SubjectRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/SubjectRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/UserRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/UserRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.java create mode 100644 src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt delete mode 100644 src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.java create mode 100644 src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt delete mode 100644 src/main/java/org/radarbase/management/repository/filters/UserFilter.java create mode 100644 src/main/java/org/radarbase/management/repository/filters/UserFilter.kt delete mode 100644 src/main/java/org/radarbase/management/repository/package-info.java create mode 100644 src/main/java/org/radarbase/management/repository/package-info.kt delete mode 100644 src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java create mode 100644 src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt delete mode 100644 src/main/java/org/radarbase/management/security/Constants.java create mode 100644 src/main/java/org/radarbase/management/security/Constants.kt delete mode 100644 src/main/java/org/radarbase/management/security/DomainUserDetailsService.java create mode 100644 src/main/java/org/radarbase/management/security/DomainUserDetailsService.kt rename src/main/java/org/radarbase/management/security/{Http401UnauthorizedEntryPoint.java => Http401UnauthorizedEntryPoint.kt} (65%) delete mode 100644 src/main/java/org/radarbase/management/security/PostgresApprovalStore.java create mode 100644 src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt delete mode 100644 src/main/java/org/radarbase/management/security/RadarAuthentication.java create mode 100644 src/main/java/org/radarbase/management/security/RadarAuthentication.kt delete mode 100644 src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.java create mode 100644 src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.kt delete mode 100644 src/main/java/org/radarbase/management/security/SecurityUtils.java create mode 100644 src/main/java/org/radarbase/management/security/SecurityUtils.kt delete mode 100644 src/main/java/org/radarbase/management/security/UserNotActivatedException.java create mode 100644 src/main/java/org/radarbase/management/security/UserNotActivatedException.kt rename src/main/java/org/radarbase/management/security/jwt/{JwtAccessTokenConverter.java => JwtAccessTokenConverter.kt} (57%) delete mode 100644 src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.java create mode 100644 src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.kt delete mode 100644 src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.java create mode 100644 src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt delete mode 100644 src/main/java/org/radarbase/management/security/jwt/SignatureException.java create mode 100644 src/main/java/org/radarbase/management/security/jwt/SignatureException.kt create mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.kt create mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.kt create mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.kt create mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.kt delete mode 100644 src/main/java/org/radarbase/management/security/package-info.java create mode 100644 src/main/java/org/radarbase/management/security/package-info.kt delete mode 100644 src/main/java/org/radarbase/management/service/AuditEventService.java create mode 100644 src/main/java/org/radarbase/management/service/AuditEventService.kt delete mode 100644 src/main/java/org/radarbase/management/service/MailService.java create mode 100644 src/main/java/org/radarbase/management/service/MailService.kt delete mode 100644 src/main/java/org/radarbase/management/service/OAuthClientService.java create mode 100644 src/main/java/org/radarbase/management/service/OAuthClientService.kt delete mode 100644 src/main/java/org/radarbase/management/service/OrganizationService.java create mode 100644 src/main/java/org/radarbase/management/service/OrganizationService.kt delete mode 100644 src/main/java/org/radarbase/management/service/PasswordService.java create mode 100644 src/main/java/org/radarbase/management/service/PasswordService.kt delete mode 100644 src/main/java/org/radarbase/management/service/ResourceUriService.java create mode 100644 src/main/java/org/radarbase/management/service/ResourceUriService.kt delete mode 100644 src/main/java/org/radarbase/management/service/SiteSettingsService.java create mode 100644 src/main/java/org/radarbase/management/service/SiteSettingsService.kt delete mode 100644 src/main/java/org/radarbase/management/service/SourceDataService.java create mode 100644 src/main/java/org/radarbase/management/service/SourceDataService.kt delete mode 100644 src/main/java/org/radarbase/management/service/SourceTypeService.java create mode 100644 src/main/java/org/radarbase/management/service/SourceTypeService.kt delete mode 100644 src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.java create mode 100644 src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.kt delete mode 100644 src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.java create mode 100644 src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.kt delete mode 100644 src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.java create mode 100644 src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.kt delete mode 100644 src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.java create mode 100644 src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/AuthorityDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/AuthorityDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/GroupDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/GroupDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/OrganizationDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/ProjectDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/RevisionDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/RevisionDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/RoleDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/RoleDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.java create mode 100644 src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/SourceDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/SourceDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/SourceDataDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/SubjectDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/TokenDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/TokenDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/UserDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/UserDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/package-info.java create mode 100644 src/main/java/org/radarbase/management/service/dto/package-info.kt rename src/main/java/org/radarbase/management/service/mapper/{CatalogSourceDataMapper.java => CatalogSourceDataMapper.kt} (55%) rename src/main/java/org/radarbase/management/service/mapper/{CatalogSourceTypeMapper.java => CatalogSourceTypeMapper.kt} (56%) delete mode 100644 src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt rename src/main/java/org/radarbase/management/service/mapper/{GroupMapper.java => GroupMapper.kt} (53%) delete mode 100644 src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/ProjectMapper.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/ProjectMapper.kt rename src/main/java/org/radarbase/management/service/mapper/{RoleMapper.java => RoleMapper.kt} (52%) delete mode 100644 src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/SourceMapper.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/SourceMapper.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt rename src/main/java/org/radarbase/management/service/mapper/{package-info.java => package-info.kt} (62%) delete mode 100644 src/main/java/org/radarbase/management/service/package-info.java create mode 100644 src/main/java/org/radarbase/management/service/package-info.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/AccountResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/AccountResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/AuditResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/AuditResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/GroupResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/GroupResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/LogsResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/LogsResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/RoleResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/RoleResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.java create mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt rename src/main/java/org/radarbase/management/web/rest/criteria/{LocalDateCriteriaRange.java => LocalDateCriteriaRange.kt} (60%) rename src/main/java/org/radarbase/management/web/rest/criteria/{SubjectAuthority.java => SubjectAuthority.kt} (69%) delete mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.java create mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.java create mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.java create mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.java create mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt rename src/main/java/org/radarbase/management/web/rest/criteria/{ZonedDateTimeCriteriaRange.java => ZonedDateTimeCriteriaRange.kt} (58%) delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ConflictException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ConflictException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/EntityName.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/EntityName.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/package-info.java create mode 100644 src/main/java/org/radarbase/management/web/rest/package-info.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.java create mode 100644 src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.java create mode 100644 src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt create mode 100644 src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.kt create mode 100644 src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.kt create mode 100644 src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.kt create mode 100644 src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.kt create mode 100644 src/main/java/org/radarbase/management/web/rest/vm/package-info.kt diff --git a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt index ee0d02c04..ce5b0ecc8 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt @@ -2,7 +2,6 @@ package org.radarbase.management.config import org.radarbase.auth.authorization.RoleAuthority import org.radarbase.management.repository.UserRepository -import org.radarbase.management.security.ClaimsTokenEnhancer import org.radarbase.management.security.Http401UnauthorizedEntryPoint import org.radarbase.management.security.JwtAuthenticationFilter import org.radarbase.management.security.PostgresApprovalStore @@ -42,7 +41,6 @@ import org.springframework.security.oauth2.provider.client.JdbcClientDetailsServ import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices import org.springframework.security.oauth2.provider.token.DefaultTokenServices -import org.springframework.security.oauth2.provider.token.TokenEnhancer import org.springframework.security.oauth2.provider.token.TokenEnhancerChain import org.springframework.security.oauth2.provider.token.TokenStore import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter @@ -66,6 +64,7 @@ open class OAuth2ServerConfiguration { @Autowired private val jwtAuthenticationFilter: JwtAuthenticationFilter? = null + @Throws(Exception::class) override fun configure(http: HttpSecurity) { http @@ -97,10 +96,11 @@ open class OAuth2ServerConfiguration { @Autowired private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null + @Bean open fun jwtAuthenticationFilter(): JwtAuthenticationFilter { return JwtAuthenticationFilter( - keyStoreHandler!!.getTokenValidator(), + keyStoreHandler!!.tokenValidator, authenticationManager!!, userRepository!!, true @@ -117,27 +117,18 @@ open class OAuth2ServerConfiguration { @Configuration @EnableResourceServer - protected open class ResourceServerConfiguration : ResourceServerConfigurerAdapter() { - @Autowired - private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null - - @Autowired - private val tokenStore: TokenStore? = null - - @Autowired - private val http401UnauthorizedEntryPoint: Http401UnauthorizedEntryPoint? = null - - @Autowired - private val logoutSuccessHandler: LogoutSuccessHandler? = null + protected open class ResourceServerConfiguration( + @Autowired private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler, + @Autowired private val tokenStore: TokenStore, + @Autowired private val http401UnauthorizedEntryPoint: Http401UnauthorizedEntryPoint, + @Autowired private val logoutSuccessHandler: LogoutSuccessHandler, + @Autowired private val authenticationManager: AuthenticationManager, + @Autowired private val userRepository: UserRepository + ) : ResourceServerConfigurerAdapter() { - @Autowired - private val authenticationManager: AuthenticationManager? = null - - @Autowired - private val userRepository: UserRepository? = null fun jwtAuthenticationFilter(): JwtAuthenticationFilter { return JwtAuthenticationFilter( - keyStoreHandler!!.getTokenValidator(), authenticationManager!!, userRepository!! + keyStoreHandler.tokenValidator, authenticationManager, userRepository ) .skipUrlPattern(HttpMethod.GET, "/management/health") .skipUrlPattern(HttpMethod.GET, "/api/meta-token/*") @@ -209,22 +200,14 @@ open class OAuth2ServerConfiguration { @Configuration @EnableAuthorizationServer - protected open class AuthorizationServerConfiguration : AuthorizationServerConfigurerAdapter() { - @Autowired - private val jpaProperties: JpaProperties? = null - - @Autowired - @Qualifier("authenticationManagerBean") - private val authenticationManager: AuthenticationManager? = null - - @Autowired - private val dataSource: DataSource? = null + protected open class AuthorizationServerConfiguration( + @Autowired private val jpaProperties: JpaProperties, + @Autowired @Qualifier("authenticationManagerBean") private val authenticationManager: AuthenticationManager, + @Autowired private val dataSource: DataSource, + @Autowired private val jdbcClientDetailsService: JdbcClientDetailsService, + @Autowired private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler + ) : AuthorizationServerConfigurerAdapter() { - @Autowired - private val jdbcClientDetailsService: JdbcClientDetailsService? = null - - @Autowired - private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null @Bean protected open fun authorizationCodeServices(): AuthorizationCodeServices { return JdbcAuthorizationCodeServices(dataSource) @@ -240,11 +223,6 @@ open class OAuth2ServerConfiguration { } } - @Bean - open fun tokenEnhancer(): TokenEnhancer { - return ClaimsTokenEnhancer() - } - @Bean open fun tokenStore(): TokenStore { return ManagementPortalJwtTokenStore(accessTokenConverter()) @@ -254,7 +232,7 @@ open class OAuth2ServerConfiguration { open fun accessTokenConverter(): ManagementPortalJwtAccessTokenConverter { logger.debug("loading token converter from keystore configurations") return ManagementPortalJwtAccessTokenConverter( - keyStoreHandler!!.getAlgorithmForSigning(), + keyStoreHandler.algorithmForSigning, keyStoreHandler.verifiers, keyStoreHandler.refreshTokenVerifiers ) @@ -273,7 +251,8 @@ open class OAuth2ServerConfiguration { override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) { val tokenEnhancerChain = TokenEnhancerChain() tokenEnhancerChain.setTokenEnhancers( - Arrays.asList(tokenEnhancer(), accessTokenConverter()) + //TODO listOf(tokenEnhancer(), accessTokenConverter()) + listOf(accessTokenConverter()) ) endpoints .authorizationCodeServices(authorizationCodeServices()) diff --git a/src/main/java/org/radarbase/management/domain/Group.kt b/src/main/java/org/radarbase/management/domain/Group.kt index 539378939..1f527bdf9 100644 --- a/src/main/java/org/radarbase/management/domain/Group.kt +++ b/src/main/java/org/radarbase/management/domain/Group.kt @@ -48,14 +48,14 @@ class Group : AbstractEntity(), Serializable { @JoinColumn(name = "project_id", nullable = false) @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) var project: Project? = null - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val group = o as Group + val group = other as Group return if (group.id == null || id == null) { false } else id == group.id diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index a6da31807..bc36271a5 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -56,11 +56,9 @@ class Project : AbstractEntity(), Serializable { @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") override var id: Long? = null - @JvmField @Column(name = "project_name", nullable = false, unique = true) var projectName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null - @JvmField @Column(name = "description", nullable = false) var description: @NotNull String? = null @@ -113,7 +111,7 @@ class Project : AbstractEntity(), Serializable { @MapKeyColumn(name = "attribute_key") @Column(name = "attribute_value") @CollectionTable(name = "project_metadata", joinColumns = [JoinColumn(name = "id")]) - var attributes: Map = HashMap() + var attributes: MutableMap = HashMap() @JvmField @set:JsonSetter(nulls = Nulls.AS_EMPTY) diff --git a/src/main/java/org/radarbase/management/domain/User.kt b/src/main/java/org/radarbase/management/domain/User.kt index ddf37bf9b..a0bcd307b 100644 --- a/src/main/java/org/radarbase/management/domain/User.kt +++ b/src/main/java/org/radarbase/management/domain/User.kt @@ -47,7 +47,7 @@ class User : AbstractEntity(), Serializable { override var id: Long? = null @Column(length = 50, unique = true, nullable = false) - var login: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) String? = null + lateinit var login: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) String private set @JvmField diff --git a/src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.java b/src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.java deleted file mode 100644 index 43b1f4d62..000000000 --- a/src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.radarbase.management.filters; - -import java.util.HashMap; -import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; - -public class CustomHttpServletRequest extends HttpServletRequestWrapper { - - private final Map additionalParams; - private final HttpServletRequest request; - - /** - * Create a new instance with the given request and additional parameters. - * - * @param request the request - * @param additionalParams the additional parameters - */ - public CustomHttpServletRequest(final HttpServletRequest request, - final Map additionalParams) { - super(request); - this.request = request; - this.additionalParams = additionalParams; - } - - @Override - public Map getParameterMap() { - final Map map = request.getParameterMap(); - final Map param = new HashMap<>(); - param.putAll(map); - param.putAll(additionalParams); - return param; - } - -} diff --git a/src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.kt b/src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.kt new file mode 100644 index 000000000..45c423b13 --- /dev/null +++ b/src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.kt @@ -0,0 +1,23 @@ +package org.radarbase.management.filters + +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletRequestWrapper + +class CustomHttpServletRequest +/** + * Create a new instance with the given request and additional parameters. + * + * @param request the request + * @param additionalParams the additional parameters + */( + private val request: HttpServletRequest, + private val additionalParams: Map> +) : HttpServletRequestWrapper(request) { + override fun getParameterMap(): Map> { + val map = request.parameterMap + val param: MutableMap> = HashMap() + param.putAll(map) + param.putAll(additionalParams) + return param + } +} diff --git a/src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.java b/src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.java deleted file mode 100644 index 8925d15b4..000000000 --- a/src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.radarbase.management.hibernate; - -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; -import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; - -public class CaseSensitivePhysicalNamingStrategy extends SpringPhysicalNamingStrategy { - - @Override - protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) { - return false; - } -} diff --git a/src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.kt b/src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.kt new file mode 100644 index 000000000..f410fd901 --- /dev/null +++ b/src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.kt @@ -0,0 +1,10 @@ +package org.radarbase.management.hibernate + +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment +import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + +class CaseSensitivePhysicalNamingStrategy : SpringPhysicalNamingStrategy() { + override fun isCaseInsensitive(jdbcEnvironment: JdbcEnvironment): Boolean { + return false + } +} diff --git a/src/main/java/org/radarbase/management/repository/AuthorityRepository.java b/src/main/java/org/radarbase/management/repository/AuthorityRepository.java deleted file mode 100644 index 577516ae6..000000000 --- a/src/main/java/org/radarbase/management/repository/AuthorityRepository.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.radarbase.management.repository; - -import org.radarbase.management.domain.Authority; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -import java.util.Optional; - -/** - * Spring Data JPA repository for the Authority entity. - */ -@RepositoryDefinition(domainClass = Authority.class, idClass = String.class) -public interface AuthorityRepository extends JpaRepository, - RevisionRepository { - - @Query("select authority from Authority authority where authority.name = :authorityName") - Optional findByAuthorityName(@Param("authorityName") String authorityName); -} diff --git a/src/main/java/org/radarbase/management/repository/AuthorityRepository.kt b/src/main/java/org/radarbase/management/repository/AuthorityRepository.kt new file mode 100644 index 000000000..a34d17d0c --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/AuthorityRepository.kt @@ -0,0 +1,17 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Authority +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param + +/** + * Spring Data JPA repository for the Authority entity. + */ +@RepositoryDefinition(domainClass = Authority::class, idClass = String::class) +interface AuthorityRepository : JpaRepository, RevisionRepository { + @Query("select authority from Authority authority where authority.name = :authorityName") + fun findByAuthorityName(@Param("authorityName") authorityName: String): Authority? +} diff --git a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java deleted file mode 100644 index 48af8daa1..000000000 --- a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.radarbase.management.repository; - -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.List; - -import ch.qos.logback.classic.pattern.TargetLengthBasedClassNameAbbreviator; -import org.radarbase.management.config.audit.AuditEventConverter; -import org.radarbase.management.domain.PersistentAuditEvent; -import org.radarbase.management.security.Constants; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.boot.actuate.audit.AuditEventRepository; -import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.annotation.Transactional; - -/** - * An implementation of Spring Boot's AuditEventRepository. - */ -@Repository -public class CustomAuditEventRepository implements AuditEventRepository { - private static final Logger logger = LoggerFactory.getLogger(CustomAuditEventRepository.class); - - private static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE"; - - private static final TargetLengthBasedClassNameAbbreviator TYPE_ABBREVIATOR = - new TargetLengthBasedClassNameAbbreviator(15); - - @Autowired - private PersistenceAuditEventRepository persistenceAuditEventRepository; - - @Autowired - private AuditEventConverter auditEventConverter; - - @Override - public List find(String principal, Instant after, String type) { - Iterable persistentAuditEvents = - persistenceAuditEventRepository - .findByPrincipalAndAuditEventDateAfterAndAuditEventType(principal, - LocalDateTime.from(after), type); - return auditEventConverter.convertToAuditEvent(persistentAuditEvents); - } - - @Override - @Transactional(propagation = Propagation.REQUIRES_NEW) - public void add(AuditEvent event) { - var eventType = event.getType(); - if (!AUTHORIZATION_FAILURE.equals(eventType) - && !Constants.ANONYMOUS_USER.equals(event.getPrincipal())) { - PersistentAuditEvent persistentAuditEvent = new PersistentAuditEvent(); - persistentAuditEvent.principal = event.getPrincipal(); - persistentAuditEvent.auditEventType = eventType; - persistentAuditEvent.auditEventDate = LocalDateTime.ofInstant(event.getTimestamp(), - ZoneId.systemDefault()); - persistentAuditEvent.setData(auditEventConverter.convertDataToStrings(event.getData())); - persistenceAuditEventRepository.save(persistentAuditEvent); - } - if (eventType != null && eventType.endsWith("_FAILURE")) { - Object typeObj = event.getData().get("type"); - String errorType = typeObj instanceof String - ? TYPE_ABBREVIATOR.abbreviate((String) typeObj) - : null; - logger.warn("{}: principal={}, error={}, message=\"{}\", details={}", - eventType, - event.getPrincipal(), - errorType, - event.getData().get("message"), - event.getData().get("details")); - } - } -} diff --git a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt new file mode 100644 index 000000000..018ae7ea4 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt @@ -0,0 +1,71 @@ +package org.radarbase.management.repository + +import ch.qos.logback.classic.pattern.TargetLengthBasedClassNameAbbreviator +import org.radarbase.management.config.audit.AuditEventConverter +import org.radarbase.management.domain.PersistentAuditEvent +import org.radarbase.management.security.Constants +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.boot.actuate.audit.AuditEventRepository +import org.springframework.stereotype.Repository +import org.springframework.transaction.annotation.Propagation +import org.springframework.transaction.annotation.Transactional +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId + +/** + * An implementation of Spring Boot's AuditEventRepository. + */ +@Repository +open class CustomAuditEventRepository( + @Autowired private val auditEventConverter: AuditEventConverter, + @Autowired private val persistenceAuditEventRepository: PersistenceAuditEventRepository +) : AuditEventRepository { + + override fun find(principal: String, after: Instant, type: String): List { + val persistentAuditEvents: Iterable? = persistenceAuditEventRepository + ?.findByPrincipalAndAuditEventDateAfterAndAuditEventType( + principal, + LocalDateTime.from(after), type + ) + return auditEventConverter.convertToAuditEvent(persistentAuditEvents) + } + + @Transactional(propagation = Propagation.REQUIRES_NEW) + override fun add(event: AuditEvent) { + val eventType = event.type + if (AUTHORIZATION_FAILURE != eventType + && Constants.ANONYMOUS_USER != event.principal + ) { + val persistentAuditEvent = PersistentAuditEvent() + persistentAuditEvent.principal = event.principal + persistentAuditEvent.auditEventType = eventType + persistentAuditEvent.auditEventDate = LocalDateTime.ofInstant( + event.timestamp, + ZoneId.systemDefault() + ) + persistentAuditEvent.data = auditEventConverter!!.convertDataToStrings(event.data) + persistenceAuditEventRepository!!.save(persistentAuditEvent) + } + if (eventType != null && eventType.endsWith("_FAILURE")) { + val typeObj = event.data["type"] + val errorType = if (typeObj is String) TYPE_ABBREVIATOR.abbreviate(typeObj as String?) else null + logger.warn( + "{}: principal={}, error={}, message=\"{}\", details={}", + eventType, + event.principal, + errorType, + event.data["message"], + event.data["details"] + ) + } + } + + companion object { + private val logger = LoggerFactory.getLogger(CustomAuditEventRepository::class.java) + private const val AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE" + private val TYPE_ABBREVIATOR = TargetLengthBasedClassNameAbbreviator(15) + } +} diff --git a/src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.java b/src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.java deleted file mode 100644 index c6f7fb604..000000000 --- a/src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.radarbase.management.repository; - -import org.radarbase.management.domain.audit.CustomRevisionEntity; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface CustomRevisionEntityRepository extends JpaRepository { -} diff --git a/src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.kt b/src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.kt new file mode 100644 index 000000000..e977d6c44 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.kt @@ -0,0 +1,6 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.audit.CustomRevisionEntity +import org.springframework.data.jpa.repository.JpaRepository + +interface CustomRevisionEntityRepository : JpaRepository diff --git a/src/main/java/org/radarbase/management/repository/MetaTokenRepository.java b/src/main/java/org/radarbase/management/repository/MetaTokenRepository.java deleted file mode 100644 index 9b9bc3931..000000000 --- a/src/main/java/org/radarbase/management/repository/MetaTokenRepository.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.radarbase.management.repository; - -import java.time.Instant; -import java.util.List; -import java.util.Optional; - -import org.radarbase.management.domain.MetaToken; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -/** - * Spring Data JPA repository for the MetaToken entity. - */ -public interface MetaTokenRepository extends JpaRepository, - RevisionRepository { - - Optional findOneByTokenName(String tokenName); - - @Query("select metaToken from MetaToken metaToken " - + "where (metaToken.fetched = true and metaToken.persistent = false)" - + " or metaToken.expiryDate < :time") - List findAllByFetchedOrExpired(@Param("time")Instant time); -} diff --git a/src/main/java/org/radarbase/management/repository/MetaTokenRepository.kt b/src/main/java/org/radarbase/management/repository/MetaTokenRepository.kt new file mode 100644 index 000000000..c954fecd8 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/MetaTokenRepository.kt @@ -0,0 +1,22 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.MetaToken +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param +import java.time.Instant + +/** + * Spring Data JPA repository for the MetaToken entity. + */ +interface MetaTokenRepository : JpaRepository, RevisionRepository { + fun findOneByTokenName(tokenName: String?): MetaToken? + + @Query( + "select metaToken from MetaToken metaToken " + + "where (metaToken.fetched = true and metaToken.persistent = false)" + + " or metaToken.expiryDate < :time" + ) + fun findAllByFetchedOrExpired(@Param("time") time: Instant?): List +} diff --git a/src/main/java/org/radarbase/management/repository/OrganizationRepository.java b/src/main/java/org/radarbase/management/repository/OrganizationRepository.java deleted file mode 100644 index 423bda374..000000000 --- a/src/main/java/org/radarbase/management/repository/OrganizationRepository.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.radarbase.management.repository; - -import java.util.Collection; -import java.util.List; -import java.util.Optional; - -import org.radarbase.management.domain.Organization; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -/** - * Spring Data JPA repository for the Organization entity. - */ -@RepositoryDefinition(domainClass = Organization.class, idClass = Long.class) -public interface OrganizationRepository extends JpaRepository, - RevisionRepository { - - @Query("select org from Organization org " - + "where org.name = :name") - Optional findOneByName(@Param("name") String name); - - @Query("select distinct org from Organization org left join fetch org.projects project " - + "where project.projectName in (:projectNames)") - List findAllByProjectNames( - @Param("projectNames") Collection projectNames); -} diff --git a/src/main/java/org/radarbase/management/repository/OrganizationRepository.kt b/src/main/java/org/radarbase/management/repository/OrganizationRepository.kt new file mode 100644 index 000000000..d471e710a --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/OrganizationRepository.kt @@ -0,0 +1,28 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Organization +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param + +/** + * Spring Data JPA repository for the Organization entity. + */ +@RepositoryDefinition(domainClass = Organization::class, idClass = Long::class) +interface OrganizationRepository : JpaRepository, RevisionRepository { + @Query( + "select org from Organization org " + + "where org.name = :name" + ) + fun findOneByName(@Param("name") name: String): Organization? + + @Query( + "select distinct org from Organization org left join fetch org.projects project " + + "where project.projectName in (:projectNames)" + ) + fun findAllByProjectNames( + @Param("projectNames") projectNames: Collection + ): List +} diff --git a/src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.java b/src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.java deleted file mode 100644 index 80c8fa417..000000000 --- a/src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.radarbase.management.repository; - -import java.time.LocalDateTime; -import java.util.List; -import org.radarbase.management.domain.PersistentAuditEvent; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; - -/** - * Spring Data JPA repository for the PersistentAuditEvent entity. - */ -public interface PersistenceAuditEventRepository extends JpaRepository { - - List findByPrincipal(String principal); - - List findByAuditEventDateAfter(LocalDateTime after); - - List findByPrincipalAndAuditEventDateAfter(String principal, - LocalDateTime after); - - List findByPrincipalAndAuditEventDateAfterAndAuditEventType( - String principle, LocalDateTime after, String type); - - Page findAllByAuditEventDateBetween(LocalDateTime fromDate, - LocalDateTime toDate, Pageable pageable); -} diff --git a/src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.kt b/src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.kt new file mode 100644 index 000000000..00b4bff3a --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.kt @@ -0,0 +1,28 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.PersistentAuditEvent +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import java.time.LocalDateTime + +/** + * Spring Data JPA repository for the PersistentAuditEvent entity. + */ +interface PersistenceAuditEventRepository : JpaRepository { + fun findByPrincipal(principal: String?): List? + fun findByAuditEventDateAfter(after: LocalDateTime?): List? + fun findByPrincipalAndAuditEventDateAfter( + principal: String?, + after: LocalDateTime? + ): List? + + fun findByPrincipalAndAuditEventDateAfterAndAuditEventType( + principle: String?, after: LocalDateTime?, type: String? + ): List + + fun findAllByAuditEventDateBetween( + fromDate: LocalDateTime?, + toDate: LocalDateTime?, pageable: Pageable? + ): Page +} diff --git a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt index bc0e44b8f..9dfd6b7be 100644 --- a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt +++ b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt @@ -9,20 +9,19 @@ import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.RepositoryDefinition import org.springframework.data.repository.history.RevisionRepository import org.springframework.data.repository.query.Param -import java.util.* /** * Spring Data JPA repository for the Project entity. */ @Suppress("unused") @RepositoryDefinition(domainClass = Project::class, idClass = Long::class) -interface ProjectRepository : JpaRepository, RevisionRepository { +interface ProjectRepository : JpaRepository, RevisionRepository { @Query( value = "select distinct project from Project project " + "left join fetch project.sourceTypes", countQuery = "select distinct count(project) from Project project" ) - fun findAllWithEagerRelationships(pageable: Pageable?): Page? + fun findAllWithEagerRelationships(pageable: Pageable): Page @Query( value = "select distinct project from Project project " @@ -35,17 +34,17 @@ interface ProjectRepository : JpaRepository, RevisionRepository ) fun findAllWithEagerRelationshipsInOrganizationsOrProjects( pageable: Pageable?, - @Param("organizationNames") organizationNames: Collection?, - @Param("projectNames") projectNames: Collection? - ): Page? + @Param("organizationNames") organizationNames: Collection, + @Param("projectNames") projectNames: Collection + ): Page @Query( "select project from Project project " + "WHERE project.organization.name = :organization_name" ) fun findAllByOrganizationName( - @Param("organization_name") organizationName: String? - ): List? + @Param("organization_name") organizationName: String + ): List @Query( "select project from Project project " @@ -54,7 +53,7 @@ interface ProjectRepository : JpaRepository, RevisionRepository + "left join fetch project.organization " + "where project.id = :id" ) - fun findOneWithEagerRelationships(@Param("id") id: Long?): Project? + fun findOneWithEagerRelationships(@Param("id") id: Long): Project? @Query( "select project from Project project " @@ -76,17 +75,17 @@ interface ProjectRepository : JpaRepository, RevisionRepository "select project.id from Project project " + "where project.projectName =:name" ) - fun findProjectIdByName(@Param("name") name: String?): Long? + fun findProjectIdByName(@Param("name") name: String): Long? @Query( "select project from Project project " + "left join fetch project.groups " + "where project.projectName = :name" ) - fun findOneWithGroupsByName(@Param("name") name: String?): Project? + fun findOneWithGroupsByName(@Param("name") name: String): Project? @Query("select project.sourceTypes from Project project WHERE project.id = :id") - fun findSourceTypesByProjectId(@Param("id") id: Long?): List? + fun findSourceTypesByProjectId(@Param("id") id: Long): List @Query( "select distinct sourceType from Project project " @@ -97,5 +96,5 @@ interface ProjectRepository : JpaRepository, RevisionRepository fun findSourceTypeByProjectIdAndSourceTypeId( @Param("id") id: Long?, @Param("sourceTypeId") sourceTypeId: Long? - ): Optional? + ): SourceType? } diff --git a/src/main/java/org/radarbase/management/repository/RoleRepository.java b/src/main/java/org/radarbase/management/repository/RoleRepository.java deleted file mode 100644 index c91c6e9da..000000000 --- a/src/main/java/org/radarbase/management/repository/RoleRepository.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.radarbase.management.repository; - -import java.util.List; -import java.util.Optional; -import org.radarbase.management.domain.Role; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -/** - * Created by nivethika on 18-5-17. - */ -@SuppressWarnings("unused") -@RepositoryDefinition(domainClass = Role.class, idClass = Long.class) -public interface RoleRepository extends JpaRepository, - RevisionRepository { - - @Query("select role from Role role inner join role.authority authority" - + " where authority.name = :authorityName") - List findRolesByAuthorityName(@Param("authorityName") String authorityName); - - @Query("select distinct role from Role role left join fetch role.authority") - List findAllWithEagerRelationships(); - - @Query("select role from Role role join role.authority " - + "where role.organization.id = :organizationId " - + "and role.authority.name = :authorityName") - Optional findOneByOrganizationIdAndAuthorityName( - @Param("organizationId") Long organizationId, - @Param("authorityName") String authorityName); - - @Query("select role from Role role join role.authority " - + "where role.project.id = :projectId " - + "and role.authority.name = :authorityName") - Optional findOneByProjectIdAndAuthorityName(@Param("projectId") Long projectId, - @Param("authorityName") String authorityName); - - @Query("select role from Role role join role.authority join role.project " - + "where role.project.projectName = :projectName " - + "and role.authority.name = :authorityName") - Optional findOneByProjectNameAndAuthorityName(@Param("projectName") String projectName, - @Param("authorityName") String authorityName); - - @Query("select role from Role role left join fetch role.authority " - + "where role.project.projectName = :projectName") - List findAllRolesByProjectName(@Param("projectName") String projectName); -} diff --git a/src/main/java/org/radarbase/management/repository/RoleRepository.kt b/src/main/java/org/radarbase/management/repository/RoleRepository.kt new file mode 100644 index 000000000..7b6a47f35 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/RoleRepository.kt @@ -0,0 +1,60 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Role +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param + +/** + * Created by nivethika on 18-5-17. + */ +@Suppress("unused") +@RepositoryDefinition(domainClass = Role::class, idClass = Long::class) +interface RoleRepository : JpaRepository, RevisionRepository { + @Query( + "select role from Role role inner join role.authority authority" + + " where authority.name = :authorityName" + ) + fun findRolesByAuthorityName(@Param("authorityName") authorityName: String?): List + + @Query("select distinct role from Role role left join fetch role.authority") + fun findAllWithEagerRelationships(): List + + @Query( + "select role from Role role join role.authority " + + "where role.organization.id = :organizationId " + + "and role.authority.name = :authorityName" + ) + fun findOneByOrganizationIdAndAuthorityName( + @Param("organizationId") organizationId: Long?, + @Param("authorityName") authorityName: String? + ): Role? + + @Query( + "select role from Role role join role.authority " + + "where role.project.id = :projectId " + + "and role.authority.name = :authorityName" + ) + fun findOneByProjectIdAndAuthorityName( + @Param("projectId") projectId: Long?, + @Param("authorityName") authorityName: String? + ): Role? + + @Query( + "select role from Role role join role.authority join role.project " + + "where role.project.projectName = :projectName " + + "and role.authority.name = :authorityName" + ) + fun findOneByProjectNameAndAuthorityName( + @Param("projectName") projectName: String?, + @Param("authorityName") authorityName: String? + ): Role? + + @Query( + "select role from Role role left join fetch role.authority " + + "where role.project.projectName = :projectName" + ) + fun findAllRolesByProjectName(@Param("projectName") projectName: String): List +} diff --git a/src/main/java/org/radarbase/management/repository/SourceDataRepository.java b/src/main/java/org/radarbase/management/repository/SourceDataRepository.java deleted file mode 100644 index 4944f0533..000000000 --- a/src/main/java/org/radarbase/management/repository/SourceDataRepository.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.radarbase.management.repository; - -import java.util.Optional; -import org.radarbase.management.domain.SourceData; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; - -/** - * Spring Data JPA repository for the SourceData entity. - */ -@SuppressWarnings("unused") -@RepositoryDefinition(domainClass = SourceData.class, idClass = Long.class) -public interface SourceDataRepository extends JpaRepository, - RevisionRepository { - - Optional findOneBySourceDataName(String sourceDataName); -} diff --git a/src/main/java/org/radarbase/management/repository/SourceDataRepository.kt b/src/main/java/org/radarbase/management/repository/SourceDataRepository.kt new file mode 100644 index 000000000..83d3079b4 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/SourceDataRepository.kt @@ -0,0 +1,15 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.SourceData +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository + +/** + * Spring Data JPA repository for the SourceData entity. + */ +@Suppress("unused") +@RepositoryDefinition(domainClass = SourceData::class, idClass = Long::class) +interface SourceDataRepository : JpaRepository, RevisionRepository { + fun findOneBySourceDataName(sourceDataName: String?): SourceData? +} diff --git a/src/main/java/org/radarbase/management/repository/SourceRepository.java b/src/main/java/org/radarbase/management/repository/SourceRepository.java deleted file mode 100644 index f1327649e..000000000 --- a/src/main/java/org/radarbase/management/repository/SourceRepository.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.radarbase.management.repository; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import org.radarbase.management.domain.Source; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -/** - * Spring Data JPA repository for the Source entity. - */ -@RepositoryDefinition(domainClass = Source.class, idClass = Long.class) -public interface SourceRepository extends JpaRepository, - RevisionRepository { - - @Override - @Query(value = "select source from Source source " - + "WHERE source.deleted = false", - countQuery = "select count(source) from Source source " - + "WHERE source.deleted = false") - Page findAll(Pageable pageable); - - @Query(value = "select source from Source source " - + "WHERE source.deleted = false " - + "AND source.project.id = :projectId", - countQuery = "select count(source) from Source source " - + "WHERE source.deleted = false " - + "AND source.project.id = :projectId") - Page findAllSourcesByProjectId(Pageable pageable, @Param("projectId") Long projectId); - - @Query(value = "select source from Source source " - + "WHERE source.deleted = false " - + "AND source.project.id = :projectId " - + "AND source.assigned = :assigned", - countQuery = "select count(source) from Source source " - + "WHERE source.deleted = false " - + "AND source.project.id = :projectId " - + "AND source.assigned = :assigned") - List findAllSourcesByProjectIdAndAssigned(@Param("projectId") Long projectId, - @Param("assigned") Boolean assigned); - - @Query(value = "select source from Source source " - + "WHERE source.deleted = false " - + "AND source.sourceId = :sourceId", - countQuery = "select count(source) from Source source " - + "WHERE source.deleted = false " - + "AND source.sourceId = :sourceId") - Optional findOneBySourceId(@Param("sourceId") UUID sourceId); - - @Query(value = "select source from Source source " - + "WHERE source.deleted = false " - + "AND source.sourceName = :sourceName", - countQuery = "select count(source) from Source source " - + "WHERE source.deleted = false " - + "AND source.sourceName = :sourceName") - Optional findOneBySourceName(@Param("sourceName") String sourceName); -} diff --git a/src/main/java/org/radarbase/management/repository/SourceRepository.kt b/src/main/java/org/radarbase/management/repository/SourceRepository.kt new file mode 100644 index 000000000..a11861da6 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/SourceRepository.kt @@ -0,0 +1,65 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Source +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param +import java.util.* + +/** + * Spring Data JPA repository for the Source entity. + */ +@RepositoryDefinition(domainClass = Source::class, idClass = Long::class) +interface SourceRepository : JpaRepository, RevisionRepository { + @Query( + value = "select source from Source source " + + "WHERE source.isDeleted = false", countQuery = "select count(source) from Source source " + + "WHERE source.isDeleted = false" + ) + override fun findAll(pageable: Pageable): Page + + @Query( + value = "select source from Source source " + + "WHERE source.isDeleted = false " + + "AND source.project.id = :projectId", countQuery = "select count(source) from Source source " + + "WHERE source.isDeleted = false " + + "AND source.project.id = :projectId" + ) + fun findAllSourcesByProjectId(pageable: Pageable, @Param("projectId") projectId: Long): Page + + @Query( + value = "select source from Source source " + + "WHERE source.isDeleted = false " + + "AND source.project.id = :projectId " + + "AND source.isAssigned = :assigned", countQuery = "select count(source) from Source source " + + "WHERE source.isDeleted = false " + + "AND source.project.id = :projectId " + + "AND source.isAssigned = :assigned" + ) + fun findAllSourcesByProjectIdAndAssigned( + @Param("projectId") projectId: Long?, + @Param("assigned") assigned: Boolean? + ): List + + @Query( + value = "select source from Source source " + + "WHERE source.isDeleted = false " + + "AND source.sourceId = :sourceId", countQuery = "select count(source) from Source source " + + "WHERE source.isDeleted = false " + + "AND source.sourceId = :sourceId" + ) + fun findOneBySourceId(@Param("sourceId") sourceId: UUID?): Source? + + @Query( + value = "select source from Source source " + + "WHERE source.isDeleted = false " + + "AND source.sourceName = :sourceName", countQuery = "select count(source) from Source source " + + "WHERE source.isDeleted = false " + + "AND source.sourceName = :sourceName" + ) + fun findOneBySourceName(@Param("sourceName") sourceName: String): Source? +} diff --git a/src/main/java/org/radarbase/management/repository/SourceTypeRepository.java b/src/main/java/org/radarbase/management/repository/SourceTypeRepository.java deleted file mode 100644 index fdfaf2006..000000000 --- a/src/main/java/org/radarbase/management/repository/SourceTypeRepository.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.radarbase.management.repository; - -import java.util.List; -import java.util.Optional; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.SourceType; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -/** - * Spring Data JPA repository for the SourceType entity. - */ -@SuppressWarnings("unused") -@RepositoryDefinition(domainClass = SourceType.class, idClass = Long.class) -public interface SourceTypeRepository extends JpaRepository, - RevisionRepository { - - @Query("select distinct sourceType from SourceType sourceType left join fetch sourceType" - + ".sourceData") - List findAllWithEagerRelationships(); - - @Query("select case when count(sourceType) > 0 then true else false end " - + "from SourceType sourceType " - + "where sourceType.producer = :producer " - + "and sourceType.model = :model " - + "and sourceType.catalogVersion = :version") - boolean hasOneByProducerAndModelAndVersion( - @Param("producer") String producer, @Param("model") String model, - @Param("version") String version); - - @Query("select sourceType from SourceType sourceType left join fetch sourceType.sourceData " - + "where sourceType.producer = :producer " - + "and sourceType.model = :model " - + "and sourceType.catalogVersion = :version") - Optional findOneWithEagerRelationshipsByProducerAndModelAndVersion( - @Param("producer") String producer, @Param("model") String model, - @Param("version") String version); - - @Query("select sourceType from SourceType sourceType left join fetch sourceType.sourceData " - + "where sourceType.producer =:producer") - List findWithEagerRelationshipsByProducer(@Param("producer") String producer); - - @Query("select sourceType from SourceType sourceType left join fetch sourceType.sourceData " - + "where sourceType.producer =:producer and sourceType.model =:model") - List findWithEagerRelationshipsByProducerAndModel( - @Param("producer") String producer, @Param("model") String model); - - @Query("select distinct sourceType.projects from SourceType sourceType left join sourceType" - + ".projects where sourceType.producer =:producer and sourceType.model =:model " - + "and sourceType.catalogVersion = :version") - List findProjectsBySourceType(@Param("producer") String producer, - @Param("model") String model, @Param("version") String version); -} diff --git a/src/main/java/org/radarbase/management/repository/SourceTypeRepository.kt b/src/main/java/org/radarbase/management/repository/SourceTypeRepository.kt new file mode 100644 index 000000000..69686686f --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/SourceTypeRepository.kt @@ -0,0 +1,69 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.SourceType +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param + +/** + * Spring Data JPA repository for the SourceType entity. + */ +@Suppress("unused") +@RepositoryDefinition(domainClass = SourceType::class, idClass = Long::class) +interface SourceTypeRepository : JpaRepository, RevisionRepository { + @Query( + "select distinct sourceType from SourceType sourceType left join fetch sourceType" + + ".sourceData" + ) + fun findAllWithEagerRelationships(): List + + @Query( + "select case when count(sourceType) > 0 then true else false end " + + "from SourceType sourceType " + + "where sourceType.producer = :producer " + + "and sourceType.model = :model " + + "and sourceType.catalogVersion = :version" + ) + fun hasOneByProducerAndModelAndVersion( + @Param("producer") producer: String, @Param("model") model: String, + @Param("version") version: String + ): Boolean + + @Query( + "select sourceType from SourceType sourceType left join fetch sourceType.sourceData " + + "where sourceType.producer = :producer " + + "and sourceType.model = :model " + + "and sourceType.catalogVersion = :version" + ) + fun findOneWithEagerRelationshipsByProducerAndModelAndVersion( + @Param("producer") producer: String, @Param("model") model: String, + @Param("version") version: String + ): SourceType? + + @Query( + "select sourceType from SourceType sourceType left join fetch sourceType.sourceData " + + "where sourceType.producer =:producer" + ) + fun findWithEagerRelationshipsByProducer(@Param("producer") producer: String): List + + @Query( + "select sourceType from SourceType sourceType left join fetch sourceType.sourceData " + + "where sourceType.producer =:producer and sourceType.model =:model" + ) + fun findWithEagerRelationshipsByProducerAndModel( + @Param("producer") producer: String, @Param("model") model: String + ): List + + @Query( + "select distinct sourceType.projects from SourceType sourceType left join sourceType" + + ".projects where sourceType.producer =:producer and sourceType.model =:model " + + "and sourceType.catalogVersion = :version" + ) + fun findProjectsBySourceType( + @Param("producer") producer: String, + @Param("model") model: String, @Param("version") version: String + ): List +} diff --git a/src/main/java/org/radarbase/management/repository/SubjectRepository.java b/src/main/java/org/radarbase/management/repository/SubjectRepository.java deleted file mode 100644 index d4d76670a..000000000 --- a/src/main/java/org/radarbase/management/repository/SubjectRepository.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.radarbase.management.repository; - -import org.radarbase.management.domain.Source; -import org.radarbase.management.domain.Subject; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -/** - * Spring Data JPA repository for the Subject entity. - */ -@SuppressWarnings("unused") -@RepositoryDefinition(domainClass = Subject.class, idClass = Long.class) -public interface SubjectRepository extends JpaRepository, - RevisionRepository, - JpaSpecificationExecutor { - - @Query("SELECT count(*) from Subject subject " - + "WHERE subject.group.id = :group_id") - long countByGroupId(@Param("group_id") Long groupId); - - @Query(value = "select distinct subject from Subject subject left join fetch subject.sources " - + "left join fetch subject.user user " - + "join user.roles roles where roles.project.projectName = :projectName and roles" - + ".authority.name in :authorities", - countQuery = "select distinct count(subject) from Subject subject " - + "left join subject.user user left join user.roles roles " - + "where roles.project.projectName = :projectName and roles" - + ".authority.name in :authorities") - Page findAllByProjectNameAndAuthoritiesIn(Pageable pageable, - @Param("projectName") String projectName, - @Param("authorities") List authorities); - - @Query("select subject from Subject subject " - + "left join fetch subject.sources " - + "WHERE subject.user.login = :login") - Optional findOneWithEagerBySubjectLogin(@Param("login") String login); - - @Query("select subject from Subject subject " - + "WHERE subject.user.login in :logins") - List findAllBySubjectLogins(@Param("logins") List logins); - - @Modifying - @Query("UPDATE Subject subject " - + "SET subject.group.id = :groupId " - + "WHERE subject.id in :ids") - void setGroupIdByIds( - @Param("groupId") Long groupId, - @Param("ids") List ids); - - @Modifying - @Query("UPDATE Subject subject " - + "SET subject.group.id = null " - + "WHERE subject.id in :ids") - void unsetGroupIdByIds(@Param("ids") List ids); - - @Query("select subject.sources from Subject subject WHERE subject.id = :id") - List findSourcesBySubjectId(@Param("id") Long id); - - @Query("select subject.sources from Subject subject WHERE subject.user.login = :login") - List findSourcesBySubjectLogin(@Param("login") String login); - - @Query("select distinct subject from Subject subject left join fetch subject.sources " - + "left join fetch subject.user user " - + "join user.roles roles where roles.project.projectName = :projectName " - + "and subject.externalId = :externalId") - Optional findOneByProjectNameAndExternalId(@Param("projectName") String projectName, - @Param("externalId") String externalId); - - @Query("select distinct subject from Subject subject left join fetch subject.sources " - + "left join fetch subject.user user " - + "join user.roles roles where roles.project.projectName = :projectName " - + "and roles.authority.name in :authorities " - + "and subject.externalId = :externalId") - Optional findOneByProjectNameAndExternalIdAndAuthoritiesIn(@Param("projectName") String - projectName, @Param("externalId") String externalId, - @Param("authorities") List authorities); - - @Query("select subject.sources from Subject subject left join subject.sources sources " - + "join sources.sourceType sourceType " - + "where sourceType.producer = :producer " - + "and sourceType.model = :model " - + "and sourceType.catalogVersion =:version " - + "and subject.user.login = :login") - List findSubjectSourcesBySourceType(@Param("login") String login, - @Param("producer") String producer, @Param("model") String model, - @Param("version") String version); - - @Query("select distinct subject.sources from Subject subject left join subject.sources sources " - + "where sources.sourceId= :sourceId " - + "and subject.user.login = :login") - Optional findSubjectSourcesBySourceId(@Param("login") String login, - @Param("sourceId") UUID sourceId); - - -} diff --git a/src/main/java/org/radarbase/management/repository/SubjectRepository.kt b/src/main/java/org/radarbase/management/repository/SubjectRepository.kt new file mode 100644 index 000000000..ac0738a87 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/SubjectRepository.kt @@ -0,0 +1,128 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Source +import org.radarbase.management.domain.Subject +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.JpaSpecificationExecutor +import org.springframework.data.jpa.repository.Modifying +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param +import java.util.* + +/** + * Spring Data JPA repository for the Subject entity. + */ +@Suppress("unused") +@RepositoryDefinition(domainClass = Subject::class, idClass = Long::class) +interface SubjectRepository : JpaRepository, RevisionRepository, + JpaSpecificationExecutor { + @Query( + "SELECT count(*) from Subject subject " + + "WHERE subject.group.id = :group_id" + ) + fun countByGroupId(@Param("group_id") groupId: Long?): Long + + @Query( + value = "select distinct subject from Subject subject left join fetch subject.sources " + + "left join fetch subject.user user " + + "join user.roles roles where roles.project.projectName = :projectName and roles" + + ".authority.name in :authorities", countQuery = "select distinct count(subject) from Subject subject " + + "left join subject.user user left join user.roles roles " + + "where roles.project.projectName = :projectName and roles" + + ".authority.name in :authorities" + ) + fun findAllByProjectNameAndAuthoritiesIn( + pageable: Pageable?, + @Param("projectName") projectName: String?, + @Param("authorities") authorities: List? + ): Page? + + @Query( + "select subject from Subject subject " + + "left join fetch subject.sources " + + "WHERE subject.user.login = :login" + ) + fun findOneWithEagerBySubjectLogin(@Param("login") login: String?): Subject? + + @Query( + "select subject from Subject subject " + + "WHERE subject.user.login in :logins" + ) + fun findAllBySubjectLogins(@Param("logins") logins: List): List + + @Modifying + @Query( + "UPDATE Subject subject " + + "SET subject.group.id = :groupId " + + "WHERE subject.id in :ids" + ) + fun setGroupIdByIds( + @Param("groupId") groupId: Long, + @Param("ids") ids: List + ) + + @Modifying + @Query( + "UPDATE Subject subject " + + "SET subject.group.id = null " + + "WHERE subject.id in :ids" + ) + fun unsetGroupIdByIds(@Param("ids") ids: List) + + @Query("select subject.sources from Subject subject WHERE subject.id = :id") + fun findSourcesBySubjectId(@Param("id") id: Long): List + + @Query("select subject.sources from Subject subject WHERE subject.user.login = :login") + fun findSourcesBySubjectLogin(@Param("login") login: String?): List + + @Query( + "select distinct subject from Subject subject left join fetch subject.sources " + + "left join fetch subject.user user " + + "join user.roles roles where roles.project.projectName = :projectName " + + "and subject.externalId = :externalId" + ) + fun findOneByProjectNameAndExternalId( + @Param("projectName") projectName: String?, + @Param("externalId") externalId: String? + ): Subject? + + @Query( + "select distinct subject from Subject subject left join fetch subject.sources " + + "left join fetch subject.user user " + + "join user.roles roles where roles.project.projectName = :projectName " + + "and roles.authority.name in :authorities " + + "and subject.externalId = :externalId" + ) + fun findOneByProjectNameAndExternalIdAndAuthoritiesIn( + @Param("projectName") projectName: String, @Param("externalId") externalId: String, + @Param("authorities") authorities: List + ): Subject? + + @Query( + "select subject.sources from Subject subject left join subject.sources sources " + + "join sources.sourceType sourceType " + + "where sourceType.producer = :producer " + + "and sourceType.model = :model " + + "and sourceType.catalogVersion =:version " + + "and subject.user.login = :login" + ) + fun findSubjectSourcesBySourceType( + @Param("login") login: String?, + @Param("producer") producer: String?, @Param("model") model: String?, + @Param("version") version: String? + ): List? + + @Query( + "select distinct subject.sources from Subject subject left join subject.sources sources " + + "where sources.sourceId= :sourceId " + + "and subject.user.login = :login" + ) + fun findSubjectSourcesBySourceId( + @Param("login") login: String?, + @Param("sourceId") sourceId: UUID + ): Source? +} diff --git a/src/main/java/org/radarbase/management/repository/UserRepository.java b/src/main/java/org/radarbase/management/repository/UserRepository.java deleted file mode 100644 index 48b2066ea..000000000 --- a/src/main/java/org/radarbase/management/repository/UserRepository.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.radarbase.management.repository; - -import org.radarbase.management.domain.User; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.EntityGraph; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Optional; - -/** - * Spring Data JPA repository for the User entity. - */ -@RepositoryDefinition(domainClass = User.class, idClass = Long.class) -@Component -public interface UserRepository extends JpaRepository, - RevisionRepository, JpaSpecificationExecutor { - - Optional findOneByActivationKey(String activationKey); - - List findAllByActivated(boolean activated); - - @Query("select user from User user " - + "left join fetch user.roles roles where " - + "roles.authority.name not in :authorities " - + "and user.activated= :activated") - List findAllByActivatedAndAuthoritiesNot(@Param("activated") boolean activated, - @Param("authorities") List authorities); - - Optional findOneByResetKey(String resetKey); - - Optional findOneByEmail(String email); - - Optional findOneByLogin(String login); - - @EntityGraph(attributePaths = {"roles", "roles.authority.name"}) - Optional findOneWithRolesByLogin(String login); - - Page findAllByLoginNot(Pageable pageable, String login); - -} diff --git a/src/main/java/org/radarbase/management/repository/UserRepository.kt b/src/main/java/org/radarbase/management/repository/UserRepository.kt new file mode 100644 index 000000000..f1071863e --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/UserRepository.kt @@ -0,0 +1,43 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.User +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.EntityGraph +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.JpaSpecificationExecutor +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param +import org.springframework.stereotype.Component + +/** + * Spring Data JPA repository for the User entity. + */ +@RepositoryDefinition(domainClass = User::class, idClass = Long::class) +@Component +interface UserRepository : JpaRepository, RevisionRepository, + JpaSpecificationExecutor { + fun findOneByActivationKey(activationKey: String): User? + fun findAllByActivated(activated: Boolean): List + + @Query( + "select user from User user " + + "left join fetch user.roles roles where " + + "roles.authority.name not in :authorities " + + "and user.activated= :activated" + ) + fun findAllByActivatedAndAuthoritiesNot( + @Param("activated") activated: Boolean, + @Param("authorities") authorities: List + ): List + + fun findOneByResetKey(resetKey: String): User? + fun findOneByEmail(email: String): User? + fun findOneByLogin(login: String): User? + + @EntityGraph(attributePaths = ["roles", "roles.authority.name"]) + fun findOneWithRolesByLogin(login: String): User? + fun findAllByLoginNot(pageable: Pageable, login: String): Page +} diff --git a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.java b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.java deleted file mode 100644 index 7868877b5..000000000 --- a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.repository.filters; - -import org.radarbase.management.domain.Subject; -import org.radarbase.management.web.rest.criteria.CriteriaRange; - -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.Expression; -import javax.persistence.criteria.JoinType; -import javax.persistence.criteria.MapJoin; -import javax.persistence.criteria.Path; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Locale; -import java.util.function.Supplier; - -public class PredicateBuilder { - private final List predicates; - private final CriteriaBuilder builder; - - public PredicateBuilder(CriteriaBuilder builder) { - this.predicates = new ArrayList<>(); - this.builder = builder; - } - - /** Add predicate to query. */ - public void add(Predicate predicate) { - if (predicate == null) { - return; - } - predicates.add(predicate); - } - - public void isNull(Expression expression) { - predicates.add(builder.isNull(expression)); - } - - /** - * Build the predicates as an AND predicate. - */ - public Predicate toAndPredicate() { - if (this.predicates.size() == 1) { - return this.predicates.get(0); - } else if (!this.predicates.isEmpty()) { - return builder.and(this.predicates.toArray(new Predicate[0])); - } else { - return null; - } - } - - /** - * Build the predicates as an AND predicate. - */ - public Predicate toOrPredicate() { - if (this.predicates.size() == 1) { - return this.predicates.get(0); - } else if (!this.predicates.isEmpty()) { - return builder.or(this.predicates.toArray(new Predicate[0])); - } else { - return null; - } - } - - /** - * Add an equal criteria to predicates if value is not null or empty. - * @param path entity path - * @param value value to compare with - * @param type of field. - */ - public void equal(Supplier> path, T value) { - if (isValidValue(value)) { - add(builder.equal(path.get(), value)); - } - } - - /** - * Add an equal criteria to predicates if value is not null or empty. - * @param path entity path - * @param value value to compare with - * @param type of field. - */ - public void equal(Expression path, T value) { - if (isValidValue(value)) { - add(builder.equal(path, value)); - } - } - - /** - * Add a like criteria to predicates if value is not null or empty, matching both sides. - * @param path entity path - * @param value value to compare with - */ - public void likeLower(Supplier> path, String value) { - if (isValidValue(value)) { - add(builder.like(builder.lower(path.get()), - "%" + value.trim().toLowerCase(Locale.ROOT) + "%")); - } - } - - /** - * Add a like criteria to predicates if value is not null or empty, matching both sides. - * @param path entity path - * @param value value to compare with - */ - public void likeLower(Expression path, String value) { - if (isValidValue(value)) { - add(builder.like(builder.lower(path), - "%" + value.trim().toLowerCase(Locale.ROOT) + "%")); - } - } - - /** - * Add a like criteria to predicates if value is not null or empty, matching both sides. - * @param root entity to fetch attributes from. - * @param attributeKey name of the attribute. - * @param attributeValue value to compare with using a like query. - */ - public void attributeLike(Root root, String attributeKey, - String attributeValue) { - if (isValidValue(attributeValue)) { - MapJoin attributesJoin = - root.joinMap("attributes", JoinType.LEFT); - add(builder.and( - builder.equal(attributesJoin.key(), attributeKey), - builder.like(attributesJoin.value(), - "%" + attributeValue + "%"))); - } - } - - public void in(Expression expr, Expression other) { - add(expr.in(other)); - } - - public void in(Expression expr, Collection other) { - add(expr.in(other)); - } - - /** - * Add comparable criteria matching given range. - * @param path entity property path. - * @param range range that should be matched. - */ - public > void range( - Path path, CriteriaRange range) { - if (range == null || range.isEmpty()) { - return; - } - range.validate(); - if (range.getIs() != null) { - add(builder.equal(path, range.getIs())); - } else { - if (range.getFrom() != null && range.getTo() != null) { - add(builder.between(path, range.getFrom(), range.getTo())); - } else if (range.getFrom() != null) { - add(builder.greaterThanOrEqualTo(path, range.getFrom())); - } else if (range.getTo() != null) { - add(builder.lessThanOrEqualTo(path, range.getTo())); - } - } - } - - /** - * Whether given String a proper value. - */ - public boolean isValidValue(Object value) { - if (value == null) { - return false; - } - if (value instanceof String str) { - return !str.isBlank() && !str.equals("null"); - } - return true; - } - - public PredicateBuilder newBuilder() { - return new PredicateBuilder(builder); - } - - public CriteriaBuilder getCriteriaBuilder() { - return builder; - } - - public boolean isEmpty() { - return this.predicates.isEmpty(); - } -} diff --git a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt new file mode 100644 index 000000000..aa1b5bb75 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.repository.filters + +import org.radarbase.management.domain.Subject +import org.radarbase.management.web.rest.criteria.CriteriaRange +import java.util.function.Supplier +import javax.persistence.criteria.CriteriaBuilder +import javax.persistence.criteria.Expression +import javax.persistence.criteria.JoinType +import javax.persistence.criteria.Path +import javax.persistence.criteria.Predicate +import javax.persistence.criteria.Root + +class PredicateBuilder(val criteriaBuilder: CriteriaBuilder) { + private val predicates: MutableList + + init { + predicates = ArrayList() + } + + /** Add predicate to query. */ + fun add(predicate: Predicate?) { + if (predicate == null) { + return + } + predicates.add(predicate) + } + + fun isNull(expression: Expression<*>?) { + predicates.add(criteriaBuilder.isNull(expression)) + } + + /** + * Build the predicates as an AND predicate. + */ + fun toAndPredicate(): Predicate? { + return if (predicates.size == 1) { + predicates[0] + } else if (!predicates.isEmpty()) { + criteriaBuilder.and(*predicates.toTypedArray()) + } else { + null + } + } + + /** + * Build the predicates as an AND predicate. + */ + fun toOrPredicate(): Predicate? { + return if (predicates.size == 1) { + predicates[0] + } else if (!predicates.isEmpty()) { + criteriaBuilder.or(*predicates.toTypedArray()) + } else { + null + } + } + + /** + * Add an equal criteria to predicates if value is not null or empty. + * @param path entity path + * @param value value to compare with + * @param type of field. + */ + fun equal(path: Supplier?>, value: T) { + if (isValidValue(value)) { + add(criteriaBuilder.equal(path.get(), value)) + } + } + + /** + * Add an equal criteria to predicates if value is not null or empty. + * @param path entity path + * @param value value to compare with + * @param type of field. + */ + fun equal(path: Expression?, value: T) { + if (isValidValue(value)) { + add(criteriaBuilder.equal(path, value)) + } + } + + /** + * Add a like criteria to predicates if value is not null or empty, matching both sides. + * @param path entity path + * @param value value to compare with + */ + fun likeLower(path: Supplier?>, value: String) { + if (isValidValue(value)) { + add( + criteriaBuilder.like( + criteriaBuilder.lower(path.get()), + "%" + value.trim { it <= ' ' }.lowercase() + "%" + ) + ) + } + } + + /** + * Add a like criteria to predicates if value is not null or empty, matching both sides. + * @param path entity path + * @param value value to compare with + */ + fun likeLower(path: Expression?, value: String?) { + if (isValidValue(value)) { + add( + criteriaBuilder.like( + criteriaBuilder.lower(path), + "%" + value!!.trim { it <= ' ' }.lowercase() + "%" + ) + ) + } + } + + /** + * Add a like criteria to predicates if value is not null or empty, matching both sides. + * @param root entity to fetch attributes from. + * @param attributeKey name of the attribute. + * @param attributeValue value to compare with using a like query. + */ + fun attributeLike( + root: Root<*>, attributeKey: String?, + attributeValue: String? + ) { + if (isValidValue(attributeValue)) { + val attributesJoin = root.joinMap("attributes", JoinType.LEFT) + add( + criteriaBuilder.and( + criteriaBuilder.equal(attributesJoin.key(), attributeKey), + criteriaBuilder.like( + attributesJoin.value(), + "%$attributeValue%" + ) + ) + ) + } + } + + fun `in`(expr: Expression<*>, other: Expression<*>?) { + add(expr.`in`(other)) + } + + fun `in`(expr: Expression<*>, other: Collection<*>?) { + add(expr.`in`(other)) + } + + /** + * Add comparable criteria matching given range. + * @param path entity property path. + * @param range range that should be matched. + */ + fun ?> range( + path: Path?, range: CriteriaRange? + ) { + if (range == null || range.isEmpty) { + return + } + range.validate() + if (range.iss != null) { + add(criteriaBuilder.equal(path, range.iss)) + } else { + val from = range.from + val to = range.to + if (from != null && to != null) { + add(criteriaBuilder.between(path, from, to)) + } else if (from != null) { + add(criteriaBuilder.greaterThanOrEqualTo(path, from)) + } else if (to != null) { + add(criteriaBuilder.lessThanOrEqualTo(path, to)) + } + } + } + + /** + * Whether given String a proper value. + */ + fun isValidValue(value: Any?): Boolean { + if (value == null) { + return false + } + return if (value is String) { + !value.isBlank() && value != "null" + } else true + } + + fun newBuilder(): PredicateBuilder { + return PredicateBuilder(criteriaBuilder) + } + + val isEmpty: Boolean + get() = predicates.isEmpty() +} diff --git a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.java b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.java deleted file mode 100644 index d403bc322..000000000 --- a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.java +++ /dev/null @@ -1,203 +0,0 @@ -package org.radarbase.management.repository.filters; - -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.domain.User; -import org.radarbase.management.web.rest.criteria.CriteriaRange; -import org.radarbase.management.web.rest.criteria.SubjectAuthority; -import org.radarbase.management.web.rest.criteria.SubjectCriteria; -import org.radarbase.management.web.rest.criteria.SubjectCriteriaLast; -import org.radarbase.management.web.rest.criteria.SubjectSortBy; -import org.radarbase.management.web.rest.criteria.SubjectSortOrder; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.springframework.data.jpa.domain.Specification; - -import javax.annotation.Nullable; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Join; -import javax.persistence.criteria.JoinType; -import javax.persistence.criteria.Order; -import javax.persistence.criteria.Path; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; -import java.time.LocalDate; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_VALIDATION; - -public class SubjectSpecification implements Specification { - private final CriteriaRange dateOfBirth; - private final CriteriaRange enrollmentDate; - private final Long groupId; - private final String humanReadableIdentifier; - private final SubjectCriteriaLast last; - private final String personName; - private final String projectName; - private final String externalId; - private final String subjectId; - private final List sort; - private final Set authority; - private final List sortLastValues; - - /** - * Subject specification based on criteria. - * @param criteria criteria to use for the specification. - */ - public SubjectSpecification(SubjectCriteria criteria) { - this.authority = criteria.getAuthority().stream() - .map(SubjectAuthority::name) - .collect(Collectors.toSet()); - this.dateOfBirth = criteria.getDateOfBirth(); - this.enrollmentDate = criteria.getEnrollmentDate(); - this.groupId = criteria.getGroupId(); - this.humanReadableIdentifier = criteria.getHumanReadableIdentifier(); - this.last = criteria.getLast(); - this.personName = criteria.getPersonName(); - this.projectName = criteria.getProjectName(); - this.externalId = criteria.getExternalId(); - this.subjectId = criteria.getLogin(); - this.sort = criteria.getParsedSort(); - if (last != null) { - this.sortLastValues = this.sort.stream() - .map(o -> getLastValue(o.getSortBy())) - .toList(); - } else { - this.sortLastValues = null; - } - } - - @Override - public Predicate toPredicate(@Nullable Root root, @Nullable CriteriaQuery query, - @Nullable CriteriaBuilder builder) { - if (root == null || query == null || builder == null) { - return null; - } - query.distinct(true); - - root.alias("subject"); - Join userJoin = root.join("user"); - userJoin.alias("user"); - - PredicateBuilder predicates = new PredicateBuilder(builder); - - addRolePredicates(userJoin, predicates); - - predicates.attributeLike(root, "Human-readable-identifier", - humanReadableIdentifier); - predicates.likeLower(root.get("externalId"), externalId); - - predicates.equal(root.get("group"), groupId); - - predicates.range(root.get("dateOfBirth"), dateOfBirth); - predicates.range(root.get("enrollmentDate"), enrollmentDate); - - predicates.likeLower(root.get("personName"), personName); - predicates.likeLower(userJoin.get("login"), subjectId); - - addContentPredicates(predicates, builder, root, query.getResultType()); - - query.orderBy(getSortOrder(root, builder)); - - return predicates.toAndPredicate(); - } - - private Predicate filterLastValues(Root root, CriteriaBuilder builder) { - Predicate[] lastPredicates = new Predicate[sort.size()]; - List> paths = new ArrayList<>(sort.size()); - for (SubjectSortOrder order : sort) { - paths.add(getPropertyPath(order.getSortBy(), root)); - } - for (int i = 0; i < sort.size(); i++) { - Predicate[] lastAndPredicates = i > 0 ? new Predicate[i + 1] : null; - for (int j = 0; j < i; j++) { - lastAndPredicates[j] = builder.equal(paths.get(j), sortLastValues.get(j)); - } - - SubjectSortOrder order = sort.get(i); - Predicate currentSort; - if (order.getDirection().isAscending()) { - currentSort = builder.greaterThan(paths.get(i), sortLastValues.get(i)); - } else { - currentSort = builder.lessThan(paths.get(i), sortLastValues.get(i)); - } - - if (lastAndPredicates != null) { - lastAndPredicates[i] = currentSort; - lastPredicates[i] = builder.and(lastAndPredicates); - } else { - lastPredicates[i] = currentSort; - } - } - if (lastPredicates.length > 1) { - return builder.or(lastPredicates); - } else { - return lastPredicates[0]; - } - } - - private void addContentPredicates(PredicateBuilder predicates, CriteriaBuilder builder, - Root root, Class queryResult) { - // Don't add content for count queries. - if (queryResult == Long.class || queryResult == long.class) { - return; - } - root.fetch("sources", JoinType.LEFT); - root.fetch("user", JoinType.INNER); - - if (last != null) { - predicates.add(filterLastValues(root, builder)); - } - } - - private String getLastValue(SubjectSortBy property) { - String result = switch (property) { - case ID -> last.getId(); - case USER_LOGIN -> last.getLogin(); - case EXTERNAL_ID -> last.getExternalId(); - }; - if (property.isUnique() && result == null) { - throw new BadRequestException("No last value given for sort property " + property, - SUBJECT, ERR_VALIDATION); - } - return result; - } - - - private Path getPropertyPath(SubjectSortBy property, Root root) { - return switch (property) { - case ID -> root.get("id"); - case USER_LOGIN -> root.get("user").get("login"); - case EXTERNAL_ID -> root.get("externalId"); - }; - } - - private void addRolePredicates(Join userJoin, PredicateBuilder predicates) { - Join rolesJoin = userJoin.join("roles"); - rolesJoin.alias("roles"); - - predicates.equal(() -> rolesJoin.get("project").get("projectName"), projectName); - if (!authority.isEmpty() && authority.size() != SubjectAuthority.values().length) { - predicates.add(rolesJoin.get("authority").get("name").in(authority)); - } - } - - private List getSortOrder(Root root, - CriteriaBuilder builder) { - return sort.stream() - .map(order -> { - Path path = getPropertyPath(order.getSortBy(), root); - if (order.getDirection().isAscending()) { - return builder.asc(path); - } else { - return builder.desc(path); - } - }) - .toList(); - } -} diff --git a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt new file mode 100644 index 000000000..162cd032d --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt @@ -0,0 +1,196 @@ +package org.radarbase.management.repository.filters + +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.Subject +import org.radarbase.management.domain.User +import org.radarbase.management.web.rest.criteria.CriteriaRange +import org.radarbase.management.web.rest.criteria.SubjectAuthority +import org.radarbase.management.web.rest.criteria.SubjectCriteria +import org.radarbase.management.web.rest.criteria.SubjectCriteriaLast +import org.radarbase.management.web.rest.criteria.SubjectSortBy +import org.radarbase.management.web.rest.criteria.SubjectSortOrder +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.springframework.data.jpa.domain.Specification +import java.time.LocalDate +import java.time.ZonedDateTime +import java.util.stream.Collectors +import javax.persistence.criteria.CriteriaBuilder +import javax.persistence.criteria.CriteriaQuery +import javax.persistence.criteria.Join +import javax.persistence.criteria.JoinType +import javax.persistence.criteria.Order +import javax.persistence.criteria.Path +import javax.persistence.criteria.Predicate +import javax.persistence.criteria.Root + +class SubjectSpecification(criteria: SubjectCriteria) : Specification { + private val dateOfBirth: CriteriaRange? + private val enrollmentDate: CriteriaRange? + private val groupId: Long? + private val humanReadableIdentifier: String? + private val last: SubjectCriteriaLast? + private val personName: String? + private val projectName: String? + private val externalId: String? + private val subjectId: String? + private val sort: List? + private val authority: Set + private var sortLastValues: List? = null + + /** + * Subject specification based on criteria. + * @param criteria criteria to use for the specification. + */ + init { + authority = criteria.authority.stream() + .map { obj: SubjectAuthority? -> obj!!.name } + .collect(Collectors.toSet()) + dateOfBirth = criteria.dateOfBirth + enrollmentDate = criteria.enrollmentDate + groupId = criteria.groupId + humanReadableIdentifier = criteria.humanReadableIdentifier + last = criteria.last + personName = criteria.personName + projectName = criteria.projectName + externalId = criteria.externalId + subjectId = criteria.login + sort = criteria.getParsedSort() + if (last != null) { + sortLastValues = sort + ?.map { o: SubjectSortOrder -> getLastValue(o.sortBy) } + ?.toList() + } else { + sortLastValues = null + } + } + + override fun toPredicate( + root: Root?, query: CriteriaQuery<*>?, + builder: CriteriaBuilder? + ): Predicate? { + if (root == null || query == null || builder == null) { + return null + } + query.distinct(true) + root.alias("subject") + val userJoin = root.join("user") + userJoin.alias("user") + val predicates = PredicateBuilder(builder) + addRolePredicates(userJoin, predicates) + predicates.attributeLike( + root, "Human-readable-identifier", + humanReadableIdentifier + ) + predicates.likeLower(root.get("externalId"), externalId) + predicates.equal(root.get("group"), groupId) + predicates.range(root.get("dateOfBirth"), dateOfBirth) + predicates.range(root.get("enrollmentDate"), enrollmentDate) + predicates.likeLower(root.get("personName"), personName) + predicates.likeLower(userJoin.get("login"), subjectId) + addContentPredicates(predicates, builder, root, query.resultType) + query.orderBy(getSortOrder(root, builder)) + return predicates.toAndPredicate()!! + } + + //TODO I don't think return type needs to be nullable + private fun filterLastValues(root: Root, builder: CriteriaBuilder): Predicate? { + val lastPredicates = arrayOfNulls( + sort!!.size + ) + val paths: MutableList> = ArrayList( + sort.size + ) + for (order in sort) { + paths.add(getPropertyPath(order.sortBy, root)) + } + for (i in sort.indices) { + val lastAndPredicates: Array? = if (i > 0) arrayOfNulls(i + 1) else null + + for (j in 0 until i) { + lastAndPredicates!![j] = builder.equal(paths[j], sortLastValues!![j]) + } + val order = sort[i] + val currentSort: Predicate? = if (order.direction.isAscending) { + builder.greaterThan(paths[i], sortLastValues!![i]!!)//TODO + } else { + builder.lessThan(paths[i], sortLastValues!![i]!!)//TODO + } + if (lastAndPredicates != null) { + lastAndPredicates[i] = currentSort + lastPredicates[i] = builder.and(*lastAndPredicates) + } else { + lastPredicates[i] = currentSort + } + } + return if (lastPredicates.size > 1) { + builder.or(*lastPredicates) + } else { + lastPredicates[0] + } + } + + private fun addContentPredicates( + predicates: PredicateBuilder, builder: CriteriaBuilder, + root: Root, queryResult: Class<*> + ) { + // Don't add content for count queries. + if (queryResult == Long::class.java || queryResult == Long::class.javaPrimitiveType) { + return + } + root.fetch("sources", JoinType.LEFT) + root.fetch("user", JoinType.INNER) + if (last != null) { + predicates.add(filterLastValues(root, builder)) + } + } + + private fun getLastValue(property: SubjectSortBy): String? { + val result = when (property) { + SubjectSortBy.ID -> last?.id + SubjectSortBy.USER_LOGIN -> last?.login + SubjectSortBy.EXTERNAL_ID -> last?.login + } + if (property.isUnique && result == null) { + throw BadRequestException( + "No last value given for sort property $property", + EntityName.Companion.SUBJECT, ErrorConstants.ERR_VALIDATION + ) + } + return result + } + + private fun getPropertyPath(property: SubjectSortBy, root: Root): Path { + return when (property) { + SubjectSortBy.ID -> root.get("id") + SubjectSortBy.USER_LOGIN -> root.get("user").get("login") + SubjectSortBy.EXTERNAL_ID -> root.get("externalId") + } + } + + private fun addRolePredicates(userJoin: Join, predicates: PredicateBuilder) { + val rolesJoin = userJoin.join("roles") + rolesJoin.alias("roles") + predicates.equal({ rolesJoin.get("project").get("projectName") }, projectName) + if (!authority.isEmpty() && authority.size != SubjectAuthority.values().size) { + predicates.add(rolesJoin.get("authority").get("name").`in`(authority)) + } + } + + private fun getSortOrder( + root: Root, + builder: CriteriaBuilder + ): List? { + return sort + ?.map { order: SubjectSortOrder -> + val path = getPropertyPath(order.sortBy, root) + if (order.direction.isAscending) { + return listOf(builder.asc(path)) + } else { + return listOf(builder.desc(path)) + } + } + ?.toList() + } +} diff --git a/src/main/java/org/radarbase/management/repository/filters/UserFilter.java b/src/main/java/org/radarbase/management/repository/filters/UserFilter.java deleted file mode 100644 index e97ec723d..000000000 --- a/src/main/java/org/radarbase/management/repository/filters/UserFilter.java +++ /dev/null @@ -1,222 +0,0 @@ -package org.radarbase.management.repository.filters; - -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.domain.Organization; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.User; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.jpa.domain.Specification; - -import javax.annotation.Nonnull; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.From; -import javax.persistence.criteria.Join; -import javax.persistence.criteria.JoinType; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; -import javax.persistence.criteria.Subquery; -import java.util.List; -import java.util.Locale; -import java.util.function.BiConsumer; -import java.util.stream.Stream; - -public class UserFilter implements Specification { - private static final Logger logger = LoggerFactory.getLogger(UserFilter.class); - - private String login; - private String email; - private String projectName; - private String organization; - private String authority; - private boolean includeUpperLevels = false; - - @Override - public Predicate toPredicate(Root root, @Nonnull CriteriaQuery query, - @Nonnull CriteriaBuilder builder) { - PredicateBuilder predicates = new PredicateBuilder(builder); - predicates.likeLower(root.get("login"), login); - predicates.likeLower(root.get("email"), email); - - filterRoles(predicates, root.join("roles", JoinType.LEFT), query); - - query.distinct(true); - var result = predicates.toAndPredicate(); - logger.debug("Filtering users by {}", result); - return result; - } - - private void filterRoles(PredicateBuilder predicates, Join roleJoin, - CriteriaQuery query) { - Stream authoritiesFiltered = Stream.of(RoleAuthority.values()) - .filter(r -> !r.isPersonal); - boolean allowNoRole = true; - - if (predicates.isValidValue(authority)) { - String authorityUpper = authority.toUpperCase(Locale.ROOT); - authoritiesFiltered = authoritiesFiltered - .filter(r -> r != null && r.getAuthority().contains(authorityUpper)); - allowNoRole = false; - } - List authoritiesAllowed = authoritiesFiltered.toList(); - if (authoritiesAllowed.isEmpty()) { - CriteriaBuilder builder = predicates.getCriteriaBuilder(); - // never match - predicates.add(builder.isTrue(builder.literal(false))); - return; - } - - determineScope(predicates, roleJoin, query, authoritiesAllowed, allowNoRole); - } - - private void determineScope( - PredicateBuilder predicates, - Join roleJoin, - CriteriaQuery query, - List authoritiesAllowed, - boolean allowNoRole) { - PredicateBuilder authorityPredicates = predicates.newBuilder(); - - boolean allowNoRoleInScope = allowNoRole; - // Is organization admin - if (predicates.isValidValue(projectName)) { - allowNoRoleInScope = false; - // Is project admin - entitySubquery(RoleAuthority.Scope.PROJECT, roleJoin, - query, authorityPredicates, authoritiesAllowed, - (b, proj) -> b.likeLower(proj.get("projectName"), projectName)); - - // Is organization admin for organization above current project - if (includeUpperLevels) { - entitySubquery(RoleAuthority.Scope.ORGANIZATION, roleJoin, - query, authorityPredicates, authoritiesAllowed, - (b, org) -> b.likeLower( - org.join("projects").get("projectName"), projectName)); - } - } else if (predicates.isValidValue(organization)) { - allowNoRoleInScope = false; - entitySubquery(RoleAuthority.Scope.ORGANIZATION, roleJoin, - query, authorityPredicates, authoritiesAllowed, - (b, org) -> b.likeLower(org.get("name"), organization)); - } - - if (authorityPredicates.isEmpty()) { - // no project or organization filters applied - addAllowedAuthorities(authorityPredicates, roleJoin, authoritiesAllowed, null); - } else if (includeUpperLevels) { - // is sys admin - addAllowedAuthorities(authorityPredicates, roleJoin, authoritiesAllowed, - RoleAuthority.Scope.GLOBAL); - } - if (allowNoRoleInScope) { - authorityPredicates.isNull(roleJoin.get("id")); - } - - predicates.add(authorityPredicates.toOrPredicate()); - } - - private boolean addAllowedAuthorities(PredicateBuilder predicates, - Join roleJoin, - List authorities, - RoleAuthority.Scope scope) { - - Stream authorityStream = authorities.stream(); - if (scope != null) { - authorityStream = authorityStream.filter(r -> r.getScope() == scope); - } - List authorityNames = authorityStream - .map(RoleAuthority::getAuthority) - .toList(); - - if (!authorityNames.isEmpty()) { - predicates.in(roleJoin.get("authority").get("name"), authorityNames); - return true; - } else { - return false; - } - } - - /** Create a subquery to filter the roles. */ - private void entitySubquery(RoleAuthority.Scope scope, - Join roleJoin, - CriteriaQuery query, - PredicateBuilder predicates, - List allowedRoles, - BiConsumer> queryMatch) { - PredicateBuilder authorityPredicates = predicates.newBuilder(); - - if (!addAllowedAuthorities(authorityPredicates, roleJoin, allowedRoles, scope)) { - return; - } - - Subquery subQuery = query.subquery(Long.class); - subQuery.distinct(true); - Root orgRoot = subQuery.from((Class) switch (scope) { - case PROJECT -> Project.class; - case ORGANIZATION -> Organization.class; - default -> throw new IllegalStateException("Unknown role scope " + scope); - }); - subQuery.select(orgRoot.get("id")); - PredicateBuilder subqueryPredicates = predicates.newBuilder(); - queryMatch.accept(subqueryPredicates, orgRoot); - subQuery.where(subqueryPredicates.toAndPredicate()); - - authorityPredicates.in(roleJoin.get( switch (scope) { - case ORGANIZATION -> "organization"; - case PROJECT -> "project"; - default -> throw new IllegalStateException("Unknown role scope " + scope); - }).get("id"), subQuery); - - predicates.add(authorityPredicates.toAndPredicate()); - } - - public String getLogin() { - return login; - } - - public void setLogin(String login) { - this.login = login; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - public String getOrganization() { - return organization; - } - - public void setOrganization(String organization) { - this.organization = organization; - } - - public String getAuthority() { - return authority; - } - - public void setAuthority(String authority) { - this.authority = authority; - } - - public boolean isIncludeUpperLevels() { - return includeUpperLevels; - } - - public void setIncludeUpperLevels(boolean includeUpperLevels) { - this.includeUpperLevels = includeUpperLevels; - } -} diff --git a/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt b/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt new file mode 100644 index 000000000..9dc2110b3 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt @@ -0,0 +1,179 @@ +package org.radarbase.management.repository.filters + +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.domain.Organization +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.User +import org.slf4j.LoggerFactory +import org.springframework.data.jpa.domain.Specification +import java.util.function.BiConsumer +import java.util.stream.Stream +import javax.annotation.Nonnull +import javax.persistence.criteria.CriteriaBuilder +import javax.persistence.criteria.CriteriaQuery +import javax.persistence.criteria.From +import javax.persistence.criteria.Join +import javax.persistence.criteria.JoinType +import javax.persistence.criteria.Predicate +import javax.persistence.criteria.Root + +class UserFilter : Specification { + var login: String? = null + var email: String? = null + var projectName: String? = null + var organization: String? = null + var authority: String? = null + var isIncludeUpperLevels = false + override fun toPredicate( + root: Root, @Nonnull query: CriteriaQuery<*>, + @Nonnull builder: CriteriaBuilder + ): Predicate { + val predicates = PredicateBuilder(builder) + predicates.likeLower(root.get("login"), login) + predicates.likeLower(root.get("email"), email) + filterRoles(predicates, root.join("roles", JoinType.LEFT), query) + query.distinct(true) + val result = predicates.toAndPredicate() + logger.debug("Filtering users by {}", result) + return result!! + } + + private fun filterRoles( + predicates: PredicateBuilder, roleJoin: Join, + query: CriteriaQuery<*> + ) { + var authoritiesFiltered = Stream.of(*RoleAuthority.values()) + .filter { r: RoleAuthority -> !r.isPersonal } + var allowNoRole = true + if (predicates.isValidValue(authority)) { + val authorityUpper = authority!!.uppercase() + authoritiesFiltered = authoritiesFiltered + .filter { r: RoleAuthority? -> r != null && r.authority.contains(authorityUpper) } + allowNoRole = false + } + val authoritiesAllowed = authoritiesFiltered.toList() + if (authoritiesAllowed.isEmpty()) { + val builder = predicates.criteriaBuilder + // never match + predicates.add(builder!!.isTrue(builder.literal(false))) + return + } + determineScope(predicates, roleJoin, query, authoritiesAllowed, allowNoRole) + } + + private fun determineScope( + predicates: PredicateBuilder, + roleJoin: Join, + query: CriteriaQuery<*>, + authoritiesAllowed: List, + allowNoRole: Boolean + ) { + val authorityPredicates = predicates.newBuilder() + var allowNoRoleInScope = allowNoRole + // Is organization admin + if (predicates.isValidValue(projectName)) { + allowNoRoleInScope = false + // Is project admin + entitySubquery( + RoleAuthority.Scope.PROJECT, roleJoin, + query, authorityPredicates, authoritiesAllowed + ) { b: PredicateBuilder?, proj: From<*, *> -> b!!.likeLower(proj.get("projectName"), projectName) } + + // Is organization admin for organization above current project + if (isIncludeUpperLevels) { + entitySubquery( + RoleAuthority.Scope.ORGANIZATION, roleJoin, + query, authorityPredicates, authoritiesAllowed + ) { b: PredicateBuilder?, org: From<*, *> -> + b!!.likeLower( + org.join("projects").get("projectName"), projectName + ) + } + } + } else if (predicates.isValidValue(organization)) { + allowNoRoleInScope = false + entitySubquery( + RoleAuthority.Scope.ORGANIZATION, roleJoin, + query, authorityPredicates, authoritiesAllowed + ) { b: PredicateBuilder?, org: From<*, *> -> b!!.likeLower(org.get("name"), organization) } + } + if (authorityPredicates.isEmpty) { + // no project or organization filters applied + addAllowedAuthorities(authorityPredicates, roleJoin, authoritiesAllowed, null) + } else if (isIncludeUpperLevels) { + // is sys admin + addAllowedAuthorities( + authorityPredicates, roleJoin, authoritiesAllowed, + RoleAuthority.Scope.GLOBAL + ) + } + if (allowNoRoleInScope) { + authorityPredicates!!.isNull(roleJoin.get("id")) + } + predicates.add(authorityPredicates!!.toOrPredicate()) + } + + private fun addAllowedAuthorities( + predicates: PredicateBuilder?, + roleJoin: Join, + authorities: List, + scope: RoleAuthority.Scope? + ): Boolean { + var authorityStream = authorities.stream() + if (scope != null) { + authorityStream = authorityStream.filter { r: RoleAuthority -> r.scope === scope } + } + val authorityNames = authorityStream + .map(RoleAuthority::authority) + .toList() + return if (!authorityNames.isEmpty()) { + predicates!!.`in`(roleJoin.get("authority").get("name"), authorityNames) + true + } else { + false + } + } + + /** Create a subquery to filter the roles. */ + private fun entitySubquery( + scope: RoleAuthority.Scope, + roleJoin: Join, + query: CriteriaQuery<*>, + predicates: PredicateBuilder?, + allowedRoles: List, + queryMatch: BiConsumer> + ) { + val authorityPredicates = predicates!!.newBuilder() + if (!addAllowedAuthorities(authorityPredicates, roleJoin, allowedRoles, scope)) { + return + } + val subQuery = query.subquery(Long::class.java) + subQuery.distinct(true) + val orgRoot = subQuery.from( + when (scope) { + RoleAuthority.Scope.PROJECT -> Project::class.java + RoleAuthority.Scope.ORGANIZATION -> Organization::class.java + else -> throw IllegalStateException("Unknown role scope $scope") + } as Class<*> + ) + subQuery.select(orgRoot.get("id")) + val subqueryPredicates = predicates.newBuilder() + queryMatch.accept(subqueryPredicates, orgRoot) + subQuery.where(subqueryPredicates!!.toAndPredicate()) + authorityPredicates!!.`in`( + roleJoin.get( + when (scope) { + RoleAuthority.Scope.ORGANIZATION -> "organization" + RoleAuthority.Scope.PROJECT -> "project" + else -> throw IllegalStateException("Unknown role scope $scope") + } + ).get("id"), subQuery + ) + predicates.add(authorityPredicates.toAndPredicate()) + } + + companion object { + private val logger = LoggerFactory.getLogger(UserFilter::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/repository/package-info.java b/src/main/java/org/radarbase/management/repository/package-info.java deleted file mode 100644 index f223176be..000000000 --- a/src/main/java/org/radarbase/management/repository/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Spring Data JPA repositories. - */ -package org.radarbase.management.repository; diff --git a/src/main/java/org/radarbase/management/repository/package-info.kt b/src/main/java/org/radarbase/management/repository/package-info.kt new file mode 100644 index 000000000..3dcb8c57a --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/package-info.kt @@ -0,0 +1,5 @@ +/** + * Spring Data JPA repositories. + */ +package org.radarbase.management.repository + diff --git a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java deleted file mode 100644 index 2382e7067..000000000 --- a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.radarbase.management.security; - -import org.radarbase.auth.authorization.AuthorizationOracle; -import org.radarbase.auth.authorization.Permission; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.Source; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.repository.UserRepository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.boot.actuate.audit.AuditEventRepository; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.OAuth2Request; -import org.springframework.security.oauth2.provider.token.TokenEnhancer; - -import java.security.Principal; -import java.time.Instant; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Collectors; - -import static org.radarbase.auth.jwt.JwtTokenVerifier.GRANT_TYPE_CLAIM; -import static org.radarbase.auth.jwt.JwtTokenVerifier.ROLES_CLAIM; -import static org.radarbase.auth.jwt.JwtTokenVerifier.SOURCES_CLAIM; - -public class ClaimsTokenEnhancer implements TokenEnhancer, InitializingBean { - private static final Logger logger = LoggerFactory.getLogger(ClaimsTokenEnhancer.class); - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private UserRepository userRepository; - - @Autowired - private AuditEventRepository auditEventRepository; - - @Autowired - private AuthorizationOracle authorizationOracle; - - @Value("${spring.application.name}") - private String appName; - - private static final String GRANT_TOKEN_EVENT = "GRANT_ACCESS_TOKEN"; - - @Override - public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, - OAuth2Authentication authentication) { - logger.debug("Enhancing token of authentication {}" , authentication); - - Map additionalInfo = new HashMap<>(); - - String userName = authentication.getName(); - - if (authentication.getPrincipal() instanceof Principal - || authentication.getPrincipal() instanceof UserDetails) { - // add the 'sub' claim in accordance with JWT spec - additionalInfo.put("sub", userName); - - userRepository.findOneByLogin(userName) - .ifPresent(user -> { - var roles = user.roles.stream() - .map(role -> { - var auth = role.authority.name; - return switch (role.getRole().getScope()) { - case GLOBAL -> auth; - case ORGANIZATION -> role.organization.name - + ":" + auth; - case PROJECT -> role.project.projectName - + ":" + auth; - }; - }) - .toList(); - additionalInfo.put(ROLES_CLAIM, roles); - - // Do not grant scopes that cannot be given to a user. - Set currentScopes = accessToken.getScope(); - Set newScopes = currentScopes.stream() - .filter(scope -> { - Permission permission = Permission.ofScope(scope); - var roleAuthorities = user.roles.stream() - .map(Role::getRole) - .collect(Collectors.toCollection(() -> - EnumSet.noneOf(RoleAuthority.class))); - return authorizationOracle.mayBeGranted(roleAuthorities, - permission); - }) - .collect(Collectors.toCollection(TreeSet::new)); - - if (!newScopes.equals(currentScopes)) { - ((DefaultOAuth2AccessToken) accessToken).setScope(newScopes); - } - }); - - List assignedSources = subjectRepository.findSourcesBySubjectLogin(userName); - - List sourceIds = assignedSources.stream() - .map(s -> s.sourceId.toString()) - .toList(); - additionalInfo.put(SOURCES_CLAIM, sourceIds); - } - // add iat and iss optional JWT claims - additionalInfo.put("iat", Instant.now().getEpochSecond()); - additionalInfo.put("iss", appName); - additionalInfo.put(GRANT_TYPE_CLAIM, - authentication.getOAuth2Request().getGrantType()); - ((DefaultOAuth2AccessToken) accessToken) - .setAdditionalInformation(additionalInfo); - - // HACK: since all granted tokens need to pass here, we can use this point to create an - // audit event for a granted token, there is an open issue about oauth2 audit events in - // spring security but it has been inactive for a long time: - // https://github.com/spring-projects/spring-security-oauth/issues/223 - Map auditData = auditData(accessToken, authentication); - auditEventRepository.add(new AuditEvent(userName, GRANT_TOKEN_EVENT, - auditData)); - logger.info("[{}] for {}: {}", GRANT_TOKEN_EVENT, userName, auditData); - - return accessToken; - } - - @Override - public void afterPropertiesSet() throws Exception { - // nothing to do for now - } - - private Map auditData(OAuth2AccessToken accessToken, - OAuth2Authentication authentication) { - Map result = new HashMap<>(); - result.put("tokenType", accessToken.getTokenType()); - result.put("scope", String.join(", ", accessToken.getScope())); - result.put("expiresIn", Integer.toString(accessToken.getExpiresIn())); - result.putAll(accessToken.getAdditionalInformation()); - OAuth2Request request = authentication.getOAuth2Request(); - result.put("clientId", request.getClientId()); - result.put("grantType", request.getGrantType()); - return result; - } -} diff --git a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt new file mode 100644 index 000000000..6000870db --- /dev/null +++ b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt @@ -0,0 +1,132 @@ +package org.radarbase.management.security + +import org.radarbase.auth.authorization.AuthorizationOracle +import org.radarbase.auth.authorization.Permission +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.auth.jwt.JwtTokenVerifier +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.Source +import org.radarbase.management.domain.User +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.repository.UserRepository +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.InitializingBean +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.boot.actuate.audit.AuditEventRepository +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken +import org.springframework.security.oauth2.common.OAuth2AccessToken +import org.springframework.security.oauth2.provider.OAuth2Authentication +import org.springframework.security.oauth2.provider.token.TokenEnhancer +import java.security.Principal +import java.time.Instant +import java.util.* + +class ClaimsTokenEnhancer( + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val userRepository: UserRepository, + @Autowired private val auditEventRepository: AuditEventRepository, + @Autowired private val authorizationOracle: AuthorizationOracle +) : TokenEnhancer, InitializingBean { + + @Value("\${spring.application.name}") + private val appName: String? = null + override fun enhance( + accessToken: OAuth2AccessToken, authentication: OAuth2Authentication + ): OAuth2AccessToken { + logger.debug("Enhancing token of authentication {}", authentication) + val additionalInfo: MutableMap = HashMap() + val userName = authentication.getName() + if (authentication.principal is Principal || authentication.principal is UserDetails) { + // add the 'sub' claim in accordance with JWT spec + additionalInfo["sub"] = userName + userRepository.findOneByLogin(userName)?.let { user: User? -> + val roles = user!!.roles!!.stream().map { role: Role -> + val auth = role.authority!!.name + when (role.role!!.scope) { + RoleAuthority.Scope.GLOBAL -> auth + RoleAuthority.Scope.ORGANIZATION -> (role.organization!!.name + ":" + auth) + + RoleAuthority.Scope.PROJECT -> (role.project!!.projectName + ":" + auth) + } + }.toList() + additionalInfo[JwtTokenVerifier.ROLES_CLAIM] = roles + + // Do not grant scopes that cannot be given to a user. + val currentScopes: MutableSet = accessToken.scope + val newScopes: Set = currentScopes + .filter { scope: String -> + val permission: Permission = Permission.ofScope(scope) + + val roleAuthorities = user + .roles!!.mapNotNull { it.role } + .let{ _ -> EnumSet.noneOf(RoleAuthority::class.java)} + .filterNotNull() + + roleAuthorities.mayBeGranted(permission) + } + .toSet() + + if (newScopes != currentScopes) { + (accessToken as DefaultOAuth2AccessToken).scope = newScopes + } + } + val assignedSources = subjectRepository.findSourcesBySubjectLogin(userName) + val sourceIds = assignedSources.stream().map { s: Source? -> s!!.sourceId.toString() }.toList() + additionalInfo[JwtTokenVerifier.SOURCES_CLAIM] = sourceIds + } + // add iat and iss optional JWT claims + additionalInfo["iat"] = Instant.now().epochSecond + additionalInfo["iss"] = appName + additionalInfo[JwtTokenVerifier.GRANT_TYPE_CLAIM] = authentication.oAuth2Request.getGrantType() + (accessToken as DefaultOAuth2AccessToken).additionalInformation = additionalInfo + + // HACK: since all granted tokens need to pass here, we can use this point to create an + // audit event for a granted token, there is an open issue about oauth2 audit events in + // spring security but it has been inactive for a long time: + // https://github.com/spring-projects/spring-security-oauth/issues/223 + val auditData = auditData(accessToken, authentication) + auditEventRepository.add( + AuditEvent( + userName, GRANT_TOKEN_EVENT, auditData + ) + ) + logger.info("[{}] for {}: {}", GRANT_TOKEN_EVENT, userName, auditData) + return accessToken + } + + @Throws(Exception::class) + override fun afterPropertiesSet() { + // nothing to do for now + } + + private fun auditData( + accessToken: OAuth2AccessToken, authentication: OAuth2Authentication + ): Map { + val result: MutableMap = HashMap() + result["tokenType"] = accessToken.tokenType + result["scope"] = java.lang.String.join(", ", accessToken.scope) + result["expiresIn"] = accessToken.expiresIn.toString() + result.putAll(accessToken.additionalInformation) + val request = authentication.oAuth2Request + result["clientId"] = request.clientId + result["grantType"] = request.getGrantType() + return result + } + + open fun mayBeGranted(role: RoleAuthority, permission: Permission): Boolean = with(authorizationOracle) { + role.mayBeGranted(permission) + } + + fun Collection.mayBeGranted(permission: Permission): Boolean = with(authorizationOracle) { + return any { it.mayBeGranted(permission) } + } + + companion object { + private val logger = LoggerFactory.getLogger(ClaimsTokenEnhancer::class.java) + private const val GRANT_TOKEN_EVENT = "GRANT_ACCESS_TOKEN" + } +} + diff --git a/src/main/java/org/radarbase/management/security/Constants.java b/src/main/java/org/radarbase/management/security/Constants.java deleted file mode 100644 index a713c34fc..000000000 --- a/src/main/java/org/radarbase/management/security/Constants.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.radarbase.management.security; - -/** - * Application constants. - */ -public final class Constants { - //Regex for acceptable logins - public static final String ENTITY_ID_REGEX = "^[_'.@A-Za-z0-9- ]*$"; - public static final String TOKEN_NAME_REGEX = "^[A-Za-z0-9.-]*$"; - - public static final String SYSTEM_ACCOUNT = "system"; - public static final String ANONYMOUS_USER = "anonymousUser"; - - private Constants() { - } -} diff --git a/src/main/java/org/radarbase/management/security/Constants.kt b/src/main/java/org/radarbase/management/security/Constants.kt new file mode 100644 index 000000000..f0ffc5e54 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/Constants.kt @@ -0,0 +1,12 @@ +package org.radarbase.management.security + +/** + * Application constants. + */ +object Constants { + //Regex for acceptable logins + const val ENTITY_ID_REGEX = "^[_'.@A-Za-z0-9- ]*$" + const val TOKEN_NAME_REGEX = "^[A-Za-z0-9.-]*$" + const val SYSTEM_ACCOUNT = "system" + const val ANONYMOUS_USER = "anonymousUser" +} diff --git a/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java b/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java deleted file mode 100644 index 14a85f33f..000000000 --- a/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.radarbase.management.security; - -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.UserRepository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.Locale; -import java.util.stream.Collectors; - -/** - * Authenticate a user from the database. - */ -@Component("userDetailsService") -public class DomainUserDetailsService implements UserDetailsService { - - private static final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class); - - private final UserRepository userRepository; - - public DomainUserDetailsService( - UserRepository userRepository) { - this.userRepository = userRepository; - } - - @Override - @Transactional - public UserDetails loadUserByUsername(final String login) { - log.debug("Authenticating {}", login); - String lowercaseLogin = login.toLowerCase(Locale.ENGLISH); - User user = userRepository.findOneWithRolesByLogin(lowercaseLogin) - .orElseThrow(() -> new UsernameNotFoundException( - "User " + lowercaseLogin + " was not found in the database")); - if (!user.activated) { - throw new UserNotActivatedException("User " + lowercaseLogin - + " was not activated"); - } - - List grantedAuthorities = user.getAuthorities().stream() - .map(authority -> new SimpleGrantedAuthority(authority.name)) - .collect(Collectors.toList()); - - return new org.springframework.security.core.userdetails.User( - lowercaseLogin, - user.password, - grantedAuthorities); - } -} diff --git a/src/main/java/org/radarbase/management/security/DomainUserDetailsService.kt b/src/main/java/org/radarbase/management/security/DomainUserDetailsService.kt new file mode 100644 index 000000000..1dd7ec586 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/DomainUserDetailsService.kt @@ -0,0 +1,47 @@ +package org.radarbase.management.security + +import org.radarbase.management.domain.Authority +import org.radarbase.management.repository.UserRepository +import org.slf4j.LoggerFactory +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.core.userdetails.User +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.core.userdetails.UsernameNotFoundException +import org.springframework.stereotype.Component +import org.springframework.transaction.annotation.Transactional + +/** + * Authenticate a user from the database. + */ +@Component("userDetailsService") +open class DomainUserDetailsService( + private val userRepository: UserRepository +) : UserDetailsService { + @Transactional + override fun loadUserByUsername(login: String): UserDetails { + log.debug("Authenticating {}", login) + val lowercaseLogin = login.lowercase() + val user = userRepository.findOneWithRolesByLogin(lowercaseLogin) + ?: throw UsernameNotFoundException( + "User $lowercaseLogin was not found in the database" + ) + if (!user.activated) { + throw UserNotActivatedException( + "User " + lowercaseLogin + + " was not activated" + ) + } + val grantedAuthorities = + user.authorities!!.mapNotNull { authority: Authority? -> SimpleGrantedAuthority(authority?.name) } + return User( + lowercaseLogin, + user.password, + grantedAuthorities + ) + } + + companion object { + private val log = LoggerFactory.getLogger(DomainUserDetailsService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/security/Http401UnauthorizedEntryPoint.java b/src/main/java/org/radarbase/management/security/Http401UnauthorizedEntryPoint.kt similarity index 65% rename from src/main/java/org/radarbase/management/security/Http401UnauthorizedEntryPoint.java rename to src/main/java/org/radarbase/management/security/Http401UnauthorizedEntryPoint.kt index d39bf8c80..dbeeea979 100644 --- a/src/main/java/org/radarbase/management/security/Http401UnauthorizedEntryPoint.java +++ b/src/main/java/org/radarbase/management/security/Http401UnauthorizedEntryPoint.kt @@ -16,33 +16,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.radarbase.management.security -package org.radarbase.management.security; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; +import org.slf4j.LoggerFactory +import org.springframework.security.core.AuthenticationException +import org.springframework.security.web.AuthenticationEntryPoint +import java.io.IOException +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse /** * Returns a 401 error code (Unauthorized) to the client. */ -public class Http401UnauthorizedEntryPoint implements AuthenticationEntryPoint { - private static final Logger log = LoggerFactory.getLogger(Http401UnauthorizedEntryPoint.class); - +class Http401UnauthorizedEntryPoint : AuthenticationEntryPoint { /** * Always returns a 401 error code to the client. */ - @Override - public void commence(HttpServletRequest request, HttpServletResponse response, - AuthenticationException arg2) - throws IOException { + @Throws(IOException::class) + override fun commence( + request: HttpServletRequest, response: HttpServletResponse, + arg2: AuthenticationException + ) { + log.debug("Pre-authenticated entry point called. Rejecting access") + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied") + } - log.debug("Pre-authenticated entry point called. Rejecting access"); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied"); + companion object { + private val log = LoggerFactory.getLogger(Http401UnauthorizedEntryPoint::class.java) } } diff --git a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt index 6abd75069..bfb1967c8 100644 --- a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt +++ b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt @@ -19,7 +19,6 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher import org.springframework.web.cors.CorsUtils import org.springframework.web.filter.OncePerRequestFilter import java.io.IOException -import java.io.Serializable import java.time.Instant import javax.annotation.Nonnull import javax.servlet.FilterChain @@ -149,8 +148,8 @@ class JwtAuthenticationFilter @JvmOverloads constructor( ): RadarToken? { val userName = token.username ?: return token val user = userRepository.findOneByLogin(userName) - return if (user.isPresent) { - token.copyWithRoles(user.get().authorityReferences) + return if (user != null) { + token.copyWithRoles(user.authorityReferences) } else { session?.removeAttribute(TOKEN_ATTRIBUTE) httpResponse.returnUnauthorized(httpRequest, "User not found") @@ -201,14 +200,14 @@ class JwtAuthenticationFilter @JvmOverloads constructor( @get:JvmStatic @set:JvmStatic - var HttpSession.radarToken: RadarToken? - get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken? + var HttpSession.radarToken: RadarToken + get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken set(value) = setAttribute(TOKEN_ATTRIBUTE, value) @get:JvmStatic @set:JvmStatic - var HttpServletRequest.radarToken: RadarToken? - get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken? + var HttpServletRequest.radarToken: RadarToken + get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken set(value) = setAttribute(TOKEN_ATTRIBUTE, value) val Authentication?.isAnonymous: Boolean diff --git a/src/main/java/org/radarbase/management/security/PostgresApprovalStore.java b/src/main/java/org/radarbase/management/security/PostgresApprovalStore.java deleted file mode 100644 index 1677c0ea3..000000000 --- a/src/main/java/org/radarbase/management/security/PostgresApprovalStore.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2012-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.radarbase.management.security; - -import static org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus.APPROVED; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import javax.sql.DataSource; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.security.oauth2.provider.approval.Approval; -import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus; -import org.springframework.security.oauth2.provider.approval.ApprovalStore; -import org.springframework.util.Assert; - -/** - * This class will be used to execute functions related to token approval. It is an duplicate of - * JdbcApprovalStore with escaped case sensitive fields to query. - * - * @author Dave Syer - * @author Modified by Nivethika - */ -public class PostgresApprovalStore implements ApprovalStore { - - private final JdbcTemplate jdbcTemplate; - - private static final Logger logger = LoggerFactory.getLogger(PostgresApprovalStore.class); - - private final RowMapper rowMapper = new AuthorizationRowMapper(); - - private static final String TABLE_NAME = "oauth_approvals"; - - private static final String FIELDS = - "\"expiresAt\", \"status\",\"lastModifiedAt\",\"userId\"," + "\"clientId\"," - + "\"scope\""; - - private static final String WHERE_KEY = "where \"userId\"=? and \"clientId\"=?"; - - private static final String WHERE_KEY_AND_SCOPE = WHERE_KEY + " and \"scope\"=?"; - - private static final String AND_LESS_THAN_EXPIRE_AT = " and \"expiresAt\" <= ?"; - - private static final String DEFAULT_ADD_APPROVAL_STATEMENT = - String.format("insert into %s ( %s ) values (?,?,?,?,?,?)", TABLE_NAME, FIELDS); - - private static final String DEFAULT_REFRESH_APPROVAL_STATEMENT = String.format( - "update %s set \"expiresAt\"=?, \"status\"=?, \"lastModifiedAt\"=? " - + WHERE_KEY_AND_SCOPE, TABLE_NAME); - - private static final String DEFAULT_GET_APPROVAL_SQL = - String.format("select %s from %s " + WHERE_KEY, FIELDS, TABLE_NAME); - - private static final String DEFAULT_DELETE_APPROVAL_SQL = - String.format("delete from %s " + WHERE_KEY_AND_SCOPE + AND_LESS_THAN_EXPIRE_AT, - TABLE_NAME); - - private static final String DEFAULT_EXPIRE_APPROVAL_STATEMENT = - String.format("update %s set " + "\"expiresAt\" = ? " - + WHERE_KEY_AND_SCOPE, TABLE_NAME); - - private String addApprovalStatement = DEFAULT_ADD_APPROVAL_STATEMENT; - - private String refreshApprovalStatement = DEFAULT_REFRESH_APPROVAL_STATEMENT; - - private String findApprovalStatement = DEFAULT_GET_APPROVAL_SQL; - - private String deleteApprovalStatment = DEFAULT_DELETE_APPROVAL_SQL; - - private String expireApprovalStatement = DEFAULT_EXPIRE_APPROVAL_STATEMENT; - - private boolean handleRevocationsAsExpiry = false; - - public PostgresApprovalStore(DataSource dataSource) { - Assert.notNull(dataSource); - this.jdbcTemplate = new JdbcTemplate(dataSource); - } - - public void setHandleRevocationsAsExpiry(boolean handleRevocationsAsExpiry) { - this.handleRevocationsAsExpiry = handleRevocationsAsExpiry; - } - - public void setAddApprovalStatement(String addApprovalStatement) { - this.addApprovalStatement = addApprovalStatement; - } - - public void setFindApprovalStatement(String findApprovalStatement) { - this.findApprovalStatement = findApprovalStatement; - } - - public void setDeleteApprovalStatment(String deleteApprovalStatment) { - this.deleteApprovalStatment = deleteApprovalStatment; - } - - public void setExpireApprovalStatement(String expireApprovalStatement) { - this.expireApprovalStatement = expireApprovalStatement; - } - - public void setRefreshApprovalStatement(String refreshApprovalStatement) { - this.refreshApprovalStatement = refreshApprovalStatement; - } - - @Override - public boolean addApprovals(final Collection approvals) { - logger.debug(String.format("adding approvals: [%s]", approvals)); - boolean success = true; - for (Approval approval : approvals) { - if (!updateApproval(refreshApprovalStatement, approval) && !updateApproval( - addApprovalStatement, approval)) { - success = false; - } - } - return success; - } - - @Override - public boolean revokeApprovals(Collection approvals) { - logger.debug(String.format("Revoking approvals: [%s]", approvals)); - boolean success = true; - for (final Approval approval : approvals) { - if (handleRevocationsAsExpiry) { - int refreshed = jdbcTemplate - .update(expireApprovalStatement, (ps) -> { - ps.setTimestamp(1, new Timestamp(System.currentTimeMillis())); - ps.setString(2, approval.getUserId()); - ps.setString(3, approval.getClientId()); - ps.setString(4, approval.getScope()); - }); - if (refreshed != 1) { - success = false; - } - } else { - int refreshed = jdbcTemplate - .update(deleteApprovalStatment, (ps) -> { - ps.setString(1, approval.getUserId()); - ps.setString(2, approval.getClientId()); - ps.setString(3, approval.getScope()); - }); - if (refreshed != 1) { - success = false; - } - } - } - return success; - } - - /** - * Purges expired approvals from database. - * @return {@code true} if removed successfully, {@code false} otherwise. - */ - public boolean purgeExpiredApprovals() { - logger.debug("Purging expired approvals from database"); - try { - int deleted = jdbcTemplate.update(deleteApprovalStatment, (ps) -> { - ps.setTimestamp(1, new Timestamp(new Date().getTime())); - }); - logger.debug(deleted + " expired approvals deleted"); - } catch (DataAccessException ex) { - logger.error("Error purging expired approvals", ex); - return false; - } - return true; - } - - @Override - public List getApprovals(String userName, String clientId) { - logger.debug("Finding approvals for userName {} and cliendId {}", userName, clientId); - return jdbcTemplate.query(findApprovalStatement, rowMapper, userName, clientId); - } - - private boolean updateApproval(final String sql, final Approval approval) { - logger.debug(String.format("refreshing approval: [%s]", approval)); - int refreshed = jdbcTemplate.update(sql, (ps) -> { - ps.setTimestamp(1, new Timestamp(approval.getExpiresAt().getTime())); - ps.setString(2, (approval.getStatus() == null ? APPROVED - : approval.getStatus()).toString()); - ps.setTimestamp(3, new Timestamp(approval.getLastUpdatedAt().getTime())); - ps.setString(4, approval.getUserId()); - ps.setString(5, approval.getClientId()); - ps.setString(6, approval.getScope()); - }); - return refreshed == 1; - } - - private static class AuthorizationRowMapper implements RowMapper { - - @Override - public Approval mapRow(ResultSet rs, int rowNum) throws SQLException { - String userName = rs.getString(4); - String clientId = rs.getString(5); - String scope = rs.getString(6); - Date expiresAt = rs.getTimestamp(1); - String status = rs.getString(2); - Date lastUpdatedAt = rs.getTimestamp(3); - - return new Approval(userName, clientId, scope, expiresAt, - ApprovalStatus.valueOf(status), lastUpdatedAt); - } - } -} diff --git a/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt b/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt new file mode 100644 index 000000000..1a5eadc0c --- /dev/null +++ b/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt @@ -0,0 +1,203 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.radarbase.management.security + +import org.slf4j.LoggerFactory +import org.springframework.dao.DataAccessException +import org.springframework.jdbc.core.JdbcTemplate +import org.springframework.jdbc.core.RowMapper +import org.springframework.security.oauth2.provider.approval.Approval +import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus +import org.springframework.security.oauth2.provider.approval.ApprovalStore +import org.springframework.util.Assert +import java.sql.PreparedStatement +import java.sql.ResultSet +import java.sql.SQLException +import java.sql.Timestamp +import java.util.* +import javax.sql.DataSource + +/** + * This class will be used to execute functions related to token approval. It is an duplicate of + * JdbcApprovalStore with escaped case sensitive fields to query. + * + * @author Dave Syer + * @author Modified by Nivethika + */ +class PostgresApprovalStore(dataSource: DataSource?) : ApprovalStore { + private val jdbcTemplate: JdbcTemplate + private val rowMapper: RowMapper = AuthorizationRowMapper() + private var addApprovalStatement = DEFAULT_ADD_APPROVAL_STATEMENT + private var refreshApprovalStatement = DEFAULT_REFRESH_APPROVAL_STATEMENT + private var findApprovalStatement = DEFAULT_GET_APPROVAL_SQL + private var deleteApprovalStatment = DEFAULT_DELETE_APPROVAL_SQL + private var expireApprovalStatement = DEFAULT_EXPIRE_APPROVAL_STATEMENT + private var handleRevocationsAsExpiry = false + + init { + Assert.notNull(dataSource) + jdbcTemplate = JdbcTemplate(dataSource) + } + + fun setHandleRevocationsAsExpiry(handleRevocationsAsExpiry: Boolean) { + this.handleRevocationsAsExpiry = handleRevocationsAsExpiry + } + + fun setAddApprovalStatement(addApprovalStatement: String) { + this.addApprovalStatement = addApprovalStatement + } + + fun setFindApprovalStatement(findApprovalStatement: String) { + this.findApprovalStatement = findApprovalStatement + } + + fun setDeleteApprovalStatment(deleteApprovalStatment: String) { + this.deleteApprovalStatment = deleteApprovalStatment + } + + fun setExpireApprovalStatement(expireApprovalStatement: String) { + this.expireApprovalStatement = expireApprovalStatement + } + + fun setRefreshApprovalStatement(refreshApprovalStatement: String) { + this.refreshApprovalStatement = refreshApprovalStatement + } + + override fun addApprovals(approvals: Collection): Boolean { + logger.debug(String.format("adding approvals: [%s]", approvals)) + var success = true + for (approval in approvals) { + if (!updateApproval(refreshApprovalStatement, approval) && !updateApproval( + addApprovalStatement, approval + ) + ) { + success = false + } + } + return success + } + + override fun revokeApprovals(approvals: Collection): Boolean { + logger.debug(String.format("Revoking approvals: [%s]", approvals)) + var success = true + for (approval in approvals) { + if (handleRevocationsAsExpiry) { + val refreshed = jdbcTemplate + .update(expireApprovalStatement) { ps: PreparedStatement -> + ps.setTimestamp(1, Timestamp(System.currentTimeMillis())) + ps.setString(2, approval.userId) + ps.setString(3, approval.clientId) + ps.setString(4, approval.scope) + } + if (refreshed != 1) { + success = false + } + } else { + val refreshed = jdbcTemplate + .update(deleteApprovalStatment) { ps: PreparedStatement -> + ps.setString(1, approval.userId) + ps.setString(2, approval.clientId) + ps.setString(3, approval.scope) + } + if (refreshed != 1) { + success = false + } + } + } + return success + } + + /** + * Purges expired approvals from database. + * @return `true` if removed successfully, `false` otherwise. + */ + fun purgeExpiredApprovals(): Boolean { + logger.debug("Purging expired approvals from database") + try { + val deleted = jdbcTemplate.update(deleteApprovalStatment) { ps: PreparedStatement -> + ps.setTimestamp( + 1, Timestamp( + Date().time + ) + ) + } + logger.debug("$deleted expired approvals deleted") + } catch (ex: DataAccessException) { + logger.error("Error purging expired approvals", ex) + return false + } + return true + } + + override fun getApprovals(userName: String, clientId: String): List { + logger.debug("Finding approvals for userName {} and cliendId {}", userName, clientId) + return jdbcTemplate.query(findApprovalStatement, rowMapper, userName, clientId) + } + + private fun updateApproval(sql: String, approval: Approval): Boolean { + logger.debug(String.format("refreshing approval: [%s]", approval)) + val refreshed = jdbcTemplate.update(sql) { ps: PreparedStatement -> + ps.setTimestamp(1, Timestamp(approval.expiresAt.time)) + ps.setString(2, (if (approval.status == null) ApprovalStatus.APPROVED else approval.status).toString()) + ps.setTimestamp(3, Timestamp(approval.lastUpdatedAt.time)) + ps.setString(4, approval.userId) + ps.setString(5, approval.clientId) + ps.setString(6, approval.scope) + } + return refreshed == 1 + } + + private class AuthorizationRowMapper : RowMapper { + @Throws(SQLException::class) + override fun mapRow(rs: ResultSet, rowNum: Int): Approval { + val userName = rs.getString(4) + val clientId = rs.getString(5) + val scope = rs.getString(6) + val expiresAt: Date = rs.getTimestamp(1) + val status = rs.getString(2) + val lastUpdatedAt: Date = rs.getTimestamp(3) + return Approval( + userName, clientId, scope, expiresAt, + ApprovalStatus.valueOf(status), lastUpdatedAt + ) + } + } + + companion object { + private val logger = LoggerFactory.getLogger(PostgresApprovalStore::class.java) + private const val TABLE_NAME = "oauth_approvals" + private const val FIELDS = ("\"expiresAt\", \"status\",\"lastModifiedAt\",\"userId\"," + "\"clientId\"," + + "\"scope\"") + private const val WHERE_KEY = "where \"userId\"=? and \"clientId\"=?" + private const val WHERE_KEY_AND_SCOPE = WHERE_KEY + " and \"scope\"=?" + private const val AND_LESS_THAN_EXPIRE_AT = " and \"expiresAt\" <= ?" + private val DEFAULT_ADD_APPROVAL_STATEMENT = + String.format("insert into %s ( %s ) values (?,?,?,?,?,?)", TABLE_NAME, FIELDS) + private val DEFAULT_REFRESH_APPROVAL_STATEMENT = String.format( + "update %s set \"expiresAt\"=?, \"status\"=?, \"lastModifiedAt\"=? " + + WHERE_KEY_AND_SCOPE, TABLE_NAME + ) + private val DEFAULT_GET_APPROVAL_SQL = String.format("select %s from %s " + WHERE_KEY, FIELDS, TABLE_NAME) + private val DEFAULT_DELETE_APPROVAL_SQL = String.format( + "delete from %s " + WHERE_KEY_AND_SCOPE + AND_LESS_THAN_EXPIRE_AT, + TABLE_NAME + ) + private val DEFAULT_EXPIRE_APPROVAL_STATEMENT = String.format( + "update %s set " + "\"expiresAt\" = ? " + + WHERE_KEY_AND_SCOPE, TABLE_NAME + ) + } +} diff --git a/src/main/java/org/radarbase/management/security/RadarAuthentication.java b/src/main/java/org/radarbase/management/security/RadarAuthentication.java deleted file mode 100644 index b743b52b5..000000000 --- a/src/main/java/org/radarbase/management/security/RadarAuthentication.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.security; - -import org.radarbase.auth.authorization.AuthorityReference; -import org.radarbase.auth.token.RadarToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; - -import javax.annotation.Nonnull; -import java.security.Principal; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -public class RadarAuthentication implements Authentication, Principal { - private final RadarToken token; - private final List authorities; - private boolean isAuthenticated; - - /** Instantiate authentication via a token. */ - public RadarAuthentication(@Nonnull RadarToken token) { - this.token = token; - isAuthenticated = true; - authorities = token.getRoles().stream() - .map(AuthorityReference::getAuthority) - .distinct() - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - } - - @Override - public String getName() { - if (token.isClientCredentials()) { - return token.getClientId(); - } else { - return token.getUsername(); - } - } - - @Override - public Collection getAuthorities() { - return authorities; - } - - @Override - public Object getCredentials() { - return token; - } - - @Override - public Object getDetails() { - return null; - } - - @Override - public Object getPrincipal() { - if (token.isClientCredentials()) { - return null; - } else { - return this; - } - } - - @Override - public boolean isAuthenticated() { - return isAuthenticated; - } - - @Override - public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { - this.isAuthenticated = isAuthenticated; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - RadarAuthentication that = (RadarAuthentication) o; - - return isAuthenticated == that.isAuthenticated - && Objects.equals(token, that.token); - } - - @Override - public int hashCode() { - int result = token != null ? token.hashCode() : 0; - result = 31 * result + (isAuthenticated ? 1 : 0); - return result; - } - - @Override - public String toString() { - return "RadarAuthentication{" + "token=" + token - + ", authenticated=" + isAuthenticated() - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/security/RadarAuthentication.kt b/src/main/java/org/radarbase/management/security/RadarAuthentication.kt new file mode 100644 index 000000000..26df1809d --- /dev/null +++ b/src/main/java/org/radarbase/management/security/RadarAuthentication.kt @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.security + +import org.radarbase.auth.authorization.AuthorityReference +import org.radarbase.auth.token.RadarToken +import org.springframework.security.core.Authentication +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.SimpleGrantedAuthority +import java.security.Principal +import java.util.stream.Collectors +import javax.annotation.Nonnull + +class RadarAuthentication(@param:Nonnull private val token: RadarToken) : Authentication, Principal { + private val authorities: List + private var isAuthenticated = true + + /** Instantiate authentication via a token. */ + init { + authorities = token.roles!!.stream() + .map(AuthorityReference::authority) + .distinct() + .map { role: String? -> SimpleGrantedAuthority(role) } + .collect(Collectors.toList()) + } + + override fun getName(): String { + return if (token.isClientCredentials) { + token.clientId!! + } else { + token.username!! + } + } + + override fun getAuthorities(): Collection { + return authorities + } + + override fun getCredentials(): Any { + return token + } + + override fun getDetails(): Any? { + return null + } + + override fun getPrincipal(): Any? { + return if (token.isClientCredentials) { + null + } else { + this + } + } + + override fun isAuthenticated(): Boolean { + return isAuthenticated + } + + @Throws(IllegalArgumentException::class) + override fun setAuthenticated(isAuthenticated: Boolean) { + this.isAuthenticated = isAuthenticated + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val that = other as RadarAuthentication + return isAuthenticated == that.isAuthenticated && token == that.token + } + + override fun hashCode(): Int { + var result = token?.hashCode() ?: 0 + result = 31 * result + if (isAuthenticated) 1 else 0 + return result + } + + override fun toString(): String { + return ("RadarAuthentication{" + "token=" + token + + ", authenticated=" + isAuthenticated() + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.java b/src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.java deleted file mode 100644 index cb0ca63b2..000000000 --- a/src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.security; - -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; - -public class RadarAuthenticationProvider implements AuthenticationProvider { - @Override - public Authentication authenticate(Authentication authentication) - throws AuthenticationException { - if (authentication.isAuthenticated()) { - return authentication; - } - return null; - } - - @Override - public boolean supports(Class authentication) { - return authentication.equals(RadarAuthentication.class); - } -} diff --git a/src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.kt b/src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.kt new file mode 100644 index 000000000..403e0e4e9 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.security + +import org.springframework.security.authentication.AuthenticationProvider +import org.springframework.security.core.Authentication +import org.springframework.security.core.AuthenticationException + +class RadarAuthenticationProvider : AuthenticationProvider { + @Throws(AuthenticationException::class) + override fun authenticate(authentication: Authentication): Authentication? { + return if (authentication.isAuthenticated) { + authentication + } else null + } + + override fun supports(authentication: Class<*>): Boolean { + return authentication == RadarAuthentication::class.java + } +} diff --git a/src/main/java/org/radarbase/management/security/SecurityUtils.java b/src/main/java/org/radarbase/management/security/SecurityUtils.java deleted file mode 100644 index ddd20113e..000000000 --- a/src/main/java/org/radarbase/management/security/SecurityUtils.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.radarbase.management.security; - -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; - -import java.util.Optional; - -/** - * Utility class for Spring Security. - */ -public final class SecurityUtils { - private SecurityUtils() { - } - - /** - * Get the login of the current user. - * - * @return the login of the current user if present - */ - public static Optional getCurrentUserLogin() { - SecurityContext securityContext = SecurityContextHolder.getContext(); - return getUserName(securityContext.getAuthentication()); - } - - /** - * Get the user name contianed in an Authentication object. - * - * @param authentication context authentication - * @return user name if present - */ - public static Optional getUserName(Authentication authentication) { - return Optional.ofNullable(authentication) - .map(Authentication::getPrincipal) - .map(principal -> { - if (principal instanceof UserDetails) { - return ((UserDetails) authentication.getPrincipal()).getUsername(); - } else if (principal instanceof String) { - return (String) authentication.getPrincipal(); - } else if (principal instanceof Authentication) { - return ((Authentication)principal).getName(); - } else { - return null; - } - }); - } -} diff --git a/src/main/java/org/radarbase/management/security/SecurityUtils.kt b/src/main/java/org/radarbase/management/security/SecurityUtils.kt new file mode 100644 index 000000000..0b6b66f42 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/SecurityUtils.kt @@ -0,0 +1,51 @@ +package org.radarbase.management.security + +import org.springframework.security.core.Authentication +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.security.core.userdetails.UserDetails + +/** + * Utility class for Spring Security. + */ +object SecurityUtils { + val currentUserLogin: String? + /** + * Get the login of the current user. + * + * @return the login of the current user if present + */ + get() { + val securityContext = SecurityContextHolder.getContext() + return getUserName(securityContext.authentication) + } + + /** + * Get the user name contianed in an Authentication object. + * + * @param authentication context authentication + * @return user name if present + */ + fun getUserName(authentication: Authentication): String? { + return authentication + .let { obj: Authentication -> obj.principal } + .let { principal: Any? -> + when (principal) { + is UserDetails -> { + return (authentication.principal as UserDetails).username + } + + is String -> { + return authentication.principal as String + } + + is Authentication -> { + return principal.name + } + + else -> { + return null + } + } + } + } +} diff --git a/src/main/java/org/radarbase/management/security/UserNotActivatedException.java b/src/main/java/org/radarbase/management/security/UserNotActivatedException.java deleted file mode 100644 index 1c679fc93..000000000 --- a/src/main/java/org/radarbase/management/security/UserNotActivatedException.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.radarbase.management.security; - -import org.springframework.security.core.AuthenticationException; - -/** - * This exception is thrown in case of a not activated user trying to authenticate. - */ -public class UserNotActivatedException extends AuthenticationException { - - private static final long serialVersionUID = 1L; - - public UserNotActivatedException(String message) { - super(message); - } - - public UserNotActivatedException(String message, Throwable t) { - super(message, t); - } -} diff --git a/src/main/java/org/radarbase/management/security/UserNotActivatedException.kt b/src/main/java/org/radarbase/management/security/UserNotActivatedException.kt new file mode 100644 index 000000000..f7e926bea --- /dev/null +++ b/src/main/java/org/radarbase/management/security/UserNotActivatedException.kt @@ -0,0 +1,15 @@ +package org.radarbase.management.security + +import org.springframework.security.core.AuthenticationException + +/** + * This exception is thrown in case of a not activated user trying to authenticate. + */ +class UserNotActivatedException : AuthenticationException { + constructor(message: String?) : super(message) + constructor(message: String?, t: Throwable?) : super(message, t) + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/security/jwt/JwtAccessTokenConverter.java b/src/main/java/org/radarbase/management/security/jwt/JwtAccessTokenConverter.kt similarity index 57% rename from src/main/java/org/radarbase/management/security/jwt/JwtAccessTokenConverter.java rename to src/main/java/org/radarbase/management/security/jwt/JwtAccessTokenConverter.kt index b318ba87e..c4b2b9bc1 100644 --- a/src/main/java/org/radarbase/management/security/jwt/JwtAccessTokenConverter.java +++ b/src/main/java/org/radarbase/management/security/jwt/JwtAccessTokenConverter.kt @@ -1,34 +1,21 @@ -package org.radarbase.management.security.jwt; +package org.radarbase.management.security.jwt -import java.util.Map; - -import com.auth0.jwt.algorithms.Algorithm; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.token.AccessTokenConverter; -import org.springframework.security.oauth2.provider.token.TokenEnhancer; +import com.auth0.jwt.algorithms.Algorithm +import org.springframework.security.oauth2.common.OAuth2AccessToken +import org.springframework.security.oauth2.provider.OAuth2Authentication +import org.springframework.security.oauth2.provider.token.AccessTokenConverter +import org.springframework.security.oauth2.provider.token.TokenEnhancer /** * Interface of a JwtAccessTokenConverter functions. */ -public interface JwtAccessTokenConverter extends TokenEnhancer, AccessTokenConverter { - - /** - * Field name for token id. - */ - String TOKEN_ID = AccessTokenConverter.JTI; - - /** - * Field name for access token id. - */ - String ACCESS_TOKEN_ID = AccessTokenConverter.ATI; - +interface JwtAccessTokenConverter : TokenEnhancer, AccessTokenConverter { /** * Decodes and verifies a JWT token string and extracts claims into a Map. * @param token string to decode. * @return claims of decoded token. */ - Map decode(String token); + fun decode(token: String): Map /** * Encodes token into JWT token. @@ -36,19 +23,30 @@ public interface JwtAccessTokenConverter extends TokenEnhancer, AccessTokenConve * @param authentication of the token. * @return JWT token string. */ - String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication); + fun encode(accessToken: OAuth2AccessToken, authentication: OAuth2Authentication): String /** * Checks whether a token is access-token or refresh-token. * Based on additional-information ati which contains the reference to access token of a * refresh token. */ - boolean isRefreshToken(OAuth2AccessToken token); + fun isRefreshToken(token: OAuth2AccessToken): Boolean /** * Algorithm to sign and verify the token. * @param algorithm to sign the JWT token */ - void setAlgorithm(Algorithm algorithm); - + fun setAlgorithm(algorithm: Algorithm) + + companion object { + /** + * Field name for token id. + */ + const val TOKEN_ID = AccessTokenConverter.JTI + + /** + * Field name for access token id. + */ + const val ACCESS_TOKEN_ID = AccessTokenConverter.ATI + } } diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt index b0e7d9496..c9d173c36 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt @@ -32,7 +32,7 @@ import java.util.stream.Stream * This class can accept an EC keypair as well as an RSA keypair for signing. EC signatures * are significantly smaller than RSA signatures. */ -class ManagementPortalJwtAccessTokenConverter( +open class ManagementPortalJwtAccessTokenConverter( algorithm: Algorithm, verifiers: MutableList, private val refreshTokenVerifiers: List @@ -163,7 +163,7 @@ class ManagementPortalJwtAccessTokenConverter( } override fun isRefreshToken(token: OAuth2AccessToken): Boolean { - return token.additionalInformation.containsKey(JwtAccessTokenConverter.ACCESS_TOKEN_ID) + return token?.additionalInformation?.containsKey(JwtAccessTokenConverter.ACCESS_TOKEN_ID) == true } override fun encode(accessToken: OAuth2AccessToken, authentication: OAuth2Authentication): String { diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.java b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.java deleted file mode 100644 index 02bc31ff8..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.java +++ /dev/null @@ -1,198 +0,0 @@ -package org.radarbase.management.security.jwt; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; - -import org.springframework.security.core.Authentication; -import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken; -import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.common.OAuth2RefreshToken; -import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.approval.Approval; -import org.springframework.security.oauth2.provider.approval.ApprovalStore; -import org.springframework.security.oauth2.provider.token.TokenStore; - -/** - * Adapted version of {@link org.springframework.security.oauth2.provider.token.store.JwtTokenStore} - * which uses interface {@link JwtAccessTokenConverter} instead of tied instance. - * - *

- * A {@link TokenStore} implementation that just reads data from the tokens themselves. - * Not really a store since it never persists anything, and methods like - * {@link #getAccessToken(OAuth2Authentication)} always return null. But - * nevertheless a useful tool since it translates access tokens to and - * from authentications. Use this wherever a{@link TokenStore} is needed, - * but remember to use the same {@link JwtAccessTokenConverter} - * instance (or one with the same verifier) as was used when the tokens were minted. - *

- * - * @author Dave Syer - * @author nivethika - */ -public class ManagementPortalJwtTokenStore implements TokenStore { - private final JwtAccessTokenConverter jwtAccessTokenConverter; - - private ApprovalStore approvalStore; - - /** - * Create a ManagementPortalJwtTokenStore with this token converter - * (should be shared with the DefaultTokenServices if used). - * - * @param jwtAccessTokenConverter JwtAccessTokenConverter used in the application. - */ - public ManagementPortalJwtTokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) { - this.jwtAccessTokenConverter = jwtAccessTokenConverter; - } - - /** - * Create a ManagementPortalJwtTokenStore with this token converter - * (should be shared with the DefaultTokenServices if used). - * - * @param jwtAccessTokenConverter JwtAccessTokenConverter used in the application. - * @param approvalStore TokenApprovalStore used in the application. - */ - public ManagementPortalJwtTokenStore(JwtAccessTokenConverter jwtAccessTokenConverter, - ApprovalStore approvalStore) { - this.jwtAccessTokenConverter = jwtAccessTokenConverter; - this.approvalStore = approvalStore; - } - - /** - * ApprovalStore to be used to validate and restrict refresh tokens. - * - * @param approvalStore the approvalStore to set - */ - public void setApprovalStore(ApprovalStore approvalStore) { - this.approvalStore = approvalStore; - } - - - @Override - public OAuth2Authentication readAuthentication(OAuth2AccessToken token) { - return readAuthentication(token.getValue()); - } - - @Override - public OAuth2Authentication readAuthentication(String token) { - return jwtAccessTokenConverter.extractAuthentication(jwtAccessTokenConverter.decode(token)); - } - - @Override - public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) { - // this is not really a store where we persist - } - - @Override - public OAuth2AccessToken readAccessToken(String tokenValue) { - OAuth2AccessToken accessToken = convertAccessToken(tokenValue); - - if (jwtAccessTokenConverter.isRefreshToken(accessToken)) { - throw new InvalidTokenException("Encoded token is a refresh token"); - } - return accessToken; - } - - private OAuth2AccessToken convertAccessToken(String tokenValue) { - return jwtAccessTokenConverter - .extractAccessToken(tokenValue, jwtAccessTokenConverter.decode(tokenValue)); - } - - @Override - public void removeAccessToken(OAuth2AccessToken token) { - // this is not really store where we persist - } - - @Override - public void storeRefreshToken(OAuth2RefreshToken refreshToken, - OAuth2Authentication authentication) { - // this is not really store where we persist - } - - @Override - public OAuth2RefreshToken readRefreshToken(String tokenValue) { - if (approvalStore != null) { - OAuth2Authentication authentication = readAuthentication(tokenValue); - if (authentication.getUserAuthentication() != null) { - String userId = authentication.getUserAuthentication().getName(); - String clientId = authentication.getOAuth2Request().getClientId(); - Collection approvals = approvalStore.getApprovals(userId, clientId); - Collection approvedScopes = new HashSet<>(); - for (Approval approval : approvals) { - if (approval.isApproved()) { - approvedScopes.add(approval.getScope()); - } - } - if (!approvedScopes.containsAll(authentication.getOAuth2Request().getScope())) { - return null; - } - } - } - OAuth2AccessToken encodedRefreshToken = convertAccessToken(tokenValue); - return createRefreshToken(encodedRefreshToken); - } - - private OAuth2RefreshToken createRefreshToken(OAuth2AccessToken encodedRefreshToken) { - if (!jwtAccessTokenConverter.isRefreshToken(encodedRefreshToken)) { - throw new InvalidTokenException("Encoded token is not a refresh token"); - } - if (encodedRefreshToken.getExpiration() != null) { - return new DefaultExpiringOAuth2RefreshToken(encodedRefreshToken.getValue(), - encodedRefreshToken.getExpiration()); - } - return new DefaultOAuth2RefreshToken(encodedRefreshToken.getValue()); - } - - @Override - public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) { - return readAuthentication(token.getValue()); - } - - @Override - public void removeRefreshToken(OAuth2RefreshToken token) { - remove(token.getValue()); - } - - private void remove(String token) { - if (approvalStore != null) { - OAuth2Authentication auth = readAuthentication(token); - String clientId = auth.getOAuth2Request().getClientId(); - Authentication user = auth.getUserAuthentication(); - if (user != null) { - Collection approvals = new ArrayList<>(); - for (String scope : auth.getOAuth2Request().getScope()) { - approvals.add(new Approval(user.getName(), clientId, scope, new Date(), - Approval.ApprovalStatus.APPROVED)); - } - approvalStore.revokeApprovals(approvals); - } - } - } - - @Override - public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) { - // this is not really store where we persist - } - - @Override - public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) { - // We don't want to accidentally issue a token, and we have no way to reconstruct - // the refresh token - return null; - } - - @Override - public Collection findTokensByClientIdAndUserName(String clientId, - String userName) { - return Collections.emptySet(); - } - - @Override - public Collection findTokensByClientId(String clientId) { - return Collections.emptySet(); - } -} diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.kt new file mode 100644 index 000000000..512b66433 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.kt @@ -0,0 +1,189 @@ +package org.radarbase.management.security.jwt + +import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken +import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken +import org.springframework.security.oauth2.common.OAuth2AccessToken +import org.springframework.security.oauth2.common.OAuth2RefreshToken +import org.springframework.security.oauth2.common.exceptions.InvalidTokenException +import org.springframework.security.oauth2.provider.OAuth2Authentication +import org.springframework.security.oauth2.provider.approval.Approval +import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus +import org.springframework.security.oauth2.provider.approval.ApprovalStore +import org.springframework.security.oauth2.provider.token.TokenStore +import java.util.* + +/** + * Adapted version of [org.springframework.security.oauth2.provider.token.store.JwtTokenStore] + * which uses interface [JwtAccessTokenConverter] instead of tied instance. + * + * + * + * A [TokenStore] implementation that just reads data from the tokens themselves. + * Not really a store since it never persists anything, and methods like + * [.getAccessToken] always return null. But + * nevertheless a useful tool since it translates access tokens to and + * from authentications. Use this wherever a[TokenStore] is needed, + * but remember to use the same [JwtAccessTokenConverter] + * instance (or one with the same verifier) as was used when the tokens were minted. + * + * + * @author Dave Syer + * @author nivethika + */ +class ManagementPortalJwtTokenStore : TokenStore { + private val jwtAccessTokenConverter: JwtAccessTokenConverter + private var approvalStore: ApprovalStore? = null + + /** + * Create a ManagementPortalJwtTokenStore with this token converter + * (should be shared with the DefaultTokenServices if used). + * + * @param jwtAccessTokenConverter JwtAccessTokenConverter used in the application. + */ + constructor(jwtAccessTokenConverter: JwtAccessTokenConverter) { + this.jwtAccessTokenConverter = jwtAccessTokenConverter + } + + /** + * Create a ManagementPortalJwtTokenStore with this token converter + * (should be shared with the DefaultTokenServices if used). + * + * @param jwtAccessTokenConverter JwtAccessTokenConverter used in the application. + * @param approvalStore TokenApprovalStore used in the application. + */ + constructor( + jwtAccessTokenConverter: JwtAccessTokenConverter, + approvalStore: ApprovalStore? + ) { + this.jwtAccessTokenConverter = jwtAccessTokenConverter + this.approvalStore = approvalStore + } + + /** + * ApprovalStore to be used to validate and restrict refresh tokens. + * + * @param approvalStore the approvalStore to set + */ + fun setApprovalStore(approvalStore: ApprovalStore?) { + this.approvalStore = approvalStore + } + + override fun readAuthentication(token: OAuth2AccessToken): OAuth2Authentication { + return readAuthentication(token.value) + } + + override fun readAuthentication(token: String): OAuth2Authentication { + return jwtAccessTokenConverter.extractAuthentication(jwtAccessTokenConverter.decode(token)) + } + + override fun storeAccessToken(token: OAuth2AccessToken, authentication: OAuth2Authentication) { + // this is not really a store where we persist + } + + override fun readAccessToken(tokenValue: String): OAuth2AccessToken { + val accessToken = convertAccessToken(tokenValue) + if (jwtAccessTokenConverter.isRefreshToken(accessToken)) { + throw InvalidTokenException("Encoded token is a refresh token") + } + return accessToken + } + + private fun convertAccessToken(tokenValue: String): OAuth2AccessToken { + return jwtAccessTokenConverter + .extractAccessToken(tokenValue, jwtAccessTokenConverter.decode(tokenValue)) + } + + override fun removeAccessToken(token: OAuth2AccessToken) { + // this is not really store where we persist + } + + override fun storeRefreshToken( + refreshToken: OAuth2RefreshToken, + authentication: OAuth2Authentication + ) { + // this is not really store where we persist + } + + override fun readRefreshToken(tokenValue: String): OAuth2RefreshToken? { + if (approvalStore != null) { + val authentication = readAuthentication(tokenValue) + if (authentication.userAuthentication != null) { + val userId = authentication.userAuthentication.name + val clientId = authentication.oAuth2Request.clientId + val approvals = approvalStore!!.getApprovals(userId, clientId) + val approvedScopes: MutableCollection = HashSet() + for (approval in approvals) { + if (approval.isApproved) { + approvedScopes.add(approval.scope) + } + } + if (!approvedScopes.containsAll(authentication.oAuth2Request.scope)) { + return null + } + } + } + val encodedRefreshToken = convertAccessToken(tokenValue) + return createRefreshToken(encodedRefreshToken) + } + + private fun createRefreshToken(encodedRefreshToken: OAuth2AccessToken): OAuth2RefreshToken { + if (!jwtAccessTokenConverter.isRefreshToken(encodedRefreshToken)) { + throw InvalidTokenException("Encoded token is not a refresh token") + } + return if (encodedRefreshToken.expiration != null) { + DefaultExpiringOAuth2RefreshToken( + encodedRefreshToken.value, + encodedRefreshToken.expiration + ) + } else DefaultOAuth2RefreshToken(encodedRefreshToken.value) + } + + override fun readAuthenticationForRefreshToken(token: OAuth2RefreshToken): OAuth2Authentication { + return readAuthentication(token.value) + } + + override fun removeRefreshToken(token: OAuth2RefreshToken) { + remove(token.value) + } + + private fun remove(token: String) { + if (approvalStore != null) { + val auth = readAuthentication(token) + val clientId = auth.oAuth2Request.clientId + val user = auth.userAuthentication + if (user != null) { + val approvals: MutableCollection = ArrayList() + for (scope in auth.oAuth2Request.scope) { + approvals.add( + Approval( + user.name, clientId, scope, Date(), + ApprovalStatus.APPROVED + ) + ) + } + approvalStore!!.revokeApprovals(approvals) + } + } + } + + override fun removeAccessTokenUsingRefreshToken(refreshToken: OAuth2RefreshToken) { + // this is not really store where we persist + } + + override fun getAccessToken(authentication: OAuth2Authentication): OAuth2AccessToken? { + // We don't want to accidentally issue a token, and we have no way to reconstruct + // the refresh token + return null + } + + override fun findTokensByClientIdAndUserName( + clientId: String, + userName: String + ): Collection { + return emptySet() + } + + override fun findTokensByClientId(clientId: String): Collection { + return emptySet() + } +} diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.java b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.java deleted file mode 100644 index aa9e2cf30..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.java +++ /dev/null @@ -1,324 +0,0 @@ -package org.radarbase.management.security.jwt; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.JWTVerifier; -import com.auth0.jwt.algorithms.Algorithm; -import org.radarbase.auth.authentication.TokenValidator; -import org.radarbase.auth.jwks.JsonWebKeySet; -import org.radarbase.auth.jwks.JwkAlgorithmParser; -import org.radarbase.auth.jwks.JwksTokenVerifierLoader; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.security.jwt.algorithm.EcdsaJwtAlgorithm; -import org.radarbase.management.security.jwt.algorithm.JwtAlgorithm; -import org.radarbase.management.security.jwt.algorithm.RsaJwtAlgorithm; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.stereotype.Component; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.servlet.ServletContext; -import java.io.IOException; -import java.security.KeyPair; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.RSAPrivateKey; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Stream; - -import static java.util.Objects.requireNonNull; -import static org.radarbase.management.security.jwt.ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL; - -/** - * Similar to Spring's - * {@link org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory}. However, - * this class does not assume a specific key type, while the Spring factory assumes RSA keys. - */ -@Component -public class ManagementPortalOauthKeyStoreHandler { - - private static final Logger logger = LoggerFactory.getLogger( - ManagementPortalOauthKeyStoreHandler.class); - - private static final List KEYSTORE_PATHS = Arrays.asList( - new ClassPathResource("/config/keystore.p12"), - new ClassPathResource("/config/keystore.jks")); - - private final char[] password; - - private final KeyStore store; - - private final Resource loadedResource; - - private final ManagementPortalProperties.Oauth oauthConfig; - - private final List verifierPublicKeyAliasList; - - private final String managementPortalBaseUrl; - - private final List verifiers; - private final List refreshTokenVerifiers; - - /** - * Keystore factory. This tries to load the first valid keystore listed in resources. - * - * @throws IllegalArgumentException if none of the provided resources can be used to load a - * keystore. - */ - @Autowired - public ManagementPortalOauthKeyStoreHandler( - Environment environment, - ServletContext servletContext, - ManagementPortalProperties managementPortalProperties) { - - checkOAuthConfig(managementPortalProperties); - - this.oauthConfig = managementPortalProperties.getOauth(); - this.password = oauthConfig.getKeyStorePassword().toCharArray(); - Map.Entry loadedStore = loadStore(); - this.loadedResource = loadedStore.getKey(); - this.store = loadedStore.getValue(); - this.verifierPublicKeyAliasList = loadVerifiersPublicKeyAliasList(); - - this.managementPortalBaseUrl = "http://localhost:" - + environment.getProperty("server.port") - + servletContext.getContextPath(); - logger.info("Using Management Portal base-url {}", this.managementPortalBaseUrl); - - List algorithms = loadAlgorithmsFromAlias() - .filter(Objects::nonNull) - .toList(); - - verifiers = algorithms.stream() - .map(algo -> JWT.require(algo).withAudience(RES_MANAGEMENT_PORTAL).build()) - .toList(); - // No need to check audience with a refresh token: it can be used - // to refresh tokens intended for other resources. - refreshTokenVerifiers = algorithms.stream() - .map(algo -> JWT.require(algo).build()) - .toList(); - } - - private static void checkOAuthConfig(ManagementPortalProperties managementPortalProperties) { - ManagementPortalProperties.Oauth oauthConfig = managementPortalProperties.getOauth(); - - if ( oauthConfig == null ) { - logger.error("Could not find valid Oauth Config. Please configure compulsary " - + "properties of Oauth configs of Management Portal"); - throw new IllegalArgumentException("OauthConfig is not provided"); - } - - if (oauthConfig.getKeyStorePassword() == null || oauthConfig.getKeyStorePassword() - .isEmpty()) { - logger.error("oauth.keyStorePassword is empty"); - throw new IllegalArgumentException("oauth.keyStorePassword is empty"); - } - - if (oauthConfig.getSigningKeyAlias() == null || oauthConfig.getSigningKeyAlias() - .isEmpty()) { - logger.error("oauth.signingKeyAlias is empty"); - throw new IllegalArgumentException("OauthConfig is not provided"); - } - - } - - @Nonnull - private Map.Entry loadStore() { - for (Resource resource : KEYSTORE_PATHS) { - if (!resource.exists()) { - logger.debug("JWT key store {} does not exist. Ignoring this resource", resource); - continue; - } - try { - String fileName = requireNonNull(resource.getFilename()).toLowerCase(Locale.ROOT); - String type = fileName.endsWith(".pfx") || fileName.endsWith(".p12") - ? "PKCS12" : "jks"; - KeyStore localStore = KeyStore.getInstance(type); - localStore.load(resource.getInputStream(), this.password); - logger.debug("Loaded JWT key store {}", resource); - return new AbstractMap.SimpleImmutableEntry<>(resource, localStore); - } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException - | IOException ex) { - logger.error("Cannot load JWT key store", ex); - } - } - throw new IllegalArgumentException("Cannot load any of the given JWT key stores " - + KEYSTORE_PATHS); - } - - private List loadVerifiersPublicKeyAliasList() { - List publicKeyAliases = new ArrayList<>(); - publicKeyAliases.add(oauthConfig.getSigningKeyAlias()); - if (oauthConfig.getCheckingKeyAliases() != null) { - publicKeyAliases.addAll(oauthConfig.getCheckingKeyAliases()); - } - return publicKeyAliases; - } - - /** - * Returns configured public keys of token verifiers. - * @return List of public keys for token verification. - */ - public JsonWebKeySet loadJwks() { - return new JsonWebKeySet(this.verifierPublicKeyAliasList.stream() - .map(this::getKeyPair) - .map(ManagementPortalOauthKeyStoreHandler::getJwtAlgorithm) - .filter(Objects::nonNull) - .map(JwtAlgorithm::getJwk) - .toList()); - } - - /** - * Load default verifiers from configured keystore and aliases. - */ - private Stream loadAlgorithmsFromAlias() { - return this.verifierPublicKeyAliasList.stream() - .map(this::getKeyPair) - .map(ManagementPortalOauthKeyStoreHandler::getJwtAlgorithm) - .filter(Objects::nonNull) - .map(JwtAlgorithm::getAlgorithm); - } - - public List getVerifiers() { - return this.verifiers; - } - - - /** - * Returns the signing algorithm extracted based on signing alias configured from keystore. - * @return signing algorithm. - */ - public Algorithm getAlgorithmForSigning() { - String signKey = oauthConfig.getSigningKeyAlias(); - logger.debug("Using JWT signing key {}", signKey); - KeyPair keyPair = getKeyPair(signKey); - if (keyPair == null) { - throw new IllegalArgumentException("Cannot load JWT signing key " + signKey - + " from JWT key store."); - } - - return getAlgorithmFromKeyPair(keyPair); - } - - /** - * Get a key pair from the store using the store password. - * @param alias key pair alias - * @return loaded key pair or {@code null} if the key store does not contain a loadable key with - * given alias. - * @throws IllegalArgumentException if the key alias password is wrong or the key cannot - * loaded. - */ - private @Nullable KeyPair getKeyPair(@Nullable String alias) { - return getKeyPair(alias, password); - } - - /** - * Get a key pair from the store with a given alias and password. - * @param alias key pair alias - * @param password key pair password - * @return loaded key pair or {@code null} if the key store does not contain a loadable key with - * given alias. - * @throws IllegalArgumentException if the key alias password is wrong or the key cannot - * loaded. - */ - private @Nullable KeyPair getKeyPair(@Nullable String alias, char[] password) { - try { - PrivateKey key = (PrivateKey) store.getKey(alias, password); - if (key == null) { - logger.warn("JWT key store {} does not contain private key pair for alias {}", - loadedResource, alias); - return null; - } - Certificate cert = store.getCertificate(alias); - if (cert == null) { - logger.warn("JWT key store {} does not contain certificate pair for alias {}", - loadedResource, alias); - return null; - } - PublicKey publicKey = cert.getPublicKey(); - if (publicKey == null) { - logger.warn("JWT key store {} does not contain public key pair for alias {}", - loadedResource, alias); - return null; - } - - return new KeyPair(publicKey, key); - } catch (NoSuchAlgorithmException ex) { - logger.warn( - "JWT key store {} contains unknown algorithm for key pair with alias {}: {}", - loadedResource, alias, ex.toString()); - return null; - } catch (UnrecoverableKeyException | KeyStoreException ex) { - throw new IllegalArgumentException("JWT key store " + loadedResource - + " contains unrecoverable key pair with alias " - + alias + " (the password may be wrong)", ex); - } - } - - /** - * Returns extracted {@link Algorithm} from the KeyPair. - * @param keyPair to find algorithm. - * @return extracted algorithm. - */ - private static Algorithm getAlgorithmFromKeyPair(KeyPair keyPair) { - JwtAlgorithm alg = getJwtAlgorithm(keyPair); - if (alg == null) { - throw new IllegalArgumentException("KeyPair type " - + keyPair.getPrivate().getAlgorithm() + " is unknown."); - } - return alg.getAlgorithm(); - } - - /** - * Get the JWT algorithm to sign or verify JWTs with. - * @param keyPair key pair for signing/verifying. - * @return algorithm or {@code null} if the key type is unknown. - */ - private static @Nullable JwtAlgorithm getJwtAlgorithm(@Nullable KeyPair keyPair) { - - if (keyPair == null) { - return null; - } - PrivateKey privateKey = keyPair.getPrivate(); - - if (privateKey instanceof ECPrivateKey) { - return new EcdsaJwtAlgorithm(keyPair); - } else if (privateKey instanceof RSAPrivateKey) { - return new RsaJwtAlgorithm(keyPair); - } else { - logger.warn("No JWT algorithm found for key type {}", privateKey.getClass()); - return null; - } - } - - /** Get the default token validator. */ - public TokenValidator getTokenValidator() { - var jwksLoader = new JwksTokenVerifierLoader( - managementPortalBaseUrl + "/oauth/token_key", - "res_ManagementPortal", - new JwkAlgorithmParser() - ); - return new TokenValidator(List.of(jwksLoader)); - } - - public List getRefreshTokenVerifiers() { - return refreshTokenVerifiers; - } -} diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt new file mode 100644 index 000000000..7fae1aed9 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt @@ -0,0 +1,289 @@ +package org.radarbase.management.security.jwt + +import com.auth0.jwt.JWT +import com.auth0.jwt.JWTVerifier +import com.auth0.jwt.algorithms.Algorithm +import org.radarbase.auth.authentication.TokenValidator +import org.radarbase.auth.jwks.JsonWebKeySet +import org.radarbase.auth.jwks.JwkAlgorithmParser +import org.radarbase.auth.jwks.JwksTokenVerifierLoader +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.config.ManagementPortalProperties.Oauth +import org.radarbase.management.security.jwt.algorithm.EcdsaJwtAlgorithm +import org.radarbase.management.security.jwt.algorithm.JwtAlgorithm +import org.radarbase.management.security.jwt.algorithm.RsaJwtAlgorithm +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.core.env.Environment +import org.springframework.core.io.ClassPathResource +import org.springframework.core.io.Resource +import org.springframework.stereotype.Component +import java.io.IOException +import java.lang.IllegalArgumentException +import java.security.KeyPair +import java.security.KeyStore +import java.security.KeyStoreException +import java.security.NoSuchAlgorithmException +import java.security.PrivateKey +import java.security.UnrecoverableKeyException +import java.security.cert.CertificateException +import java.security.interfaces.ECPrivateKey +import java.security.interfaces.RSAPrivateKey +import java.util.* +import java.util.AbstractMap.SimpleImmutableEntry +import java.util.stream.Stream +import javax.annotation.Nonnull +import javax.servlet.ServletContext +import kotlin.collections.Map.Entry + +/** + * Similar to Spring's + * [org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory]. However, + * this class does not assume a specific key type, while the Spring factory assumes RSA keys. + */ +@Component +class ManagementPortalOauthKeyStoreHandler @Autowired constructor( + environment: Environment, servletContext: ServletContext, managementPortalProperties: ManagementPortalProperties +) { + private val password: CharArray + private val store: KeyStore + private val loadedResource: Resource + private val oauthConfig: Oauth + private val verifierPublicKeyAliasList: List + private val managementPortalBaseUrl: String + val verifiers: MutableList + val refreshTokenVerifiers: MutableList + + /** + * Keystore factory. This tries to load the first valid keystore listed in resources. + * + * @throws IllegalArgumentException if none of the provided resources can be used to load a + * keystore. + */ + init { + checkOAuthConfig(managementPortalProperties) + oauthConfig = managementPortalProperties.oauth + password = oauthConfig.keyStorePassword.toCharArray() + val loadedStore: Entry = loadStore() + loadedResource = loadedStore.key + store = loadedStore.value + verifierPublicKeyAliasList = loadVerifiersPublicKeyAliasList() + managementPortalBaseUrl = + ("http://localhost:" + environment.getProperty("server.port") + servletContext.contextPath) + logger.info("Using Management Portal base-url {}", managementPortalBaseUrl) + val algorithms = loadAlgorithmsFromAlias().filter { obj: Algorithm? -> Objects.nonNull(obj) }.toList() + verifiers = algorithms.stream().map { algo: Algorithm? -> + JWT.require(algo).withAudience(ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL).build() + }.toList() + // No need to check audience with a refresh token: it can be used + // to refresh tokens intended for other resources. + refreshTokenVerifiers = algorithms.stream().map { algo: Algorithm? -> JWT.require(algo).build() }.toList() + } + + @Nonnull + private fun loadStore(): Entry { + for (resource in KEYSTORE_PATHS) { + if (!resource.exists()) { + logger.debug("JWT key store {} does not exist. Ignoring this resource", resource) + continue + } + try { + val fileName = Objects.requireNonNull(resource.filename).lowercase() + val type = if (fileName.endsWith(".pfx") || fileName.endsWith(".p12")) "PKCS12" else "jks" + val localStore = KeyStore.getInstance(type) + localStore.load(resource.inputStream, password) + logger.debug("Loaded JWT key store {}", resource) + if (resource != null && localStore != null) + return SimpleImmutableEntry(resource, localStore) + } catch (ex: CertificateException) { + logger.error("Cannot load JWT key store", ex) + } catch (ex: NoSuchAlgorithmException) { + logger.error("Cannot load JWT key store", ex) + } catch (ex: KeyStoreException) { + logger.error("Cannot load JWT key store", ex) + } catch (ex: IOException) { + logger.error("Cannot load JWT key store", ex) + } + } + throw IllegalArgumentException( + "Cannot load any of the given JWT key stores " + KEYSTORE_PATHS + ) + } + + private fun loadVerifiersPublicKeyAliasList(): List { + val publicKeyAliases: MutableList = ArrayList() + publicKeyAliases.add(oauthConfig.signingKeyAlias) + if (oauthConfig.checkingKeyAliases != null) { + publicKeyAliases.addAll(oauthConfig.checkingKeyAliases) + } + return publicKeyAliases + } + + /** + * Returns configured public keys of token verifiers. + * @return List of public keys for token verification. + */ + fun loadJwks(): JsonWebKeySet { + return JsonWebKeySet(verifierPublicKeyAliasList.map { alias: String? -> this.getKeyPair(alias) } + .map { keyPair: KeyPair? -> getJwtAlgorithm(keyPair) }.mapNotNull { obj: JwtAlgorithm? -> obj?.jwk }) + } + + /** + * Load default verifiers from configured keystore and aliases. + */ + private fun loadAlgorithmsFromAlias(): Stream { + return verifierPublicKeyAliasList.stream().map { alias: String? -> this.getKeyPair(alias) } + .map { keyPair: KeyPair? -> getJwtAlgorithm(keyPair) }.filter { obj: JwtAlgorithm? -> Objects.nonNull(obj) } + .map { obj: JwtAlgorithm? -> obj?.algorithm } + } + + val algorithmForSigning: Algorithm + /** + * Returns the signing algorithm extracted based on signing alias configured from keystore. + * @return signing algorithm. + */ + get() { + val signKey = oauthConfig.signingKeyAlias + logger.debug("Using JWT signing key {}", signKey) + val keyPair = getKeyPair(signKey) ?: throw IllegalArgumentException( + "Cannot load JWT signing key " + signKey + " from JWT key store." + ) + return getAlgorithmFromKeyPair(keyPair) + } + + /** + * Get a key pair from the store using the store password. + * @param alias key pair alias + * @return loaded key pair or `null` if the key store does not contain a loadable key with + * given alias. + * @throws IllegalArgumentException if the key alias password is wrong or the key cannot + * loaded. + */ + private fun getKeyPair(alias: String?): KeyPair? { + return getKeyPair(alias, password) + } + + /** + * Get a key pair from the store with a given alias and password. + * @param alias key pair alias + * @param password key pair password + * @return loaded key pair or `null` if the key store does not contain a loadable key with + * given alias. + * @throws IllegalArgumentException if the key alias password is wrong or the key cannot + * load. + */ + private fun getKeyPair(alias: String?, password: CharArray): KeyPair? { + return try { + val key = store.getKey(alias, password) as PrivateKey? + if (key == null) { + logger.warn( + "JWT key store {} does not contain private key pair for alias {}", loadedResource, alias + ) + return null + } + val cert = store.getCertificate(alias) + if (cert == null) { + logger.warn( + "JWT key store {} does not contain certificate pair for alias {}", loadedResource, alias + ) + return null + } + val publicKey = cert.publicKey + if (publicKey == null) { + logger.warn( + "JWT key store {} does not contain public key pair for alias {}", loadedResource, alias + ) + return null + } + KeyPair(publicKey, key) + } catch (ex: NoSuchAlgorithmException) { + logger.warn( + "JWT key store {} contains unknown algorithm for key pair with alias {}: {}", + loadedResource, + alias, + ex.toString() + ) + null + } catch (ex: UnrecoverableKeyException) { + throw IllegalArgumentException( + "JWT key store $loadedResource contains unrecoverable key pair with alias $alias (the password may be wrong)", + ex + ) + } catch (ex: KeyStoreException) { + throw IllegalArgumentException( + "JWT key store $loadedResource contains unrecoverable key pair with alias $alias (the password may be wrong)", + ex + ) + } + } + + val tokenValidator: TokenValidator + /** Get the default token validator. */ + get() { + val jwksLoader = JwksTokenVerifierLoader( + "$managementPortalBaseUrl/oauth/token_key", "res_ManagementPortal", JwkAlgorithmParser() + ) + return TokenValidator(java.util.List.of(jwksLoader)) + } + + companion object { + private val logger = LoggerFactory.getLogger( + ManagementPortalOauthKeyStoreHandler::class.java + ) + private val KEYSTORE_PATHS = Arrays.asList( + ClassPathResource("/config/keystore.p12"), ClassPathResource("/config/keystore.jks") + ) + + private fun checkOAuthConfig(managementPortalProperties: ManagementPortalProperties) { + val oauthConfig = managementPortalProperties.oauth + if (oauthConfig == null) { + logger.error( + "Could not find valid Oauth Config. Please configure compulsary " + "properties of Oauth configs of Management Portal" + ) + throw IllegalArgumentException("OauthConfig is not provided") + } + if (oauthConfig.keyStorePassword == null || oauthConfig.keyStorePassword.isEmpty()) { + logger.error("oauth.keyStorePassword is empty") + throw IllegalArgumentException("oauth.keyStorePassword is empty") + } + if (oauthConfig.signingKeyAlias == null || oauthConfig.signingKeyAlias.isEmpty()) { + logger.error("oauth.signingKeyAlias is empty") + throw IllegalArgumentException("OauthConfig is not provided") + } + } + + /** + * Returns extracted [Algorithm] from the KeyPair. + * @param keyPair to find algorithm. + * @return extracted algorithm. + */ + private fun getAlgorithmFromKeyPair(keyPair: KeyPair): Algorithm { + val alg = getJwtAlgorithm(keyPair) ?: throw IllegalArgumentException( + "KeyPair type " + keyPair.private.algorithm + " is unknown." + ) + return alg.algorithm + } + + /** + * Get the JWT algorithm to sign or verify JWTs with. + * @param keyPair key pair for signing/verifying. + * @return algorithm or `null` if the key type is unknown. + */ + private fun getJwtAlgorithm(keyPair: KeyPair?): JwtAlgorithm? { + if (keyPair == null) { + return null + } + val privateKey = keyPair.private + return if (privateKey is ECPrivateKey) { + EcdsaJwtAlgorithm(keyPair) + } else if (privateKey is RSAPrivateKey) { + RsaJwtAlgorithm(keyPair) + } else { + logger.warn( + "No JWT algorithm found for key type {}", privateKey.javaClass + ) + null + } + } + } +} diff --git a/src/main/java/org/radarbase/management/security/jwt/SignatureException.java b/src/main/java/org/radarbase/management/security/jwt/SignatureException.java deleted file mode 100644 index 958b95300..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/SignatureException.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.radarbase.management.security.jwt; - -public class SignatureException extends RuntimeException { - - public SignatureException() { - super(); - } - - public SignatureException(String message) { - super(message); - } - - public SignatureException(String message, Throwable ex) { - super(message, ex); - } - - public SignatureException(Throwable ex) { - super(ex); - } -} diff --git a/src/main/java/org/radarbase/management/security/jwt/SignatureException.kt b/src/main/java/org/radarbase/management/security/jwt/SignatureException.kt new file mode 100644 index 000000000..8f790fb7d --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/SignatureException.kt @@ -0,0 +1,8 @@ +package org.radarbase.management.security.jwt + +class SignatureException : RuntimeException { + constructor() : super() + constructor(message: String?) : super(message) + constructor(message: String?, ex: Throwable?) : super(message, ex) + constructor(ex: Throwable?) : super(ex) +} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.kt b/src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.kt new file mode 100644 index 000000000..303b078fb --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.kt @@ -0,0 +1,24 @@ +package org.radarbase.management.security.jwt.algorithm + +import org.radarbase.auth.jwks.JsonWebKey +import org.radarbase.auth.jwks.MPJsonWebKey +import java.security.KeyPair +import java.util.* + +abstract class AsymmetricalJwtAlgorithm protected constructor(protected val keyPair: KeyPair) : JwtAlgorithm { + protected abstract val encodedStringHeader: String + protected abstract val encodedStringFooter: String + protected abstract val keyType: String + override val verifierKeyEncodedString: String + get() = """ + ${encodedStringHeader} + ${String(Base64.getEncoder().encode(keyPair.public.encoded))} + ${encodedStringFooter} + """.trimIndent() + override val jwk: JsonWebKey + get() = MPJsonWebKey( + algorithm.name, + keyType, + verifierKeyEncodedString + ) +} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.kt b/src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.kt new file mode 100644 index 000000000..a886cdfdb --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.kt @@ -0,0 +1,25 @@ +package org.radarbase.management.security.jwt.algorithm + +import com.auth0.jwt.algorithms.Algorithm +import java.security.KeyPair +import java.security.interfaces.ECPrivateKey +import java.security.interfaces.ECPublicKey + +class EcdsaJwtAlgorithm(keyPair: KeyPair) : AsymmetricalJwtAlgorithm(keyPair) { + /** ECDSA JWT algorithm. */ + init { + require(keyPair.private is ECPrivateKey) { "Cannot make EcdsaJwtAlgorithm with " + keyPair.private.javaClass } + } + + override val algorithm: Algorithm + get() = Algorithm.ECDSA256( + keyPair.public as ECPublicKey, + keyPair.private as ECPrivateKey + ) + override val encodedStringHeader: String + get() = "-----BEGIN EC PUBLIC KEY-----" + override val encodedStringFooter: String + get() = "-----END EC PUBLIC KEY-----" + override val keyType: String + get() = "EC" +} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.kt b/src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.kt new file mode 100644 index 000000000..7429ad473 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.kt @@ -0,0 +1,25 @@ +package org.radarbase.management.security.jwt.algorithm + +import com.auth0.jwt.algorithms.Algorithm +import org.radarbase.auth.jwks.JsonWebKey + +/** + * Encodes a signing and verification algorithm for JWT. + */ +interface JwtAlgorithm { + /** + * Auth0 Algorithm used in JWTs. + */ + val algorithm: Algorithm + + /** + * Encoded public key for storage or transmission. + */ + val verifierKeyEncodedString: String + + /** + * JavaWebKey for given algorithm for token verification. + * @return instance of [JsonWebKey] + */ + val jwk: JsonWebKey +} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.kt b/src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.kt new file mode 100644 index 000000000..0592c9ba0 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.kt @@ -0,0 +1,25 @@ +package org.radarbase.management.security.jwt.algorithm + +import com.auth0.jwt.algorithms.Algorithm +import java.security.KeyPair +import java.security.interfaces.RSAPrivateKey +import java.security.interfaces.RSAPublicKey + +class RsaJwtAlgorithm(keyPair: KeyPair) : AsymmetricalJwtAlgorithm(keyPair) { + /** RSA JWT algorithm. */ + init { + require(keyPair.private is RSAPrivateKey) { "Cannot make RsaJwtAlgorithm with " + keyPair.private.javaClass } + } + + override val algorithm: Algorithm + get() = Algorithm.RSA256( + keyPair.public as RSAPublicKey, + keyPair.private as RSAPrivateKey + ) + override val encodedStringHeader: String + get() = "-----BEGIN PUBLIC KEY-----" + override val encodedStringFooter: String + get() = "-----END PUBLIC KEY-----" + override val keyType: String + get() = "RSA" +} diff --git a/src/main/java/org/radarbase/management/security/package-info.java b/src/main/java/org/radarbase/management/security/package-info.java deleted file mode 100644 index 30c9babd1..000000000 --- a/src/main/java/org/radarbase/management/security/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Spring Security configuration. - */ -package org.radarbase.management.security; diff --git a/src/main/java/org/radarbase/management/security/package-info.kt b/src/main/java/org/radarbase/management/security/package-info.kt new file mode 100644 index 000000000..9739a9a01 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/package-info.kt @@ -0,0 +1,5 @@ +/** + * Spring Security configuration. + */ +package org.radarbase.management.security + diff --git a/src/main/java/org/radarbase/management/service/AuditEventService.java b/src/main/java/org/radarbase/management/service/AuditEventService.java deleted file mode 100644 index 219c81f92..000000000 --- a/src/main/java/org/radarbase/management/service/AuditEventService.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.config.audit.AuditEventConverter; -import org.radarbase.management.repository.PersistenceAuditEventRepository; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.time.LocalDateTime; -import java.util.Optional; - -/** - * Service for managing audit events.

This is the default implementation to support SpringBoot - * Actuator AuditEventRepository

- */ -@Service -@Transactional -public class AuditEventService { - - private final PersistenceAuditEventRepository persistenceAuditEventRepository; - - private final AuditEventConverter auditEventConverter; - - public AuditEventService( - PersistenceAuditEventRepository persistenceAuditEventRepository, - AuditEventConverter auditEventConverter) { - this.persistenceAuditEventRepository = persistenceAuditEventRepository; - this.auditEventConverter = auditEventConverter; - } - - public Page findAll(Pageable pageable) { - return persistenceAuditEventRepository.findAll(pageable) - .map(auditEventConverter::convertToAuditEvent); - } - - /** - * Find audit events by dates. - * - * @param fromDate start of the date range - * @param toDate end of the date range - * @param pageable the pageable - * @return a page of audit events - */ - public Page findByDates(LocalDateTime fromDate, LocalDateTime toDate, - Pageable pageable) { - return persistenceAuditEventRepository - .findAllByAuditEventDateBetween(fromDate, toDate, pageable) - .map(auditEventConverter::convertToAuditEvent); - } - - public Optional find(Long id) { - return persistenceAuditEventRepository.findById(id) - .map(auditEventConverter::convertToAuditEvent); - } -} diff --git a/src/main/java/org/radarbase/management/service/AuditEventService.kt b/src/main/java/org/radarbase/management/service/AuditEventService.kt new file mode 100644 index 000000000..9881c7195 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/AuditEventService.kt @@ -0,0 +1,64 @@ +package org.radarbase.management.service + +import org.radarbase.management.config.audit.AuditEventConverter +import org.radarbase.management.domain.PersistentAuditEvent +import org.radarbase.management.repository.PersistenceAuditEventRepository +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.time.LocalDateTime +import java.util.* + +/** + * Service for managing audit events. + * + * This is the default implementation to support SpringBoot + * Actuator AuditEventRepository + */ +@Service +@Transactional +class AuditEventService( + private val persistenceAuditEventRepository: PersistenceAuditEventRepository, + private val auditEventConverter: AuditEventConverter +) { + fun findAll(pageable: Pageable?): Page { + return persistenceAuditEventRepository.findAll(pageable) + .map { persistentAuditEvent: PersistentAuditEvent? -> + auditEventConverter.convertToAuditEvent( + persistentAuditEvent!! + ) + } + } + + /** + * Find audit events by dates. + * + * @param fromDate start of the date range + * @param toDate end of the date range + * @param pageable the pageable + * @return a page of audit events + */ + fun findByDates( + fromDate: LocalDateTime?, toDate: LocalDateTime?, + pageable: Pageable? + ): Page { + return persistenceAuditEventRepository + .findAllByAuditEventDateBetween(fromDate, toDate, pageable) + .map { persistentAuditEvent: PersistentAuditEvent? -> + auditEventConverter.convertToAuditEvent( + persistentAuditEvent!! + ) + } + } + + fun find(id: Long): Optional { + return persistenceAuditEventRepository.findById(id) + .map { persistentAuditEvent: PersistentAuditEvent? -> + auditEventConverter.convertToAuditEvent( + persistentAuditEvent!! + ) + } + } +} diff --git a/src/main/java/org/radarbase/management/service/GroupService.kt b/src/main/java/org/radarbase/management/service/GroupService.kt index b30b94195..3cda93ef0 100644 --- a/src/main/java/org/radarbase/management/service/GroupService.kt +++ b/src/main/java/org/radarbase/management/service/GroupService.kt @@ -48,14 +48,13 @@ open class GroupService( open fun getGroup(projectName: String, groupName: String): GroupDTO { return groupMapper.groupToGroupDTOFull( groupRepository.findByProjectNameAndName( - projectName, - groupName + projectName, groupName + ) ?: throw NotFoundException( + "Group $groupName not found in project $projectName", + EntityName.GROUP, + ErrorConstants.ERR_GROUP_NOT_FOUND ) - ?: throw NotFoundException( - "Group $groupName not found in project $projectName", - EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND - ) - ) + )!! } /** @@ -67,16 +66,14 @@ open class GroupService( */ @Transactional open fun deleteGroup(projectName: String, groupName: String, unlinkSubjects: Boolean) { - val group = groupRepository.findByProjectNameAndName(projectName, groupName) - ?: throw NotFoundException( - "Group $groupName not found in project $projectName", - EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND - ) + val group = groupRepository.findByProjectNameAndName(projectName, groupName) ?: throw NotFoundException( + "Group $groupName not found in project $projectName", EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + ) if (!unlinkSubjects) { val subjectCount = subjectRepository.countByGroupId(group.id) if (subjectCount > 0) { - val msg = ("Group " + groupName + " has subjects. " - + "Add `unlinkSubjects=true` query param to confirm deletion") + val msg = + ("Group " + groupName + " has subjects. " + "Add `unlinkSubjects=true` query param to confirm deletion") throw ConflictException(msg, EntityName.GROUP, ErrorConstants.ERR_VALIDATION) } } @@ -91,26 +88,30 @@ open class GroupService( * @throws ConflictException if the group name already exists. */ @Transactional - open fun createGroup(projectName: String, groupDto: GroupDTO): GroupDTO { - val project = projectRepository.findOneWithGroupsByName(projectName) - ?: throw NotFoundException( - "Project with name $projectName not found", - EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND - ) - if (project.groups.stream() - .anyMatch { g: Group -> g.name == groupDto.name } - ) { + open fun createGroup(projectName: String, groupDto: GroupDTO): GroupDTO? { + val project = projectRepository.findOneWithGroupsByName(projectName) ?: throw NotFoundException( + "Project with name $projectName not found", EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND + ) + if (project.groups.stream().anyMatch { g: Group -> g.name == groupDto.name }) { throw ConflictException( "Group " + groupDto.name + " already exists in project " + projectName, - EntityName.GROUP, ErrorConstants.ERR_GROUP_EXISTS + EntityName.GROUP, + ErrorConstants.ERR_GROUP_EXISTS ) } val group = groupMapper.groupDTOToGroup(groupDto) - group.project = project - val groupDtoResult = groupMapper.groupToGroupDTOFull(groupRepository.save(group)) - project.groups.add(group) - projectRepository.save(project) - return groupDtoResult + if (group != null) { + group.project = project + val groupDtoResult = groupMapper.groupToGroupDTOFull(groupRepository.save(group)) + project.groups.add(group) + projectRepository.save(project) + return groupDtoResult + } + else { + throw NotFoundException( + "Group ${groupDto.name} not found in project $projectName", EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + ) + } } /** @@ -119,11 +120,9 @@ open class GroupService( * @throws NotFoundException if the project is not found. */ fun listGroups(projectName: String): List { - val project = projectRepository.findOneWithGroupsByName(projectName) - ?: throw NotFoundException( - "Project with name $projectName not found", - EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND - ) + val project = projectRepository.findOneWithGroupsByName(projectName) ?: throw NotFoundException( + "Project with name $projectName not found", EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND + ) return groupMapper.groupToGroupDTOs(project.groups) } @@ -137,59 +136,51 @@ open class GroupService( */ @Transactional open fun updateGroupSubjects( - projectName: String, groupName: String, + projectName: String, + groupName: String, subjectsToAdd: List, subjectsToRemove: List ) { groupRepository ?: throw NullPointerException() - val group = groupRepository.findByProjectNameAndName(projectName, groupName) - ?: throw NotFoundException( - "Group $groupName not found in project $projectName", - EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND - ) + val group = groupRepository.findByProjectNameAndName(projectName, groupName) ?: throw NotFoundException( + "Group $groupName not found in project $projectName", EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + ) val entitiesToAdd = getSubjectEntities(projectName, subjectsToAdd) val entitiesToRemove = getSubjectEntities(projectName, subjectsToRemove) if (entitiesToAdd.isNotEmpty()) { - val idsToAdd = entitiesToAdd.stream() - .map(Subject::id) - .toList() - subjectRepository.setGroupIdByIds(group.id, idsToAdd) + val idsToAdd = entitiesToAdd.mapNotNull(Subject::id).toList() + subjectRepository.setGroupIdByIds(group.id!!, idsToAdd) } if (entitiesToRemove.isNotEmpty()) { - val idsToRemove = entitiesToRemove.stream() - .map(Subject::id) - .toList() + val idsToRemove = entitiesToRemove.mapNotNull(Subject::id) subjectRepository.unsetGroupIdByIds(idsToRemove) } } private fun getSubjectEntities( - projectName: String, - subjectsToModify: List + projectName: String, subjectsToModify: List ): List { val logins: MutableList = ArrayList() val ids: MutableList = ArrayList() extractSubjectIdentities(subjectsToModify, logins, ids) val subjectEntities: MutableList = ArrayList(subjectsToModify.size) - if (!ids.isEmpty()) { + if (ids.isNotEmpty()) { subjectEntities.addAll(subjectRepository.findAllById(ids)) } - if (!logins.isEmpty()) { + if (logins.isNotEmpty()) { subjectEntities.addAll(subjectRepository.findAllBySubjectLogins(logins)) } for (s in subjectEntities) { val login = s.user!!.login s.activeProject ?: throw BadRequestException( - "Subject $login is not assigned to a project", - EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION + "Subject $login is not assigned to a project", EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION ) if (projectName != s.activeProject!!.projectName) { throw BadRequestException( - "Subject $login belongs to a different project", - EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION + "Subject $login belongs to a different project", EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION ) } } @@ -197,9 +188,7 @@ open class GroupService( } private fun extractSubjectIdentities( - subjectsToModify: List, - logins: MutableList, - ids: MutableList + subjectsToModify: List, logins: MutableList, ids: MutableList ) { // Each item should specify either a login or an ID, // since having both will require an extra validation step @@ -211,15 +200,14 @@ open class GroupService( val id = item.id if (id == null && login == null) { throw BadRequestException( - "Subject identification must be specified", - EntityName.GROUP, ErrorConstants.ERR_VALIDATION + "Subject identification must be specified", EntityName.GROUP, ErrorConstants.ERR_VALIDATION ) } if (id != null && login != null) { throw BadRequestException( - "Subject identification must be specify either ID or Login. " - + "Do not provide both values to avoid potential confusion.", - EntityName.GROUP, ErrorConstants.ERR_VALIDATION + "Subject identification must be specify either ID or Login. " + "Do not provide both values to avoid potential confusion.", + EntityName.GROUP, + ErrorConstants.ERR_VALIDATION ) } if (id != null) { diff --git a/src/main/java/org/radarbase/management/service/MailService.java b/src/main/java/org/radarbase/management/service/MailService.java deleted file mode 100644 index 788222773..000000000 --- a/src/main/java/org/radarbase/management/service/MailService.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.radarbase.management.service; - -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.util.Locale; -import javax.mail.internet.MimeMessage; - -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.User; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.MessageSource; -import org.springframework.mail.javamail.JavaMailSender; -import org.springframework.mail.javamail.MimeMessageHelper; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; -import org.thymeleaf.context.Context; -import org.thymeleaf.spring5.SpringTemplateEngine; - -/** - * Service for sending emails.

We use the @Async annotation to send emails asynchronously.

- */ -@Service -public class MailService { - - private static final Logger log = LoggerFactory.getLogger(MailService.class); - - private static final String USER = "user"; - - private static final String BASE_URL = "baseUrl"; - - private static final String EXPIRY = "expiry"; - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Autowired - private JavaMailSender javaMailSender; - - @Autowired - private MessageSource messageSource; - - @Autowired - private SpringTemplateEngine templateEngine; - - /** - * Send an email. - * @param to email address to send to - * @param subject subject line - * @param content email contents - * @param isMultipart send as multipart - * @param isHtml send as html - */ - @Async - public void sendEmail(String to, String subject, String content, boolean isMultipart, - boolean isHtml) { - log.debug( - "Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}", - isMultipart, isHtml, to, subject, content); - - // Prepare message using a Spring helper - MimeMessage mimeMessage = javaMailSender.createMimeMessage(); - try { - MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, - StandardCharsets.UTF_8.name()); - message.setTo(to); - message.setFrom(managementPortalProperties.getMail().getFrom()); - message.setSubject(subject); - message.setText(content, isHtml); - javaMailSender.send(mimeMessage); - log.debug("Sent email to User '{}'", to); - } catch (Exception e) { - log.warn("Email could not be sent to user '{}'", to, e); - } - } - - /** - * Send an account activation email to a given user. - * @param user the user to send to - */ - @Async - public void sendActivationEmail(User user) { - log.debug("Sending activation email to '{}'", user.email); - Locale locale = Locale.forLanguageTag(user.langKey); - Context context = new Context(locale); - context.setVariable(USER, user); - context.setVariable(BASE_URL, - managementPortalProperties.getCommon().getManagementPortalBaseUrl()); - String content = templateEngine.process("activationEmail", context); - String subject = messageSource.getMessage("email.activation.title", null, locale); - sendEmail(user.email, subject, content, false, true); - } - - /** - * Send account creation email to a given user. - * @param user the user - */ - @Async - public void sendCreationEmail(User user, long duration) { - log.debug("Sending creation email to '{}'", user.email); - Locale locale = Locale.forLanguageTag(user.langKey); - Context context = new Context(locale); - context.setVariable(USER, user); - context.setVariable(BASE_URL, - managementPortalProperties.getCommon().getManagementPortalBaseUrl()); - context.setVariable(EXPIRY, Duration.ofSeconds(duration).toHours()); - String content = templateEngine.process("creationEmail", context); - String subject = messageSource.getMessage("email.activation.title", null, locale); - sendEmail(user.email, subject, content, false, true); - } - - /** - * Send account creation email for a user to an address different than the users' address. - * @param user the created user - * @param email the address to send to - */ - @Async - public void sendCreationEmailForGivenEmail(User user, String email) { - log.debug("Sending creation email to '{}'", email); - Locale locale = Locale.forLanguageTag(user.langKey); - Context context = new Context(locale); - context.setVariable(USER, user); - context.setVariable(BASE_URL, - managementPortalProperties.getCommon().getManagementPortalBaseUrl()); - String content = templateEngine.process("creationEmail", context); - String subject = messageSource.getMessage("email.activation.title", null, locale); - sendEmail(email, subject, content, false, true); - } - - /** - * Send a password reset email to a given user. - * @param user the user - */ - @Async - public void sendPasswordResetMail(User user) { - log.debug("Sending password reset email to '{}'", user.email); - Locale locale = Locale.forLanguageTag(user.langKey); - Context context = new Context(locale); - context.setVariable(USER, user); - context.setVariable(BASE_URL, - managementPortalProperties.getCommon().getManagementPortalBaseUrl()); - String content = templateEngine.process("passwordResetEmail", context); - String subject = messageSource.getMessage("email.reset.title", null, locale); - sendEmail(user.email, subject, content, false, true); - } -} diff --git a/src/main/java/org/radarbase/management/service/MailService.kt b/src/main/java/org/radarbase/management/service/MailService.kt new file mode 100644 index 000000000..3f894424d --- /dev/null +++ b/src/main/java/org/radarbase/management/service/MailService.kt @@ -0,0 +1,157 @@ +package org.radarbase.management.service + +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.User +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.MessageSource +import org.springframework.mail.javamail.JavaMailSender +import org.springframework.mail.javamail.MimeMessageHelper +import org.springframework.scheduling.annotation.Async +import org.springframework.stereotype.Service +import org.thymeleaf.context.Context +import org.thymeleaf.spring5.SpringTemplateEngine +import java.nio.charset.StandardCharsets +import java.time.Duration +import java.util.* + +/** + * Service for sending emails. + * + * We use the @Async annotation to send emails asynchronously. + */ +@Service +class MailService { + @Autowired + private val managementPortalProperties: ManagementPortalProperties? = null + + @Autowired + private val javaMailSender: JavaMailSender? = null + + @Autowired + private val messageSource: MessageSource? = null + + @Autowired + private val templateEngine: SpringTemplateEngine? = null + + /** + * Send an email. + * @param to email address to send to + * @param subject subject line + * @param content email contents + * @param isMultipart send as multipart + * @param isHtml send as html + */ + @Async + fun sendEmail( + to: String?, subject: String?, content: String?, isMultipart: Boolean, + isHtml: Boolean + ) { + log.debug( + "Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}", + isMultipart, isHtml, to, subject, content + ) + + // Prepare message using a Spring helper + val mimeMessage = javaMailSender!!.createMimeMessage() + try { + val message = MimeMessageHelper( + mimeMessage, isMultipart, + StandardCharsets.UTF_8.name() + ) + message.setTo(to) + message.setFrom(managementPortalProperties!!.mail.from) + message.setSubject(subject) + message.setText(content, isHtml) + javaMailSender.send(mimeMessage) + log.debug("Sent email to User '{}'", to) + } catch (e: Exception) { + log.warn("Email could not be sent to user '{}'", to, e) + } + } + + /** + * Send an account activation email to a given user. + * @param user the user to send to + */ + @Async + fun sendActivationEmail(user: User) { + log.debug("Sending activation email to '{}'", user.email) + val locale = Locale.forLanguageTag(user.langKey) + val context = Context(locale) + context.setVariable(USER, user) + context.setVariable( + BASE_URL, + managementPortalProperties!!.common.managementPortalBaseUrl + ) + val content = templateEngine!!.process("activationEmail", context) + val subject = messageSource!!.getMessage("email.activation.title", null, locale) + sendEmail(user.email, subject, content, false, true) + } + + /** + * Send account creation email to a given user. + * @param user the user + */ + @Async + fun sendCreationEmail(user: User, duration: Long) { + log.debug("Sending creation email to '{}'", user.email) + val locale = Locale.forLanguageTag(user.langKey) + val context = Context(locale) + context.setVariable(USER, user) + context.setVariable( + BASE_URL, + managementPortalProperties!!.common.managementPortalBaseUrl + ) + context.setVariable(EXPIRY, Duration.ofSeconds(duration).toHours()) + val content = templateEngine!!.process("creationEmail", context) + val subject = messageSource!!.getMessage("email.activation.title", null, locale) + sendEmail(user.email, subject, content, false, true) + } + + /** + * Send account creation email for a user to an address different than the users' address. + * @param user the created user + * @param email the address to send to + */ + @Async + fun sendCreationEmailForGivenEmail(user: User, email: String?) { + log.debug("Sending creation email to '{}'", email) + val locale = Locale.forLanguageTag(user.langKey) + val context = Context(locale) + context.setVariable(USER, user) + context.setVariable( + BASE_URL, + managementPortalProperties!!.common.managementPortalBaseUrl + ) + val content = templateEngine!!.process("creationEmail", context) + val subject = messageSource!!.getMessage("email.activation.title", null, locale) + sendEmail(email, subject, content, false, true) + } + + /** + * Send a password reset email to a given user. + * @param user the user + */ + @Async + fun sendPasswordResetMail(user: User) { + log.debug("Sending password reset email to '{}'", user.email) + val locale = Locale.forLanguageTag(user.langKey) + val context = Context(locale) + context.setVariable(USER, user) + context.setVariable( + BASE_URL, + managementPortalProperties!!.common.managementPortalBaseUrl + ) + val content = templateEngine!!.process("passwordResetEmail", context) + val subject = messageSource!!.getMessage("email.reset.title", null, locale) + sendEmail(user.email, subject, content, false, true) + } + + companion object { + private val log = LoggerFactory.getLogger(MailService::class.java) + private const val USER = "user" + private const val BASE_URL = "baseUrl" + private const val EXPIRY = "expiry" + } +} diff --git a/src/main/java/org/radarbase/management/service/MetaTokenService.kt b/src/main/java/org/radarbase/management/service/MetaTokenService.kt index 9a8bfe961..a89752a6b 100644 --- a/src/main/java/org/radarbase/management/service/MetaTokenService.kt +++ b/src/main/java/org/radarbase/management/service/MetaTokenService.kt @@ -76,8 +76,8 @@ open class MetaTokenService { // process the response if the token is not fetched or not expired return if (metaToken.isValid) { val refreshToken = oAuthClientService!!.createAccessToken( - metaToken.subject!!.user, - metaToken.clientId + metaToken.subject!!.user!!, + metaToken.clientId!! ) .refreshToken .value @@ -112,14 +112,12 @@ open class MetaTokenService { @Transactional(readOnly = true) open fun getToken(tokenName: String): MetaToken { return metaTokenRepository!!.findOneByTokenName(tokenName) - .orElseThrow { - NotFoundException( + ?: throw NotFoundException( "Meta token not found with tokenName", EntityName.META_TOKEN, ErrorConstants.ERR_TOKEN_NOT_FOUND, Collections.singletonMap("tokenName", tokenName) ) - } } /** @@ -169,14 +167,15 @@ open class MetaTokenService { subject, clientId, false, Instant.now().plus(timeout), persistent ) - return if (metaToken.id != null && metaToken.tokenName != null) { + val tokenName = metaToken.tokenName + return if (metaToken.id != null && tokenName != null) { // get base url from settings val baseUrl = managementPortalProperties!!.common.managementPortalBaseUrl // create complete uri string val tokenUrl = baseUrl + ResourceUriService.getUri(metaToken).getPath() // create response ClientPairInfoDTO( - URL(baseUrl), metaToken.tokenName, + URL(baseUrl), tokenName, URL(tokenUrl), timeout ) } else { diff --git a/src/main/java/org/radarbase/management/service/OAuthClientService.java b/src/main/java/org/radarbase/management/service/OAuthClientService.java deleted file mode 100644 index afc8fcf2e..000000000 --- a/src/main/java/org/radarbase/management/service/OAuthClientService.java +++ /dev/null @@ -1,188 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.domain.User; -import org.radarbase.management.service.dto.ClientDetailsDTO; -import org.radarbase.management.service.mapper.ClientDetailsMapper; -import org.radarbase.management.web.rest.errors.ConflictException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.InvalidRequestException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.security.oauth2.provider.NoSuchClientException; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.OAuth2Request; -import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; -import org.springframework.stereotype.Service; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.radarbase.management.web.rest.errors.EntityName.OAUTH_CLIENT; -import static org.springframework.security.oauth2.common.util.OAuth2Utils.GRANT_TYPE; - -/** - * The service layer to handle OAuthClient and Token related functions. - * Created by nivethika on 03/08/2018. - */ -@Service -public class OAuthClientService { - - private static final Logger log = LoggerFactory.getLogger(OAuthClientService.class); - - private static final String PROTECTED_KEY = "protected"; - - @Autowired - private JdbcClientDetailsService clientDetailsService; - - @Autowired - private ClientDetailsMapper clientDetailsMapper; - - @Autowired - private AuthorizationServerEndpointsConfiguration authorizationServerEndpointsConfiguration; - - public List findAllOAuthClients() { - return clientDetailsService.listClientDetails(); - } - - /** - * Find ClientDetails by OAuth client id. - * - * @param clientId The client ID to look up - * @return a ClientDetails object with the requested client ID - * @throws NotFoundException If there is no client with the requested ID - */ - public ClientDetails findOneByClientId(String clientId) { - try { - return clientDetailsService.loadClientByClientId(clientId); - } catch (NoSuchClientException e) { - log.error("Pair client request for unknown client id: {}", clientId); - Map errorParams = new HashMap<>(); - errorParams.put("clientId", clientId); - throw new NotFoundException("Client not found for client-id", OAUTH_CLIENT, - ErrorConstants.ERR_OAUTH_CLIENT_ID_NOT_FOUND, errorParams); - } - } - - /** - * Update Oauth-client with new information. - * - * @param clientDetailsDto information to update. - * @return Updated {@link ClientDetails} instance. - */ - public ClientDetails updateOauthClient(ClientDetailsDTO clientDetailsDto) { - ClientDetails details = - clientDetailsMapper.clientDetailsDTOToClientDetails(clientDetailsDto); - // update client. - clientDetailsService.updateClientDetails(details); - - ClientDetails updated = findOneByClientId(clientDetailsDto.getClientId()); - // updateClientDetails does not update secret, so check for it separately - if (clientDetailsDto.getClientSecret() != null && !clientDetailsDto.getClientSecret() - .equals(updated.getClientSecret())) { - clientDetailsService.updateClientSecret(clientDetailsDto.getClientId(), - clientDetailsDto.getClientSecret()); - } - return findOneByClientId(clientDetailsDto.getClientId()); - } - - /** - * Checks whether a client is a protected client. - * - * @param details ClientDetails. - */ - public static void checkProtected(ClientDetails details) { - Map info = details.getAdditionalInformation(); - if (Objects.nonNull(info) && info.containsKey(PROTECTED_KEY) && info.get(PROTECTED_KEY) - .toString().equalsIgnoreCase("true")) { - throw new InvalidRequestException("Cannot modify protected client", OAUTH_CLIENT, - ErrorConstants.ERR_OAUTH_CLIENT_PROTECTED, - Collections.singletonMap("client_id", details.getClientId())); - } - } - - /** - * Deletes an oauth client. - * @param clientId of the auth-client to delete. - */ - public void deleteClientDetails(String clientId) { - clientDetailsService.removeClientDetails(clientId); - } - - /** - * Creates new oauth-client. - * - * @param clientDetailsDto data to create oauth-client. - * @return created {@link ClientDetails}. - */ - public ClientDetails createClientDetail(ClientDetailsDTO clientDetailsDto) { - // check if the client id exists - try { - ClientDetails existingClient = - clientDetailsService.loadClientByClientId(clientDetailsDto.getClientId()); - if (existingClient != null) { - throw new ConflictException("OAuth client already exists with this id", - OAUTH_CLIENT, ErrorConstants.ERR_CLIENT_ID_EXISTS, - Collections.singletonMap("client_id", clientDetailsDto.getClientId())); - } - } catch (NoSuchClientException ex) { - // Client does not exist yet, we can go ahead and create it - log.info("No client existing with client-id {}. Proceeding to create new client", - clientDetailsDto.getClientId()); - } - ClientDetails details = - clientDetailsMapper.clientDetailsDTOToClientDetails(clientDetailsDto); - // create oauth client. - clientDetailsService.addClientDetails(details); - - return findOneByClientId(clientDetailsDto.getClientId()); - - } - - /** - * Internally creates an {@link OAuth2AccessToken} token using authorization-code flow. This - * method bypasses the usual authorization code flow mechanism, so it should only be used where - * appropriate, e.g., for subject impersonation. - * - * @param clientId oauth client id. - * @param user user of the token. - * @return Created {@link OAuth2AccessToken} instance. - */ - public OAuth2AccessToken createAccessToken(User user, String clientId) { - Set authorities = user.getAuthorities().stream() - .map(a -> new SimpleGrantedAuthority(a.name)) - .collect(Collectors.toSet()); - // lookup the OAuth client - // getOAuthClient checks if the id exists - ClientDetails client = findOneByClientId(clientId); - - Map requestParameters = Collections.singletonMap( - GRANT_TYPE , "authorization_code"); - - Set responseTypes = Collections.singleton("code"); - - OAuth2Request oAuth2Request = new OAuth2Request( - requestParameters, clientId, authorities, true, client.getScope(), - client.getResourceIds(), null, responseTypes, Collections.emptyMap()); - - Authentication authenticationToken = new UsernamePasswordAuthenticationToken( - user.getLogin(), null, authorities); - - return authorizationServerEndpointsConfiguration.getEndpointsConfigurer() - .getTokenServices() - .createAccessToken(new OAuth2Authentication(oAuth2Request, authenticationToken)); - } -} diff --git a/src/main/java/org/radarbase/management/service/OAuthClientService.kt b/src/main/java/org/radarbase/management/service/OAuthClientService.kt new file mode 100644 index 000000000..a0d6fd53f --- /dev/null +++ b/src/main/java/org/radarbase/management/service/OAuthClientService.kt @@ -0,0 +1,179 @@ +package org.radarbase.management.service + +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.User +import org.radarbase.management.service.dto.ClientDetailsDTO +import org.radarbase.management.service.mapper.ClientDetailsMapper +import org.radarbase.management.web.rest.errors.ConflictException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidRequestException +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.Authentication +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.oauth2.common.OAuth2AccessToken +import org.springframework.security.oauth2.common.util.OAuth2Utils +import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration +import org.springframework.security.oauth2.provider.ClientDetails +import org.springframework.security.oauth2.provider.NoSuchClientException +import org.springframework.security.oauth2.provider.OAuth2Authentication +import org.springframework.security.oauth2.provider.OAuth2Request +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService +import org.springframework.stereotype.Service +import java.util.* + +/** + * The service layer to handle OAuthClient and Token related functions. + * Created by nivethika on 03/08/2018. + */ +@Service +class OAuthClientService { + @Autowired + private val clientDetailsService: JdbcClientDetailsService? = null + + @Autowired + private val clientDetailsMapper: ClientDetailsMapper? = null + + @Autowired + private val authorizationServerEndpointsConfiguration: AuthorizationServerEndpointsConfiguration? = null + fun findAllOAuthClients(): List { + return clientDetailsService!!.listClientDetails() + } + + /** + * Find ClientDetails by OAuth client id. + * + * @param clientId The client ID to look up + * @return a ClientDetails object with the requested client ID + * @throws NotFoundException If there is no client with the requested ID + */ + fun findOneByClientId(clientId: String?): ClientDetails { + return try { + clientDetailsService!!.loadClientByClientId(clientId) + } catch (e: NoSuchClientException) { + log.error("Pair client request for unknown client id: {}", clientId) + val errorParams: MutableMap = HashMap() + errorParams["clientId"] = clientId + throw NotFoundException( + "Client not found for client-id", EntityName.Companion.OAUTH_CLIENT, + ErrorConstants.ERR_OAUTH_CLIENT_ID_NOT_FOUND, errorParams + ) + } + } + + /** + * Update Oauth-client with new information. + * + * @param clientDetailsDto information to update. + * @return Updated [ClientDetails] instance. + */ + fun updateOauthClient(clientDetailsDto: ClientDetailsDTO): ClientDetails { + val details: ClientDetails? = clientDetailsMapper!!.clientDetailsDTOToClientDetails(clientDetailsDto) + // update client. + clientDetailsService!!.updateClientDetails(details) + val updated = findOneByClientId(clientDetailsDto.clientId) + // updateClientDetails does not update secret, so check for it separately + if (clientDetailsDto.clientSecret != null && clientDetailsDto.clientSecret != updated.clientSecret) { + clientDetailsService.updateClientSecret( + clientDetailsDto.clientId, + clientDetailsDto.clientSecret + ) + } + return findOneByClientId(clientDetailsDto.clientId) + } + + /** + * Deletes an oauth client. + * @param clientId of the auth-client to delete. + */ + fun deleteClientDetails(clientId: String?) { + clientDetailsService!!.removeClientDetails(clientId) + } + + /** + * Creates new oauth-client. + * + * @param clientDetailsDto data to create oauth-client. + * @return created [ClientDetails]. + */ + fun createClientDetail(clientDetailsDto: ClientDetailsDTO): ClientDetails { + // check if the client id exists + try { + val existingClient = clientDetailsService!!.loadClientByClientId(clientDetailsDto.clientId) + if (existingClient != null) { + throw ConflictException( + "OAuth client already exists with this id", + EntityName.Companion.OAUTH_CLIENT, ErrorConstants.ERR_CLIENT_ID_EXISTS, + Collections.singletonMap("client_id", clientDetailsDto.clientId) + ) + } + } catch (ex: NoSuchClientException) { + // Client does not exist yet, we can go ahead and create it + log.info( + "No client existing with client-id {}. Proceeding to create new client", + clientDetailsDto.clientId + ) + } + val details: ClientDetails? = clientDetailsMapper!!.clientDetailsDTOToClientDetails(clientDetailsDto) + // create oauth client. + clientDetailsService!!.addClientDetails(details) + return findOneByClientId(clientDetailsDto.clientId) + } + + /** + * Internally creates an [OAuth2AccessToken] token using authorization-code flow. This + * method bypasses the usual authorization code flow mechanism, so it should only be used where + * appropriate, e.g., for subject impersonation. + * + * @param clientId oauth client id. + * @param user user of the token. + * @return Created [OAuth2AccessToken] instance. + */ + fun createAccessToken(user: User, clientId: String): OAuth2AccessToken { + val authorities = user.authorities!! + .map { a: Authority? -> SimpleGrantedAuthority(a?.name) } + // lookup the OAuth client + // getOAuthClient checks if the id exists + val client = findOneByClientId(clientId) + val requestParameters = Collections.singletonMap( + OAuth2Utils.GRANT_TYPE, "authorization_code" + ) + val responseTypes = setOf("code") + val oAuth2Request = OAuth2Request( + requestParameters, clientId, authorities, true, client.scope, + client.resourceIds, null, responseTypes, emptyMap() + ) + val authenticationToken: Authentication = UsernamePasswordAuthenticationToken( + user.login, null, authorities + ) + return authorizationServerEndpointsConfiguration!!.getEndpointsConfigurer() + .tokenServices + .createAccessToken(OAuth2Authentication(oAuth2Request, authenticationToken)) + } + + companion object { + private val log = LoggerFactory.getLogger(OAuthClientService::class.java) + private const val PROTECTED_KEY = "protected" + + /** + * Checks whether a client is a protected client. + * + * @param details ClientDetails. + */ + fun checkProtected(details: ClientDetails) { + val info = details.additionalInformation + if (Objects.nonNull(info) && info.containsKey(PROTECTED_KEY) && info[PROTECTED_KEY] + .toString().equals("true", ignoreCase = true) + ) { + throw InvalidRequestException( + "Cannot modify protected client", EntityName.Companion.OAUTH_CLIENT, + ErrorConstants.ERR_OAUTH_CLIENT_PROTECTED, + Collections.singletonMap("client_id", details.clientId) + ) + } + } + } +} diff --git a/src/main/java/org/radarbase/management/service/OrganizationService.java b/src/main/java/org/radarbase/management/service/OrganizationService.java deleted file mode 100644 index b1d7a1703..000000000 --- a/src/main/java/org/radarbase/management/service/OrganizationService.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.domain.Organization; -import org.radarbase.management.domain.Project; -import org.radarbase.management.repository.OrganizationRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.service.dto.OrganizationDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.mapper.OrganizationMapper; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Stream; - -import static org.radarbase.auth.authorization.Permission.ORGANIZATION_READ; - -/** - * Service Implementation for managing Organization. - */ -@Service -@Transactional -public class OrganizationService { - - private static final Logger log = LoggerFactory.getLogger(OrganizationService.class); - - @Autowired - private OrganizationRepository organizationRepository; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private OrganizationMapper organizationMapper; - - @Autowired - private ProjectMapper projectMapper; - - @Autowired - private AuthService authService; - - /** - * Save an organization. - * - * @param organizationDto the entity to save - * @return the persisted entity - */ - public OrganizationDTO save(OrganizationDTO organizationDto) { - log.debug("Request to save Organization : {}", organizationDto); - var org = organizationMapper.organizationDTOToOrganization(organizationDto); - org = organizationRepository.save(org); - return organizationMapper.organizationToOrganizationDTO(org); - } - - /** - * Get all the organizations. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public List findAll() { - List organizationsOfUser; - - var referents = authService.referentsByScope(ORGANIZATION_READ); - - if (referents.getGlobal()) { - organizationsOfUser = organizationRepository.findAll(); - } else { - Set projectNames = referents.getAllProjects(); - - Stream organizationsOfProject = !projectNames.isEmpty() - ? organizationRepository.findAllByProjectNames(projectNames).stream() - : Stream.of(); - - Stream organizationsOfRole = referents.getOrganizations() - .stream() - .flatMap(name -> organizationRepository.findOneByName(name).stream()); - - organizationsOfUser = Stream.concat(organizationsOfRole, organizationsOfProject) - .distinct() - .toList(); - } - - return organizationMapper.organizationsToOrganizationDTOs(organizationsOfUser); - } - - /** - * Get one organization by name. - * - * @param name the name of the entity - * @return the entity - */ - @Transactional(readOnly = true) - public Optional findByName(String name) { - log.debug("Request to get Organization by name: {}", name); - return organizationRepository.findOneByName(name) - .map(organizationMapper::organizationToOrganizationDTO); - } - - /** - * Get all projects belonging to the organization. - * - * @return the list of projects - */ - @Transactional(readOnly = true) - public List findAllProjectsByOrganizationName(String organizationName) { - var referents = authService.referentsByScope(ORGANIZATION_READ); - if (referents.isEmpty()) { - return Collections.emptyList(); - } - - Stream projectStream; - - if (referents.getGlobal() || referents.hasOrganization(organizationName)) { - projectStream = projectRepository.findAllByOrganizationName(organizationName).stream(); - } else if (referents.hasAnyProjects()) { - projectStream = projectRepository.findAllByOrganizationName(organizationName).stream() - .filter(project -> referents.hasAnyProject(project.projectName)); - } else { - return List.of(); - } - - return projectStream - .map(projectMapper::projectToProjectDTO) - .toList(); - } -} diff --git a/src/main/java/org/radarbase/management/service/OrganizationService.kt b/src/main/java/org/radarbase/management/service/OrganizationService.kt new file mode 100644 index 000000000..aeb07f9de --- /dev/null +++ b/src/main/java/org/radarbase/management/service/OrganizationService.kt @@ -0,0 +1,110 @@ +package org.radarbase.management.service + +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.Organization +import org.radarbase.management.domain.Project +import org.radarbase.management.repository.OrganizationRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.dto.OrganizationDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.mapper.OrganizationMapper +import org.radarbase.management.service.mapper.ProjectMapper +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +/** + * Service Implementation for managing Organization. + */ +@Service +@Transactional +open class OrganizationService( + @Autowired private val organizationRepository: OrganizationRepository, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val organizationMapper: OrganizationMapper, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val authService: AuthService +) { + + /** + * Save an organization. + * + * @param organizationDto the entity to save + * @return the persisted entity + */ + fun save(organizationDto: OrganizationDTO): OrganizationDTO { + log.debug("Request to save Organization : {}", organizationDto) + var org = organizationMapper.organizationDTOToOrganization(organizationDto) + org = organizationRepository.save(org) + return organizationMapper.organizationToOrganizationDTO(org) + } + + /** + * Get all the organizations. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(): List { + val organizationsOfUser: List + val referents = authService.referentsByScope(Permission.ORGANIZATION_READ) + organizationsOfUser = if (referents.global) { + organizationRepository.findAll() + } else { + val projectNames = referents.allProjects + val organizationsOfProject = + organizationRepository.findAllByProjectNames(projectNames) + val organizationsOfRole = referents.organizations + .mapNotNull { name: String -> organizationRepository.findOneByName(name) } + (organizationsOfRole + organizationsOfProject) + .distinct() + .toList() + } + return organizationMapper.organizationsToOrganizationDTOs(organizationsOfUser) + } + + /** + * Get one organization by name. + * + * @param name the name of the entity + * @return the entity + */ + @Transactional(readOnly = true) + open fun findByName(name: String): OrganizationDTO? { + log.debug("Request to get Organization by name: {}", name) + return organizationRepository.findOneByName(name)?.let { organizationMapper.organizationToOrganizationDTO(it) } + } + + /** + * Get all projects belonging to the organization. + * + * @return the list of projects + */ + @Transactional(readOnly = true) + open fun findAllProjectsByOrganizationName(organizationName: String): List { + val referents = authService.referentsByScope(Permission.ORGANIZATION_READ) + if (referents.isEmpty()) { + return emptyList() + } + val projectStream: List = if (referents.global || referents.hasOrganization(organizationName)) { + projectRepository.findAllByOrganizationName(organizationName) + } else if (referents.hasAnyProjects()) { + projectRepository.findAllByOrganizationName(organizationName) + .filter { project: Project -> + referents.hasAnyProject( + project.projectName!! + ) + } + } else { + return listOf() + } + return projectStream + .mapNotNull { project: Project? -> projectMapper.projectToProjectDTO(project) } + .toList() + } + + companion object { + private val log = LoggerFactory.getLogger(OrganizationService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/service/PasswordService.java b/src/main/java/org/radarbase/management/service/PasswordService.java deleted file mode 100644 index a4299cd23..000000000 --- a/src/main/java/org/radarbase/management/service/PasswordService.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.service; - -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; - -import java.security.SecureRandom; -import java.util.Locale; -import java.util.Random; - -import static org.radarbase.management.web.rest.errors.EntityName.USER; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_PASSWORD_TOO_LONG; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_PASSWORD_TOO_WEAK; - -@Service -public class PasswordService { - public static final int[] NUMERIC; - public static final int[] ALPHANUMERIC; - private static final int[] LOWER; - private static final int[] UPPER; - - static { - String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - String lower = upper.toLowerCase(Locale.ROOT); - String digits = "0123456789"; - UPPER = upper.chars().toArray(); - LOWER = lower.chars().toArray(); - NUMERIC = digits.chars().toArray(); - ALPHANUMERIC = (upper + lower + digits).chars().toArray(); - } - - private final PasswordEncoder passwordEncoder; - private final Random random = new SecureRandom(); - - public PasswordService(PasswordEncoder passwordEncoder) { - this.passwordEncoder = passwordEncoder; - } - - /** - * Encodes a plaintext password. - * @param password password to encode. - * @return encoded password. - */ - public String encode(String password) { - return passwordEncoder.encode(password); - } - - /** - * Generates a random password that is already encoded. - * @return encoded password. - */ - public String generateEncodedPassword() { - return encode(generateString(ALPHANUMERIC, 30)); - } - - /** - * Generates a random numeric reset key. - * @return reset key. - */ - public String generateResetKey() { - return generateString(NUMERIC, 20); - } - - private String generateString(int[] allowedCharacters, int length) { - return random.ints(0, allowedCharacters.length) - .map(i -> allowedCharacters[i]) - .limit(length) - .collect(() -> new StringBuilder(length), - StringBuilder::appendCodePoint, StringBuilder::append) - .toString(); - } - - /** - * Check that given password is strong enough, based on complexity and length. - * @param password password to check. - * @throws BadRequestException if the password is too weak or too long. - */ - public void checkPasswordStrength(String password) { - if (isPasswordWeak(password)) { - throw new BadRequestException("Weak password. Use a password with more variety of" - + "numeric, alphabetical and symbol characters.", USER, ERR_PASSWORD_TOO_WEAK); - } else if (password.length() > 100) { - throw new BadRequestException("Password too long", USER, ERR_PASSWORD_TOO_LONG); - } - } - - /** Check whether given password is too weak. */ - private boolean isPasswordWeak(String password) { - return password.length() < 8 - || noneInRange(password, UPPER[0], UPPER[UPPER.length - 1]) - || noneInRange(password, LOWER[0], LOWER[LOWER.length - 1]) - || noneInRange(password, NUMERIC[0], NUMERIC[NUMERIC.length - 1]); - } - - private boolean noneInRange(String str, int startInclusive, int endInclusive) { - return str.chars().noneMatch(c -> c >= startInclusive && c < endInclusive); - } -} diff --git a/src/main/java/org/radarbase/management/service/PasswordService.kt b/src/main/java/org/radarbase/management/service/PasswordService.kt new file mode 100644 index 000000000..9245e110e --- /dev/null +++ b/src/main/java/org/radarbase/management/service/PasswordService.kt @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.service + +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.stereotype.Service +import java.security.SecureRandom +import java.util.* + +@Service +class PasswordService(private val passwordEncoder: PasswordEncoder) { + private val random: Random = SecureRandom() + + /** + * Encodes a plaintext password. + * @param password password to encode. + * @return encoded password. + */ + fun encode(password: String?): String { + return passwordEncoder.encode(password) + } + + /** + * Generates a random password that is already encoded. + * @return encoded password. + */ + fun generateEncodedPassword(): String { + return encode(generateString(ALPHANUMERIC, 30)) + } + + /** + * Generates a random numeric reset key. + * @return reset key. + */ + fun generateResetKey(): String { + return generateString(NUMERIC, 20) + } + + private fun generateString(allowedCharacters: IntArray, length: Int): String { + return random.ints(0, allowedCharacters.size) + .map { i: Int -> allowedCharacters[i] } + .limit(length.toLong()) + .collect( + { StringBuilder(length) }, + { obj: StringBuilder, codePoint: Int -> obj.appendCodePoint(codePoint) }) { obj: StringBuilder, s: StringBuilder? -> + obj.append( + s + ) + } + .toString() + } + + /** + * Check that given password is strong enough, based on complexity and length. + * @param password password to check. + * @throws BadRequestException if the password is too weak or too long. + */ + fun checkPasswordStrength(password: String?) { + if (isPasswordWeak(password)) { + throw BadRequestException( + "Weak password. Use a password with more variety of" + + "numeric, alphabetical and symbol characters.", + EntityName.Companion.USER, + ErrorConstants.ERR_PASSWORD_TOO_WEAK + ) + } else if (password!!.length > 100) { + throw BadRequestException( + "Password too long", + EntityName.Companion.USER, + ErrorConstants.ERR_PASSWORD_TOO_LONG + ) + } + } + + /** Check whether given password is too weak. */ + private fun isPasswordWeak(password: String?): Boolean { + return (password!!.length < 8 || noneInRange(password, UPPER[0], UPPER[UPPER.size - 1]) + || noneInRange(password, LOWER[0], LOWER[LOWER.size - 1]) + || noneInRange(password, NUMERIC[0], NUMERIC[NUMERIC.size - 1])) + } + + private fun noneInRange(str: String?, startInclusive: Int, endInclusive: Int): Boolean { + return str!!.chars().noneMatch { c: Int -> c >= startInclusive && c < endInclusive } + } + + companion object { + val NUMERIC: IntArray + val ALPHANUMERIC: IntArray + private val LOWER: IntArray + private val UPPER: IntArray + + init { + val upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + val lower = upper.lowercase() + val digits = "0123456789" + UPPER = upper.chars().toArray() + LOWER = lower.chars().toArray() + NUMERIC = digits.chars().toArray() + ALPHANUMERIC = (upper + lower + digits).chars().toArray() + } + } +} diff --git a/src/main/java/org/radarbase/management/service/ProjectService.kt b/src/main/java/org/radarbase/management/service/ProjectService.kt index 5f273f341..5856587f0 100644 --- a/src/main/java/org/radarbase/management/service/ProjectService.kt +++ b/src/main/java/org/radarbase/management/service/ProjectService.kt @@ -37,11 +37,11 @@ open class ProjectService( * @param projectDto the entity to save * @return the persisted entity */ - fun save(projectDto: ProjectDTO?): ProjectDTO { + fun save(projectDto: ProjectDTO): ProjectDTO { log.debug("Request to save Project : {}", projectDto) var project = projectMapper.projectDTOToProject(projectDto) - project = projectRepository.save(project) - return projectMapper.projectToProjectDTO(project) + project = project?.let { projectRepository.save(it) } + return projectMapper.projectToProjectDTO(project)!! } /** @@ -50,8 +50,8 @@ open class ProjectService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(fetchMinimal: Boolean?, pageable: Pageable?): Page<*> { - val projects: Page? + open fun findAll(fetchMinimal: Boolean, pageable: Pageable): Page<*> { + val projects: Page val referents = authService.referentsByScope(Permission.PROJECT_READ) projects = if (referents.isEmpty()) { PageImpl(listOf()) @@ -62,10 +62,10 @@ open class ProjectService( pageable, referents.organizations, referents.allProjects ) } - return if (!fetchMinimal!!) { - projects!!.map { project: Project? -> projectMapper.projectToProjectDTO(project) } + return if (!fetchMinimal) { + projects.map { project: Project -> projectMapper.projectToProjectDTO(project) } } else { - projects!!.map { project: Project? -> projectMapper.projectToMinimalProjectDetailsDTO(project) } + projects.map { project: Project -> projectMapper.projectToMinimalProjectDetailsDTO(project) } } } @@ -76,15 +76,17 @@ open class ProjectService( * @return the entity */ @Transactional(readOnly = true) - open fun findOne(id: Long): ProjectDTO { + open fun findOne(id: Long): ProjectDTO? { log.debug("Request to get Project : {}", id) - return projectRepository.findOneWithEagerRelationships(id) - .let { project: Project? -> projectMapper.projectToProjectDTO(project) } ?: throw NotFoundException( - "Project not found with id", - EntityName.PROJECT, - ErrorConstants.ERR_PROJECT_ID_NOT_FOUND, - Collections.singletonMap("id", id.toString()) - ) + val project = projectRepository.findOneWithEagerRelationships(id) + ?: throw NotFoundException( + "Project not found with id", + EntityName.PROJECT, + ErrorConstants.ERR_PROJECT_ID_NOT_FOUND, + Collections.singletonMap("id", id.toString()) + ) + + return projectMapper.projectToProjectDTO(project) } /** @@ -96,13 +98,14 @@ open class ProjectService( @Transactional(readOnly = true) open fun findOneByName(name: String): ProjectDTO { log.debug("Request to get Project by name: {}", name) - return projectRepository.findOneWithEagerRelationshipsByName(name) - .let { project: Project? -> projectMapper.projectToProjectDTO(project) } ?: throw NotFoundException( - "Project not found with projectName $name", - EntityName.PROJECT, - ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND, - Collections.singletonMap("projectName", name) - ) + val project = projectRepository.findOneWithEagerRelationshipsByName(name) + ?: throw NotFoundException( + "Project not found with projectName $name", + EntityName.PROJECT, + ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND, + Collections.singletonMap("projectName", name)) + + return projectMapper.projectToProjectDTO(project)!! } /** @@ -112,10 +115,10 @@ open class ProjectService( * @return the list of source-types assigned. */ @Transactional(readOnly = true) - open fun findSourceTypesByProjectId(id: Long?): List { + open fun findSourceTypesByProjectId(id: Long): List { log.debug("Request to get Project.sourceTypes of project: {}", id) val sourceTypes = projectRepository.findSourceTypesByProjectId(id) - return sourceTypeMapper.sourceTypesToSourceTypeDTOs(sourceTypes) + return sourceTypeMapper.sourceTypesToSourceTypeDTOs(sourceTypes).filterNotNull() } /** diff --git a/src/main/java/org/radarbase/management/service/ResourceUriService.java b/src/main/java/org/radarbase/management/service/ResourceUriService.java deleted file mode 100644 index 1c23760c8..000000000 --- a/src/main/java/org/radarbase/management/service/ResourceUriService.java +++ /dev/null @@ -1,150 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.domain.MetaToken; -import org.radarbase.management.domain.Source; -import org.radarbase.management.domain.User; -import org.radarbase.management.service.dto.ClientDetailsDTO; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.OrganizationDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.dto.SourceDataDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.web.rest.util.HeaderUtil; - -import java.net.URI; -import java.net.URISyntaxException; - -/** - * Consolidates the generation of location URI's for all of the resources. - */ -public final class ResourceUriService { - - private ResourceUriService() { - // utility class - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(OrganizationDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "organizations", resource.getName())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(SubjectDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "subjects", resource.getLogin())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(ClientDetailsDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "oauth-clients", resource.getClientId())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(MinimalSourceDetailsDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "sources", resource.getSourceName())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(RoleDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "roles", resource.getProjectName(), - resource.getAuthorityName())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(SourceTypeDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "source-types", resource.getProducer(), - resource.getModel(), resource.getCatalogVersion())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(SourceDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "sources", resource.getSourceName())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(Source resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "sources", resource.sourceName)); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(User resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "users", resource.getLogin())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(SourceDataDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "source-data", resource.getSourceDataName())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(ProjectDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "projects", resource.getProjectName())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(MetaToken resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "meta-token", resource.getTokenName())); - } -} diff --git a/src/main/java/org/radarbase/management/service/ResourceUriService.kt b/src/main/java/org/radarbase/management/service/ResourceUriService.kt new file mode 100644 index 000000000..c02792779 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/ResourceUriService.kt @@ -0,0 +1,164 @@ +package org.radarbase.management.service + +import org.radarbase.management.domain.MetaToken +import org.radarbase.management.domain.Source +import org.radarbase.management.domain.User +import org.radarbase.management.service.dto.ClientDetailsDTO +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.OrganizationDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.dto.SourceDTO +import org.radarbase.management.service.dto.SourceDataDTO +import org.radarbase.management.service.dto.SourceTypeDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.web.rest.util.HeaderUtil +import java.net.URI +import java.net.URISyntaxException + +/** + * Consolidates the generation of location URI's for all of the resources. + */ +object ResourceUriService { + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: OrganizationDTO): URI { + return URI(HeaderUtil.buildPath("api", "organizations", resource.name)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: SubjectDTO): URI { + return URI(resource.login?.let { HeaderUtil.buildPath("api", "subjects", it) }) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: ClientDetailsDTO): URI { + return URI(HeaderUtil.buildPath("api", "oauth-clients", resource.clientId)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: MinimalSourceDetailsDTO): URI { + return URI(HeaderUtil.buildPath("api", "sources", resource.sourceName!!)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: RoleDTO?): URI { + return URI( + HeaderUtil.buildPath( + "api", "roles", resource?.projectName!!, + resource.authorityName!! + ) + ) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: SourceTypeDTO): URI { + return URI( + HeaderUtil.buildPath( + "api", "source-types", resource.producer, + resource.model, resource.model + ) + ) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: SourceDTO): URI { + return URI(HeaderUtil.buildPath("api", "sources", resource.sourceName)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: Source): URI { + return URI(HeaderUtil.buildPath("api", "sources", resource.sourceName!!)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: User): URI { + return URI(HeaderUtil.buildPath("api", "users", resource.login)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: SourceDataDTO): URI { + return URI(HeaderUtil.buildPath("api", "source-data", resource.sourceDataName!!)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: ProjectDTO): URI { + return URI(HeaderUtil.buildPath("api", "projects", resource.projectName!!)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: MetaToken): URI { + return URI(HeaderUtil.buildPath("api", "meta-token", resource.tokenName!!)) + } +} diff --git a/src/main/java/org/radarbase/management/service/RevisionService.kt b/src/main/java/org/radarbase/management/service/RevisionService.kt index dcf742280..14e45c0e8 100644 --- a/src/main/java/org/radarbase/management/service/RevisionService.kt +++ b/src/main/java/org/radarbase/management/service/RevisionService.kt @@ -151,9 +151,9 @@ open class RevisionService(@param:Autowired private val revisionEntityRepository * @param pageable Page information * @return the page of revisions [RevisionInfoDTO] */ - fun getRevisions(pageable: Pageable?): Page { + fun getRevisions(pageable: Pageable): Page { return revisionEntityRepository.findAll(pageable) - .map { rev: CustomRevisionEntity -> RevisionInfoDTO.from(rev, getChangesForRevision(rev.id)) } + .map { rev -> RevisionInfoDTO.from(rev!!, getChangesForRevision(rev.id)) } } /** diff --git a/src/main/java/org/radarbase/management/service/RoleService.kt b/src/main/java/org/radarbase/management/service/RoleService.kt index c350c19ea..7bc960bd1 100644 --- a/src/main/java/org/radarbase/management/service/RoleService.kt +++ b/src/main/java/org/radarbase/management/service/RoleService.kt @@ -27,24 +27,16 @@ import java.util.function.Consumer */ @Service @Transactional -open class RoleService { - @Autowired - private val roleRepository: RoleRepository? = null +open class RoleService( + @Autowired private val roleRepository: RoleRepository, + @Autowired private val authorityRepository: AuthorityRepository, + @Autowired private val organizationRepository: OrganizationRepository, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val roleMapper: RoleMapper, + @Autowired private val userService: UserService +) { - @Autowired - private val authorityRepository: AuthorityRepository? = null - - @Autowired - private val organizationRepository: OrganizationRepository? = null - - @Autowired - private val projectRepository: ProjectRepository? = null - - @Autowired - private val roleMapper: RoleMapper? = null - - @Autowired - private val userService: UserService? = null + private val log = LoggerFactory.getLogger(RoleService::class.java) /** * Save a role. @@ -52,11 +44,11 @@ open class RoleService { * @param roleDto the entity to save * @return the persisted entity */ - fun save(roleDto: RoleDTO?): RoleDTO { + fun save(roleDto: RoleDTO): RoleDTO? { log.debug("Request to save Role : {}", roleDto) - var role = roleMapper!!.roleDTOToRole(roleDto) - role = roleRepository!!.save(role) - return roleMapper.roleToRoleDTO(role) + var role = roleMapper.roleDTOToRole(roleDto) + role = role?.let { roleRepository.save(it) } + return role?.let { roleMapper.roleToRoleDTO(it) } } /** @@ -70,24 +62,21 @@ open class RoleService { */ @Transactional(readOnly = true) open fun findAll(): List { - val optUser = userService!!.userWithAuthorities - if (optUser.isEmpty) { - // return an empty list if we do not have a current user (e.g. with client credentials + val optUser = userService.userWithAuthorities + ?: // return an empty list if we do not have a current user (e.g. with client credentials // oauth2 grant) return emptyList() - } - val currentUser = optUser.get() - val currentUserAuthorities: List? = currentUser.authorities?.map { auth -> auth?.name!! } + val currentUserAuthorities: List? = optUser.authorities?.map { auth -> auth?.name!! } return if (currentUserAuthorities?.contains(RoleAuthority.SYS_ADMIN.authority) == true) { log.debug("Request to get all Roles") - roleRepository!!.findAll().stream().map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }.toList() + roleRepository.findAll().filterNotNull().map { role: Role -> roleMapper.roleToRoleDTO(role) }.toList() } else (if (currentUserAuthorities?.contains(RoleAuthority.PROJECT_ADMIN.authority) == true) { log.debug("Request to get project admin's project Projects") - currentUser.roles?.filter { role: Role? -> - (RoleAuthority.PROJECT_ADMIN.authority == role?.authority?.name) - }?.map { r: Role? -> r?.project?.projectName }?.distinct() - ?.flatMap { name: String? -> roleRepository!!.findAllRolesByProjectName(name) } - ?.map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }?.toList() + optUser.roles?.asSequence()?.filter { role: Role? -> + (RoleAuthority.PROJECT_ADMIN.authority == role?.authority?.name) + }?.mapNotNull { r: Role -> r.project?.projectName }?.distinct() + ?.flatMap { name: String -> roleRepository.findAllRolesByProjectName(name) } + ?.map { role -> roleMapper.roleToRoleDTO(role) }?.toList() } else { emptyList() }) as List @@ -101,8 +90,8 @@ open class RoleService { @Transactional(readOnly = true) open fun findSuperAdminRoles(): List { log.debug("Request to get admin Roles") - return roleRepository?.findRolesByAuthorityName(RoleAuthority.SYS_ADMIN.authority) - ?.map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }?.toList()!! + return roleRepository.findRolesByAuthorityName(RoleAuthority.SYS_ADMIN.authority) + .map { role: Role -> roleMapper.roleToRoleDTO(role) }.toList() } /** @@ -114,8 +103,8 @@ open class RoleService { @Transactional(readOnly = true) open fun findOne(id: Long): RoleDTO { log.debug("Request to get Role : {}", id) - val role = roleRepository!!.findById(id).get() - return roleMapper!!.roleToRoleDTO(role) + val role = roleRepository.findById(id).get() + return roleMapper.roleToRoleDTO(role) } /** @@ -125,7 +114,7 @@ open class RoleService { */ fun delete(id: Long) { log.debug("Request to delete Role : {}", id) - roleRepository!!.deleteById(id) + roleRepository.deleteById(id) } /** @@ -134,10 +123,11 @@ open class RoleService { * @return role from database */ fun getGlobalRole(role: RoleAuthority): Role { - return roleRepository!!.findRolesByAuthorityName(role.authority).stream().findAny() - .orElseGet { createNewRole(role) { r: Role? -> } } + return roleRepository.findRolesByAuthorityName(role.authority).firstOrNull() + ?: createNewRole(role) { _: Role? -> } } + /** * Get or create given organization role. * @param role to get or create @@ -145,20 +135,19 @@ open class RoleService { * @return role from database */ fun getOrganizationRole(role: RoleAuthority, organizationId: Long): Role { - return roleRepository!!.findOneByOrganizationIdAndAuthorityName( + return roleRepository.findOneByOrganizationIdAndAuthorityName( organizationId, role.authority - ).orElseGet { - createNewRole(role) { r: Role -> - r.organization = organizationRepository!!.findById(organizationId).orElseThrow { - NotFoundException( - "Cannot find organization for authority", - EntityName.USER, - ErrorConstants.ERR_INVALID_AUTHORITY, - Map.of( - "authorityName", role.authority, "projectId", organizationId.toString() - ) - ) - } + ) + ?: createNewRole(role) { r: Role -> + r.organization = organizationRepository.findById(organizationId).orElseThrow { + NotFoundException( + "Cannot find organization for authority", + EntityName.USER, + ErrorConstants.ERR_INVALID_AUTHORITY, + Map.of( + "authorityName", role.authority, "projectId", organizationId.toString() + ) + ) } } } @@ -170,19 +159,15 @@ open class RoleService { * @return role from database */ fun getProjectRole(role: RoleAuthority, projectId: Long): Role { - return roleRepository!!.findOneByProjectIdAndAuthorityName( + return roleRepository.findOneByProjectIdAndAuthorityName( projectId, role.authority - ).orElseGet { - createNewRole(role) { r: Role -> - r.project = projectRepository!!.findByIdWithOrganization(projectId) ?: throw NotFoundException( - "Cannot find project for authority", - EntityName.USER, - ErrorConstants.ERR_INVALID_AUTHORITY, - Map.of( - "authorityName", role.authority, "projectId", projectId.toString() - ) + ) + ?: createNewRole(role) { r: Role -> + r.project = projectRepository.findByIdWithOrganization(projectId) ?: throw NotFoundException( + "Cannot find project for authority", EntityName.USER, ErrorConstants.ERR_INVALID_AUTHORITY, Map.of( + "authorityName", role.authority, "projectId", projectId.toString() ) - } + ) } } @@ -193,20 +178,20 @@ open class RoleService { */ fun getRolesByProject(projectName: String): List { log.debug("Request to get all Roles for projectName $projectName") - return roleRepository!!.findAllRolesByProjectName(projectName).stream() - .map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }.toList() + return roleRepository.findAllRolesByProjectName(projectName) + .map { role: Role -> roleMapper.roleToRoleDTO(role) }.toList() } private fun getAuthority(role: RoleAuthority): Authority { - return authorityRepository!!.findByAuthorityName(role.authority) - .orElseGet { authorityRepository.saveAndFlush(Authority(role)) } + return authorityRepository.findByAuthorityName(role.authority) + ?: authorityRepository.saveAndFlush(Authority(role)) } private fun createNewRole(role: RoleAuthority, apply: Consumer): Role { val newRole = Role() newRole.authority = getAuthority(role) apply.accept(newRole) - return roleRepository!!.save(newRole) + return roleRepository.save(newRole) } /** @@ -217,10 +202,10 @@ open class RoleService { */ fun findOneByProjectNameAndAuthorityName( projectName: String?, authorityName: String? - ): Optional { + ): RoleDTO? { log.debug("Request to get role of project {} and authority {}", projectName, authorityName) - return roleRepository!!.findOneByProjectNameAndAuthorityName(projectName, authorityName) - .map { role: Role? -> roleMapper!!.roleToRoleDTO(role) } + return roleRepository.findOneByProjectNameAndAuthorityName(projectName, authorityName) + .let { role -> role?.let { roleMapper.roleToRoleDTO(it) } } } companion object { @@ -237,7 +222,7 @@ open class RoleService { fun getRoleAuthority(roleDto: RoleDTO): RoleAuthority { val authority: RoleAuthority authority = try { - valueOfAuthority(roleDto.authorityName) + valueOfAuthority(roleDto.authorityName!!) } catch (ex: IllegalArgumentException) { throw BadRequestException( "Authority not found with " + "authorityName", diff --git a/src/main/java/org/radarbase/management/service/SiteSettingsService.java b/src/main/java/org/radarbase/management/service/SiteSettingsService.java deleted file mode 100644 index 57098f51e..000000000 --- a/src/main/java/org/radarbase/management/service/SiteSettingsService.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.config.ManagementPortalProperties.SiteSettings; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.service.dto.SiteSettingsDto; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * Service class for managing SiteSettings. - */ -@Service -@Transactional -public class SiteSettingsService { - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - /** - * Convert a {@link SiteSettings} to a {@link SiteSettingsDto} object. - * @param siteSettings The object to convert - * @return the newly created DTO object - */ - public SiteSettingsDto createSiteSettingsDto(SiteSettings siteSettings) { - - SiteSettingsDto siteSettingsDto = new SiteSettingsDto(); - - siteSettingsDto.setHiddenSubjectFields(siteSettings.getHiddenSubjectFields()); - return siteSettingsDto; - } - - // NAMING! - public SiteSettingsDto getSiteSettingsDto() { - return createSiteSettingsDto(managementPortalProperties.getSiteSettings()); - } -} diff --git a/src/main/java/org/radarbase/management/service/SiteSettingsService.kt b/src/main/java/org/radarbase/management/service/SiteSettingsService.kt new file mode 100644 index 000000000..9226f49a1 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/SiteSettingsService.kt @@ -0,0 +1,33 @@ +package org.radarbase.management.service + +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.config.ManagementPortalProperties.SiteSettings +import org.radarbase.management.service.dto.SiteSettingsDto +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +/** + * Service class for managing SiteSettings. + */ +@Service +@Transactional +class SiteSettingsService { + @Autowired + private val managementPortalProperties: ManagementPortalProperties? = null + + /** + * Convert a [SiteSettings] to a [SiteSettingsDto] object. + * @param siteSettings The object to convert + * @return the newly created DTO object + */ + fun createSiteSettingsDto(siteSettings: SiteSettings): SiteSettingsDto { + val siteSettingsDto = SiteSettingsDto() + siteSettingsDto.hiddenSubjectFields = siteSettings.hiddenSubjectFields + return siteSettingsDto + } + + val siteSettingsDto: SiteSettingsDto + // NAMING! + get() = createSiteSettingsDto(managementPortalProperties!!.siteSettings) +} diff --git a/src/main/java/org/radarbase/management/service/SourceDataService.java b/src/main/java/org/radarbase/management/service/SourceDataService.java deleted file mode 100644 index d838e170a..000000000 --- a/src/main/java/org/radarbase/management/service/SourceDataService.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.repository.SourceDataRepository; -import org.radarbase.management.service.dto.SourceDataDTO; -import org.radarbase.management.service.mapper.SourceDataMapper; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.Optional; - -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE_DATA; - -/** - * Service Implementation for managing SourceData. - */ -@Service -@Transactional -public class SourceDataService { - - private static final Logger log = LoggerFactory.getLogger(SourceDataService.class); - - private final SourceDataRepository sourceDataRepository; - - private final SourceDataMapper sourceDataMapper; - - public SourceDataService(SourceDataRepository sourceDataRepository, - SourceDataMapper sourceDataMapper) { - this.sourceDataRepository = sourceDataRepository; - this.sourceDataMapper = sourceDataMapper; - } - - /** - * Save a sourceData. - * - * @param sourceDataDto the entity to save - * @return the persisted entity - */ - public SourceDataDTO save(SourceDataDTO sourceDataDto) { - log.debug("Request to save SourceData : {}", sourceDataDto); - if (sourceDataDto.getSourceDataType() == null) { - throw new BadRequestException(ErrorConstants.ERR_VALIDATION, SOURCE_DATA, - "Source Data must contain a type or a topic."); - } - SourceData sourceData = sourceDataMapper.sourceDataDTOToSourceData(sourceDataDto); - sourceData = sourceDataRepository.save(sourceData); - return sourceDataMapper.sourceDataToSourceDataDTO(sourceData); - } - - /** - * Get all the sourceData. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public List findAll() { - log.debug("Request to get all SourceData"); - - return sourceDataRepository.findAll().stream() - .map(sourceDataMapper::sourceDataToSourceDataDTO) - .toList(); - } - - /** - * Get all the sourceData with pagination. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public Page findAll(Pageable pageable) { - log.debug("Request to get all SourceData"); - return sourceDataRepository.findAll(pageable) - .map(sourceDataMapper::sourceDataToSourceDataDTO); - } - - /** - * Get one sourceData by id. - * - * @param id the id of the entity - * @return the entity - */ - @Transactional(readOnly = true) - public SourceDataDTO findOne(Long id) { - log.debug("Request to get SourceData : {}", id); - SourceData sourceData = sourceDataRepository.findById(id).get(); - return sourceDataMapper.sourceDataToSourceDataDTO(sourceData); - } - - /** - * Get one sourceData by name. - * - * @param sourceDataName the sourceDataType of the entity - * @return the entity - */ - @Transactional(readOnly = true) - public Optional findOneBySourceDataName(String sourceDataName) { - log.debug("Request to get SourceData : {}", sourceDataName); - return sourceDataRepository.findOneBySourceDataName(sourceDataName) - .map(sourceDataMapper::sourceDataToSourceDataDTO); - } - - /** - * Delete the sourceData by id. - * - * @param id the id of the entity - */ - @Transactional - public void delete(Long id) { - log.debug("Request to delete SourceData : {}", id); - sourceDataRepository.deleteById(id); - } -} diff --git a/src/main/java/org/radarbase/management/service/SourceDataService.kt b/src/main/java/org/radarbase/management/service/SourceDataService.kt new file mode 100644 index 000000000..03ab7afd0 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/SourceDataService.kt @@ -0,0 +1,109 @@ +package org.radarbase.management.service + +import org.radarbase.management.domain.SourceData +import org.radarbase.management.repository.SourceDataRepository +import org.radarbase.management.service.dto.SourceDataDTO +import org.radarbase.management.service.mapper.SourceDataMapper +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.slf4j.LoggerFactory +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +/** + * Service Implementation for managing SourceData. + */ +@Service +@Transactional +open class SourceDataService( + private val sourceDataRepository: SourceDataRepository, + private val sourceDataMapper: SourceDataMapper +) { + /** + * Save a sourceData. + * + * @param sourceDataDto the entity to save + * @return the persisted entity + */ + fun save(sourceDataDto: SourceDataDTO?): SourceDataDTO? { + log.debug("Request to save SourceData : {}", sourceDataDto) + if (sourceDataDto!!.sourceDataType == null) { + throw BadRequestException( + ErrorConstants.ERR_VALIDATION, EntityName.Companion.SOURCE_DATA, + "Source Data must contain a type or a topic." + ) + } + var sourceData = sourceDataMapper.sourceDataDTOToSourceData(sourceDataDto) + sourceData = sourceDataRepository.save(sourceData) + return sourceDataMapper.sourceDataToSourceDataDTO(sourceData) + } + + /** + * Get all the sourceData. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(): List { + log.debug("Request to get all SourceData") + return sourceDataRepository.findAll().stream() + .map { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } + .toList() + } + + /** + * Get all the sourceData with pagination. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(pageable: Pageable?): Page { + log.debug("Request to get all SourceData") + return sourceDataRepository.findAll(pageable) + .map { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } + } + + /** + * Get one sourceData by id. + * + * @param id the id of the entity + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOne(id: Long): SourceDataDTO? { + log.debug("Request to get SourceData : {}", id) + val sourceData = sourceDataRepository.findById(id).get() + return sourceDataMapper.sourceDataToSourceDataDTO(sourceData) + } + + /** + * Get one sourceData by name. + * + * @param sourceDataName the sourceDataType of the entity + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOneBySourceDataName(sourceDataName: String?): SourceDataDTO? { + log.debug("Request to get SourceData : {}", sourceDataName) + return sourceDataRepository.findOneBySourceDataName(sourceDataName) + .let { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } + } + + /** + * Delete the sourceData by id. + * + * @param id the id of the entity + */ + @Transactional + open fun delete(id: Long?) { + log.debug("Request to delete SourceData : {}", id) + sourceDataRepository.deleteById(id) + } + + companion object { + private val log = LoggerFactory.getLogger(SourceDataService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/service/SourceService.kt b/src/main/java/org/radarbase/management/service/SourceService.kt index 2d6465f1c..ccf937a07 100644 --- a/src/main/java/org/radarbase/management/service/SourceService.kt +++ b/src/main/java/org/radarbase/management/service/SourceService.kt @@ -17,7 +17,6 @@ import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable -import org.springframework.data.history.Revision import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.util.* @@ -41,7 +40,7 @@ open class SourceService( * @param sourceDto the entity to save * @return the persisted entity */ - fun save(sourceDto: SourceDTO?): SourceDTO { + fun save(sourceDto: SourceDTO): SourceDTO { log.debug("Request to save Source : {}", sourceDto) var source = sourceMapper.sourceDTOToSource(sourceDto) source = sourceRepository.save(source) @@ -54,11 +53,11 @@ open class SourceService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(): List? { + open fun findAll(): List { return sourceRepository .findAll() - .stream() - .map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } + .filterNotNull() + .map { source: Source -> sourceMapper.sourceToSourceDTO(source) } .toList() } @@ -76,7 +75,7 @@ open class SourceService( it.let { it1 -> sourceRepository .findAll(it1) - ?.map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } + ?.map { source -> source?.let { it2 -> sourceMapper.sourceToSourceDTO(it2) } } } } } @@ -88,10 +87,10 @@ open class SourceService( * @return the entity */ @Transactional(readOnly = true) - open fun findOneByName(sourceName: String?): Optional { + open fun findOneByName(sourceName: String): SourceDTO? { log.debug("Request to get Source : {}", sourceName) return sourceRepository.findOneBySourceName(sourceName) - .map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } + .let { source: Source? -> source?.let { sourceMapper.sourceToSourceDTO(it) } } } /** @@ -104,7 +103,7 @@ open class SourceService( open fun findOneById(id: Long): Optional { log.debug("Request to get Source by id: {}", id) return Optional.ofNullable(sourceRepository.findById(id).orElse(null)) - .map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } + .map { source: Source? -> source?.let { sourceMapper.sourceToSourceDTO(it) } } } /** @@ -117,7 +116,7 @@ open class SourceService( log.info("Request to delete Source : {}", id) val sourceHistory = sourceRepository.findRevisions(id) val sources = sourceHistory.content - .map { obj: Revision -> obj.entity } + .mapNotNull { obj -> obj.entity } .filter{ it.isAssigned ?: false } .toList() @@ -139,9 +138,9 @@ open class SourceService( * * @return list of sources */ - fun findAllByProjectId(projectId: Long?, pageable: Pageable?): Page { + fun findAllByProjectId(projectId: Long, pageable: Pageable): Page { return sourceRepository.findAllSourcesByProjectId(pageable, projectId) - .map { source: Source? -> sourceMapper.sourceToSourceWithoutProjectDTO(source) } + .map { source -> sourceMapper.sourceToSourceWithoutProjectDTO(source) } } /** @@ -150,11 +149,11 @@ open class SourceService( * @return list of sources */ fun findAllMinimalSourceDetailsByProject( - projectId: Long?, - pageable: Pageable? + projectId: Long, + pageable: Pageable ): Page { return sourceRepository.findAllSourcesByProjectId(pageable, projectId) - .map { source: Source? -> sourceMapper.sourceToMinimalSourceDetailsDTO(source) } + .map { source: Source -> sourceMapper.sourceToMinimalSourceDetailsDTO(source) } } /** @@ -212,10 +211,8 @@ open class SourceService( @Transactional @Throws(NotAuthorizedException::class) open fun updateSource(sourceDto: SourceDTO): SourceDTO? { - val existingSourceOpt = sourceRepository.findById(sourceDto.id) - if (existingSourceOpt.isEmpty) { - return null - } + val existingSourceOpt = sourceDto.id?.let { sourceRepository.findById(it) } ?: return null + val existingSource = existingSourceOpt.get() authService.checkPermission(Permission.SOURCE_UPDATE, { e: EntityDetails -> e.source = existingSource.sourceName @@ -230,7 +227,7 @@ open class SourceService( }) // if the source is being transferred to another project. - if (existingSource.project!!.id != sourceDto.project.id) { + if (existingSource.project?.id != sourceDto.project?.id) { if (existingSource.isAssigned!!) { throw InvalidRequestException( "Cannot transfer an assigned source", EntityName.SOURCE, @@ -242,17 +239,17 @@ open class SourceService( // to be transferred. val sourceType = projectRepository .findSourceTypeByProjectIdAndSourceTypeId( - sourceDto.project.id, - existingSource.sourceType!!.id + sourceDto.project?.id, + existingSource.sourceType?.id ) - if (sourceType!!.isEmpty) { - throw InvalidRequestException( + ?: throw InvalidRequestException( "Cannot transfer a source to a project which doesn't have compatible " + "source-type", IdentifierGenerator.ENTITY_NAME, "error.invalidTransfer" ) - } + + //TODO all the nullchecks are the result of jvmfiel;d annotations not allowing lateinits // set old source-type, ensures compatibility - sourceDto.sourceType = sourceTypeMapper.sourceTypeToSourceTypeDTO(existingSource.sourceType) + sourceDto.sourceType = existingSource.sourceType?.let { sourceTypeMapper.sourceTypeToSourceTypeDTO(it) }!! } return save(sourceDto) } diff --git a/src/main/java/org/radarbase/management/service/SourceTypeService.java b/src/main/java/org/radarbase/management/service/SourceTypeService.java deleted file mode 100644 index 7cdc9d44a..000000000 --- a/src/main/java/org/radarbase/management/service/SourceTypeService.java +++ /dev/null @@ -1,242 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.repository.SourceDataRepository; -import org.radarbase.management.repository.SourceTypeRepository; -import org.radarbase.management.service.catalog.CatalogSourceData; -import org.radarbase.management.service.catalog.CatalogSourceType; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.mapper.CatalogSourceDataMapper; -import org.radarbase.management.service.mapper.CatalogSourceTypeMapper; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.service.mapper.SourceTypeMapper; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.validation.constraints.NotNull; -import java.util.Collections; -import java.util.List; - -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE_TYPE; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SOURCE_TYPE_NOT_FOUND; - -/** - * Service Implementation for managing SourceType. - */ -@Service -@Transactional -public class SourceTypeService { - - private static final Logger log = LoggerFactory.getLogger(SourceTypeService.class); - - @Autowired - private SourceTypeRepository sourceTypeRepository; - - @Autowired - private SourceTypeMapper sourceTypeMapper; - - @Autowired - private SourceDataRepository sourceDataRepository; - - @Autowired - private CatalogSourceTypeMapper catalogSourceTypeMapper; - - @Autowired - private CatalogSourceDataMapper catalogSourceDataMapper; - - @Autowired - private ProjectMapper projectMapper; - - /** - * Save a sourceType. - * - * @param sourceTypeDto the entity to save - * @return the persisted entity - */ - public SourceTypeDTO save(SourceTypeDTO sourceTypeDto) { - log.debug("Request to save SourceType : {}", sourceTypeDto); - SourceType sourceType = sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDto); - // populate the SourceType of our SourceData's - for (SourceData data : sourceType.sourceData) { - data.sourceType = sourceType; - } - sourceType = sourceTypeRepository.save(sourceType); - sourceDataRepository.saveAll(sourceType.sourceData); - return sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); - } - - /** - * Get all the sourceTypes. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public List findAll() { - log.debug("Request to get all SourceTypes"); - List result = sourceTypeRepository.findAllWithEagerRelationships(); - return result.stream() - .map(sourceTypeMapper::sourceTypeToSourceTypeDTO) - .toList(); - - } - - /** - * Get all sourceTypes with pagination. - * - * @param pageable params - * @return the list of entities - */ - public Page findAll(Pageable pageable) { - log.debug("Request to get SourceTypes"); - return sourceTypeRepository.findAll(pageable) - .map(sourceTypeMapper::sourceTypeToSourceTypeDTO); - } - - /** - * Delete the sourceType by id. - * - * @param id the id of the entity - */ - public void delete(Long id) { - log.debug("Request to delete SourceType : {}", id); - sourceTypeRepository.deleteById(id); - } - - /** - * Fetch SourceType by producer and model. - */ - public SourceTypeDTO findByProducerAndModelAndVersion(@NotNull String producer, - @NotNull String model, @NotNull String version) { - log.debug("Request to get SourceType by producer and model and version: {}, {}, {}", - producer, model, version); - return sourceTypeRepository - .findOneWithEagerRelationshipsByProducerAndModelAndVersion(producer, model, version) - .map(sourceTypeMapper::sourceTypeToSourceTypeDTO).orElseThrow( - () -> new NotFoundException( - "SourceType not found with producer, model, " + "version ", SOURCE_TYPE, - ERR_SOURCE_TYPE_NOT_FOUND, Collections.singletonMap("producer-model-version", - producer + "-" + model + "-" + version))); - } - - /** - * Fetch SourceType by producer. - */ - public List findByProducer(String producer) { - log.debug("Request to get SourceType by producer: {}", producer); - List sourceTypes = sourceTypeRepository - .findWithEagerRelationshipsByProducer(producer); - return sourceTypeMapper.sourceTypesToSourceTypeDTOs( - sourceTypes); - } - - /** - * Fetch SourceType by producer and model. - */ - public List findByProducerAndModel(String producer, String model) { - log.debug("Request to get SourceType by producer and model: {}, {}", producer, model); - List sourceTypes = sourceTypeRepository - .findWithEagerRelationshipsByProducerAndModel(producer, model); - return sourceTypeMapper.sourceTypesToSourceTypeDTOs( - sourceTypes); - } - - /** - * Find projects associated to a particular SourceType. - * - * @param producer the SourceType producer - * @param model the SourceType model - * @param version the SourceType catalogVersion - * @return the list of projects associated with this SourceType - */ - public List findProjectsBySourceType(String producer, String model, String - version) { - return projectMapper.projectsToProjectDTOs(sourceTypeRepository - .findProjectsBySourceType(producer, model, version)); - } - - /** - * Converts given {@link CatalogSourceType} to {@link SourceType} and saves it to the databse - * after validations. - * @param catalogSourceTypes list of source-type from catalogue-server. - */ - @Transactional - public void saveSourceTypesFromCatalogServer(List catalogSourceTypes) { - for (CatalogSourceType catalogSourceType : catalogSourceTypes) { - SourceType sourceType = catalogSourceTypeMapper - .catalogSourceTypeToSourceType(catalogSourceType); - - if (!isSourceTypeValid(sourceType)) { - continue; - } - - // check whether a source-type is already available with given config - if (sourceTypeRepository.hasOneByProducerAndModelAndVersion( - sourceType.producer, sourceType.model, - sourceType.catalogVersion)) { - // skip for existing source-types - log.info("Source-type {} is already available ", sourceType.producer - + "_" + sourceType.model - + "_" + sourceType.catalogVersion); - } else { - try { - // create new source-type - sourceType = sourceTypeRepository.save(sourceType); - - // create source-data for the new source-type - for (CatalogSourceData catalogSourceData : catalogSourceType.getData()) { - saveSourceData(sourceType, catalogSourceData); - } - } catch (RuntimeException ex) { - log.error("Failed to import source type {}", sourceType, ex); - } - } - } - log.info("Completed source-type import from catalog-server"); - } - - private void saveSourceData(SourceType sourceType, CatalogSourceData catalogSourceData) { - try { - SourceData sourceData = catalogSourceDataMapper - .catalogSourceDataToSourceData(catalogSourceData); - // sourceDataName should be unique - // generated by combining sourceDataType and source-type configs - sourceData.sourceDataName(sourceType.producer - + "_" + sourceType.model - + "_" + sourceType.catalogVersion - + "_" + sourceData.sourceDataType); - sourceData.sourceType(sourceType); - sourceDataRepository.save(sourceData); - } catch (RuntimeException ex) { - log.error("Failed to import source data {}", catalogSourceData, ex); - } - } - - private static boolean isSourceTypeValid(SourceType sourceType) { - if (sourceType.producer == null) { - log.warn("Catalog source-type {} does not have a vendor. " - + "Skipping importing this type", sourceType.name); - return false; - } - - if (sourceType.model == null) { - log.warn("Catalog source-type {} does not have a model. " - + "Skipping importing this type", sourceType.name); - return false; - } - - if (sourceType.catalogVersion == null) { - log.warn("Catalog source-type {} does not have a version. " - + "Skipping importing this type", sourceType.name); - return false; - } - return true; - } -} diff --git a/src/main/java/org/radarbase/management/service/SourceTypeService.kt b/src/main/java/org/radarbase/management/service/SourceTypeService.kt new file mode 100644 index 000000000..f0025ff43 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/SourceTypeService.kt @@ -0,0 +1,245 @@ +package org.radarbase.management.service + +import org.radarbase.management.domain.SourceType +import org.radarbase.management.repository.SourceDataRepository +import org.radarbase.management.repository.SourceTypeRepository +import org.radarbase.management.service.catalog.CatalogSourceData +import org.radarbase.management.service.catalog.CatalogSourceType +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SourceTypeDTO +import org.radarbase.management.service.mapper.CatalogSourceDataMapper +import org.radarbase.management.service.mapper.CatalogSourceTypeMapper +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.service.mapper.SourceTypeMapper +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.util.* +import javax.validation.constraints.NotNull + +/** + * Service Implementation for managing SourceType. + */ +@Service +@Transactional +open class SourceTypeService( + @Autowired private val sourceTypeRepository: SourceTypeRepository, + @Autowired private val sourceTypeMapper: SourceTypeMapper, + @Autowired private val sourceDataRepository: SourceDataRepository, + @Autowired private val catalogSourceTypeMapper: CatalogSourceTypeMapper, + @Autowired private val catalogSourceDataMapper: CatalogSourceDataMapper, + @Autowired private val projectMapper: ProjectMapper +) { + + /** + * Save a sourceType. + * + * @param sourceTypeDto the entity to save + * @return the persisted entity + */ + fun save(sourceTypeDto: SourceTypeDTO): SourceTypeDTO { + log.debug("Request to save SourceType : {}", sourceTypeDto) + var sourceType = sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDto) + // populate the SourceType of our SourceData's + for (data in sourceType.sourceData) { + data.sourceType = sourceType + } + sourceType = sourceTypeRepository.save(sourceType) + sourceDataRepository.saveAll(sourceType.sourceData) + return sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) + } + + /** + * Get all the sourceTypes. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(): List { + log.debug("Request to get all SourceTypes") + val result = sourceTypeRepository.findAllWithEagerRelationships() + return result + .map { sourceType: SourceType -> sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) } + .toList() + } + + /** + * Get all sourceTypes with pagination. + * + * @param pageable params + * @return the list of entities + */ + fun findAll(pageable: Pageable): Page { + log.debug("Request to get SourceTypes") + return sourceTypeRepository.findAll(pageable) + .map { sourceType: SourceType -> sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) } + } + + /** + * Delete the sourceType by id. + * + * @param id the id of the entity + */ + fun delete(id: Long) { + log.debug("Request to delete SourceType : {}", id) + sourceTypeRepository.deleteById(id) + } + + /** + * Fetch SourceType by producer and model. + */ + fun findByProducerAndModelAndVersion( + producer: @NotNull String, + model: @NotNull String, version: @NotNull String + ): SourceTypeDTO { + log.debug( + "Request to get SourceType by producer and model and version: {}, {}, {}", + producer, model, version + ) + return sourceTypeRepository + .findOneWithEagerRelationshipsByProducerAndModelAndVersion(producer, model, version) + .let { sourceType: SourceType? -> sourceType?.let { sourceTypeMapper.sourceTypeToSourceTypeDTO(it) } } + ?: throw NotFoundException( + "SourceType not found with producer, model, " + "version ", EntityName.Companion.SOURCE_TYPE, + ErrorConstants.ERR_SOURCE_TYPE_NOT_FOUND, Collections.singletonMap( + "producer-model-version", + "$producer-$model-$version" + ) + ) + } + + /** + * Fetch SourceType by producer. + */ + fun findByProducer(producer: String): List { + log.debug("Request to get SourceType by producer: {}", producer) + val sourceTypes = sourceTypeRepository + .findWithEagerRelationshipsByProducer(producer) + return sourceTypeMapper.sourceTypesToSourceTypeDTOs( + sourceTypes + ) + } + + /** + * Fetch SourceType by producer and model. + */ + fun findByProducerAndModel(producer: String, model: String): List { + log.debug("Request to get SourceType by producer and model: {}, {}", producer, model) + val sourceTypes = sourceTypeRepository + .findWithEagerRelationshipsByProducerAndModel(producer, model) + return sourceTypeMapper.sourceTypesToSourceTypeDTOs( + sourceTypes + ) + } + + /** + * Find projects associated to a particular SourceType. + * + * @param producer the SourceType producer + * @param model the SourceType model + * @param version the SourceType catalogVersion + * @return the list of projects associated with this SourceType + */ + fun findProjectsBySourceType(producer: String, model: String, version: String): List { + return projectMapper.projectsToProjectDTOs( + sourceTypeRepository + .findProjectsBySourceType(producer, model, version) + ) + } + + /** + * Converts given [CatalogSourceType] to [SourceType] and saves it to the databse + * after validations. + * @param catalogSourceTypes list of source-type from catalogue-server. + */ + @Transactional + open fun saveSourceTypesFromCatalogServer(catalogSourceTypes: List) { + for (catalogSourceType in catalogSourceTypes) { + var sourceType = catalogSourceTypeMapper + .catalogSourceTypeToSourceType(catalogSourceType) + if (!isSourceTypeValid(sourceType)) { + continue + } + + // check whether a source-type is already available with given config + if (sourceTypeRepository.hasOneByProducerAndModelAndVersion( + sourceType!!.producer!!, sourceType.model!!, + sourceType.catalogVersion!! + ) + ) { + // skip for existing source-types + log.info( + "Source-type {} is already available ", sourceType.producer + + "_" + sourceType.model + + "_" + sourceType.catalogVersion + ) + } else { + try { + // create new source-type + sourceType = sourceTypeRepository.save(sourceType) + + // create source-data for the new source-type + for (catalogSourceData in catalogSourceType.data!!) { + saveSourceData(sourceType, catalogSourceData) + } + } catch (ex: RuntimeException) { + log.error("Failed to import source type {}", sourceType, ex) + } + } + } + log.info("Completed source-type import from catalog-server") + } + + private fun saveSourceData(sourceType: SourceType?, catalogSourceData: CatalogSourceData?) { + try { + val sourceData = catalogSourceDataMapper + .catalogSourceDataToSourceData(catalogSourceData) + // sourceDataName should be unique + // generated by combining sourceDataType and source-type configs + sourceData!!.sourceDataName( + sourceType!!.producer + + "_" + sourceType.model + + "_" + sourceType.catalogVersion + + "_" + sourceData.sourceDataType + ) + sourceData.sourceType(sourceType) + sourceDataRepository.save(sourceData) + } catch (ex: RuntimeException) { + log.error("Failed to import source data {}", catalogSourceData, ex) + } + } + + companion object { + private val log = LoggerFactory.getLogger(SourceTypeService::class.java) + private fun isSourceTypeValid(sourceType: SourceType?): Boolean { + if (sourceType!!.producer == null) { + log.warn( + "Catalog source-type {} does not have a vendor. " + + "Skipping importing this type", sourceType.name + ) + return false + } + if (sourceType.model == null) { + log.warn( + "Catalog source-type {} does not have a model. " + + "Skipping importing this type", sourceType.name + ) + return false + } + if (sourceType.catalogVersion == null) { + log.warn( + "Catalog source-type {} does not have a version. " + + "Skipping importing this type", sourceType.name + ) + return false + } + return true + } + } +} diff --git a/src/main/java/org/radarbase/management/service/SubjectService.kt b/src/main/java/org/radarbase/management/service/SubjectService.kt index 56571a6b8..84dcd8ec1 100644 --- a/src/main/java/org/radarbase/management/service/SubjectService.kt +++ b/src/main/java/org/radarbase/management/service/SubjectService.kt @@ -77,8 +77,7 @@ open class SubjectService( */ @Transactional open fun createSubject(subjectDto: SubjectDTO): SubjectDTO? { - val subject = subjectMapper.subjectDTOToSubject(subjectDto) - if (subject == null) throw NullPointerException() + val subject = subjectMapper.subjectDTOToSubject(subjectDto) ?: throw NullPointerException() //assign roles val user = subject.user val project = projectMapper.projectDTOToProject(subjectDto.project) @@ -126,17 +125,20 @@ open class SubjectService( * @throws java.util.NoSuchElementException if the authority name is not in the database */ private fun getProjectParticipantRole(project: Project?, authority: RoleAuthority): Role { - return roleRepository.findOneByProjectIdAndAuthorityName( - project!!.id, authority.authority - ).orElseGet { - val subjectRole = Role() - val auth = authorityRepository.findByAuthorityName( - authority.authority - ).orElseGet { authorityRepository.save(Authority(authority)) } - subjectRole.authority = auth - subjectRole.project = project - roleRepository.save(subjectRole) - } + val ans: Role? = roleRepository.findOneByProjectIdAndAuthorityName( + project?.id, authority.authority + ) + return if (ans == null) { + val subjectRole = Role() + val auth: Authority = authorityRepository.findByAuthorityName( + authority.authority + ) ?: authorityRepository.save(Authority(authority)) + + subjectRole.authority = auth + subjectRole.project = project + roleRepository.save(subjectRole) + subjectRole + } else ans } /** @@ -169,18 +171,18 @@ open class SubjectService( } private fun updateParticipantRoles(subject: Subject, subjectDto: SubjectDTO): MutableSet? { - if (subjectDto.project == null || subjectDto.project.projectName == null) { + if (subjectDto.project == null || subjectDto.project!!.projectName == null) { return subject.user!!.roles } val existingRoles = subject.user!!.roles?.map { - // make participant inactive in projects that do not match the new project - if (it.authority!!.name == RoleAuthority.PARTICIPANT.authority && it.project!!.projectName != subjectDto.project.projectName) { - return@map getProjectParticipantRole(it.project, RoleAuthority.INACTIVE_PARTICIPANT) - } else { - // do not modify other roles. - return@map it - } - }?.toMutableSet() + // make participant inactive in projects that do not match the new project + if (it.authority!!.name == RoleAuthority.PARTICIPANT.authority && it.project!!.projectName != subjectDto.project!!.projectName) { + return@map getProjectParticipantRole(it.project, RoleAuthority.INACTIVE_PARTICIPANT) + } else { + // do not modify other roles. + return@map it + } + }?.toMutableSet() // Ensure that given project is present val newProjectRole = @@ -215,12 +217,12 @@ open class SubjectService( private fun ensureSubject(subjectDto: SubjectDTO): Subject { return subjectRepository.findById(subjectDto.id).orElseThrow { - NotFoundException( - "Subject with ID " + subjectDto.id + " not found.", - EntityName.SUBJECT, - ErrorConstants.ERR_SUBJECT_NOT_FOUND - ) - } + NotFoundException( + "Subject with ID " + subjectDto.id + " not found.", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND + ) + } } /** @@ -255,8 +257,8 @@ open class SubjectService( assignedSource = updateSourceAssignedSubject(subject, sourceRegistrationDto) } else if (sourceType.canRegisterDynamically!!) { val sources = subjectRepository.findSubjectSourcesBySourceType( - subject.user!!.login, sourceType.producer, sourceType.model, sourceType.catalogVersion - ) + subject.user!!.login, sourceType.producer, sourceType.model, sourceType.catalogVersion + ) // create a source and register metadata // we allow only one source of a source-type per subject if (sources.isNullOrEmpty()) { @@ -268,7 +270,7 @@ open class SubjectService( source.sourceName = sourceRegistrationDto.sourceName + "_" + source.sourceName } // make sure there is no source available on the same name. - if (sourceRepository.findOneBySourceName(source.sourceName).isPresent) { + if (sourceRepository.findOneBySourceName(source.sourceName!!) != null) { throw ConflictException( "SourceName already in use. Cannot create a " + "source with existing source-name ", EntityName.SUBJECT, @@ -312,18 +314,20 @@ open class SubjectService( ): Source { // for manually registered devices only add meta-data val source = subjectRepository.findSubjectSourcesBySourceId( - subject.user!!.login, sourceRegistrationDto.sourceId - ).orElseThrow { - val errorParams: MutableMap = HashMap() - errorParams["sourceId"] = sourceRegistrationDto.sourceId.toString() - errorParams["subject-login"] = subject.user!!.login - NotFoundException( - "No source with source-id to assigned to the " + "subject with subject-login", - EntityName.SUBJECT, - ErrorConstants.ERR_SOURCE_NOT_FOUND, - errorParams - ) - } + subject.user?.login, sourceRegistrationDto.sourceId + ) + if (source == null) { + val errorParams: MutableMap = HashMap() + errorParams["sourceId"] = sourceRegistrationDto.sourceId.toString() + errorParams["subject-login"] = subject.user?.login + throw NotFoundException( + "No source with source-id to assigned to the subject with subject-login", + EntityName.SUBJECT, + ErrorConstants.ERR_SOURCE_NOT_FOUND, + errorParams + ) + } + if (sourceRegistrationDto.sourceName != null) { source.sourceName = sourceRegistrationDto.sourceName } @@ -339,9 +343,8 @@ open class SubjectService( * @return list of sources */ fun getSources(subject: Subject): List { - val sources = subjectRepository.findSourcesBySubjectLogin( - subject.user?.login - ) + val sources = subjectRepository.findSourcesBySubjectLogin(subject.user?.login) + if (sources.isEmpty()) throw org.webjars.NotFoundException("Could not find sources for user ${subject.user}") return sourceMapper.sourcesToMinimalSourceDetailsDTOs(sources) } @@ -351,11 +354,16 @@ open class SubjectService( * @param login the login */ fun deleteSubject(login: String?) { - subjectRepository.findOneWithEagerBySubjectLogin(login).ifPresent { subject: Subject -> + subjectRepository.findOneWithEagerBySubjectLogin(login)?.let { subject: Subject -> unassignAllSources(subject) subjectRepository.delete(subject) log.debug("Deleted Subject: {}", subject) - } + } ?: throw NotFoundException( + "subject not found for given login.", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) } /** @@ -370,7 +378,7 @@ open class SubjectService( val sources: List? = revisions?.content?.flatMap { p: Revision -> p.entity.sources } ?.distinctBy { obj: Source -> obj.sourceId } - return sources?.map { p: Source? -> sourceMapper.sourceToMinimalSourceDetailsDTO(p) }?.toList() + return sources?.map { p: Source -> sourceMapper.sourceToMinimalSourceDetailsDTO(p) }?.toList() } /** @@ -388,14 +396,11 @@ open class SubjectService( // directly by e.g. findOneByLogin val latest = getLatestRevision(login) authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> - e.project(latest.project.projectName).subject(latest.getLogin()) + e.project(latest.project?.projectName).subject(latest.login) }) return revisionService.findRevision( - revision, - latest.id, - Subject::class.java, - subjectMapper::subjectToSubjectReducedProjectDTO - ) ?: throw NotFoundException( + revision, latest.id, Subject::class.java, subjectMapper::subjectToSubjectReducedProjectDTO + ) ?: throw NotFoundException( "subject not found for given login and revision.", EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND, @@ -413,25 +418,25 @@ open class SubjectService( @Throws(NotFoundException::class) fun getLatestRevision(login: String?): SubjectDTO { val user = revisionService.getLatestRevisionForEntity( - User::class.java, java.util.List.of(AuditEntity.property("login").eq(login)) + User::class.java, listOf(AuditEntity.property("login").eq(login)) ).orElseThrow { - NotFoundException( - "Subject latest revision not found " + "for login", - EntityName.SUBJECT, - ErrorConstants.ERR_SUBJECT_NOT_FOUND, - Collections.singletonMap("subjectLogin", login) - ) - } as UserDTO + NotFoundException( + "Subject latest revision not found " + "for login", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) + } as UserDTO return revisionService.getLatestRevisionForEntity( - Subject::class.java, java.util.List.of(AuditEntity.property("user").eq(user)) + Subject::class.java, listOf(AuditEntity.property("user").eq(user)) ).orElseThrow { - NotFoundException( - "Subject latest revision not found " + "for login", - EntityName.SUBJECT, - ErrorConstants.ERR_SUBJECT_NOT_FOUND, - Collections.singletonMap("subjectLogin", login) - ) - } as SubjectDTO + NotFoundException( + "Subject latest revision not found " + "for login", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) + } as SubjectDTO } /** @@ -442,11 +447,9 @@ open class SubjectService( @Nonnull fun findOneByLogin(login: String?): Subject { val subject = subjectRepository.findOneWithEagerBySubjectLogin(login) - return subject.orElseThrow { - NotFoundException( - "Subject not found with login", EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND - ) - } + return subject ?: throw NotFoundException( + "Subject not found with login", EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND + ) } /** diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt index 36c8355cb..3adcb8c2f 100644 --- a/src/main/java/org/radarbase/management/service/UserService.kt +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -60,15 +60,20 @@ open class UserService( * @return an [Optional] which is populated with the activated user if the registration * key was found, and is empty otherwise. */ - fun activateRegistration(key: String?): Optional { + fun activateRegistration(key: String): User { log.debug("Activating user for activation key {}", key) - return userRepository.findOneByActivationKey(key).map { user: User -> - // activate given user for the registration key. - user.activated = true - user.activationKey = null - log.debug("Activated user: {}", user) - user - } + return userRepository.findOneByActivationKey(key).let { user: User? -> + // activate given user for the registration key. + user?.activated = true + user?.activationKey = null + log.debug("Activated user: {}", user) + user + } ?: throw NotFoundException( + "User with activation key $key not found", + EntityName.USER, + ErrorConstants.ERR_ENTITY_NOT_FOUND, + Map.of("activationKey", key) + ) } /** @@ -78,20 +83,18 @@ open class UserService( * @return an [Optional] which is populated with the user whose password was reset if * the reset key was found, and is empty otherwise */ - fun completePasswordReset(newPassword: String?, key: String?): Optional { + fun completePasswordReset(newPassword: String, key: String): User? { log.debug("Reset user password for reset key {}", key) - return userRepository.findOneByResetKey(key).filter { user: User -> - val oneDayAgo = ZonedDateTime.now().minusSeconds( - managementPortalProperties.common.activationKeyTimeoutInSeconds.toLong() - ) - user.resetDate!!.isAfter(oneDayAgo) - }.map { user: User -> - user.password = passwordService.encode(newPassword) - user.resetKey = null - user.resetDate = null - user.activated = true - user - } + val user = userRepository.findOneByResetKey(key) + val oneDayAgo = ZonedDateTime.now().minusSeconds( + managementPortalProperties.common.activationKeyTimeoutInSeconds.toLong() + ) + if (user?.resetDate?.isAfter(oneDayAgo) == true) user.password = passwordService.encode(newPassword) + user?.resetKey = null + user?.resetDate = null + user?.activated = true + + return user } /** @@ -103,12 +106,14 @@ open class UserService( * @return an [Optional] which holds the user if an deactivated user was found with the * given login, and is empty otherwise */ - fun requestActivationReset(login: String?): Optional { - return userRepository.findOneByLogin(login).filter { p: User -> !p.activated }.map { user: User -> - user.resetKey = passwordService.generateResetKey() - user.resetDate = ZonedDateTime.now() - user - } + fun requestActivationReset(login: String): User? { + val user = userRepository.findOneByLogin(login) + if (user?.activated != true) { + user?.resetKey = passwordService.generateResetKey() + user?.resetDate = ZonedDateTime.now() + } + + return user } /** @@ -117,12 +122,11 @@ open class UserService( * @return an [Optional] which holds the user if an activated user was found with the * given email address, and is empty otherwise */ - fun requestPasswordReset(mail: String?): Optional { - return userRepository.findOneByEmail(mail).filter(User::activated).map { user: User -> - user.resetKey = passwordService.generateResetKey() - user.resetDate = ZonedDateTime.now() - user - } + fun requestPasswordReset(mail: String): User? { + val user = userRepository.findOneByEmail(mail) + if (user?.activated == true) user.resetKey = passwordService.generateResetKey() + user?.resetDate = ZonedDateTime.now() + return user } /** @@ -151,30 +155,30 @@ open class UserService( user.resetKey = passwordService.generateResetKey() user.resetDate = ZonedDateTime.now() user.activated = false - user.roles = getUserRoles(userDto.roles, setOf()) + user.roles = userDto.roles?.let { getUserRoles(it, mutableSetOf()) } user = userRepository.save(user) log.debug("Created Information for User: {}", user) return user } @Throws(NotAuthorizedException::class) - private fun getUserRoles(roleDtos: Set?, oldRoles: Set): MutableSet? { + private fun getUserRoles(roleDtos: Set?, oldRoles: MutableSet): MutableSet? { if (roleDtos == null) { return null } - val roles = roleDtos.stream().map { roleDto: RoleDTO -> - val authority = getRoleAuthority(roleDto) - when (authority.scope) { - RoleAuthority.Scope.GLOBAL -> roleService.getGlobalRole(authority) - RoleAuthority.Scope.ORGANIZATION -> roleService.getOrganizationRole( - authority, roleDto.organizationId - ) + val roles = roleDtos.map { roleDto: RoleDTO -> + val authority = getRoleAuthority(roleDto) + when (authority.scope) { + RoleAuthority.Scope.GLOBAL -> roleService.getGlobalRole(authority) + RoleAuthority.Scope.ORGANIZATION -> roleService.getOrganizationRole( + authority, roleDto.organizationId!! + ) - RoleAuthority.Scope.PROJECT -> roleService.getProjectRole( - authority, roleDto.projectId - ) - } - }.collect(Collectors.toSet()) + RoleAuthority.Scope.PROJECT -> roleService.getProjectRole( + authority, roleDto.projectId!! + ) + } + }.toMutableSet() checkAuthorityForRoleChange(roles, oldRoles) return roles } @@ -220,12 +224,12 @@ open class UserService( * @param langKey language key */ fun updateUser( - userName: String, firstName: String?, lastName: String?, email: String, langKey: String? + userName: String, firstName: String?, lastName: String?, email: String?, langKey: String? ) { - val userWithEmail = userRepository.findOneByEmail(email) + val userWithEmail = email?.let { userRepository.findOneByEmail(it) } val user: User - if (userWithEmail.isPresent) { - user = userWithEmail.get() + if (userWithEmail != null) { + user = userWithEmail if (!user.login.equals(userName, ignoreCase = true)) { throw ConflictException( "Email address $email already in use", @@ -235,14 +239,12 @@ open class UserService( ) } } else { - user = userRepository.findOneByLogin(userName).orElseThrow { - NotFoundException( - "User with login $userName not found", - EntityName.USER, - ErrorConstants.ERR_ENTITY_NOT_FOUND, - Map.of("user", userName) - ) - } + user = userRepository.findOneByLogin(userName) ?: throw NotFoundException( + "User with login $userName not found", + EntityName.USER, + ErrorConstants.ERR_ENTITY_NOT_FOUND, + Map.of("user", userName) + ) } user.firstName = firstName user.lastName = lastName @@ -261,8 +263,8 @@ open class UserService( @Transactional @Throws(NotAuthorizedException::class) open fun updateUser(userDto: UserDTO): UserDTO? { - val userOpt = userRepository.findById(userDto.id) - return if (userOpt.isPresent) { + val userOpt = userDto.id?.let { userRepository.findById(it) } + return if (userOpt?.isPresent == true) { var user = userOpt.get() user.firstName = userDto.firstName user.lastName = userDto.lastName @@ -285,23 +287,26 @@ open class UserService( * Delete the user with the given login. * @param login the login to delete */ - fun deleteUser(login: String?) { - userRepository.findOneByLogin(login).ifPresent { user: User -> + fun deleteUser(login: String) { + val user = userRepository.findOneByLogin(login) + if (user != null) { userRepository.delete(user) log.debug("Deleted User: {}", user) } + else { + log.warn("could not delete User with login: {}", login) + } } /** * Change the password of the user with the given login. * @param password the new password */ - fun changePassword(password: String?) { - val currentUser = SecurityUtils.getCurrentUserLogin().orElseThrow { - InvalidRequestException( - "Cannot change password of unknown user", null, ErrorConstants.ERR_ENTITY_NOT_FOUND - ) - } + fun changePassword(password: String) { + val currentUser = SecurityUtils.currentUserLogin + ?: throw InvalidRequestException( + "Cannot change password of unknown user", "", ErrorConstants.ERR_ENTITY_NOT_FOUND + ) changePassword(currentUser, password) } @@ -310,12 +315,16 @@ open class UserService( * @param password the new password * @param login of the user to change password */ - fun changePassword(login: String?, password: String?) { - userRepository.findOneByLogin(login).ifPresent { user: User -> + fun changePassword(login: String, password: String) { + val user = userRepository.findOneByLogin(login) + + if (user != null) + { val encryptedPassword = passwordService.encode(password) user.password = encryptedPassword log.debug("Changed password for User: {}", user) } + } /** @@ -324,7 +333,7 @@ open class UserService( * @return the requested page of users */ @Transactional(readOnly = true) - open fun getAllManagedUsers(pageable: Pageable?): Page { + open fun getAllManagedUsers(pageable: Pageable): Page { log.debug("Request to get all Users") return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER) .map { user: User? -> userMapper.userToUserDTO(user) } @@ -337,18 +346,17 @@ open class UserService( * and is empty otherwise */ @Transactional(readOnly = true) - open fun getUserWithAuthoritiesByLogin(login: String?): Optional { - return userRepository.findOneWithRolesByLogin(login).map { user: User? -> userMapper.userToUserDTO(user) } + open fun getUserWithAuthoritiesByLogin(login: String): UserDTO? { + return userMapper.userToUserDTO(userRepository.findOneWithRolesByLogin(login)) } @get:Transactional(readOnly = true) - open val userWithAuthorities: Optional + open val userWithAuthorities: User? /** * Get the current user. * @return the currently authenticated user, or null if no user is currently authenticated */ - get() = SecurityUtils.getCurrentUserLogin() - .flatMap { currentUser: String? -> userRepository.findOneWithRolesByLogin(currentUser) } + get() = SecurityUtils.currentUserLogin?.let { userRepository.findOneWithRolesByLogin(it) } /** * Not activated users should be automatically deleted after 3 days. @@ -407,18 +415,20 @@ open class UserService( @Transactional @Throws(NotAuthorizedException::class) open fun updateRoles(login: String, roleDtos: Set?) { - val user = userRepository.findOneByLogin(login).orElseThrow { - NotFoundException( - "User with login $login not found", - EntityName.USER, - ErrorConstants.ERR_ENTITY_NOT_FOUND, - Map.of("user", login) - ) - } + val user = userRepository.findOneByLogin(login) + ?: throw NotFoundException( + "User with login $login not found", + EntityName.USER, + ErrorConstants.ERR_ENTITY_NOT_FOUND, + Map.of("user", login) + ) + val managedRoles = user.roles - val oldRoles = java.util.Set.copyOf(managedRoles) + val oldRoles = managedRoles?.toMutableSet() + managedRoles?.clear() - managedRoles?.addAll(getUserRoles(roleDtos, oldRoles)!!) + managedRoles?.addAll(roleDtos?.let { oldRoles?.let { oldroles -> getUserRoles(it, oldroles) } }!!) + ?: throw Exception("could not add rolser for user: $user") userRepository.save(user) } diff --git a/src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.java b/src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.java deleted file mode 100644 index 56892b301..000000000 --- a/src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.radarbase.management.service.catalog; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class CatalogSourceData { - @JsonProperty("app_provider") - private String appProvider; - - @JsonProperty("processing_state") - private String processingState; - - @JsonProperty - private String type; - - @JsonProperty - private String doc; - - @JsonProperty("sample_rate") - private SampleRateConfig sampleRate; - - @JsonProperty - private String unit; - - @JsonProperty - private List fields; - - private String topic; - - @JsonProperty("key_schema") - private String keySchema; - - @JsonProperty("value_schema") - private String valueSchema; - - private List tags; - - public String getTopic() { - return topic; - } - - public void setTopic(String topic) { - this.topic = topic; - } - - public String getKeySchema() { - return keySchema; - } - - public void setKeySchema(String keySchema) { - this.keySchema = keySchema; - } - - public String getValueSchema() { - return valueSchema; - } - - public void setValueSchema(String valueSchema) { - this.valueSchema = valueSchema; - } - - public List getTags() { - return tags; - } - - public void setTags(List tags) { - this.tags = tags; - } - - public String getType() { - return type; - } - - public String getDoc() { - return doc; - } - - public SampleRateConfig getSampleRate() { - return sampleRate; - } - - public String getUnit() { - return unit; - } - - public List getFields() { - return fields; - } - - public String getProcessingState() { - return processingState; - } - - public void setProcessingState(String processingState) { - this.processingState = processingState; - } - - public void setAppProvider(String appProvider) { - this.appProvider = appProvider; - } - - public String getAppProvider() { - return appProvider; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static class DataField { - @JsonProperty - private String name; - - public String getName() { - return name; - } - - @Override - public String toString() { - return "DataField{" + "name='" + name + '\'' - + '}'; - } - } - - @Override - public String toString() { - return "CatalogSourceData{" + "appProvider='" + appProvider + '\'' - + ", processingState='" + processingState + '\'' - + ", type='" + type + '\'' - + ", doc='" + doc + '\'' - + ", sampleRate=" + sampleRate - + ", unit='" + unit + '\'' - + ", fields=" + fields - + ", topic='" + topic + '\'' - + ", keySchema='" + keySchema + '\'' - + ", valueSchema='" + valueSchema + '\'' - + ", tags=" + tags - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.kt b/src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.kt new file mode 100644 index 000000000..2f7dfa81e --- /dev/null +++ b/src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.kt @@ -0,0 +1,61 @@ +package org.radarbase.management.service.catalog + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonIgnoreProperties(ignoreUnknown = true) +class CatalogSourceData { + @JsonProperty("app_provider") + var appProvider: String? = null + + @JsonProperty("processing_state") + var processingState: String? = null + + @JsonProperty + val type: String? = null + + @JsonProperty + val doc: String? = null + + @JsonProperty("sample_rate") + val sampleRate: SampleRateConfig? = null + + @JsonProperty + val unit: String? = null + + @JsonProperty + val fields: List? = null + var topic: String? = null + + @JsonProperty("key_schema") + var keySchema: String? = null + + @JsonProperty("value_schema") + var valueSchema: String? = null + var tags: List? = null + + @JsonIgnoreProperties(ignoreUnknown = true) + class DataField { + @JsonProperty + val name: String? = null + override fun toString(): String { + return ("DataField{" + "name='" + name + '\'' + + '}') + } + } + + override fun toString(): String { + return ("CatalogSourceData{" + "appProvider='" + appProvider + '\'' + + ", processingState='" + processingState + '\'' + + ", type='" + type + '\'' + + ", doc='" + doc + '\'' + + ", sampleRate=" + sampleRate + + ", unit='" + unit + '\'' + + ", fields=" + fields + + ", topic='" + topic + '\'' + + ", keySchema='" + keySchema + '\'' + + ", valueSchema='" + valueSchema + '\'' + + ", tags=" + tags + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.java b/src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.java deleted file mode 100644 index 9cfff8bd2..000000000 --- a/src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.radarbase.management.service.catalog; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import org.hibernate.validator.constraints.NotEmpty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class CatalogSourceType { - - @JsonProperty("assessment_type") - private String assessmentType; - - @JsonProperty("app_provider") - private String appProvider; - - @JsonProperty - private String vendor; - - @JsonProperty - private String model; - - @JsonProperty - private String version; - - @JsonProperty - private String name; - - @JsonProperty - private String doc; - - @JsonProperty - private String scope; - - @JsonProperty - private Map properties; - - @JsonProperty - @NotEmpty - private List data; - - public String getName() { - return name; - } - - public String getDoc() { - return doc; - } - - public Map getProperties() { - return properties; - } - - public String getAppProvider() { - return appProvider; - } - - public String getVendor() { - return vendor; - } - - public String getModel() { - return model; - } - - public String getVersion() { - return version; - } - - public String getScope() { - return scope; - } - - public List getData() { - return data; - } - - public String getAssessmentType() { - return assessmentType; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CatalogSourceType that = (CatalogSourceType) o; - return Objects.equals(assessmentType, that.assessmentType) - && Objects.equals(appProvider, that.appProvider) - && Objects.equals(vendor, that.vendor) - && Objects.equals(model, that.model) - && Objects.equals(version, that.version) - && Objects.equals(name, that.name) - && Objects.equals(doc, that.doc) - && Objects.equals(scope, that.scope) - && Objects.equals(properties, that.properties) - && Objects.equals(data, that.data); - } - - @Override - public int hashCode() { - - return Objects - .hash(assessmentType, appProvider, vendor, model, version, name, doc, scope, properties, - data); - } -} diff --git a/src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.kt b/src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.kt new file mode 100644 index 000000000..fe5dfb76a --- /dev/null +++ b/src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.kt @@ -0,0 +1,58 @@ +package org.radarbase.management.service.catalog + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty +import org.hibernate.validator.constraints.NotEmpty +import java.util.* + +@JsonIgnoreProperties(ignoreUnknown = true) +class CatalogSourceType { + @JsonProperty("assessment_type") + val assessmentType: String? = null + + @JsonProperty("app_provider") + val appProvider: String? = null + + @JsonProperty + val vendor: String? = null + + @JsonProperty + val model: String? = null + + @JsonProperty + val version: String? = null + + @JsonProperty + val name: String? = null + + @JsonProperty + val doc: String? = null + + @JsonProperty + val scope: String? = null + + @JsonProperty + val properties: Map = emptyMap() + + @JsonProperty + val data: @NotEmpty MutableList? = null + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val that = other as CatalogSourceType + return assessmentType == that.assessmentType && appProvider == that.appProvider && vendor == that.vendor && model == that.model && version == that.version && name == that.name && doc == that.doc && scope == that.scope && properties == that.properties && data == that.data + } + + override fun hashCode(): Int { + return Objects + .hash( + assessmentType, appProvider, vendor, model, version, name, doc, scope, properties, + data + ) + } +} diff --git a/src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.java b/src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.java deleted file mode 100644 index 9e323b639..000000000 --- a/src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.radarbase.management.service.catalog; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class SampleRateConfig { - - @JsonProperty - private Double interval; - - @JsonProperty - private Double frequency; - - @JsonProperty - private boolean dynamic; - - @JsonProperty - private boolean configurable; - - public Double getInterval() { - return interval; - } - - public Double getFrequency() { - return frequency; - } - - public boolean isDynamic() { - return dynamic; - } - - public boolean isConfigurable() { - return configurable; - } - - @Override - public String toString() { - return "SampleRateConfig{interval=" + interval - + ", frequency=" + frequency - + ", dynamic=" + dynamic - + ", configurable=" + configurable - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.kt b/src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.kt new file mode 100644 index 000000000..1bc02797c --- /dev/null +++ b/src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.kt @@ -0,0 +1,26 @@ +package org.radarbase.management.service.catalog + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonIgnoreProperties(ignoreUnknown = true) +class SampleRateConfig { + @JsonProperty + val interval: Double? = null + + @JsonProperty + val frequency: Double? = null + + @JsonProperty + val isDynamic = false + + @JsonProperty + val isConfigurable = false + override fun toString(): String { + return ("SampleRateConfig{interval=" + interval + + ", frequency=" + frequency + + ", dynamic=" + isDynamic + + ", configurable=" + isConfigurable + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.java b/src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.java deleted file mode 100644 index ca505772d..000000000 --- a/src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.radarbase.management.service.catalog; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class SourceTypeResponse { - - @JsonProperty("passive-source-types") - private List passiveSources; - - @JsonProperty("active-source-types") - private List activeSources; - - @JsonProperty("monitor-source-types") - private List monitorSources; - - @JsonProperty("connector-source-types") - private List connectorSources; - - public List getPassiveSources() { - return passiveSources; - } - - public List getActiveSources() { - return activeSources; - } - - public List getMonitorSources() { - return monitorSources; - } - - public List getConnectorSources() { - return connectorSources; - } -} diff --git a/src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.kt b/src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.kt new file mode 100644 index 000000000..693f16bdb --- /dev/null +++ b/src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.kt @@ -0,0 +1,19 @@ +package org.radarbase.management.service.catalog + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonIgnoreProperties(ignoreUnknown = true) +class SourceTypeResponse { + @JsonProperty("passive-source-types") + val passiveSources: List? = null + + @JsonProperty("active-source-types") + val activeSources: List? = null + + @JsonProperty("monitor-source-types") + val monitorSources: List? = null + + @JsonProperty("connector-source-types") + val connectorSources: List? = null +} diff --git a/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.java b/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.java deleted file mode 100644 index a4914b052..000000000 --- a/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.util.Objects; - -/** - * Created by nivethika on 30-8-17. - */ -public class AttributeMapDTO { - private String key; - - private String value; - - public AttributeMapDTO() { - this(null, null); - } - - public AttributeMapDTO(String key, String value) { - this.key = key; - this.value = value; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - AttributeMapDTO attributeMapDto = (AttributeMapDTO) o; - - return Objects.equals(key, attributeMapDto.key) - && Objects.equals(value, attributeMapDto.value); - } - - @Override - public int hashCode() { - return Objects.hash(key, value); - } - - @Override - public String toString() { - return "AttributeMapDTO{" - + " key='" + key + "'" - + ", value='" + value + "'" - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt b/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt new file mode 100644 index 000000000..7f54176ee --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt @@ -0,0 +1,31 @@ +package org.radarbase.management.service.dto + +import java.util.* + +/** + * Created by nivethika on 30-8-17. + */ +class AttributeMapDTO @JvmOverloads constructor(var key: String? = null, var value: String? = null) { + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val attributeMapDto = o as AttributeMapDTO + return key == attributeMapDto.key && value == attributeMapDto.value + } + + override fun hashCode(): Int { + return Objects.hash(key, value) + } + + override fun toString(): String { + return ("AttributeMapDTO{" + + " key='" + key + "'" + + ", value='" + value + "'" + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/AuthorityDTO.java b/src/main/java/org/radarbase/management/service/dto/AuthorityDTO.java deleted file mode 100644 index c1d6d1b5c..000000000 --- a/src/main/java/org/radarbase/management/service/dto/AuthorityDTO.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.radarbase.management.service.dto; - -import org.radarbase.auth.authorization.RoleAuthority; - -public class AuthorityDTO { - private String name; - private String scope; - - public AuthorityDTO() { - // POJO constructor - } - - public AuthorityDTO(RoleAuthority role) { - this.name = role.getAuthority(); - this.scope = role.getScope().name(); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getScope() { - return scope; - } - - public void setScope(String scope) { - this.scope = scope; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/AuthorityDTO.kt b/src/main/java/org/radarbase/management/service/dto/AuthorityDTO.kt new file mode 100644 index 000000000..f6bed0a64 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/AuthorityDTO.kt @@ -0,0 +1,14 @@ +package org.radarbase.management.service.dto + +import org.radarbase.auth.authorization.RoleAuthority + +class AuthorityDTO { + var name: String? = null + var scope: String? = null + + constructor() + constructor(role: RoleAuthority) { + name = role.authority + scope = role.scope.name + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.java b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.java deleted file mode 100644 index 39ccea7a9..000000000 --- a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.util.Map; -import java.util.Set; -import javax.validation.constraints.NotNull; - -/** - * Created by dverbeec on 7/09/2017. - */ -public class ClientDetailsDTO { - - @NotNull - private String clientId; - private String clientSecret; - private Set scope; - private Set resourceIds; - private Set authorizedGrantTypes; - private Set autoApproveScopes; - private Long accessTokenValiditySeconds; - private Long refreshTokenValiditySeconds; - private Set authorities; - private Set registeredRedirectUri; - private Map additionalInformation; - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public String getClientSecret() { - return clientSecret; - } - - public void setClientSecret(String clientSecret) { - this.clientSecret = clientSecret; - } - - public Set getScope() { - return scope; - } - - public void setScope(Set scope) { - this.scope = scope; - } - - public Set getResourceIds() { - return resourceIds; - } - - public void setResourceIds(Set resourceIds) { - this.resourceIds = resourceIds; - } - - public Set getAuthorizedGrantTypes() { - return authorizedGrantTypes; - } - - public void setAuthorizedGrantTypes(Set authorizedGrantTypes) { - this.authorizedGrantTypes = authorizedGrantTypes; - } - - public Set getAutoApproveScopes() { - return autoApproveScopes; - } - - public void setAutoApproveScopes(Set autoApproveScopes) { - this.autoApproveScopes = autoApproveScopes; - } - - public Long getAccessTokenValiditySeconds() { - return accessTokenValiditySeconds; - } - - public void setAccessTokenValiditySeconds(Long accessTokenValiditySeconds) { - this.accessTokenValiditySeconds = accessTokenValiditySeconds; - } - - public Long getRefreshTokenValiditySeconds() { - return refreshTokenValiditySeconds; - } - - public void setRefreshTokenValiditySeconds(Long refreshTokenValiditySeconds) { - this.refreshTokenValiditySeconds = refreshTokenValiditySeconds; - } - - public Set getAuthorities() { - return authorities; - } - - public void setAuthorities(Set authorities) { - this.authorities = authorities; - } - - public Set getRegisteredRedirectUri() { - return registeredRedirectUri; - } - - public void setRegisteredRedirectUri(Set registeredRedirectUri) { - this.registeredRedirectUri = registeredRedirectUri; - } - - public Map getAdditionalInformation() { - return additionalInformation; - } - - public void setAdditionalInformation(Map additionalInformation) { - this.additionalInformation = additionalInformation; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt new file mode 100644 index 000000000..b2a19c2f6 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt @@ -0,0 +1,20 @@ +package org.radarbase.management.service.dto + +import javax.validation.constraints.NotNull + +/** + * Created by dverbeec on 7/09/2017. + */ +class ClientDetailsDTO { + lateinit var clientId: @NotNull String + var clientSecret: String? = null + var scope: Set? = null + var resourceIds: Set? = null + var authorizedGrantTypes: Set? = null + var autoApproveScopes: Set? = null + var accessTokenValiditySeconds: Long? = null + var refreshTokenValiditySeconds: Long? = null + var authorities: Set? = null + var registeredRedirectUri: Set? = null + var additionalInformation: Map? = null +} diff --git a/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.java b/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.java deleted file mode 100644 index 865509b8a..000000000 --- a/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.net.URL; -import java.time.Duration; -import java.time.Instant; -import java.util.Objects; - -/** - * Created by dverbeec on 29/08/2017. - */ -public class ClientPairInfoDTO { - - private final String tokenName; - - private final URL tokenUrl; - - private final URL baseUrl; - - private final long timeout; - - private final Instant timesOutAt; - - - /** - * Initialize with the given refresh token. - * @param baseUrl the base url of the platform - * @param tokenName the refresh token - * @param tokenUrl the refresh token - */ - public ClientPairInfoDTO(URL baseUrl, String tokenName, URL tokenUrl, Duration timeout) { - if (tokenUrl == null) { - throw new IllegalArgumentException("tokenUrl can not be null"); - } - this.baseUrl = baseUrl; - this.tokenName = tokenName; - this.tokenUrl = tokenUrl; - this.timeout = timeout.toMillis(); - this.timesOutAt = Instant.now().plus(timeout); - } - - public String getTokenName() { - return tokenName; - } - - public URL getTokenUrl() { - return tokenUrl; - } - - public URL getBaseUrl() { - return baseUrl; - } - - public long getTimeout() { - return timeout; - } - - public Instant getTimesOutAt() { - return timesOutAt; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ClientPairInfoDTO that = (ClientPairInfoDTO) o; - return Objects.equals(tokenName, that.tokenName) - && Objects.equals(tokenUrl, that.tokenUrl) - && Objects.equals(baseUrl, that.baseUrl) - && Objects.equals(timeout, that.timeout) - && Objects.equals(timesOutAt, that.timesOutAt); - } - - @Override - public int hashCode() { - - return Objects.hash(baseUrl, tokenName, tokenUrl, timeout, timesOutAt); - } - - @Override - public String toString() { - return "ClientPairInfoDTO{" - + "tokenName='" + tokenName + '\'' - + ", tokenUrl=" + tokenUrl + '\'' - + ", timeout=" + timeout + '\'' - + ", timesOutAt=" + timesOutAt + '\'' - + ", baseUrl=" + baseUrl + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt b/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt new file mode 100644 index 000000000..9955c4d22 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt @@ -0,0 +1,56 @@ +package org.radarbase.management.service.dto + +import java.net.URL +import java.time.Duration +import java.time.Instant +import java.util.* + +/** + * Created by dverbeec on 29/08/2017. + */ +class ClientPairInfoDTO(baseUrl: URL, tokenName: String, tokenUrl: URL?, timeout: Duration) { + val tokenName: String + val tokenUrl: URL + val baseUrl: URL + val timeout: Long + val timesOutAt: Instant + + /** + * Initialize with the given refresh token. + * @param baseUrl the base url of the platform + * @param tokenName the refresh token + * @param tokenUrl the refresh token + */ + init { + requireNotNull(tokenUrl) { "tokenUrl can not be null" } + this.baseUrl = baseUrl + this.tokenName = tokenName + this.tokenUrl = tokenUrl + this.timeout = timeout.toMillis() + timesOutAt = Instant.now().plus(timeout) + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val that = o as ClientPairInfoDTO + return tokenName == that.tokenName && tokenUrl == that.tokenUrl && baseUrl == that.baseUrl && timeout == that.timeout && timesOutAt == that.timesOutAt + } + + override fun hashCode(): Int { + return Objects.hash(baseUrl, tokenName, tokenUrl, timeout, timesOutAt) + } + + override fun toString(): String { + return ("ClientPairInfoDTO{" + + "tokenName='" + tokenName + '\'' + + ", tokenUrl=" + tokenUrl + '\'' + + ", timeout=" + timeout + '\'' + + ", timesOutAt=" + timesOutAt + '\'' + + ", baseUrl=" + baseUrl + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/GroupDTO.java b/src/main/java/org/radarbase/management/service/dto/GroupDTO.java deleted file mode 100644 index 66e426ee9..000000000 --- a/src/main/java/org/radarbase/management/service/dto/GroupDTO.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.radarbase.management.service.dto; - -import com.fasterxml.jackson.annotation.JsonInclude; - -import javax.validation.constraints.NotNull; -import java.util.Objects; - -/** - * A DTO for the Group entity. - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class GroupDTO { - - private Long id; - - private Long projectId; - - @NotNull - private String name; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getProjectId() { - return projectId; - } - - public void setProjectId(Long projectId) { - this.projectId = projectId; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - GroupDTO groupDto = (GroupDTO) o; - - if (id == null || groupDto.id == null) { - return false; - } - - return Objects.equals(id, groupDto.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "GroupDTO{" - + "id=" + id - + ", name='" + name + "'" - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt b/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt new file mode 100644 index 000000000..7daa3ba88 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt @@ -0,0 +1,38 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import java.util.* +import javax.validation.constraints.NotNull + +/** + * A DTO for the Group entity. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +class GroupDTO { + var id: Long? = null + var projectId: Long? = null + var name: @NotNull String? = null + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val groupDto = o as GroupDTO + return if (id == null || groupDto.id == null) { + false + } else id == groupDto.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("GroupDTO{" + + "id=" + id + + ", name='" + name + "'" + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.java b/src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.java deleted file mode 100644 index 999df6474..000000000 --- a/src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.radarbase.management.service.dto; - -/** - * Created by nivethika on 21-6-17. - */ -public class MinimalProjectDetailsDTO { - - private Long id; - - private String projectName; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.kt new file mode 100644 index 000000000..01dec5bc1 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.kt @@ -0,0 +1,9 @@ +package org.radarbase.management.service.dto + +/** + * Created by nivethika on 21-6-17. + */ +class MinimalProjectDetailsDTO { + var id: Long? = null + var projectName: String? = null +} diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.java b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.java deleted file mode 100644 index 03a6cb145..000000000 --- a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.java +++ /dev/null @@ -1,163 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * Created by nivethika on 13-6-17. - */ -public class MinimalSourceDetailsDTO { - - private Long id; - private Long sourceTypeId; - private String sourceTypeProducer; - private String sourceTypeModel; - private String sourceTypeCatalogVersion; - private String expectedSourceName; - private UUID sourceId; - private String sourceName; - private Boolean assigned; - private Map attributes = new HashMap<>(); - - public Long getId() { - return id; - } - - public MinimalSourceDetailsDTO id(Long id) { - this.id = id; - return this; - } - - public Long getSourceTypeId() { - return sourceTypeId; - } - - public MinimalSourceDetailsDTO sourceTypeId(Long sourceTypeId) { - this.sourceTypeId = sourceTypeId; - return this; - } - - public String getExpectedSourceName() { - return expectedSourceName; - } - - public MinimalSourceDetailsDTO setExpectedSourceName(String expectedSourceName) { - this.expectedSourceName = expectedSourceName; - return this; - } - - public UUID getSourceId() { - return sourceId; - } - - public MinimalSourceDetailsDTO sourceId(UUID sourceId) { - this.sourceId = sourceId; - return this; - } - - public Boolean isAssigned() { - return assigned; - } - - public MinimalSourceDetailsDTO assigned(Boolean assigned) { - this.assigned = assigned; - return this; - } - - public String getSourceName() { - return sourceName; - } - - public MinimalSourceDetailsDTO sourceName(String sourceName) { - this.sourceName = sourceName; - return this; - } - - public Map getAttributes() { - return attributes; - } - - public MinimalSourceDetailsDTO attributes(Map attributes) { - this.attributes = attributes; - return this; - } - - public String getSourceTypeCatalogVersion() { - return sourceTypeCatalogVersion; - } - - public MinimalSourceDetailsDTO sourceTypeCatalogVersion(String sourceTypeCatalogVersion) { - this.sourceTypeCatalogVersion = sourceTypeCatalogVersion; - return this; - } - - public String getSourceTypeModel() { - return sourceTypeModel; - } - - public MinimalSourceDetailsDTO sourceTypeModel(String sourceTypeModel) { - this.sourceTypeModel = sourceTypeModel; - return this; - } - - public String getSourceTypeProducer() { - return sourceTypeProducer; - } - - public MinimalSourceDetailsDTO sourceTypeProducer(String sourceTypeProducer) { - this.sourceTypeProducer = sourceTypeProducer; - return this; - } - - public void setId(Long id) { - this.id = id; - } - - public void setSourceTypeId(Long sourceTypeId) { - this.sourceTypeId = sourceTypeId; - } - - public void setSourceTypeProducer(String sourceTypeProducer) { - this.sourceTypeProducer = sourceTypeProducer; - } - - public void setSourceTypeModel(String sourceTypeModel) { - this.sourceTypeModel = sourceTypeModel; - } - - public void setSourceTypeCatalogVersion(String sourceTypeCatalogVersion) { - this.sourceTypeCatalogVersion = sourceTypeCatalogVersion; - } - - public void setSourceId(UUID sourceId) { - this.sourceId = sourceId; - } - - public void setSourceName(String sourceName) { - this.sourceName = sourceName; - } - - public void setAssigned(Boolean assigned) { - this.assigned = assigned; - } - - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - @Override - public String toString() { - return "MinimalSourceDetailsDTO{" - + "id=" + id - + ", sourceTypeId=" + sourceTypeId - + ", sourceTypeProducer='" + sourceTypeProducer + '\'' - + ", sourceTypeModel='" + sourceTypeModel + '\'' - + ", sourceTypeCatalogVersion='" + sourceTypeCatalogVersion + '\'' - + ", expectedSourceName='" + expectedSourceName + '\'' - + ", sourceId=" + sourceId - + ", sourceName='" + sourceName + '\'' - + ", assigned=" + assigned - + ", attributes=" + attributes + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt new file mode 100644 index 000000000..fe111ae5b --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt @@ -0,0 +1,83 @@ +package org.radarbase.management.service.dto + +import java.util.* + +/** + * Created by nivethika on 13-6-17. + */ +class MinimalSourceDetailsDTO { + var id: Long? = null + var sourceTypeId: Long? = null + var sourceTypeProducer: String? = null + var sourceTypeModel: String? = null + var sourceTypeCatalogVersion: String? = null + var expectedSourceName: String? = null + private set + lateinit var sourceId: UUID + var sourceName: String? = null + var isAssigned: Boolean? = null + var attributes: Map = HashMap() + fun id(id: Long?): MinimalSourceDetailsDTO { + this.id = id + return this + } + + fun sourceTypeId(sourceTypeId: Long?): MinimalSourceDetailsDTO { + this.sourceTypeId = sourceTypeId + return this + } + + fun setExpectedSourceName(expectedSourceName: String?): MinimalSourceDetailsDTO { + this.expectedSourceName = expectedSourceName + return this + } + + fun sourceId(sourceId: UUID): MinimalSourceDetailsDTO { + this.sourceId = sourceId + return this + } + + fun assigned(assigned: Boolean?): MinimalSourceDetailsDTO { + isAssigned = assigned + return this + } + + fun sourceName(sourceName: String?): MinimalSourceDetailsDTO { + this.sourceName = sourceName + return this + } + + fun attributes(attributes: Map): MinimalSourceDetailsDTO { + this.attributes = attributes + return this + } + + fun sourceTypeCatalogVersion(sourceTypeCatalogVersion: String?): MinimalSourceDetailsDTO { + this.sourceTypeCatalogVersion = sourceTypeCatalogVersion + return this + } + + fun sourceTypeModel(sourceTypeModel: String?): MinimalSourceDetailsDTO { + this.sourceTypeModel = sourceTypeModel + return this + } + + fun sourceTypeProducer(sourceTypeProducer: String?): MinimalSourceDetailsDTO { + this.sourceTypeProducer = sourceTypeProducer + return this + } + + override fun toString(): String { + return ("MinimalSourceDetailsDTO{" + + "id=" + id + + ", sourceTypeId=" + sourceTypeId + + ", sourceTypeProducer='" + sourceTypeProducer + '\'' + + ", sourceTypeModel='" + sourceTypeModel + '\'' + + ", sourceTypeCatalogVersion='" + sourceTypeCatalogVersion + '\'' + + ", expectedSourceName='" + expectedSourceName + '\'' + + ", sourceId=" + sourceId + + ", sourceName='" + sourceName + '\'' + + ", assigned=" + isAssigned + + ", attributes=" + attributes + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.java b/src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.java deleted file mode 100644 index 455dc89db..000000000 --- a/src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.radarbase.management.service.dto; - -/** - * Created by nivethika on 22-6-17. - */ -public class MinimalSourceTypeDTO { - - private long id; - - private String model; - - private String producer; - - private String catalogVersion; - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getModel() { - return model; - } - - public void setModel(String model) { - this.model = model; - } - - public String getProducer() { - return producer; - } - - public void setProducer(String producer) { - this.producer = producer; - } - - public String getCatalogVersion() { - return catalogVersion; - } - - public void setCatalogVersion(String catalogVersion) { - this.catalogVersion = catalogVersion; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.kt b/src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.kt new file mode 100644 index 000000000..c0a4dacbe --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.kt @@ -0,0 +1,11 @@ +package org.radarbase.management.service.dto + +/** + * Created by nivethika on 22-6-17. + */ +class MinimalSourceTypeDTO { + var id: Long = 0 + var model: String? = null + var producer: String? = null + var catalogVersion: String? = null +} diff --git a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.java b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.java deleted file mode 100644 index a4c216c76..000000000 --- a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.radarbase.management.service.dto; - - -import com.fasterxml.jackson.annotation.JsonInclude; -import java.io.Serializable; -import java.util.List; -import java.util.Objects; -import javax.validation.constraints.NotNull; - -/** - * A DTO for the Organization entity. - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class OrganizationDTO implements Serializable { - private static final long serialVersionUID = 1L; - - private Long id; - - @NotNull - private String name; - - @NotNull - private String description; - - @NotNull - private String location; - - private List projects; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - - public List getProjects() { - return projects; - } - - public void setProjects(List projects) { - this.projects = projects; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - var orgDto = (OrganizationDTO) o; - return Objects.equals(name, orgDto.name) - && Objects.equals(description, orgDto.description) - && Objects.equals(location, orgDto.location); - } - - @Override - public int hashCode() { - return Objects.hashCode(name); - } - - @Override - public String toString() { - return "OrganizationDTO{" - + "id=" + id - + ", name='" + name + "'" - + ", description='" + description + "'" - + ", location='" + location + "'" - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt new file mode 100644 index 000000000..00aab1319 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt @@ -0,0 +1,45 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import java.io.Serializable +import java.util.* +import javax.validation.constraints.NotNull + +/** + * A DTO for the Organization entity. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +class OrganizationDTO : Serializable { + var id: Long? = null + lateinit var name: @NotNull String + lateinit var description: @NotNull String + lateinit var location: @NotNull String + var projects: List? = null + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val orgDto = other as OrganizationDTO + return name == orgDto.name && description == orgDto.description && location == orgDto.location + } + + override fun hashCode(): Int { + return Objects.hashCode(name) + } + + override fun toString(): String { + return ("OrganizationDTO{" + + "id=" + id + + ", name='" + name + "'" + + ", description='" + description + "'" + + ", location='" + location + "'" + + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.java b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.java deleted file mode 100644 index 62afd3d61..000000000 --- a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.java +++ /dev/null @@ -1,209 +0,0 @@ -package org.radarbase.management.service.dto; - - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import java.io.Serializable; -import java.time.ZonedDateTime; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import javax.validation.constraints.NotNull; -import org.radarbase.management.domain.enumeration.ProjectStatus; - -/** - * A DTO for the Project entity. - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class ProjectDTO implements Serializable { - private static final long serialVersionUID = 1L; - - public static final String EXTERNAL_PROJECT_URL_KEY = "External-project-url"; - public static final String EXTERNAL_PROJECT_ID_KEY = "External-project-id"; - public static final String WORK_PACKAGE_KEY = "Work-package"; - public static final String PHASE_KEY = "Phase"; - public static final String HUMAN_READABLE_PROJECT_NAME = "Human-readable-project-name"; - public static final String PRIVACY_POLICY_URL = "Privacy-policy-url"; - - private Long id; - - @NotNull - private String projectName; - - private String humanReadableProjectName; - - @NotNull - private String description; - - private OrganizationDTO organization; - - private String organizationName; - - @NotNull - private String location; - - private ZonedDateTime startDate; - - private ProjectStatus projectStatus; - - private ZonedDateTime endDate; - - @JsonInclude(Include.NON_EMPTY) - private Set sourceTypes; - - private Map attributes; - - @JsonInclude(Include.NON_EMPTY) - private Set groups; - - private Long persistentTokenTimeout; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public OrganizationDTO getOrganization() { - return organization; - } - - public void setOrganization(OrganizationDTO organization) { - this.organization = organization; - } - - public String getOrganizationName() { - return organizationName; - } - - public void setOrganizationName(String organizationName) { - this.organizationName = organizationName; - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - - public ZonedDateTime getStartDate() { - return startDate; - } - - public void setStartDate(ZonedDateTime startDate) { - this.startDate = startDate; - } - - public ProjectStatus getProjectStatus() { - return projectStatus; - } - - public void setProjectStatus(ProjectStatus projectStatus) { - this.projectStatus = projectStatus; - } - - public ZonedDateTime getEndDate() { - return endDate; - } - - public void setEndDate(ZonedDateTime endDate) { - this.endDate = endDate; - } - - public Set getSourceTypes() { - return sourceTypes; - } - - public void setSourceTypes(Set sourceTypes) { - this.sourceTypes = sourceTypes; - } - - public Map getAttributes() { - return attributes; - } - - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - public Set getGroups() { - return groups; - } - - public void setGroups(Set groups) { - this.groups = groups; - } - - public String getHumanReadableProjectName() { - return humanReadableProjectName; - } - - public void setHumanReadableProjectName(String humanReadableProjectName) { - this.humanReadableProjectName = humanReadableProjectName; - } - - public Long getPersistentTokenTimeout() { - return persistentTokenTimeout; - } - - public void setPersistentTokenTimeout(Long persistentTokenTimeout) { - this.persistentTokenTimeout = persistentTokenTimeout; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - ProjectDTO projectDto = (ProjectDTO) o; - if (id == null || projectDto.id == null) { - return false; - } - - return Objects.equals(id, projectDto.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "ProjectDTO{" - + "id=" + id - + ", projectName='" + projectName + "'" - + ", description='" + description + "'" - + ", organization='" + organization + "'" - + ", organizationName='" + organizationName + "'" - + ", location='" + location + "'" - + ", startDate='" + startDate + "'" - + ", projectStatus='" + projectStatus + "'" - + ", endDate='" + endDate + "'" - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt new file mode 100644 index 000000000..3d4655f89 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt @@ -0,0 +1,73 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import org.radarbase.management.domain.enumeration.ProjectStatus +import java.io.Serializable +import java.time.ZonedDateTime +import java.util.* +import javax.validation.constraints.NotNull + +/** + * A DTO for the Project entity. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +class ProjectDTO : Serializable { + var id: Long? = null + var projectName: @NotNull String? = null + var humanReadableProjectName: String? = null + var description: @NotNull String? = null + var organization: OrganizationDTO? = null + var organizationName: String? = null + var location: @NotNull String? = null + var startDate: ZonedDateTime? = null + var projectStatus: ProjectStatus? = null + var endDate: ZonedDateTime? = null + + @JsonInclude(JsonInclude.Include.NON_EMPTY) + var sourceTypes: Set? = null + var attributes: Map? = null + + @JsonInclude(JsonInclude.Include.NON_EMPTY) + var groups: Set? = null + var persistentTokenTimeout: Long? = null + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val projectDto = o as ProjectDTO + return if (id == null || projectDto.id == null) { + false + } else id == projectDto.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("ProjectDTO{" + + "id=" + id + + ", projectName='" + projectName + "'" + + ", description='" + description + "'" + + ", organization='" + organization + "'" + + ", organizationName='" + organizationName + "'" + + ", location='" + location + "'" + + ", startDate='" + startDate + "'" + + ", projectStatus='" + projectStatus + "'" + + ", endDate='" + endDate + "'" + + '}') + } + + companion object { + private const val serialVersionUID = 1L + const val EXTERNAL_PROJECT_URL_KEY = "External-project-url" + const val EXTERNAL_PROJECT_ID_KEY = "External-project-id" + const val WORK_PACKAGE_KEY = "Work-package" + const val PHASE_KEY = "Phase" + const val HUMAN_READABLE_PROJECT_NAME = "Human-readable-project-name" + const val PRIVACY_POLICY_URL = "Privacy-policy-url" + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java b/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java deleted file mode 100644 index 9cf948d11..000000000 --- a/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.radarbase.management.service.dto; - -import org.hibernate.envers.RevisionType; -import org.radarbase.management.domain.audit.CustomRevisionEntity; -import org.springframework.data.history.Revision; - -import java.time.Instant; - -public class RevisionDTO { - private int id; - private Instant timestamp; - private String author; - private Object entity; - private RevisionType revisionType; - - public RevisionDTO() { - // JSON initializer - } - - /** - * Create a DTO from a revision, type and entity. - * @param revision the revision - * @param revisionType the type - * @param entity the entity - */ - public RevisionDTO(Revision revision, RevisionType revisionType, Object entity) { - id = revision.getRequiredRevisionNumber().intValue(); - timestamp = revision.getRequiredRevisionInstant(); - author = ((CustomRevisionEntity) revision.getMetadata().getDelegate()).auditor; - this.entity = entity; - this.revisionType = revisionType; - } - - public int getId() { - return id; - } - - public Instant getTimestamp() { - return timestamp; - } - - public String getAuthor() { - return author; - } - - public Object getEntity() { - return entity; - } - - public RevisionType getRevisionType() { - return revisionType; - } - - public RevisionDTO setId(int id) { - this.id = id; - return this; - } - - public RevisionDTO setTimestamp(Instant timestamp) { - this.timestamp = timestamp; - return this; - } - - public RevisionDTO setAuthor(String author) { - this.author = author; - return this; - } - - public RevisionDTO setEntity(Object entity) { - this.entity = entity; - return this; - } - - public RevisionDTO setRevisionType(RevisionType revisionType) { - this.revisionType = revisionType; - return this; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/RevisionDTO.kt b/src/main/java/org/radarbase/management/service/dto/RevisionDTO.kt new file mode 100644 index 000000000..de8c97c42 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/RevisionDTO.kt @@ -0,0 +1,60 @@ +package org.radarbase.management.service.dto + +import org.hibernate.envers.RevisionType +import org.radarbase.management.domain.audit.CustomRevisionEntity +import org.springframework.data.history.Revision +import java.time.Instant + +class RevisionDTO { + var id = 0 + private set + var timestamp: Instant? = null + private set + var author: String? = null + private set + var entity: Any? = null + private set + var revisionType: RevisionType? = null + private set + + constructor() + + /** + * Create a DTO from a revision, type and entity. + * @param revision the revision + * @param revisionType the type + * @param entity the entity + */ + constructor(revision: Revision<*, *>, revisionType: RevisionType?, entity: Any?) { + id = revision.requiredRevisionNumber.toInt() + timestamp = revision.requiredRevisionInstant + author = (revision.metadata.getDelegate() as CustomRevisionEntity).auditor + this.entity = entity + this.revisionType = revisionType + } + + fun setId(id: Int): RevisionDTO { + this.id = id + return this + } + + fun setTimestamp(timestamp: Instant?): RevisionDTO { + this.timestamp = timestamp + return this + } + + fun setAuthor(author: String?): RevisionDTO { + this.author = author + return this + } + + fun setEntity(entity: Any?): RevisionDTO { + this.entity = entity + return this + } + + fun setRevisionType(revisionType: RevisionType?): RevisionDTO { + this.revisionType = revisionType + return this + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java b/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java deleted file mode 100644 index 1b957e1de..000000000 --- a/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.util.Locale; -import java.util.stream.Collectors; -import org.hibernate.envers.RevisionType; -import org.radarbase.management.domain.audit.CustomRevisionEntity; - -import java.io.Serializable; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * Class for representing comprehensive information about a revision. - */ -public class RevisionInfoDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - private int id; - - private Date timestamp; - - private String author; - - // Groups the changes by revision type and class name - private Map>> changes; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public Date getTimestamp() { - return timestamp; - } - - public void setTimestamp(Date timestamp) { - this.timestamp = timestamp; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - public Map>> getChanges() { - return changes; - } - - public void setChanges(Map>> changes) { - this.changes = changes; - } - - /** - * Create a RevisionInfoDTO from a {@link CustomRevisionEntity} and a set of changes grouped - * by revision type. - * - *

This method is convenient when using a CustomRevisionEntity in combination with - * {@link org.hibernate.envers.CrossTypeRevisionChangesReader}. The Map will be transformed - * so changes are additionally grouped by class name.

- * @param revisionEntity the revision entity - * @param changes the changes - * @return the RevisionInfoDTO object - */ - public static RevisionInfoDTO from(CustomRevisionEntity revisionEntity, Map> changes) { - RevisionInfoDTO result = new RevisionInfoDTO(); - result.setAuthor(revisionEntity.auditor); - result.setTimestamp(revisionEntity.timestamp); - result.setId(revisionEntity.id); - result.setChanges(changes.entrySet().stream() - .filter(e -> e.getValue() != null) - .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream() - .filter(Objects::nonNull) - .collect(Collectors.groupingBy(obj -> obj.getClass() - .getSimpleName() - .replaceAll("DTO$","") - .toLowerCase(Locale.US)))))); - return result; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.kt b/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.kt new file mode 100644 index 000000000..1309b2ee8 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.kt @@ -0,0 +1,52 @@ +package org.radarbase.management.service.dto + +import org.hibernate.envers.RevisionType +import org.radarbase.management.domain.audit.CustomRevisionEntity +import java.io.Serializable +import java.util.* + +/** + * Class for representing comprehensive information about a revision. + */ +class RevisionInfoDTO : Serializable { + var id = 0 + var timestamp: Date? = null + var author: String? = null + + // Groups the changes by revision type and class name + var changes: Map>>? = null + + companion object { + private const val serialVersionUID = 1L + + /** + * Create a RevisionInfoDTO from a [CustomRevisionEntity] and a set of changes grouped + * by revision type. + * + * + * This method is convenient when using a CustomRevisionEntity in combination with + * [org.hibernate.envers.CrossTypeRevisionChangesReader]. The Map will be transformed + * so changes are additionally grouped by class name. + * @param revisionEntity the revision entity + * @param changes the changes + * @return the RevisionInfoDTO object + */ + fun from(revisionEntity: CustomRevisionEntity, changes: Map>): RevisionInfoDTO { + val result = RevisionInfoDTO() + result.author = revisionEntity.auditor + result.timestamp = revisionEntity.timestamp + result.id = revisionEntity.id + result.changes = changes.entries + .associateBy ( + { obj -> obj.key }, + { + it.value.groupBy { obj -> + obj.javaClass.getSimpleName().replace("DTO$".toRegex(), "").lowercase() + } + } + ) + + return result + } + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/RoleDTO.java b/src/main/java/org/radarbase/management/service/dto/RoleDTO.java deleted file mode 100644 index 8ecf6fc7d..000000000 --- a/src/main/java/org/radarbase/management/service/dto/RoleDTO.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.radarbase.management.service.dto; - -import com.fasterxml.jackson.annotation.JsonInclude; - -import java.util.Objects; - -/** - * Created by nivethika on 23-5-17. - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class RoleDTO { - private Long id; - - private Long organizationId; - - private String organizationName; - - private Long projectId; - - private String projectName; - - private String authorityName; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getOrganizationId() { - return organizationId; - } - - public void setOrganizationId(Long organizationId) { - this.organizationId = organizationId; - } - - public String getOrganizationName() { - return organizationName; - } - - public void setOrganizationName(String organizationName) { - this.organizationName = organizationName; - } - - public Long getProjectId() { - return projectId; - } - - public void setProjectId(Long projectId) { - this.projectId = projectId; - } - - public String getAuthorityName() { - return authorityName; - } - - public void setAuthorityName(String authorityName) { - this.authorityName = authorityName; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - @Override - public String toString() { - return "RoleDTO{" + "id=" + id - + ", organizationId=" + organizationId - + ", projectId=" + projectId - + ", authorityName='" + authorityName + '\'' - + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - RoleDTO roleDto = (RoleDTO) o; - - return Objects.equals(id, roleDto.id) - && Objects.equals(organizationId, roleDto.organizationId) - && Objects.equals(organizationName, roleDto.organizationName) - && Objects.equals(projectId, roleDto.projectId) - && Objects.equals(projectName, roleDto.projectName) - && Objects.equals(authorityName, roleDto.authorityName); - } - - @Override - public int hashCode() { - return id != null ? id.hashCode() : 0; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt b/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt new file mode 100644 index 000000000..73f60a599 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt @@ -0,0 +1,38 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude + +/** + * Created by nivethika on 23-5-17. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +class RoleDTO { + var id: Long? = null + var organizationId: Long? = null + var organizationName: String? = null + var projectId: Long? = null + var projectName: String? = null + var authorityName: String? = null + override fun toString(): String { + return ("RoleDTO{" + "id=" + id + + ", organizationId=" + organizationId + + ", projectId=" + projectId + + ", authorityName='" + authorityName + '\'' + + '}') + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val roleDto = o as RoleDTO + return id == roleDto.id && organizationId == roleDto.organizationId && organizationName == roleDto.organizationName && projectId == roleDto.projectId && projectName == roleDto.projectName && authorityName == roleDto.authorityName + } + + override fun hashCode(): Int { + return if (id != null) id.hashCode() else 0 + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.java b/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.java deleted file mode 100644 index 6798501f8..000000000 --- a/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.radarbase.management.service.dto; - - -import org.radarbase.management.config.ManagementPortalProperties; - -import java.io.Serializable; -import java.util.List; -import java.util.Objects; - -/** - * A DTO for the {@link ManagementPortalProperties.SiteSettings} entity. - */ -public class SiteSettingsDto implements Serializable { - - private List hiddenSubjectFields = List.of(); - - public List getHiddenSubjectFields() { - return hiddenSubjectFields; - } - - public void setHiddenSubjectFields(List hiddenSubjectFields) { - this.hiddenSubjectFields = hiddenSubjectFields; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o == null || getClass() != o.getClass()) { - return false; - } - SiteSettingsDto that = (SiteSettingsDto) o; - return Objects.equals(hiddenSubjectFields, that.hiddenSubjectFields); - } - - @Override - public int hashCode() { - return Objects.hash(hiddenSubjectFields); - } - - @Override - public String toString() { - return "SiteSettingsDTO{" - + "hiddenSubjectProperties=" - + hiddenSubjectFields - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt b/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt new file mode 100644 index 000000000..b45250e80 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt @@ -0,0 +1,33 @@ +package org.radarbase.management.service.dto + +import org.radarbase.management.config.ManagementPortalProperties +import java.io.Serializable +import java.util.* + +/** + * A DTO for the [ManagementPortalProperties.SiteSettings] entity. + */ +class SiteSettingsDto : Serializable { + var hiddenSubjectFields = listOf() + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val that = o as SiteSettingsDto + return hiddenSubjectFields == that.hiddenSubjectFields + } + + override fun hashCode(): Int { + return Objects.hash(hiddenSubjectFields) + } + + override fun toString(): String { + return ("SiteSettingsDTO{" + + "hiddenSubjectProperties=" + + hiddenSubjectFields + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDTO.java b/src/main/java/org/radarbase/management/service/dto/SourceDTO.java deleted file mode 100644 index c2ec2e436..000000000 --- a/src/main/java/org/radarbase/management/service/dto/SourceDTO.java +++ /dev/null @@ -1,152 +0,0 @@ -package org.radarbase.management.service.dto; - - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import java.io.Serializable; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; -import javax.validation.constraints.NotNull; - -/** - * A DTO for the Source entity. - */ -public class SourceDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - private Long id; - - private UUID sourceId; - - @NotNull - private String sourceName; - - private String expectedSourceName; - - @NotNull - private Boolean assigned; - - @NotNull - private SourceTypeDTO sourceType; - - private String subjectLogin; - - @JsonInclude(Include.NON_NULL) - private MinimalProjectDetailsDTO project; - - private Map attributes; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public UUID getSourceId() { - return sourceId; - } - - public void setSourceId(UUID sourceId) { - this.sourceId = sourceId; - } - - public Boolean getAssigned() { - return assigned; - } - - public void setAssigned(Boolean assigned) { - this.assigned = assigned; - } - - public SourceTypeDTO getSourceType() { - return sourceType; - } - - public void setSourceType(SourceTypeDTO sourceType) { - this.sourceType = sourceType; - } - - public MinimalProjectDetailsDTO getProject() { - return project; - } - - public void setProject(MinimalProjectDetailsDTO project) { - this.project = project; - } - - public Map getAttributes() { - return attributes; - } - - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - public String getSourceName() { - return sourceName; - } - - public void setSourceName(String sourceName) { - this.sourceName = sourceName; - } - - public String getExpectedSourceName() { - return expectedSourceName; - } - - public void setExpectedSourceName(String expectedSourceName) { - this.expectedSourceName = expectedSourceName; - } - - public String getSubjectLogin() { - return subjectLogin; - } - - public void setSubjectLogin(String subjectLogin) { - this.subjectLogin = subjectLogin; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - SourceDTO source = (SourceDTO) o; - return Objects.equals(id, source.id) - && Objects.equals(sourceId, source.sourceId) - && Objects.equals(sourceName, source.sourceName) - && Objects.equals(expectedSourceName, source.expectedSourceName) - && Objects.equals(assigned, source.assigned) - && Objects.equals(sourceType, source.sourceType) - && Objects.equals(subjectLogin, source.subjectLogin) - && Objects.equals(project, source.project) - && Objects.equals(attributes, source.attributes); - } - - @Override - public int hashCode() { - - return Objects.hash(id, sourceId, sourceName, expectedSourceName, assigned, sourceType, - subjectLogin, project, attributes); - } - - @Override - public String toString() { - return "SourceDTO{" - + "id=" + id - + ", sourceId='" + sourceId + '\'' - + ", sourceName='" + sourceName + '\'' - + ", assigned=" + assigned - + ", sourceType=" + sourceType - + ", project=" + project - + ", subjectLogin=" + subjectLogin - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt new file mode 100644 index 000000000..b7ff95330 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt @@ -0,0 +1,56 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import java.io.Serializable +import java.util.* +import javax.validation.constraints.NotNull + +/** + * A DTO for the Source entity. + */ +class SourceDTO : Serializable { + var id: Long? = null + var sourceId: UUID? = null + lateinit var sourceName: @NotNull String + var expectedSourceName: String? = null + var assigned: @NotNull Boolean? = null + lateinit var sourceType: @NotNull SourceTypeDTO + var subjectLogin: String? = null + + @JsonInclude(JsonInclude.Include.NON_NULL) + var project: MinimalProjectDetailsDTO? = null + var attributes: Map? = null + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val source = other as SourceDTO + return id == source.id && sourceId == source.sourceId && sourceName == source.sourceName && expectedSourceName == source.expectedSourceName && assigned == source.assigned && sourceType == source.sourceType && subjectLogin == source.subjectLogin && project == source.project && attributes == source.attributes + } + + override fun hashCode(): Int { + return Objects.hash( + id, sourceId, sourceName, expectedSourceName, assigned, sourceType, + subjectLogin, project, attributes + ) + } + + override fun toString(): String { + return ("SourceDTO{" + + "id=" + id + + ", sourceId='" + sourceId + '\'' + + ", sourceName='" + sourceName + '\'' + + ", assigned=" + assigned + + ", sourceType=" + sourceType + + ", project=" + project + + ", subjectLogin=" + subjectLogin + + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.java b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.java deleted file mode 100644 index fbf5019d4..000000000 --- a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.java +++ /dev/null @@ -1,195 +0,0 @@ -package org.radarbase.management.service.dto; - - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; - -import java.io.Serializable; -import java.util.Objects; - -/** - * A DTO for the SourceData entity. - */ -public class SourceDataDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - private Long id; - - //Source data type. - private String sourceDataType; - - private String sourceDataName; - - //Default data frequency - private String frequency; - - //Measurement unit. - private String unit; - - // Define if the samples are RAW data or instead they the result of some computation - private String processingState; - - // the storage - private String dataClass; - - private String keySchema; - - private String valueSchema; - - private String topic; - - private String provider; - - private boolean enabled = true; - - @JsonInclude(Include.NON_NULL) - private MinimalSourceTypeDTO sourceType; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getFrequency() { - return frequency; - } - - public void setFrequency(String frequency) { - this.frequency = frequency; - } - - /** Get source data type. Defaults to the topic of the source data. */ - public String getSourceDataType() { - if (sourceDataType == null) { - return topic; - } else { - return sourceDataType; - } - } - - public void setSourceDataType(String sourceDataType) { - this.sourceDataType = sourceDataType; - } - - public String getUnit() { - return unit; - } - - public void setUnit(String unit) { - this.unit = unit; - } - - public String getProcessingState() { - return processingState; - } - - public void setProcessingState(String processingState) { - this.processingState = processingState; - } - - public String getDataClass() { - return dataClass; - } - - public void setDataClass(String dataClass) { - this.dataClass = dataClass; - } - - public String getKeySchema() { - return keySchema; - } - - public void setKeySchema(String keySchema) { - this.keySchema = keySchema; - } - - public String getValueSchema() { - return valueSchema; - } - - public void setValueSchema(String valueSchema) { - this.valueSchema = valueSchema; - } - - public String getTopic() { - return topic; - } - - public void setTopic(String topic) { - this.topic = topic; - } - - public String getProvider() { - return provider; - } - - public void setProvider(String provider) { - this.provider = provider; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getSourceDataName() { - return sourceDataName; - } - - public void setSourceDataName(String sourceDataName) { - this.sourceDataName = sourceDataName; - } - - public MinimalSourceTypeDTO getSourceType() { - return sourceType; - } - - public void setSourceType(MinimalSourceTypeDTO sourceType) { - this.sourceType = sourceType; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - SourceDataDTO sourceDataDto = (SourceDataDTO) o; - if (sourceDataDto.id == null || id == null) { - return false; - } - return Objects.equals(id, sourceDataDto.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "SourceDataDTO{" - + "id=" + id - + ", sourceDataType='" + sourceDataType + '\'' - + ", sourceDataName='" + sourceDataName + '\'' - + ", frequency='" + frequency + '\'' - + ", unit='" + unit + '\'' - + ", processingState=" + processingState - + ", dataClass=" + dataClass - + ", keySchema='" + keySchema + '\'' - + ", valueSchema='" + valueSchema + '\'' - + ", topic='" + topic + '\'' - + ", provider='" + provider + '\'' - + ", enabled=" + enabled - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt new file mode 100644 index 000000000..187af33bd --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt @@ -0,0 +1,74 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import java.io.Serializable +import java.util.* + +/** + * A DTO for the SourceData entity. + */ +class SourceDataDTO : Serializable { + var id: Long? = null + + //Source data type. + var sourceDataType: String? = null + var sourceDataName: String? = null + + //Default data frequency + var frequency: String? = null + + //Measurement unit. + var unit: String? = null + + // Define if the samples are RAW data or the result of some computation + var processingState: String? = null + + // the storage + var dataClass: String? = null + var keySchema: String? = null + var valueSchema: String? = null + var topic: String? = null + var provider: String? = null + var isEnabled = true + + @JsonInclude(JsonInclude.Include.NON_NULL) + var sourceType: MinimalSourceTypeDTO? = null + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val sourceDataDto = o as SourceDataDTO + return if (sourceDataDto.id == null || id == null) { + false + } else id == sourceDataDto.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("SourceDataDTO{" + + "id=" + id + + ", sourceDataType='" + sourceDataType + '\'' + + ", sourceDataName='" + sourceDataName + '\'' + + ", frequency='" + frequency + '\'' + + ", unit='" + unit + '\'' + + ", processingState=" + processingState + + ", dataClass=" + dataClass + + ", keySchema='" + keySchema + '\'' + + ", valueSchema='" + valueSchema + '\'' + + ", topic='" + topic + '\'' + + ", provider='" + provider + '\'' + + ", enabled=" + isEnabled + + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.java b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.java deleted file mode 100644 index 16ca3da5b..000000000 --- a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.java +++ /dev/null @@ -1,177 +0,0 @@ -package org.radarbase.management.service.dto; - - -import java.io.Serializable; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import javax.validation.constraints.NotNull; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; - -/** - * A DTO for the SourceType entity. - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class SourceTypeDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - private Long id; - - @NotNull - private String producer; - - @NotNull - private String model; - - @NotNull - private String catalogVersion; - - @NotNull - private String sourceTypeScope; - - @NotNull - private Boolean canRegisterDynamically = false; - - private String name; - - private String description; - - private String assessmentType; - - private String appProvider; - - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private Set sourceData = new HashSet<>(); - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getProducer() { - return producer; - } - - public void setProducer(String producer) { - this.producer = producer; - } - - public String getModel() { - return model; - } - - public String getCatalogVersion() { - return catalogVersion; - } - - public void setCatalogVersion(String catalogVersion) { - this.catalogVersion = catalogVersion; - } - - public void setModel(String model) { - this.model = model; - } - - public String getSourceTypeScope() { - return sourceTypeScope; - } - - public void setSourceTypeScope(String sourceTypeScope) { - this.sourceTypeScope = sourceTypeScope; - } - - public Set getSourceData() { - return sourceData; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setSourceData(Set sourceData) { - this.sourceData = sourceData; - } - - public Boolean getCanRegisterDynamically() { - return canRegisterDynamically; - } - - public void setCanRegisterDynamically(Boolean canRegisterDynamically) { - this.canRegisterDynamically = canRegisterDynamically; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getAssessmentType() { - return assessmentType; - } - - public void setAssessmentType(String assessmentType) { - this.assessmentType = assessmentType; - } - - public String getAppProvider() { - return appProvider; - } - - public void setAppProvider(String appProvider) { - this.appProvider = appProvider; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - SourceTypeDTO sourceTypeDto = (SourceTypeDTO) o; - - if (id == null || sourceTypeDto.id == null) { - return false; - } - - return Objects.equals(id, sourceTypeDto.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "SourceTypeDTO{" - + "id=" + id - + ", producer='" + producer + "'" - + ", model='" + model + "'" - + ", catalogVersion='" + catalogVersion + "'" - + ", sourceTypeScope='" + sourceTypeScope + "'" - + ", canRegisterDynamically='" + canRegisterDynamically + "'" - + ", name='" + name + '\'' - + ", description=" + description - + ", appProvider=" + appProvider - + ", assessmentType=" + assessmentType - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt new file mode 100644 index 000000000..1eb8c3b85 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt @@ -0,0 +1,64 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import java.io.Serializable +import java.util.* +import javax.validation.constraints.NotNull + +/** + * A DTO for the SourceType entity. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +class SourceTypeDTO : Serializable { + var id: Long? = null + lateinit var producer: @NotNull String + lateinit var model: @NotNull String + lateinit var catalogVersion: @NotNull String + lateinit var sourceTypeScope: @NotNull String + var canRegisterDynamically: @NotNull Boolean = false + var name: String? = null + var description: String? = null + var assessmentType: String? = null + var appProvider: String? = null + + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + var sourceData: Set = HashSet() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val sourceTypeDto = other as SourceTypeDTO + return if (id == null || sourceTypeDto.id == null) { + false + } else id == sourceTypeDto.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("SourceTypeDTO{" + + "id=" + id + + ", producer='" + producer + "'" + + ", model='" + model + "'" + + ", catalogVersion='" + catalogVersion + "'" + + ", sourceTypeScope='" + sourceTypeScope + "'" + + ", canRegisterDynamically='" + canRegisterDynamically + "'" + + ", name='" + name + '\'' + + ", description=" + description + + ", appProvider=" + appProvider + + ", assessmentType=" + assessmentType + + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/SubjectDTO.java b/src/main/java/org/radarbase/management/service/dto/SubjectDTO.java deleted file mode 100644 index 4c5eeb39d..000000000 --- a/src/main/java/org/radarbase/management/service/dto/SubjectDTO.java +++ /dev/null @@ -1,256 +0,0 @@ -package org.radarbase.management.service.dto; - - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; - -import java.io.Serializable; -import java.time.LocalDate; -import java.time.ZonedDateTime; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; -import java.util.ArrayList; - -/** - * A DTO for the Subject entity. - */ -public class SubjectDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - public enum SubjectStatus { - DEACTIVATED, // activated = false, removed = false - ACTIVATED, // activated = true, removed = false - DISCONTINUED, // activated = false, removed = true - INVALID // activated = true, removed = true (invalid state, makes no sense) - } - - public static final String HUMAN_READABLE_IDENTIFIER_KEY = "Human-readable-identifier"; - - private Long id; - - private String login; - - private String externalLink; - - private String externalId; - - private SubjectStatus status = SubjectStatus.DEACTIVATED; - - @JsonInclude(Include.NON_NULL) - private String createdBy; - - @JsonInclude(Include.NON_NULL) - private ZonedDateTime createdDate; - - @JsonInclude(Include.NON_NULL) - private String lastModifiedBy; - - @JsonInclude(Include.NON_NULL) - private ZonedDateTime lastModifiedDate; - - @JsonInclude(Include.NON_NULL) - private ProjectDTO project; - - private String group; - - private LocalDate dateOfBirth; - - private ZonedDateTime enrollmentDate; - - private String personName; - - private List roles = new ArrayList<>(); - - private Set sources = new HashSet<>(); - - private Map attributes = new HashMap<>(); - - public SubjectStatus getStatus() { - return status; - } - - public String getPersonName() { - return personName; - } - - public void setPersonName(String personName) { - this.personName = personName; - } - - public void setStatus(SubjectStatus status) { - this.status = status; - } - - - public String getCreatedBy() { - return createdBy; - } - - public void setCreatedBy(String createdBy) { - this.createdBy = createdBy; - } - - public ProjectDTO getProject() { - return project; - } - - public void setProject(ProjectDTO project) { - this.project = project; - } - - public String getGroup() { - return group; - } - - public void setGroup(String group) { - this.group = group; - } - - public LocalDate getDateOfBirth() { - return this.dateOfBirth; - } - - public void setDateOfBirth(LocalDate dateOfBirth) { - this.dateOfBirth = dateOfBirth; - } - - public void setEnrollmentDate(ZonedDateTime enrollmentDate) { - this.enrollmentDate = enrollmentDate; - } - - public ZonedDateTime getEnrollmentDate() { - return this.enrollmentDate; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public ZonedDateTime getCreatedDate() { - return createdDate; - } - - public void setCreatedDate(ZonedDateTime createdDate) { - this.createdDate = createdDate; - } - - public String getLastModifiedBy() { - return lastModifiedBy; - } - - public void setLastModifiedBy(String lastModifiedBy) { - this.lastModifiedBy = lastModifiedBy; - } - - public ZonedDateTime getLastModifiedDate() { - return lastModifiedDate; - } - - public void setLastModifiedDate(ZonedDateTime lastModifiedDate) { - this.lastModifiedDate = lastModifiedDate; - } - - public String getExternalLink() { - return externalLink; - } - - public void setExternalLink(String externalLink) { - this.externalLink = externalLink; - } - - public String getExternalId() { - return externalId; - } - - public void setExternalId(String externalId) { - this.externalId = externalId; - } - - public List getRoles() { - return roles; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setRoles(List roles) { - this.roles = roles; - } - - /** - * Gets the login. If no login is present, a new UUID is generated and stored as the login - * before returning it. - * @return the login - */ - public String getLogin() { - if (this.login == null) { - this.login = UUID.randomUUID().toString(); - } - return login; - } - - public void setLogin(String login) { - this.login = login; - } - - public Set getSources() { - return sources; - } - - public void setSources(Set sources) { - this.sources = sources; - } - - public Map getAttributes() { - return attributes; - } - - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - SubjectDTO subjectDto = (SubjectDTO) o; - - if (id == null || subjectDto.id == null) { - return false; - } - - return !Objects.equals(id, subjectDto.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "SubjectDTO{" - + "id=" + id - + ", login='" + login + '\'' - + ", externalLink='" + externalLink + '\'' - + ", externalId='" + externalId + '\'' - + ", status=" + status - + ", project=" + (project == null ? "null" : project.getProjectName()) - + ", attributes=" + attributes + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt b/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt new file mode 100644 index 000000000..337ec975d --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt @@ -0,0 +1,96 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import java.io.Serializable +import java.time.LocalDate +import java.time.ZonedDateTime +import java.util.* + +/** + * A DTO for the Subject entity. + */ +class SubjectDTO : Serializable { + enum class SubjectStatus { + DEACTIVATED, + + // activated = false, removed = false + ACTIVATED, + + // activated = true, removed = false + DISCONTINUED, + + // activated = false, removed = true + INVALID // activated = true, removed = true (invalid state, makes no sense) + } + + var id: Long? = null + private var _login: String? = null + var login: String? + get() = { + if (_login == null) { + _login = UUID.randomUUID().toString() + _login + } else { + _login + } + }.toString() + set(value) { + _login = value + } + + var externalLink: String? = null + var externalId: String? = null + var status = SubjectStatus.DEACTIVATED + + @JsonInclude(JsonInclude.Include.NON_NULL) + var createdBy: String? = null + + @JsonInclude(JsonInclude.Include.NON_NULL) + var createdDate: ZonedDateTime? = null + + @JsonInclude(JsonInclude.Include.NON_NULL) + var lastModifiedBy: String? = null + + @JsonInclude(JsonInclude.Include.NON_NULL) + var lastModifiedDate: ZonedDateTime? = null + + @JsonInclude(JsonInclude.Include.NON_NULL) + var project: ProjectDTO? = null + var group: String? = null + var dateOfBirth: LocalDate? = null + var enrollmentDate: ZonedDateTime? = null + var personName: String? = null + + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + var roles: List = ArrayList() + var sources: Set = HashSet() + var attributes: Map = HashMap() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val subjectDto = other as SubjectDTO + return if (id == null || subjectDto.id == null) { + false + } else id != subjectDto.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("SubjectDTO{" + "id=" + id + ", login='" + login + '\'' + ", externalLink='" + externalLink + '\'' + ", externalId='" + externalId + '\'' + ", status=" + status + ", project=" + (project?.projectName) + ", attributes=" + attributes + '}') + } + + companion object { + private const val serialVersionUID = 1L + const val HUMAN_READABLE_IDENTIFIER_KEY = "Human-readable-identifier" + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/TokenDTO.java b/src/main/java/org/radarbase/management/service/dto/TokenDTO.java deleted file mode 100644 index ca891ff6e..000000000 --- a/src/main/java/org/radarbase/management/service/dto/TokenDTO.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.net.URL; -import java.util.Objects; - -public class TokenDTO { - private final String refreshToken; - - private final URL baseUrl; - - private final URL privacyPolicyUrl; - - /** - * Create a meta-token using refreshToken, baseUrl of platform, and privacyPolicyURL for this - * token. - * @param refreshToken refreshToken. - * @param baseUrl baseUrl of the platform - * @param privacyPolicyUrl privacyPolicyUrl for this token. - */ - public TokenDTO(String refreshToken, URL baseUrl, URL privacyPolicyUrl) { - this.refreshToken = refreshToken; - this.baseUrl = baseUrl; - this.privacyPolicyUrl = privacyPolicyUrl; - } - - public String getRefreshToken() { - return refreshToken; - } - - public URL getBaseUrl() { - return baseUrl; - } - - public URL getPrivacyPolicyUrl() { - return privacyPolicyUrl; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TokenDTO that = (TokenDTO) o; - return Objects.equals(refreshToken, that.refreshToken) - && Objects.equals(baseUrl, that.baseUrl) - && Objects.equals(privacyPolicyUrl, that.privacyPolicyUrl); - } - - @Override - public int hashCode() { - - return Objects.hash(refreshToken, baseUrl, privacyPolicyUrl); - } - - @Override - public String toString() { - return "TokenDTO{" - + "refreshToken='" + refreshToken - + ", baseUrl=" + baseUrl - + ", privacyPolicyUrl=" + privacyPolicyUrl - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt b/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt new file mode 100644 index 000000000..df681db36 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt @@ -0,0 +1,37 @@ +package org.radarbase.management.service.dto + +import java.net.URL +import java.util.* + +class TokenDTO +/** + * Create a meta-token using refreshToken, baseUrl of platform, and privacyPolicyURL for this + * token. + * @param refreshToken refreshToken. + * @param baseUrl baseUrl of the platform + * @param privacyPolicyUrl privacyPolicyUrl for this token. + */(val refreshToken: String, val baseUrl: URL, val privacyPolicyUrl: URL) { + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val that = o as TokenDTO + return refreshToken == that.refreshToken && baseUrl == that.baseUrl && privacyPolicyUrl == that.privacyPolicyUrl + } + + override fun hashCode(): Int { + return Objects.hash(refreshToken, baseUrl, privacyPolicyUrl) + } + + override fun toString(): String { + return ("TokenDTO{" + + "refreshToken='" + refreshToken + + ", baseUrl=" + baseUrl + + ", privacyPolicyUrl=" + privacyPolicyUrl + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/UserDTO.java b/src/main/java/org/radarbase/management/service/dto/UserDTO.java deleted file mode 100644 index 8965981b3..000000000 --- a/src/main/java/org/radarbase/management/service/dto/UserDTO.java +++ /dev/null @@ -1,177 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.time.ZonedDateTime; -import java.util.Set; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; -import org.hibernate.validator.constraints.Email; -import org.radarbase.management.security.Constants; - -/** - * A DTO representing a user, with his authorities. - */ -public class UserDTO { - - private Long id; - - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Size(min = 1, max = 50) - private String login; - - @Size(max = 50) - private String firstName; - - @Size(max = 50) - private String lastName; - - @Email - @Size(min = 5, max = 100) - private String email; - - private boolean activated = false; - - @Size(min = 2, max = 5) - private String langKey; - - private String createdBy; - - private ZonedDateTime createdDate; - - private String lastModifiedBy; - - private ZonedDateTime lastModifiedDate; - - private Set roles; - - private Set authorities; - - private String accessToken; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getLogin() { - return login; - } - - public void setLogin(String login) { - this.login = login; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public boolean isActivated() { - return activated; - } - - public void setActivated(boolean activated) { - this.activated = activated; - } - - public String getLangKey() { - return langKey; - } - - public void setLangKey(String langKey) { - this.langKey = langKey; - } - - public String getCreatedBy() { - return createdBy; - } - - public void setCreatedBy(String createdBy) { - this.createdBy = createdBy; - } - - public ZonedDateTime getCreatedDate() { - return createdDate; - } - - public void setCreatedDate(ZonedDateTime createdDate) { - this.createdDate = createdDate; - } - - public String getLastModifiedBy() { - return lastModifiedBy; - } - - public void setLastModifiedBy(String lastModifiedBy) { - this.lastModifiedBy = lastModifiedBy; - } - - public ZonedDateTime getLastModifiedDate() { - return lastModifiedDate; - } - - public void setLastModifiedDate(ZonedDateTime lastModifiedDate) { - this.lastModifiedDate = lastModifiedDate; - } - - public Set getAuthorities() { - return authorities; - } - - public void setAuthorities(Set authorities) { - this.authorities = authorities; - } - - public Set getRoles() { - return roles; - } - - public void setRoles(Set roles) { - this.roles = roles; - } - - public String getAccessToken() { - return accessToken; - } - - public void setAccessToken(String accessToken) { - this.accessToken = accessToken; - } - - @Override - public String toString() { - return "UserDTO{" - + "login='" + login + '\'' - + ", firstName='" + firstName + '\'' - + ", lastName='" + lastName + '\'' - + ", email='" + email + '\'' - + ", activated=" + activated - + ", langKey='" + langKey + '\'' - + ", createdBy=" + createdBy - + ", createdDate=" + createdDate - + ", lastModifiedBy='" + lastModifiedBy + '\'' - + ", lastModifiedDate=" + lastModifiedDate - + "}"; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/UserDTO.kt b/src/main/java/org/radarbase/management/service/dto/UserDTO.kt new file mode 100644 index 000000000..204bf4b4a --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/UserDTO.kt @@ -0,0 +1,40 @@ +package org.radarbase.management.service.dto + +import org.hibernate.validator.constraints.Email +import java.time.ZonedDateTime +import javax.validation.constraints.Pattern +import javax.validation.constraints.Size + +/** + * A DTO representing a user, with his authorities. + */ +open class UserDTO { + var id: Long? = null + lateinit var login: @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") @Size(max = 50, min = 1) String + var firstName: @Size(max = 50) String? = null + var lastName: @Size(max = 50) String? = null + var email: @Email @Size(min = 5, max = 100) String? = null + var isActivated = false + var langKey: @Size(min = 2, max = 5) String? = null + var createdBy: String? = null + var createdDate: ZonedDateTime? = null + var lastModifiedBy: String? = null + var lastModifiedDate: ZonedDateTime? = null + var roles: Set? = null + var authorities: Set? = null + var accessToken: String? = null + override fun toString(): String { + return ("UserDTO{" + + "login='" + login + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", email='" + email + '\'' + + ", activated=" + isActivated + + ", langKey='" + langKey + '\'' + + ", createdBy=" + createdBy + + ", createdDate=" + createdDate + + ", lastModifiedBy='" + lastModifiedBy + '\'' + + ", lastModifiedDate=" + lastModifiedDate + + "}") + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/package-info.java b/src/main/java/org/radarbase/management/service/dto/package-info.java deleted file mode 100644 index 56a5af8f8..000000000 --- a/src/main/java/org/radarbase/management/service/dto/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Data Transfer Objects. - * - *

The names of the classes in this package should end in {@code DTO}.

- */ -package org.radarbase.management.service.dto; diff --git a/src/main/java/org/radarbase/management/service/dto/package-info.kt b/src/main/java/org/radarbase/management/service/dto/package-info.kt new file mode 100644 index 000000000..7725988f2 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/package-info.kt @@ -0,0 +1,8 @@ +/** + * Data Transfer Objects. + * + * + * The names of the classes in this package should end in `DTO`. + */ +package org.radarbase.management.service.dto + diff --git a/src/main/java/org/radarbase/management/service/mapper/CatalogSourceDataMapper.java b/src/main/java/org/radarbase/management/service/mapper/CatalogSourceDataMapper.kt similarity index 55% rename from src/main/java/org/radarbase/management/service/mapper/CatalogSourceDataMapper.java rename to src/main/java/org/radarbase/management/service/mapper/CatalogSourceDataMapper.kt index 3c5fd6af4..3e405ffa1 100644 --- a/src/main/java/org/radarbase/management/service/mapper/CatalogSourceDataMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/CatalogSourceDataMapper.kt @@ -1,14 +1,12 @@ -package org.radarbase.management.service.mapper; +package org.radarbase.management.service.mapper -import java.util.List; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.service.catalog.CatalogSourceData; +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.radarbase.management.domain.SourceData +import org.radarbase.management.service.catalog.CatalogSourceData @Mapper(componentModel = "spring") -public interface CatalogSourceDataMapper { - +interface CatalogSourceDataMapper { @Mapping(target = "id", ignore = true) @Mapping(source = "type", target = "sourceDataType") @Mapping(target = "sourceDataName", ignore = true) @@ -17,8 +15,8 @@ public interface CatalogSourceDataMapper { @Mapping(source = "appProvider", target = "provider") @Mapping(target = "enabled", expression = "java(true)") @Mapping(target = "sourceType", ignore = true) - SourceData catalogSourceDataToSourceData(CatalogSourceData catalogSourceData); - - List catalogSourceDataListToSourceDataList( - List catalogSourceType); + fun catalogSourceDataToSourceData(catalogSourceData: CatalogSourceData?): SourceData? + fun catalogSourceDataListToSourceDataList( + catalogSourceType: List? + ): List? } diff --git a/src/main/java/org/radarbase/management/service/mapper/CatalogSourceTypeMapper.java b/src/main/java/org/radarbase/management/service/mapper/CatalogSourceTypeMapper.kt similarity index 56% rename from src/main/java/org/radarbase/management/service/mapper/CatalogSourceTypeMapper.java rename to src/main/java/org/radarbase/management/service/mapper/CatalogSourceTypeMapper.kt index d822315e0..98a8cfe9b 100644 --- a/src/main/java/org/radarbase/management/service/mapper/CatalogSourceTypeMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/CatalogSourceTypeMapper.kt @@ -1,14 +1,12 @@ -package org.radarbase.management.service.mapper; +package org.radarbase.management.service.mapper -import java.util.List; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.service.catalog.CatalogSourceType; +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.radarbase.management.domain.SourceType +import org.radarbase.management.service.catalog.CatalogSourceType @Mapper(componentModel = "spring") -public interface CatalogSourceTypeMapper { - +interface CatalogSourceTypeMapper { @Mapping(source = "vendor", target = "producer") @Mapping(source = "version", target = "catalogVersion") @Mapping(source = "doc", target = "description") @@ -17,7 +15,6 @@ public interface CatalogSourceTypeMapper { @Mapping(target = "id", ignore = true) @Mapping(target = "projects", ignore = true) @Mapping(target = "canRegisterDynamically", ignore = true) - SourceType catalogSourceTypeToSourceType(CatalogSourceType catalogSourceType); - - List catalogSourceTypesToSourceTypes(List catalogSourceType); + fun catalogSourceTypeToSourceType(catalogSourceType: CatalogSourceType?): SourceType? + fun catalogSourceTypesToSourceTypes(catalogSourceType: List?): List? } diff --git a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java deleted file mode 100644 index 70f8d0c9f..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.radarbase.management.service.mapper; - -import org.mapstruct.DecoratedWith; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.radarbase.management.service.dto.ClientDetailsDTO; -import org.radarbase.management.service.mapper.decorator.ClientDetailsMapperDecorator; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.security.oauth2.provider.client.BaseClientDetails; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * Created by dverbeec on 7/09/2017. - */ -@Mapper(componentModel = "spring", uses = {BaseClientDetails.class}) -@DecoratedWith(ClientDetailsMapperDecorator.class) -public interface ClientDetailsMapper { - - @Mapping(target = "clientSecret", ignore = true) - @Mapping(target = "autoApproveScopes", ignore = true) - ClientDetailsDTO clientDetailsToClientDetailsDTO(ClientDetails details); - - List clientDetailsToClientDetailsDTO(List detailsList); - - BaseClientDetails clientDetailsDTOToClientDetails(ClientDetailsDTO detailsDto); - - List clientDetailsDTOToClientDetails(List detailsDtoList); - - /** - * Map a set of authorities represented as strings to a collection of {@link GrantedAuthority}s. - * @param authorities the set of authorities to be mapped - * @return a collection of {@link GrantedAuthority}s - */ - default Collection map(Set authorities) { - if (Objects.isNull(authorities)) { - return Collections.emptySet(); - } - return authorities.stream() - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - } - - /** - * Map a collection of authorities represented as {@link GrantedAuthority}s to a set of strings. - * @param authorities the collection of {@link GrantedAuthority}s to be mapped - * @return the set of strings - */ - default Set map(Collection authorities) { - if (Objects.isNull(authorities)) { - return Collections.emptySet(); - } - return authorities.stream() - .map(GrantedAuthority::getAuthority) - .collect(Collectors.toSet()); - } - - /** - * Transforms the values in the input map to strings so the result is a - * {@link Map}. - * @param additionalInformation a {@link Map} to be transformed - * @return a new map with the same keys as the input map, but the values are transformed to - * strings using their {@link Object#toString()} method - */ - default Map map(Map additionalInformation) { - if (Objects.isNull(additionalInformation)) { - return Collections.emptyMap(); - } - return additionalInformation.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString())); - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt new file mode 100644 index 000000000..7d4258077 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt @@ -0,0 +1,72 @@ +package org.radarbase.management.service.mapper + +import org.mapstruct.DecoratedWith +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.radarbase.management.service.dto.ClientDetailsDTO +import org.radarbase.management.service.mapper.decorator.ClientDetailsMapperDecorator +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.oauth2.provider.ClientDetails +import org.springframework.security.oauth2.provider.client.BaseClientDetails +import java.util.* +import java.util.stream.Collectors + +/** + * Created by dverbeec on 7/09/2017. + */ +@Mapper(componentModel = "spring", uses = [BaseClientDetails::class]) +@DecoratedWith( + ClientDetailsMapperDecorator::class +) +interface ClientDetailsMapper { + @Mapping(target = "clientSecret", ignore = true) + @Mapping(target = "autoApproveScopes", ignore = true) + fun clientDetailsToClientDetailsDTO(details: ClientDetails): ClientDetailsDTO + fun clientDetailsToClientDetailsDTO(detailsList: List): List? + fun clientDetailsDTOToClientDetails(detailsDto: ClientDetailsDTO?): BaseClientDetails + fun clientDetailsDTOToClientDetails(detailsDtoList: List): List + + /** + * Map a set of authorities represented as strings to a collection of [GrantedAuthority]s. + * @param authorities the set of authorities to be mapped + * @return a collection of [GrantedAuthority]s + */ + fun map(authorities: Set): Collection? { + return if (Objects.isNull(authorities)) { + emptySet() + } else authorities.stream() + .map { role: String? -> SimpleGrantedAuthority(role) } + .collect(Collectors.toList()) + } + + /** + * Map a collection of authorities represented as [GrantedAuthority]s to a set of strings. + * @param authorities the collection of [GrantedAuthority]s to be mapped + * @return the set of strings + */ + fun map(authorities: Collection): Set? { + return if (Objects.isNull(authorities)) { + emptySet() + } else authorities.stream() + .map { obj: GrantedAuthority -> obj.authority } + .collect(Collectors.toSet()) + } + + /** + * Transforms the values in the input map to strings so the result is a + * [Map]. + * @param additionalInformation a [Map] to be transformed + * @return a new map with the same keys as the input map, but the values are transformed to + * strings using their [Object.toString] method + */ + fun map(additionalInformation: Map): Map? { + return if (Objects.isNull(additionalInformation)) { + emptyMap() + } else additionalInformation.entries + .associateBy( + { it.key }, + { e -> e.value.toString() } + ) + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/GroupMapper.java b/src/main/java/org/radarbase/management/service/mapper/GroupMapper.kt similarity index 53% rename from src/main/java/org/radarbase/management/service/mapper/GroupMapper.java rename to src/main/java/org/radarbase/management/service/mapper/GroupMapper.kt index 50962275f..451741d3b 100644 --- a/src/main/java/org/radarbase/management/service/mapper/GroupMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/GroupMapper.kt @@ -6,38 +6,34 @@ * * See the file LICENSE in the root of this repository. */ +package org.radarbase.management.service.mapper -package org.radarbase.management.service.mapper; - -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.MappingConstants; -import org.mapstruct.Named; -import org.radarbase.management.domain.Group; -import org.radarbase.management.service.dto.GroupDTO; - -import java.util.Collection; -import java.util.List; +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.MappingConstants +import org.mapstruct.Named +import org.radarbase.management.domain.Group +import org.radarbase.management.service.dto.GroupDTO @Mapper(componentModel = MappingConstants.ComponentModel.SPRING) -public interface GroupMapper { +interface GroupMapper { @Named("groupToGroupDTO") @Mapping(target = "id", ignore = true) @Mapping(target = "projectId", ignore = true) @Mapping(target = "name", source = "name") - GroupDTO groupToGroupDTO(Group group); + fun groupToGroupDTO(group: Group): GroupDTO @Named("groupToGroupDTOFull") @Mapping(source = "project.id", target = "projectId") @Mapping(target = "name", source = "name") - GroupDTO groupToGroupDTOFull(Group group); + fun groupToGroupDTOFull(group: Group): GroupDTO @Mapping(target = "id", ignore = true) @Mapping(target = "project.id", ignore = true) @Mapping(target = "name", source = "name") - Group groupDTOToGroup(GroupDTO groupDto); + fun groupDTOToGroup(groupDto: GroupDTO): Group - @IterableMapping(qualifiedByName = "groupToGroupDTOFull") - List groupToGroupDTOs(Collection groups); + @IterableMapping(qualifiedByName = ["groupToGroupDTOFull"]) + fun groupToGroupDTOs(groups: Collection): List } diff --git a/src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.java b/src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.java deleted file mode 100644 index 120f24a45..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.radarbase.management.service.mapper; - -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.radarbase.management.domain.Organization; -import org.radarbase.management.service.dto.OrganizationDTO; - -import java.util.List; - -/** - * Mapper for the entity Organization and its DTO OrganizationDTO. - */ -@Mapper(componentModel = "spring", uses = {ProjectMapper.class}) -public interface OrganizationMapper { - @Named("organizationToOrganizationDTO") - @Mapping(target = "projects", qualifiedByName = "projectReducedDTO") - OrganizationDTO organizationToOrganizationDTO(Organization organization); - - @Named("organizationToOrganizationDTOWithoutProjects") - @Mapping(target = "projects", ignore = true) - OrganizationDTO organizationToOrganizationDTOWithoutProjects(Organization organization); - - @Mapping(target = "projects", ignore = true) - Organization organizationDTOToOrganization(OrganizationDTO organizationDto); - - @IterableMapping(qualifiedByName = "organizationToOrganizationDTO") - List organizationsToOrganizationDTOs(List organizations); -} diff --git a/src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.kt b/src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.kt new file mode 100644 index 000000000..f5fe06a37 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.kt @@ -0,0 +1,28 @@ +package org.radarbase.management.service.mapper + +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.Named +import org.radarbase.management.domain.Organization +import org.radarbase.management.service.dto.OrganizationDTO + +/** + * Mapper for the entity Organization and its DTO OrganizationDTO. + */ +@Mapper(componentModel = "spring", uses = [ProjectMapper::class]) +interface OrganizationMapper { + @Named("organizationToOrganizationDTO") + @Mapping(target = "projects", qualifiedByName = ["projectReducedDTO"]) + fun organizationToOrganizationDTO(organization: Organization): OrganizationDTO + + @Named("organizationToOrganizationDTOWithoutProjects") + @Mapping(target = "projects", ignore = true) + fun organizationToOrganizationDTOWithoutProjects(organization: Organization): OrganizationDTO + + @Mapping(target = "projects", ignore = true) + fun organizationDTOToOrganization(organizationDto: OrganizationDTO): Organization + + @IterableMapping(qualifiedByName = ["organizationToOrganizationDTO"]) + fun organizationsToOrganizationDTOs(organizations: List): List +} diff --git a/src/main/java/org/radarbase/management/service/mapper/ProjectMapper.java b/src/main/java/org/radarbase/management/service/mapper/ProjectMapper.java deleted file mode 100644 index 48df0de89..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/ProjectMapper.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.radarbase.management.service.mapper; - -import java.util.List; -import org.mapstruct.DecoratedWith; -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.radarbase.management.domain.Project; -import org.radarbase.management.service.dto.MinimalProjectDetailsDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.mapper.decorator.ProjectMapperDecorator; - -/** - * Mapper for the entity Project and its DTO ProjectDTO. - */ -@Mapper(componentModel = "spring", - uses = {GroupMapper.class, SourceTypeMapper.class, OrganizationMapper.class}) -@DecoratedWith(ProjectMapperDecorator.class) -public interface ProjectMapper { - @Mapping(target = "humanReadableProjectName", ignore = true) - @Mapping(target = "organization", source = "organization", - qualifiedByName = "organizationToOrganizationDTOWithoutProjects") - @Mapping(target = "persistentTokenTimeout", ignore = true) - @Mapping(target = "groups", qualifiedByName = "groupToGroupDTO") - @Mapping(target = "sourceTypes", qualifiedByName = "sourceTypeToSourceTypeDTOReduced") - ProjectDTO projectToProjectDTO(Project project); - - @Named(value = "projectReducedDTO") - @Mapping(target = "humanReadableProjectName", ignore = true) - @Mapping(target = "organization", ignore = true) - @Mapping(target = "sourceTypes", ignore = true) - @Mapping(target = "persistentTokenTimeout", ignore = true) - @Mapping(target = "groups", qualifiedByName = "groupToGroupDTO") - ProjectDTO projectToProjectDTOReduced(Project project); - - @IterableMapping(qualifiedByName = "projectReducedDTO") - List projectsToProjectDTOs(List projects); - - @Mapping(target = "roles", ignore = true) - @Mapping(target = "groups", ignore = true) - @Mapping(target = "organization", ignore = true) - Project projectDTOToProject(ProjectDTO projectDto); - - List projectDTOsToProjects(List projectDtos); - - MinimalProjectDetailsDTO projectToMinimalProjectDetailsDTO(Project project); - - List projectsToMinimalProjectDetailsDTOs(List projects); - - @Mapping(target = "description", ignore = true) - @Mapping(target = "roles", ignore = true) - @Mapping(target = "organizationName", ignore = true) - @Mapping(target = "organization", ignore = true) - @Mapping(target = "location", ignore = true) - @Mapping(target = "startDate", ignore = true) - @Mapping(target = "endDate", ignore = true) - @Mapping(target = "projectStatus", ignore = true) - @Mapping(target = "sourceTypes", ignore = true) - @Mapping(target = "attributes", ignore = true) - @Mapping(target = "groups", ignore = true) - Project descriptiveDTOToProject(MinimalProjectDetailsDTO minimalProjectDetailsDto); - - List descriptiveDTOsToProjects( - List minimalProjectDetailsDtos); -} diff --git a/src/main/java/org/radarbase/management/service/mapper/ProjectMapper.kt b/src/main/java/org/radarbase/management/service/mapper/ProjectMapper.kt new file mode 100644 index 000000000..dfba59d60 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/ProjectMapper.kt @@ -0,0 +1,66 @@ +package org.radarbase.management.service.mapper + +import org.mapstruct.DecoratedWith +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.Named +import org.radarbase.management.domain.Project +import org.radarbase.management.service.dto.MinimalProjectDetailsDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.mapper.decorator.ProjectMapperDecorator + +/** + * Mapper for the entity Project and its DTO ProjectDTO. + */ +@Mapper(componentModel = "spring", uses = [GroupMapper::class, SourceTypeMapper::class, OrganizationMapper::class]) +@DecoratedWith( + ProjectMapperDecorator::class +) +interface ProjectMapper { + @Mapping(target = "humanReadableProjectName", ignore = true) + @Mapping( + target = "organization", + source = "organization", + qualifiedByName = ["organizationToOrganizationDTOWithoutProjects"] + ) + @Mapping(target = "persistentTokenTimeout", ignore = true) + @Mapping(target = "groups", qualifiedByName = ["groupToGroupDTO"]) + @Mapping(target = "sourceTypes", qualifiedByName = ["sourceTypeToSourceTypeDTOReduced"]) + fun projectToProjectDTO(project: Project?): ProjectDTO? + + @Named(value = "projectReducedDTO") + @Mapping(target = "humanReadableProjectName", ignore = true) + @Mapping(target = "organization", ignore = true) + @Mapping(target = "sourceTypes", ignore = true) + @Mapping(target = "persistentTokenTimeout", ignore = true) + @Mapping(target = "groups", qualifiedByName = ["groupToGroupDTO"]) + fun projectToProjectDTOReduced(project: Project?): ProjectDTO? + + @IterableMapping(qualifiedByName = ["projectReducedDTO"]) + fun projectsToProjectDTOs(projects: List): List + + @Mapping(target = "roles", ignore = true) + @Mapping(target = "groups", ignore = true) + @Mapping(target = "organization", ignore = true) + fun projectDTOToProject(projectDto: ProjectDTO?): Project? + fun projectDTOsToProjects(projectDtos: List): List + fun projectToMinimalProjectDetailsDTO(project: Project): MinimalProjectDetailsDTO + fun projectsToMinimalProjectDetailsDTOs(projects: List): List + + @Mapping(target = "description", ignore = true) + @Mapping(target = "roles", ignore = true) + @Mapping(target = "organizationName", ignore = true) + @Mapping(target = "organization", ignore = true) + @Mapping(target = "location", ignore = true) + @Mapping(target = "startDate", ignore = true) + @Mapping(target = "endDate", ignore = true) + @Mapping(target = "projectStatus", ignore = true) + @Mapping(target = "sourceTypes", ignore = true) + @Mapping(target = "attributes", ignore = true) + @Mapping(target = "groups", ignore = true) + fun descriptiveDTOToProject(minimalProjectDetailsDto: MinimalProjectDetailsDTO?): Project? + fun descriptiveDTOsToProjects( + minimalProjectDetailsDtos: List + ): List +} diff --git a/src/main/java/org/radarbase/management/service/mapper/RoleMapper.java b/src/main/java/org/radarbase/management/service/mapper/RoleMapper.kt similarity index 52% rename from src/main/java/org/radarbase/management/service/mapper/RoleMapper.java rename to src/main/java/org/radarbase/management/service/mapper/RoleMapper.kt index 7602a66ef..16606507f 100644 --- a/src/main/java/org/radarbase/management/service/mapper/RoleMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/RoleMapper.kt @@ -1,37 +1,30 @@ -package org.radarbase.management.service.mapper; +package org.radarbase.management.service.mapper - -import java.util.Set; - -import org.mapstruct.DecoratedWith; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.radarbase.management.domain.Role; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.mapper.decorator.RoleMapperDecorator; +import org.mapstruct.DecoratedWith +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.radarbase.management.domain.Role +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.mapper.decorator.RoleMapperDecorator /** * Created by nivethika on 23-5-17. */ -@Mapper(componentModel = "spring", uses = {ProjectMapper.class}) -@DecoratedWith(RoleMapperDecorator.class) -public interface RoleMapper { - +@Mapper(componentModel = "spring", uses = [ProjectMapper::class]) +@DecoratedWith(RoleMapperDecorator::class) +interface RoleMapper { @Mapping(source = "authority.name", target = "authorityName") @Mapping(source = "project.id", target = "projectId") @Mapping(source = "project.projectName", target = "projectName") @Mapping(source = "organization.id", target = "organizationId") @Mapping(source = "organization.name", target = "organizationName") - RoleDTO roleToRoleDTO(Role role); + fun roleToRoleDTO(role: Role): RoleDTO @Mapping(target = "authority", ignore = true) @Mapping(source = "projectId", target = "project.id") @Mapping(target = "users", ignore = true) @Mapping(source = "organizationId", target = "organization.id") - Role roleDTOToRole(RoleDTO roleDtp); - - Set roleDTOsToRoles(Set roleDtos); - - Set rolesToRoleDTOs(Set roles); - + fun roleDTOToRole(roleDto: RoleDTO?): Role? + fun roleDTOsToRoles(roleDtos: Set): Set + fun rolesToRoleDTOs(roles: Set): Set } diff --git a/src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.java b/src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.java deleted file mode 100644 index 753221e28..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.radarbase.management.service.mapper; - -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.service.dto.SourceDataDTO; - -import java.util.List; - -/** - * Mapper for the entity SourceData and its DTO SourceDataDTO. - */ -@Mapper(componentModel = "spring", uses = {SourceTypeMapper.class}) -public interface SourceDataMapper { - - @Named("sourceDataDTO") - SourceDataDTO sourceDataToSourceDataDTO(SourceData sourceData); - - @Named("sourceDataReducedDTO") - @Mapping(target = "sourceType", ignore = true) - SourceDataDTO sourceDataToSourceDataDTOReduced(SourceData sourceData); - - @IterableMapping(qualifiedByName = "sourceDataReducedDTO") - List sourceDataToSourceDataDTOs(List sourceData); - - SourceData sourceDataDTOToSourceData(SourceDataDTO sourceDataDto); - - List sourceDataDTOsToSourceData(List sourceDataDtos); - - /** - * generating the fromId for all mappers if the databaseType is sql, as the class has - * relationship to it might need it, instead of creating a new attribute to know if the entity - * has any relationship from some other entity. - * - * @param id id of the entity - * @return the entity instance - */ - - default SourceData sourceDataFromId(Long id) { - if (id == null) { - return null; - } - SourceData sourceData = new SourceData(); - sourceData.setId(id); - return sourceData; - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.kt b/src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.kt new file mode 100644 index 000000000..7413d4a15 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.kt @@ -0,0 +1,43 @@ +package org.radarbase.management.service.mapper + +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.Named +import org.radarbase.management.domain.SourceData +import org.radarbase.management.service.dto.SourceDataDTO + +/** + * Mapper for the entity SourceData and its DTO SourceDataDTO. + */ +@Mapper(componentModel = "spring", uses = [SourceTypeMapper::class]) +interface SourceDataMapper { + @Named("sourceDataDTO") + fun sourceDataToSourceDataDTO(sourceData: SourceData?): SourceDataDTO? + + @Named("sourceDataReducedDTO") + @Mapping(target = "sourceType", ignore = true) + fun sourceDataToSourceDataDTOReduced(sourceData: SourceData): SourceDataDTO + + @IterableMapping(qualifiedByName = ["sourceDataReducedDTO"]) + fun sourceDataToSourceDataDTOs(sourceData: List): List + fun sourceDataDTOToSourceData(sourceDataDto: SourceDataDTO): SourceData + fun sourceDataDTOsToSourceData(sourceDataDtos: List): List + + /** + * generating the fromId for all mappers if the databaseType is sql, as the class has + * relationship to it might need it, instead of creating a new attribute to know if the entity + * has any relationship from some other entity. + * + * @param id id of the entity + * @return the entity instance + */ + fun sourceDataFromId(id: Long?): SourceData? { + if (id == null) { + return null + } + val sourceData = SourceData() + sourceData.id = id + return sourceData + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/SourceMapper.java b/src/main/java/org/radarbase/management/service/mapper/SourceMapper.java deleted file mode 100644 index 5d6f21eeb..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/SourceMapper.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.radarbase.management.service.mapper; - -import org.mapstruct.DecoratedWith; -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.radarbase.management.domain.Source; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.mapper.decorator.SourceMapperDecorator; - -import java.util.List; - -/** - * Mapper for the entity Source and its DTO SourceDTO. - */ -@Mapper(componentModel = "spring", uses = {SourceTypeMapper.class, ProjectMapper.class}) -@DecoratedWith(SourceMapperDecorator.class) -public interface SourceMapper { - - @Mapping(source = "source.subject.user.login", target = "subjectLogin") - SourceDTO sourceToSourceDTO(Source source); - - @Named("sourceWithoutProjectDTO") - @Mapping(source = "source.subject.user.login", target = "subjectLogin") - @Mapping(target = "project", ignore = true) - SourceDTO sourceToSourceWithoutProjectDTO(Source source); - - @IterableMapping(qualifiedByName = "sourceWithoutProjectDTO") - List sourcesToSourceDTOs(List sources); - - @Mapping(source = "sourceType.id", target = "sourceTypeId") - @Mapping(source = "sourceType.producer", target = "sourceTypeProducer") - @Mapping(source = "sourceType.model", target = "sourceTypeModel") - @Mapping(source = "sourceType.catalogVersion", target = "sourceTypeCatalogVersion") - @Mapping(source = "assigned" , target = "assigned") - MinimalSourceDetailsDTO sourceToMinimalSourceDetailsDTO(Source source); - - List sourcesToMinimalSourceDetailsDTOs(List sources); - - @Mapping(target = "sourceType", ignore = true) - @Mapping(target = "project", ignore = true) - @Mapping(target = "subject", ignore = true) - @Mapping(target = "deleted", constant = "false") - Source minimalSourceDTOToSource(MinimalSourceDetailsDTO minimalSourceDetailsDto); - - @Mapping(target = "subject", ignore = true) - @Mapping(target = "deleted", constant = "false") - Source sourceDTOToSource(SourceDTO sourceDto); -} diff --git a/src/main/java/org/radarbase/management/service/mapper/SourceMapper.kt b/src/main/java/org/radarbase/management/service/mapper/SourceMapper.kt new file mode 100644 index 000000000..097ede263 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/SourceMapper.kt @@ -0,0 +1,49 @@ +package org.radarbase.management.service.mapper + +import org.mapstruct.DecoratedWith +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.Named +import org.radarbase.management.domain.Source +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.SourceDTO +import org.radarbase.management.service.mapper.decorator.SourceMapperDecorator + +/** + * Mapper for the entity Source and its DTO SourceDTO. + */ +@Mapper(componentModel = "spring", uses = [SourceTypeMapper::class, ProjectMapper::class]) +@DecoratedWith( + SourceMapperDecorator::class +) +interface SourceMapper { + @Mapping(source = "source.subject.user.login", target = "subjectLogin") + fun sourceToSourceDTO(source: Source): SourceDTO + + @Named("sourceWithoutProjectDTO") + @Mapping(source = "source.subject.user.login", target = "subjectLogin") + @Mapping(target = "project", ignore = true) + fun sourceToSourceWithoutProjectDTO(source: Source): SourceDTO + + @IterableMapping(qualifiedByName = ["sourceWithoutProjectDTO"]) + fun sourcesToSourceDTOs(sources: List): List + + @Mapping(source = "sourceType.id", target = "sourceTypeId") + @Mapping(source = "sourceType.producer", target = "sourceTypeProducer") + @Mapping(source = "sourceType.model", target = "sourceTypeModel") + @Mapping(source = "sourceType.catalogVersion", target = "sourceTypeCatalogVersion") + @Mapping(source = "assigned", target = "assigned") + fun sourceToMinimalSourceDetailsDTO(source: Source): MinimalSourceDetailsDTO + fun sourcesToMinimalSourceDetailsDTOs(sources: List): List + + @Mapping(target = "sourceType", ignore = true) + @Mapping(target = "project", ignore = true) + @Mapping(target = "subject", ignore = true) + @Mapping(target = "deleted", constant = "false") + fun minimalSourceDTOToSource(minimalSourceDetailsDto: MinimalSourceDetailsDTO): Source? + + @Mapping(target = "subject", ignore = true) + @Mapping(target = "deleted", constant = "false") + fun sourceDTOToSource(sourceDto: SourceDTO): Source +} diff --git a/src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.java b/src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.java deleted file mode 100644 index f4b9e0a4a..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.radarbase.management.service.mapper; - -import java.util.List; -import java.util.Set; -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.service.dto.MinimalSourceTypeDTO; -import org.radarbase.management.service.dto.SourceDataDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; - -/** - * Mapper for the entity SourceType and its DTO SourceTypeDTO. - */ -@Mapper(componentModel = "spring", uses = {SourceDataMapper.class,}) -public interface SourceTypeMapper { - @Named("sourceTypeToSourceTypeDTO") - SourceTypeDTO sourceTypeToSourceTypeDTO(SourceType sourceType); - - @Named("sourceTypeToSourceTypeDTOReduced") - @Mapping(target = "sourceData", ignore = true) - @Mapping(target = "assessmentType", ignore = true) - @Mapping(target = "appProvider", ignore = true) - @Mapping(target = "description", ignore = true) - SourceTypeDTO sourceTypeToSourceTypeDTOReduced(SourceType sourceType); - - @IterableMapping(qualifiedByName = "sourceTypeToSourceTypeDTOReduced") - List sourceTypesToSourceTypeDTOs(List sourceTypes); - - @Mapping(target = "projects", ignore = true) - SourceType sourceTypeDTOToSourceType(SourceTypeDTO sourceTypeDto); - - List sourceTypeDTOsToSourceTypes(List sourceTypeDtos); - - MinimalSourceTypeDTO sourceTypeToMinimalSourceTypeDetailsDTO(SourceType sourceType); - - List sourceTypesToMinimalSourceTypeDetailsDTOs( - List sourceTypes); - - @IterableMapping(qualifiedByName = "sourceDataReducedDTO") - Set map(Set sourceData); - - @Mapping(target = "sourceTypeScope", ignore = true) - @Mapping(target = "sourceData", ignore = true) - @Mapping(target = "canRegisterDynamically", ignore = true) - @Mapping(target = "name", ignore = true) - @Mapping(target = "description", ignore = true) - @Mapping(target = "assessmentType", ignore = true) - @Mapping(target = "projects", ignore = true) - @Mapping(target = "appProvider", ignore = true) - SourceType minimalDTOToSourceType(MinimalSourceTypeDTO minimalSourceTypeDetailsDto); - - List minimalDTOsToSourceTypes(List minimalProjectDetailsDtos); - - /** - * Generating the fromId for all mappers if the databaseType is sql, as the class has - * relationship to it might need it, instead of creating a new attribute to know if the entity - * has any relationship from some other entity. - * - * @param id id of the entity - * @return the entity instance - */ - - default SourceType sourceTypeFromId(Long id) { - if (id == null) { - return null; - } - SourceType sourceType = new SourceType(); - sourceType.setId(id); - return sourceType; - } - - -} diff --git a/src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.kt b/src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.kt new file mode 100644 index 000000000..e32b769e7 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.kt @@ -0,0 +1,69 @@ +package org.radarbase.management.service.mapper + +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.Named +import org.radarbase.management.domain.SourceData +import org.radarbase.management.domain.SourceType +import org.radarbase.management.service.dto.MinimalSourceTypeDTO +import org.radarbase.management.service.dto.SourceDataDTO +import org.radarbase.management.service.dto.SourceTypeDTO + +/** + * Mapper for the entity SourceType and its DTO SourceTypeDTO. + */ +@Mapper(componentModel = "spring", uses = [SourceDataMapper::class]) +interface SourceTypeMapper { + @Named("sourceTypeToSourceTypeDTO") + fun sourceTypeToSourceTypeDTO(sourceType: SourceType): SourceTypeDTO + + @Named("sourceTypeToSourceTypeDTOReduced") + @Mapping(target = "sourceData", ignore = true) + @Mapping(target = "assessmentType", ignore = true) + @Mapping(target = "appProvider", ignore = true) + @Mapping(target = "description", ignore = true) + fun sourceTypeToSourceTypeDTOReduced(sourceType: SourceType?): SourceTypeDTO? + + @IterableMapping(qualifiedByName = ["sourceTypeToSourceTypeDTOReduced"]) + fun sourceTypesToSourceTypeDTOs(sourceTypes: List): List + + @Mapping(target = "projects", ignore = true) + fun sourceTypeDTOToSourceType(sourceTypeDto: SourceTypeDTO): SourceType + fun sourceTypeDTOsToSourceTypes(sourceTypeDtos: List): List + fun sourceTypeToMinimalSourceTypeDetailsDTO(sourceType: SourceType): MinimalSourceTypeDTO + fun sourceTypesToMinimalSourceTypeDetailsDTOs( + sourceTypes: List + ): List + + @IterableMapping(qualifiedByName = ["sourceDataReducedDTO"]) + fun map(sourceData: Set?): Set? + + @Mapping(target = "sourceTypeScope", ignore = true) + @Mapping(target = "sourceData", ignore = true) + @Mapping(target = "canRegisterDynamically", ignore = true) + @Mapping(target = "name", ignore = true) + @Mapping(target = "description", ignore = true) + @Mapping(target = "assessmentType", ignore = true) + @Mapping(target = "projects", ignore = true) + @Mapping(target = "appProvider", ignore = true) + fun minimalDTOToSourceType(minimalSourceTypeDetailsDto: MinimalSourceTypeDTO?): SourceType? + fun minimalDTOsToSourceTypes(minimalProjectDetailsDtos: List?): List? + + /** + * Generating the fromId for all mappers if the databaseType is sql, as the class has + * relationship to it might need it, instead of creating a new attribute to know if the entity + * has any relationship from some other entity. + * + * @param id id of the entity + * @return the entity instance + */ + fun sourceTypeFromId(id: Long?): SourceType? { + if (id == null) { + return null + } + val sourceType = SourceType() + sourceType.id = id + return sourceType + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java deleted file mode 100644 index c98f70bfe..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.radarbase.management.service.mapper.decorator; - - -import org.radarbase.management.service.dto.ClientDetailsDTO; -import org.radarbase.management.service.mapper.ClientDetailsMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.security.oauth2.provider.ClientDetails; - -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -/** - * Decorator for ClientDetailsMapper. The ClientDetails interface does not expose a method to get - * all auto-approve scopes, instead it only has a method to check if a given scope is auto-approve. - * This decorator adds the subset of scopes for which isAutoApprove returns true to the DTO. - */ -public abstract class ClientDetailsMapperDecorator implements ClientDetailsMapper { - - @Autowired - @Qualifier("delegate") - private ClientDetailsMapper delegate; - - @Override - public ClientDetailsDTO clientDetailsToClientDetailsDTO(ClientDetails details) { - ClientDetailsDTO clientDetailsDto = delegate.clientDetailsToClientDetailsDTO(details); - // collect the scopes that are auto-approve and set them in our DTO - clientDetailsDto.setAutoApproveScopes(details.getScope().stream() - .filter(details::isAutoApprove) - .collect(Collectors.toSet())); - return clientDetailsDto; - } - - @Override - public List clientDetailsToClientDetailsDTO(List details) { - if (Objects.isNull(details)) { - return null; - } - return details.stream() - .map(this::clientDetailsToClientDetailsDTO) - .toList(); - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt new file mode 100644 index 000000000..e0e6217cf --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt @@ -0,0 +1,36 @@ +package org.radarbase.management.service.mapper.decorator + +import org.radarbase.management.service.dto.ClientDetailsDTO +import org.radarbase.management.service.mapper.ClientDetailsMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.security.oauth2.provider.ClientDetails +import java.util.* +import java.util.stream.Collectors + +/** + * Decorator for ClientDetailsMapper. The ClientDetails interface does not expose a method to get + * all auto-approve scopes, instead it only has a method to check if a given scope is auto-approve. + * This decorator adds the subset of scopes for which isAutoApprove returns true to the DTO. + */ +abstract class ClientDetailsMapperDecorator : ClientDetailsMapper { + @Autowired + @Qualifier("delegate") + private val delegate: ClientDetailsMapper? = null + override fun clientDetailsToClientDetailsDTO(details: ClientDetails): ClientDetailsDTO { + val clientDetailsDto = delegate!!.clientDetailsToClientDetailsDTO(details) + // collect the scopes that are auto-approve and set them in our DTO + clientDetailsDto.autoApproveScopes = details.scope.stream() + .filter { scope: String? -> details.isAutoApprove(scope) } + .collect(Collectors.toSet()) + return clientDetailsDto + } + + override fun clientDetailsToClientDetailsDTO(detailsList: List): List? { + return if (Objects.isNull(detailsList)) { + null + } else detailsList.stream() + .map { details: ClientDetails -> this.clientDetailsToClientDetailsDTO(details) } + .toList() + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java deleted file mode 100644 index 4d60d9afa..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.radarbase.management.service.mapper.decorator; - -import org.radarbase.management.domain.Project; -import org.radarbase.management.repository.OrganizationRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.service.MetaTokenService; -import org.radarbase.management.service.dto.MinimalProjectDetailsDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -import static org.radarbase.management.service.dto.ProjectDTO.HUMAN_READABLE_PROJECT_NAME; -import static org.radarbase.management.web.rest.errors.EntityName.ORGANIZATION; - -import java.util.Collections; - -/** - * Created by nivethika on 30-8-17. - */ -public abstract class ProjectMapperDecorator implements ProjectMapper { - - @Autowired - @Qualifier("delegate") - private ProjectMapper delegate; - - @Autowired - private OrganizationRepository organizationRepository; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private MetaTokenService metaTokenService; - - @Override - public ProjectDTO projectToProjectDTO(Project project) { - if (project == null) { - return null; - } - ProjectDTO dto = delegate.projectToProjectDTO(project); - - dto.setHumanReadableProjectName(project.attributes.get(HUMAN_READABLE_PROJECT_NAME)); - - try { - dto.setPersistentTokenTimeout( - metaTokenService.getMetaTokenTimeout(true, project).toMillis()); - } catch (BadRequestException ex) { - dto.setPersistentTokenTimeout(null); - } - - return dto; - } - - - @Override - public ProjectDTO projectToProjectDTOReduced(Project project) { - if (project == null) { - return null; - } - ProjectDTO dto = delegate.projectToProjectDTOReduced(project); - dto.setHumanReadableProjectName(project.attributes.get(HUMAN_READABLE_PROJECT_NAME)); - dto.setSourceTypes(null); - return dto; - } - - @Override - public Project projectDTOToProject(ProjectDTO projectDto) { - if (projectDto == null) { - return null; - } - - Project project = delegate.projectDTOToProject(projectDto); - String projectName = projectDto.getHumanReadableProjectName(); - if (projectName != null && !projectName.isEmpty()) { - project.attributes.put(HUMAN_READABLE_PROJECT_NAME, projectName); - } - - var orgDto = projectDto.getOrganization(); - if (orgDto != null && orgDto.getName() != null) { - var org = organizationRepository.findOneByName(orgDto.getName()) - .orElseThrow(() -> new NotFoundException("Organization not found with name", - ORGANIZATION, - ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, - Collections.singletonMap("name", orgDto.getName()))); - project.organization = org; - } - - return project; - } - - @Override - public Project descriptiveDTOToProject(MinimalProjectDetailsDTO minimalProjectDetailsDto) { - if (minimalProjectDetailsDto == null) { - return null; - } - return projectRepository.getById(minimalProjectDetailsDto.getId()); - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt new file mode 100644 index 000000000..48d862398 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt @@ -0,0 +1,77 @@ +package org.radarbase.management.service.mapper.decorator + +import org.radarbase.management.domain.Project +import org.radarbase.management.repository.OrganizationRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.MetaTokenService +import org.radarbase.management.service.dto.MinimalProjectDetailsDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import java.util.* + +/** + * Created by nivethika on 30-8-17. + */ +abstract class ProjectMapperDecorator( + @Autowired @Qualifier("delegate") private val delegate: ProjectMapper, + @Autowired private val organizationRepository: OrganizationRepository, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val metaTokenService: MetaTokenService +) : ProjectMapper { + + override fun projectToProjectDTO(project: Project?): ProjectDTO? { + val dto = delegate.projectToProjectDTO(project) + dto?.humanReadableProjectName = project?.attributes?.get(ProjectDTO.HUMAN_READABLE_PROJECT_NAME) + try { + dto?.persistentTokenTimeout = metaTokenService.getMetaTokenTimeout(true, project).toMillis() + } catch (ex: BadRequestException) { + dto?.persistentTokenTimeout = null + } + return dto + } + + override fun projectToProjectDTOReduced(project: Project?): ProjectDTO? { + if (project == null) { + return null + } + val dto = delegate.projectToProjectDTOReduced(project) + dto?.humanReadableProjectName = project.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] + dto?.sourceTypes = null + return dto + } + + override fun projectDTOToProject(projectDto: ProjectDTO?): Project? { + if (projectDto == null) { + return null + } + val project = delegate.projectDTOToProject(projectDto) + val projectName = projectDto.humanReadableProjectName + if (!projectName.isNullOrEmpty()) { + project!!.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] = projectName + } + val orgDto = projectDto.organization + if (orgDto?.name != null) { + val org = organizationRepository.findOneByName(orgDto.name) + ?: throw NotFoundException( + "Organization not found with name", + EntityName.Companion.ORGANIZATION, + ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, + Collections.singletonMap("name", orgDto.name) + ) + project!!.organization = org + } + return project + } + + override fun descriptiveDTOToProject(minimalProjectDetailsDto: MinimalProjectDetailsDTO?): Project? { + return if (minimalProjectDetailsDto == null) { + null + } else minimalProjectDetailsDto.id?.let { projectRepository.getById(it) } + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java deleted file mode 100644 index 581ca9995..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.radarbase.management.service.mapper.decorator; - -import org.radarbase.management.domain.Role; -import org.radarbase.management.repository.AuthorityRepository; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.mapper.RoleMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -/** - * Created by nivethika on 03-8-18. - */ -public abstract class RoleMapperDecorator implements RoleMapper { - - @Autowired - @Qualifier("delegate") - private RoleMapper delegate; - - @Autowired - private AuthorityRepository authorityRepository; - - /** - * Overrides standard RoleMapperImpl and loads authority from repository if not specified. - * @param roleDto to convert to Role. - * @return converted Role instance. - */ - @Override - public Role roleDTOToRole(RoleDTO roleDto) { - if (roleDto == null) { - return null; - } - - Role role = delegate.roleDTOToRole(roleDto); - - if (role.authority == null) { - role.authority = authorityRepository.getById(roleDto.getAuthorityName()); - } - - return role; - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt new file mode 100644 index 000000000..0fb761825 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt @@ -0,0 +1,36 @@ +package org.radarbase.management.service.mapper.decorator + +import org.radarbase.management.domain.Role +import org.radarbase.management.repository.AuthorityRepository +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.mapper.RoleMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier + +/** + * Created by nivethika on 03-8-18. + */ +abstract class RoleMapperDecorator : RoleMapper { + @Autowired + @Qualifier("delegate") + private val delegate: RoleMapper? = null + + @Autowired + private val authorityRepository: AuthorityRepository? = null + + /** + * Overrides standard RoleMapperImpl and loads authority from repository if not specified. + * @param roleDto to convert to Role. + * @return converted Role instance. + */ + override fun roleDTOToRole(roleDto: RoleDTO?): Role? { + if (roleDto == null) { + return null + } + val role = delegate!!.roleDTOToRole(roleDto) + if (role!!.authority == null) { + role.authority = roleDto.authorityName?.let { authorityRepository!!.getById(it) } + } + return role + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java deleted file mode 100644 index fd69ec511..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.radarbase.management.service.mapper.decorator; - -import org.radarbase.management.domain.Source; -import org.radarbase.management.repository.SourceRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.mapper.SourceMapper; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -import java.util.Map; -import java.util.NoSuchElementException; - -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SOURCE_NOT_FOUND; - -/** - * Created by nivethika on 13-6-17. - */ - -public abstract class SourceMapperDecorator implements SourceMapper { - - @Autowired - @Qualifier("delegate") - private SourceMapper delegate; - - @Autowired - private SourceRepository sourceRepository; - - @Autowired - private SubjectRepository subjectRepository; - - @Override - public Source minimalSourceDTOToSource(MinimalSourceDetailsDTO minimalSource) { - Source source = sourceRepository - .findOneBySourceId(minimalSource.getSourceId()) - .orElseThrow(() -> new NotFoundException( - "Source ID " + minimalSource.getSourceId() + " not found", - SOURCE, ERR_SOURCE_NOT_FOUND, - Map.of("sourceId", minimalSource.getSourceId().toString()))); - source.setAssigned(minimalSource.isAssigned()); - return source; - } - - @Override - public Source sourceDTOToSource(SourceDTO sourceDto) { - Source source = delegate.sourceDTOToSource(sourceDto); - if (sourceDto.getId() != null) { - Source existingSource = sourceRepository.findById(sourceDto.getId()) - .orElseThrow(() -> new NotFoundException( - "Source ID " + sourceDto.getId() + " not found", - SOURCE, ERR_SOURCE_NOT_FOUND, - Map.of("sourceId", sourceDto.getId().toString()))); - if (sourceDto.getSubjectLogin() == null) { - source.subject = existingSource.subject; - } else { - source.subject = subjectRepository - .findOneWithEagerBySubjectLogin(sourceDto.getSubjectLogin()) - .orElseThrow(NoSuchElementException::new); - } - } - return source; - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt new file mode 100644 index 000000000..eb418185c --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt @@ -0,0 +1,61 @@ +package org.radarbase.management.service.mapper.decorator + +import org.radarbase.management.domain.Source +import org.radarbase.management.repository.SourceRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.SourceDTO +import org.radarbase.management.service.mapper.SourceMapper +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import java.util.Map + +/** + * Created by nivethika on 13-6-17. + */ +abstract class SourceMapperDecorator( + @Autowired @Qualifier("delegate") private val delegate: SourceMapper, + @Autowired private val sourceRepository: SourceRepository, + @Autowired private val subjectRepository: SubjectRepository +) : SourceMapper { + + override fun minimalSourceDTOToSource(minimalSourceDetailsDto: MinimalSourceDetailsDTO): Source? { + val source = sourceRepository + .findOneBySourceId(minimalSourceDetailsDto.sourceId) + ?: throw + NotFoundException( + "Source ID " + minimalSourceDetailsDto.sourceId + " not found", + EntityName.Companion.SOURCE, ErrorConstants.ERR_SOURCE_NOT_FOUND, + Map.of("sourceId", minimalSourceDetailsDto.sourceId.toString()) + ) + source.isAssigned = minimalSourceDetailsDto.isAssigned + return source + } + + override fun sourceDTOToSource(sourceDto: SourceDTO): Source { + val source = delegate.sourceDTOToSource(sourceDto) + if (sourceDto.id != null) { + val existingSource = sourceDto.id?.let { + sourceRepository.findById(it) + .orElseThrow { + NotFoundException( + "Source ID " + sourceDto.id + " not found", + EntityName.Companion.SOURCE, ErrorConstants.ERR_SOURCE_NOT_FOUND, + Map.of("sourceId", sourceDto.id.toString()) + ) + } + }!! + if (sourceDto.subjectLogin == null) { + source.subject = existingSource.subject + } else { + source.subject = subjectRepository + .findOneWithEagerBySubjectLogin(sourceDto.subjectLogin) + ?: throw NoSuchElementException() + } + } + return source + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt index 3317d9b05..19ece43e4 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt @@ -33,8 +33,8 @@ abstract class SubjectMapperDecorator( } val dto = subjectToSubjectWithoutProjectDTO(subject) val project = subject.activeProject - .let { p -> projectRepository.findOneWithEagerRelationships(p?.id) } - dto!!.project = projectMapper.projectToProjectDTO(project) + .let { p -> projectRepository.findOneWithEagerRelationships(p?.id!!) } + dto?.project = projectMapper.projectToProjectDTO(project) addAuditInfo(subject, dto) return dto } @@ -44,7 +44,7 @@ abstract class SubjectMapperDecorator( return null } val dto = subjectToSubjectWithoutProjectDTO(subject) - subject.activeProject?.let { project -> dto!!.project = projectMapper.projectToProjectDTOReduced(project) } + subject.activeProject?.let { project -> dto?.project = projectMapper.projectToProjectDTOReduced(project) } addAuditInfo(subject, dto) return dto } @@ -62,7 +62,7 @@ abstract class SubjectMapperDecorator( return null } val dto = delegate.subjectToSubjectWithoutProjectDTO(subject) - dto!!.status = getSubjectStatus(subject) + dto?.status = getSubjectStatus(subject) return dto } @@ -72,24 +72,24 @@ abstract class SubjectMapperDecorator( } val subject = delegate.subjectDTOToSubject(subjectDto) setSubjectStatus(subjectDto, subject) - subject!!.group = getGroup(subjectDto) + subject?.group = getGroup(subjectDto) return subject } private fun getGroup(subjectDto: SubjectDTO?): Group? { return if (subjectDto!!.group == null) { null - } else if (subjectDto.project.id != null) { - groupRepository.findByProjectIdAndName(subjectDto.project.id, subjectDto.group) + } else if (subjectDto.project?.id != null) { + groupRepository.findByProjectIdAndName(subjectDto.project?.id, subjectDto.group) ?: throw BadRequestException( "Group " + subjectDto.group + " not found in project " - + subjectDto.project.id, + + subjectDto.project?.id, EntityName.SUBJECT, ErrorConstants.ERR_GROUP_NOT_FOUND) - } else if (subjectDto.project.projectName != null) { - groupRepository.findByProjectNameAndName(subjectDto.project.projectName, subjectDto.group) + } else if (subjectDto.project?.projectName != null) { + groupRepository.findByProjectNameAndName(subjectDto.project?.projectName, subjectDto.group) ?: throw BadRequestException( "Group " + subjectDto.group + " not found in project " - + subjectDto.project.projectName, + + subjectDto.project?.projectName, EntityName.SUBJECT, ErrorConstants.ERR_GROUP_NOT_FOUND ) } else { diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.java deleted file mode 100644 index 839bd6ff3..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.radarbase.management.service.mapper.decorator; - -import org.radarbase.management.domain.User; -import org.radarbase.management.domain.audit.EntityAuditInfo; -import org.radarbase.management.service.RevisionService; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.UserMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -public abstract class UserMapperDecorator implements UserMapper { - - @Autowired - @Qualifier("delegate") - private UserMapper delegate; - - @Autowired - private RevisionService revisionService; - - @Override - public UserDTO userToUserDTO(User user) { - if (user == null) { - return null; - } - - UserDTO dto = delegate.userToUserDTO(user); - - EntityAuditInfo auditInfo = revisionService.getAuditInfo(user); - dto.setCreatedDate(auditInfo.getCreatedAt()); - dto.setCreatedBy(auditInfo.getCreatedBy()); - dto.setLastModifiedDate(auditInfo.getLastModifiedAt()); - dto.setLastModifiedBy(auditInfo.getLastModifiedBy()); - - return dto; - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt new file mode 100644 index 000000000..02f4fa2eb --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt @@ -0,0 +1,29 @@ +package org.radarbase.management.service.mapper.decorator + +import org.radarbase.management.domain.User +import org.radarbase.management.service.RevisionService +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.UserMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier + +abstract class UserMapperDecorator : UserMapper { + @Autowired + @Qualifier("delegate") + private val delegate: UserMapper? = null + + @Autowired + private val revisionService: RevisionService? = null + override fun userToUserDTO(user: User?): UserDTO? { + if (user == null) { + return null + } + val dto = delegate!!.userToUserDTO(user) + val auditInfo = revisionService!!.getAuditInfo(user) + dto?.createdDate = auditInfo.createdAt + dto?.createdBy = auditInfo.createdBy + dto?.lastModifiedDate = auditInfo.lastModifiedAt + dto?.lastModifiedBy = auditInfo.lastModifiedBy + return dto + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/package-info.java b/src/main/java/org/radarbase/management/service/mapper/package-info.kt similarity index 62% rename from src/main/java/org/radarbase/management/service/mapper/package-info.java rename to src/main/java/org/radarbase/management/service/mapper/package-info.kt index 0b5b3b448..0f781e947 100644 --- a/src/main/java/org/radarbase/management/service/mapper/package-info.java +++ b/src/main/java/org/radarbase/management/service/mapper/package-info.kt @@ -1,4 +1,5 @@ /** * MapStruct mappers for mapping domain objects and Data Transfer Objects. */ -package org.radarbase.management.service.mapper; +package org.radarbase.management.service.mapper + diff --git a/src/main/java/org/radarbase/management/service/package-info.java b/src/main/java/org/radarbase/management/service/package-info.java deleted file mode 100644 index 30311a71e..000000000 --- a/src/main/java/org/radarbase/management/service/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Service layer beans. - */ -package org.radarbase.management.service; diff --git a/src/main/java/org/radarbase/management/service/package-info.kt b/src/main/java/org/radarbase/management/service/package-info.kt new file mode 100644 index 000000000..763684f5a --- /dev/null +++ b/src/main/java/org/radarbase/management/service/package-info.kt @@ -0,0 +1,5 @@ +/** + * Service layer beans. + */ +package org.radarbase.management.service + diff --git a/src/main/java/org/radarbase/management/web/rest/AccountResource.java b/src/main/java/org/radarbase/management/web/rest/AccountResource.java deleted file mode 100644 index c9f959762..000000000 --- a/src/main/java/org/radarbase/management/web/rest/AccountResource.java +++ /dev/null @@ -1,233 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import org.radarbase.auth.authorization.Permission; -import org.radarbase.auth.token.DataRadarToken; -import org.radarbase.auth.token.RadarToken; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.User; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.MailService; -import org.radarbase.management.service.PasswordService; -import org.radarbase.management.service.UserService; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.UserMapper; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.RadarWebApplicationException; -import org.radarbase.management.web.rest.vm.KeyAndPasswordVM; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.Authentication; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import javax.validation.Valid; - -import static org.radarbase.management.security.JwtAuthenticationFilter.setRadarToken; -import static org.radarbase.management.web.rest.errors.EntityName.USER; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_ACCESS_DENIED; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_EMAIL_NOT_REGISTERED; - -/** - * REST controller for managing the current user's account. - */ -@RestController -@RequestMapping("/api") -public class AccountResource { - - private static final Logger log = LoggerFactory.getLogger(AccountResource.class); - - @Autowired - private UserService userService; - - @Autowired - private MailService mailService; - - @Autowired - private UserMapper userMapper; - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Autowired - private AuthService authService; - - @Autowired - private PasswordService passwordService; - - @Autowired(required = false) - private RadarToken token; - - /** - * GET /activate : activate the registered user. - * - * @param key the activation key - * @return the ResponseEntity with status 200 (OK) and the activated user in body, or status 500 - * (Internal Server Error) if the user couldn't be activated - */ - @GetMapping("/activate") - @Timed - public ResponseEntity activateAccount(@RequestParam(value = "key") String key) { - return userService.activateRegistration(key) - .map(user -> new ResponseEntity(HttpStatus.OK)) - .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND)); - } - - /** - * POST /login : check if the user is authenticated. - * - * @param session the HTTP session - * @return user account details if the user is authenticated - */ - @PostMapping("/login") - @Timed - public UserDTO login(HttpSession session) throws NotAuthorizedException { - if (token == null) { - throw new NotAuthorizedException("Cannot login without credentials"); - } - log.debug("Logging in user to session with principal {}", token.getUsername()); - setRadarToken(session, new DataRadarToken(token)); - return getAccount(); - } - - /** - * POST /logout : log out. - * - * @param request the HTTP request - * @return no content response if the user is authenticated - */ - @PostMapping("/logout") - @Timed - public ResponseEntity logout(HttpServletRequest request) { - log.debug("Unauthenticate a user"); - HttpSession session = request.getSession(false); - if (session != null) { - session.invalidate(); - } - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - /** - * GET /account : get the current user. - * - * @return the ResponseEntity with status 200 (OK) and the current user in body, or status 401 - * (Internal Server Error) if the user couldn't be returned - */ - @GetMapping("/account") - @Timed - public UserDTO getAccount() { - User currentUser = userService.getUserWithAuthorities() - .orElseThrow(() -> new RadarWebApplicationException(HttpStatus.FORBIDDEN, - "Cannot get account without user", USER, ERR_ACCESS_DENIED)); - - UserDTO userDto = userMapper.userToUserDTO(currentUser); - if (managementPortalProperties.getAccount().getEnableExposeToken()) { - userDto.setAccessToken(token.getToken()); - } - return userDto; - } - - /** - * POST /account : update the current user information. - * - * @param userDto the current user information - * @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) or 500 (Internal - * Server Error) if the user couldn't be updated - */ - @PostMapping("/account") - @Timed - public ResponseEntity saveAccount(@Valid @RequestBody UserDTO userDto, - Authentication authentication) throws NotAuthorizedException { - authService.checkPermission(Permission.USER_UPDATE, e -> e.user(userDto.getLogin())); - userService.updateUser(authentication.getName(), userDto.getFirstName(), - userDto.getLastName(), userDto.getEmail(), userDto.getLangKey()); - - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - /** - * POST /account/change_password : changes the current user's password. - * - * @param password the new password - * @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) if the new - * password is not strong enough - */ - @PostMapping(path = "/account/change_password", - produces = MediaType.TEXT_PLAIN_VALUE) - @Timed - public ResponseEntity changePassword(@RequestBody String password) { - passwordService.checkPasswordStrength(password); - userService.changePassword(password); - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - - /** - * POST /account/reset-activation/init : Resend the password activation email - * to the user. - * - * @param login the login of the user - * @return the ResponseEntity with status 200 (OK) if the email was sent, or status 400 (Bad - * Request) if the email address is not registered or user is not deactivated - */ - @PostMapping(path = "/account/reset-activation/init") - @Timed - public ResponseEntity requestActivationReset(@RequestBody String login) { - User user = userService.requestActivationReset(login) - .orElseThrow(() -> new BadRequestException( - "Cannot find a deactivated user with login " + login, - USER, ERR_EMAIL_NOT_REGISTERED)); - - mailService.sendCreationEmail(user, managementPortalProperties.getCommon() - .getActivationKeyTimeoutInSeconds()); - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - /** - * POST /account/reset_password/init : Email the user a password reset link. - * - * @param mail the mail of the user - * @return the ResponseEntity with status 200 (OK) if the email was sent, or status 400 (Bad - * Request) if the email address is not registered - */ - @PostMapping(path = "/account/reset_password/init") - @Timed - public ResponseEntity requestPasswordReset(@RequestBody String mail) { - User user = userService.requestPasswordReset(mail) - .orElseThrow(() -> new BadRequestException("email address not registered", - USER, ERR_EMAIL_NOT_REGISTERED)); - - mailService.sendPasswordResetMail(user); - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - /** - * POST /account/reset_password/finish : Finish to reset the password of the user. - * - * @param keyAndPassword the generated key and the new password - * @return the ResponseEntity with status 200 (OK) if the password has been reset, or status 400 - * (Bad Request) or 500 (Internal Server Error) if the password could not be reset - */ - @PostMapping(path = "/account/reset_password/finish", - produces = MediaType.TEXT_PLAIN_VALUE) - @Timed - public ResponseEntity finishPasswordReset( - @RequestBody KeyAndPasswordVM keyAndPassword) { - passwordService.checkPasswordStrength(keyAndPassword.getNewPassword()); - return userService - .completePasswordReset(keyAndPassword.getNewPassword(), keyAndPassword.getKey()) - .map(user -> new ResponseEntity(HttpStatus.NO_CONTENT)) - .orElse(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/AccountResource.kt b/src/main/java/org/radarbase/management/web/rest/AccountResource.kt new file mode 100644 index 000000000..852d433a1 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/AccountResource.kt @@ -0,0 +1,234 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.auth.token.DataRadarToken +import org.radarbase.auth.token.RadarToken +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.User +import org.radarbase.management.security.JwtAuthenticationFilter +import org.radarbase.management.security.JwtAuthenticationFilter.Companion.radarToken +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.MailService +import org.radarbase.management.service.PasswordService +import org.radarbase.management.service.UserService +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.UserMapper +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.RadarWebApplicationException +import org.radarbase.management.web.rest.vm.KeyAndPasswordVM +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.security.core.Authentication +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import java.lang.Exception +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpSession +import javax.validation.Valid + +/** + * REST controller for managing the current user's account. + */ +@RestController +@RequestMapping("/api") +class AccountResource( + @Autowired private val userService: UserService, + @Autowired private val mailService: MailService, + @Autowired private val userMapper: UserMapper, + @Autowired private val managementPortalProperties: ManagementPortalProperties, + @Autowired private val authService: AuthService, + @Autowired private val passwordService: PasswordService +) { + + @Autowired(required = false) + private val token: RadarToken? = null + + /** + * GET /activate : activate the registered user. + * + * @param key the activation key + * @return the ResponseEntity with status 200 (OK) and the activated user in body, or status 500 + * (Internal Server Error) if the user couldn't be activated + */ + @GetMapping("/activate") + @Timed + fun activateAccount(@RequestParam(value = "key") key: String): ResponseEntity { + return try { + userService.activateRegistration(key) + ResponseEntity(HttpStatus.OK) + } catch (e: Exception) { + ResponseEntity(HttpStatus.NOT_FOUND) + } + } + + /** + * POST /login : check if the user is authenticated. + * + * @param session the HTTP session + * @return user account details if the user is authenticated + */ + @PostMapping("/login") + @Timed + @Throws(NotAuthorizedException::class) + fun login(session: HttpSession?): UserDTO? { + if (token == null) { + throw NotAuthorizedException("Cannot login without credentials") + } + log.debug("Logging in user to session with principal {}", token.username) + session?.radarToken = DataRadarToken(token) + return account + } + + /** + * POST /logout : log out. + * + * @param request the HTTP request + * @return no content response if the user is authenticated + */ + @PostMapping("/logout") + @Timed + fun logout(request: HttpServletRequest): ResponseEntity { + log.debug("Unauthenticate a user") + val session = request.getSession(false) + session?.invalidate() + return ResponseEntity(HttpStatus.NO_CONTENT) + } + + @get:Timed + @get:GetMapping("/account") + val account: UserDTO? + /** + * GET /account : get the current user. + * + * @return the ResponseEntity with status 200 (OK) and the current user in body, or status 401 + * (Internal Server Error) if the user couldn't be returned + */ + get() { + val currentUser = userService.userWithAuthorities + ?: throw RadarWebApplicationException( + HttpStatus.FORBIDDEN, + "Cannot get account without user", EntityName.Companion.USER, ErrorConstants.ERR_ACCESS_DENIED + ) + val userDto = userMapper.userToUserDTO(currentUser) + if (managementPortalProperties.account.enableExposeToken) { + userDto?.accessToken = token!!.token + } + return userDto + } + + /** + * POST /account : update the current user information. + * + * @param userDto the current user information + * @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) or 500 (Internal + * Server Error) if the user couldn't be updated + */ + @PostMapping("/account") + @Timed + @Throws(NotAuthorizedException::class) + fun saveAccount( + @RequestBody userDto: @Valid UserDTO, + authentication: Authentication + ): ResponseEntity { + authService.checkPermission(Permission.USER_UPDATE, { e: EntityDetails -> + e.user(userDto.login) }) + userService.updateUser( + authentication.name, userDto.firstName, + userDto.lastName, userDto.email, userDto.langKey + ) + return ResponseEntity(HttpStatus.NO_CONTENT) + } + + /** + * POST /account/change_password : changes the current user's password. + * + * @param password the new password + * @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) if the new + * password is not strong enough + */ + @PostMapping(path = ["/account/change_password"], produces = [MediaType.TEXT_PLAIN_VALUE]) + @Timed + fun changePassword(@RequestBody password: String): ResponseEntity { + passwordService.checkPasswordStrength(password) + userService.changePassword(password) + return ResponseEntity(HttpStatus.NO_CONTENT) + } + + /** + * POST /account/reset-activation/init : Resend the password activation email + * to the user. + * + * @param login the login of the user + * @return the ResponseEntity with status 200 (OK) if the email was sent, or status 400 (Bad + * Request) if the email address is not registered or user is not deactivated + */ + @PostMapping(path = ["/account/reset-activation/init"]) + @Timed + fun requestActivationReset(@RequestBody login: String): ResponseEntity { + val user = userService.requestActivationReset(login) + ?: throw BadRequestException( + "Cannot find a deactivated user with login $login", + EntityName.Companion.USER, ErrorConstants.ERR_EMAIL_NOT_REGISTERED + ) + + mailService.sendCreationEmail( + user, managementPortalProperties.common + .activationKeyTimeoutInSeconds.toLong() + ) + return ResponseEntity(HttpStatus.NO_CONTENT) + } + + /** + * POST /account/reset_password/init : Email the user a password reset link. + * + * @param mail the mail of the user + * @return the ResponseEntity with status 200 (OK) if the email was sent, or status 400 (Bad + * Request) if the email address is not registered + */ + @PostMapping(path = ["/account/reset_password/init"]) + @Timed + fun requestPasswordReset(@RequestBody mail: String): ResponseEntity { + val user = userService.requestPasswordReset(mail) + ?: throw BadRequestException( + "email address not registered", + EntityName.Companion.USER, ErrorConstants.ERR_EMAIL_NOT_REGISTERED + ) + mailService.sendPasswordResetMail(user) + return ResponseEntity(HttpStatus.NO_CONTENT) + } + + /** + * POST /account/reset_password/finish : Finish to reset the password of the user. + * + * @param keyAndPassword the generated key and the new password + * @return the ResponseEntity with status 200 (OK) if the password has been reset, or status 400 + * (Bad Request) or 500 (Internal Server Error) if the password could not be reset + */ + @PostMapping(path = ["/account/reset_password/finish"], produces = [MediaType.TEXT_PLAIN_VALUE]) + @Timed + fun finishPasswordReset( + @RequestBody keyAndPassword: KeyAndPasswordVM + ): ResponseEntity { + passwordService.checkPasswordStrength(keyAndPassword.newPassword) + userService.completePasswordReset(keyAndPassword.newPassword, keyAndPassword.key) + ?: return ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) + + return ResponseEntity(HttpStatus.NO_CONTENT) + } + + companion object { + private val log = LoggerFactory.getLogger(AccountResource::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/AuditResource.java b/src/main/java/org/radarbase/management/web/rest/AuditResource.java deleted file mode 100644 index a7f87675d..000000000 --- a/src/main/java/org/radarbase/management/web/rest/AuditResource.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.swagger.v3.oas.annotations.Parameter; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuditEventService; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import tech.jhipster.web.util.ResponseUtil; - -import java.time.LocalDate; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.AUDIT_READ; - -/** - * REST controller for getting the audit events. - */ -@RestController -@RequestMapping("/management/audits") -public class AuditResource { - private final AuditEventService auditEventService; - private final AuthService authService; - - public AuditResource(AuditEventService auditEventService, AuthService authService) { - this.auditEventService = auditEventService; - this.authService = authService; - } - - /** - * GET /audits : get a page of AuditEvents. - * - * @param pageable the pagination information - * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body - */ - @GetMapping - public ResponseEntity> getAll(@Parameter Pageable pageable) - throws NotAuthorizedException { - authService.checkPermission(AUDIT_READ); - Page page = auditEventService.findAll(pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/management/audits"); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } - - /** - * GET /audits : get a page of AuditEvents between the fromDate and toDate. - * - * @param fromDate the start of the time period of AuditEvents to get - * @param toDate the end of the time period of AuditEvents to get - * @param pageable the pagination information - * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body - */ - - @GetMapping(params = {"fromDate", "toDate"}) - public ResponseEntity> getByDates( - @RequestParam(value = "fromDate") LocalDate fromDate, - @RequestParam(value = "toDate") LocalDate toDate, - @Parameter Pageable pageable) throws NotAuthorizedException { - authService.checkPermission(AUDIT_READ); - Page page = auditEventService - .findByDates(fromDate.atTime(0, 0), toDate.atTime(23, 59), pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/management/audits"); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } - - /** - * GET /audits/:id : get an AuditEvent by id. - * - * @param id the id of the entity to get - * @return the ResponseEntity with status 200 (OK) and the AuditEvent in body, or status - * 404 (Not Found) - */ - @GetMapping("/{id:.+}") - public ResponseEntity get(@PathVariable Long id) throws NotAuthorizedException { - authService.checkPermission(AUDIT_READ); - return ResponseUtil.wrapOrNotFound(auditEventService.find(id)); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/AuditResource.kt b/src/main/java/org/radarbase/management/web/rest/AuditResource.kt new file mode 100644 index 000000000..04b80b4c4 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/AuditResource.kt @@ -0,0 +1,77 @@ +package org.radarbase.management.web.rest + +import io.swagger.v3.oas.annotations.Parameter +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuditEventService +import org.radarbase.management.service.AuthService +import org.radarbase.management.web.rest.util.PaginationUtil +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.data.domain.Pageable +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.time.LocalDate + +/** + * REST controller for getting the audit events. + */ +@RestController +@RequestMapping("/management/audits") +class AuditResource(private val auditEventService: AuditEventService, private val authService: AuthService) { + /** + * GET /audits : get a page of AuditEvents. + * + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body + */ + @GetMapping + @Throws(NotAuthorizedException::class) + fun getAll(@Parameter pageable: Pageable?): ResponseEntity> { + authService.checkPermission(Permission.AUDIT_READ) + val page = auditEventService.findAll(pageable) + val headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits") + return ResponseEntity(page!!.content, headers, HttpStatus.OK) + } + + /** + * GET /audits : get a page of AuditEvents between the fromDate and toDate. + * + * @param fromDate the start of the time period of AuditEvents to get + * @param toDate the end of the time period of AuditEvents to get + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body + */ + @GetMapping(params = ["fromDate", "toDate"]) + @Throws(NotAuthorizedException::class) + fun getByDates( + @RequestParam(value = "fromDate") fromDate: LocalDate, + @RequestParam(value = "toDate") toDate: LocalDate, + @Parameter pageable: Pageable? + ): ResponseEntity> { + authService.checkPermission(Permission.AUDIT_READ) + val page = auditEventService + .findByDates(fromDate.atTime(0, 0), toDate.atTime(23, 59), pageable) + val headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits") + return ResponseEntity(page!!.content, headers, HttpStatus.OK) + } + + /** + * GET /audits/:id : get an AuditEvent by id. + * + * @param id the id of the entity to get + * @return the ResponseEntity with status 200 (OK) and the AuditEvent in body, or status + * 404 (Not Found) + */ + @GetMapping("/{id:.+}") + @Throws(NotAuthorizedException::class) + operator fun get(@PathVariable id: Long): ResponseEntity { + authService.checkPermission(Permission.AUDIT_READ) + return ResponseUtil.wrapOrNotFound(auditEventService.find(id)) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/GroupResource.java b/src/main/java/org/radarbase/management/web/rest/GroupResource.java deleted file mode 100644 index 3bafc1289..000000000 --- a/src/main/java/org/radarbase/management/web/rest/GroupResource.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.web.rest; - -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.GroupService; -import org.radarbase.management.service.dto.GroupDTO; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.vm.GroupPatchOperation; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; - -import javax.validation.Valid; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.PROJECT_READ; -import static org.radarbase.auth.authorization.Permission.PROJECT_UPDATE; -import static org.radarbase.auth.authorization.Permission.SUBJECT_UPDATE; -import static org.radarbase.management.web.rest.errors.EntityName.GROUP; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_VALIDATION; - -@RestController -@RequestMapping("/api/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/groups") -public class GroupResource { - @Autowired - private GroupService groupService; - - @Autowired - private AuthService authService; - - /** - * Create group. - * @param projectName project name - * @param groupDto group specification - * @return created response - * @throws NotAuthorizedException if PROJECT_UPDATE permissions are not present. - */ - @PostMapping - public ResponseEntity createGroup( - @PathVariable String projectName, - @Valid @RequestBody GroupDTO groupDto) throws NotAuthorizedException { - authService.checkPermission(PROJECT_UPDATE, e -> e.project(projectName)); - GroupDTO groupDtoResult = groupService.createGroup(projectName, groupDto); - URI location = MvcUriComponentsBuilder.fromController(getClass()) - .path("/{groupName}") - .buildAndExpand(projectName, groupDtoResult.getName()) - .toUri(); - return ResponseEntity.created(location) - .body(groupDtoResult); - } - - /** - * List groups. - * @param projectName project name - * @return list of groups - * @throws NotAuthorizedException if PROJECT_READ permissions are not present. - */ - @GetMapping - public List listGroups( - @PathVariable String projectName) throws NotAuthorizedException { - authService.checkPermission(PROJECT_READ, e -> e.project(projectName)); - return groupService.listGroups(projectName); - } - - /** - * Get a single group. - * @param projectName project name - * @param groupName group name - * @return group - * @throws NotAuthorizedException if PROJECT_READ permissions are not present. - */ - @GetMapping("/{groupName:" + Constants.ENTITY_ID_REGEX + "}") - public GroupDTO getGroup( - @PathVariable String projectName, - @PathVariable String groupName) throws NotAuthorizedException { - authService.checkPermission(PROJECT_READ, e -> e.project(projectName)); - return groupService.getGroup(projectName, groupName); - } - - /** - * Delete a single group. - * @param projectName project name - * @param groupName group name - * @throws NotAuthorizedException if PROJECT_UPDATE permissions are not present. - */ - @DeleteMapping("/{groupName:" + Constants.ENTITY_ID_REGEX + "}") - public ResponseEntity deleteGroup( - @RequestParam(defaultValue = "false") Boolean unlinkSubjects, - @PathVariable String projectName, - @PathVariable String groupName) throws NotAuthorizedException { - authService.checkPermission(PROJECT_UPDATE, e -> e.project(projectName)); - groupService.deleteGroup(projectName, groupName, unlinkSubjects); - return ResponseEntity.noContent().build(); - } - - /** - * Add subjects to a single group. - * @param projectName project name - * @param groupName group name - * @param patchOperations json-patch request body - * @throws NotAuthorizedException if PROJECT_UPDATE permissions are not present. - */ - @PatchMapping("/{groupName:" + Constants.ENTITY_ID_REGEX + "}/subjects") - public ResponseEntity changeGroupSubjects( - @PathVariable String projectName, - @PathVariable String groupName, - @RequestBody List patchOperations) throws NotAuthorizedException { - // Technically, this request modifies subjects, - // so it would make sense to check permissions per subject, - // but I assume that only those who are authorized to perform project-wide actions - // should be allowed to use this endpoint - authService.checkPermission(SUBJECT_UPDATE, e -> e.project(projectName)); - - var addedItems = new ArrayList(); - var removedItems = new ArrayList(); - for (GroupPatchOperation operation : patchOperations) { - String opCode = operation.getOp(); - switch (opCode) { - case "add": - addedItems.addAll(operation.getValue()); - break; - case "remove": - removedItems.addAll(operation.getValue()); - break; - default: - throw new BadRequestException( - "Group patch operation '" + opCode + "' is not supported", - GROUP, ERR_VALIDATION); - } - } - - groupService.updateGroupSubjects(projectName, groupName, addedItems, removedItems); - return ResponseEntity.noContent().build(); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/GroupResource.kt b/src/main/java/org/radarbase/management/web/rest/GroupResource.kt new file mode 100644 index 000000000..22ab46839 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/GroupResource.kt @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.web.rest + +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.GroupService +import org.radarbase.management.service.dto.GroupDTO +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.vm.GroupPatchOperation +import org.radarbase.management.web.rest.vm.GroupPatchOperation.SubjectPatchValue +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PatchMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder +import javax.validation.Valid + +@RestController +@RequestMapping("/api/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/groups") +class GroupResource { + @Autowired + private val groupService: GroupService? = null + + @Autowired + private val authService: AuthService? = null + + /** + * Create group. + * @param projectName project name + * @param groupDto group specification + * @return created response + * @throws NotAuthorizedException if PROJECT_UPDATE permissions are not present. + */ + @PostMapping + @Throws(NotAuthorizedException::class) + fun createGroup( + @PathVariable projectName: String?, + @RequestBody groupDto: @Valid GroupDTO? + ): ResponseEntity { + authService!!.checkPermission(Permission.PROJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) + val groupDtoResult = groupService!!.createGroup(projectName!!, groupDto!!) + val location = MvcUriComponentsBuilder.fromController(javaClass) + .path("/{groupName}") + .buildAndExpand(projectName, groupDtoResult?.name) + .toUri() + return ResponseEntity.created(location) + .body(groupDtoResult) + } + + /** + * List groups. + * @param projectName project name + * @return list of groups + * @throws NotAuthorizedException if PROJECT_READ permissions are not present. + */ + @GetMapping + @Throws(NotAuthorizedException::class) + fun listGroups( + @PathVariable projectName: String? + ): List { + authService!!.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.project(projectName) }) + return groupService!!.listGroups(projectName!!) + } + + /** + * Get a single group. + * @param projectName project name + * @param groupName group name + * @return group + * @throws NotAuthorizedException if PROJECT_READ permissions are not present. + */ + @GetMapping("/{groupName:" + Constants.ENTITY_ID_REGEX + "}") + @Throws( + NotAuthorizedException::class + ) + fun getGroup( + @PathVariable projectName: String?, + @PathVariable groupName: String? + ): GroupDTO { + authService!!.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.project(projectName) }) + return groupService!!.getGroup(projectName!!, groupName!!) + } + + /** + * Delete a single group. + * @param projectName project name + * @param groupName group name + * @throws NotAuthorizedException if PROJECT_UPDATE permissions are not present. + */ + @DeleteMapping("/{groupName:" + Constants.ENTITY_ID_REGEX + "}") + @Throws( + NotAuthorizedException::class + ) + fun deleteGroup( + @RequestParam(defaultValue = "false") unlinkSubjects: Boolean?, + @PathVariable projectName: String?, + @PathVariable groupName: String? + ): ResponseEntity<*> { + authService!!.checkPermission(Permission.PROJECT_UPDATE, { (_, project): EntityDetails -> project }) + groupService!!.deleteGroup(projectName!!, groupName!!, unlinkSubjects!!) + return ResponseEntity.noContent().build() + } + + /** + * Add subjects to a single group. + * @param projectName project name + * @param groupName group name + * @param patchOperations json-patch request body + * @throws NotAuthorizedException if PROJECT_UPDATE permissions are not present. + */ + @PatchMapping("/{groupName:" + Constants.ENTITY_ID_REGEX + "}/subjects") + @Throws( + NotAuthorizedException::class + ) + fun changeGroupSubjects( + @PathVariable projectName: String?, + @PathVariable groupName: String?, + @RequestBody patchOperations: List + ): ResponseEntity<*> { + // Technically, this request modifies subjects, + // so it would make sense to check permissions per subject, + // but I assume that only those who are authorized to perform project-wide actions + // should be allowed to use this endpoint + authService!!.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) + val addedItems = ArrayList() + val removedItems = ArrayList() + for (operation in patchOperations) { + val opCode = operation.op + when (opCode) { + "add" -> operation.value?.let { addedItems.addAll(it) } + "remove" -> operation.value?.let { removedItems.addAll(it) } + else -> throw BadRequestException( + "Group patch operation '$opCode' is not supported", + EntityName.Companion.GROUP, ErrorConstants.ERR_VALIDATION + ) + } + } + groupService!!.updateGroupSubjects(projectName!!, groupName!!, addedItems.filterNotNull(), removedItems.filterNotNull()) + return ResponseEntity.noContent().build() + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/LogsResource.java b/src/main/java/org/radarbase/management/web/rest/LogsResource.java deleted file mode 100644 index 16101a535..000000000 --- a/src/main/java/org/radarbase/management/web/rest/LogsResource.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.radarbase.management.web.rest; - -import ch.qos.logback.classic.Level; -import ch.qos.logback.classic.LoggerContext; -import io.micrometer.core.annotation.Timed; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.web.rest.vm.LoggerVM; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.security.access.annotation.Secured; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; - -/** - * Controller for view and managing Log Level at runtime. - */ -@RestController -@RequestMapping("/management") -public class LogsResource { - - /** - * Returns all the logger configurations from current logger context. - * @return the logger configurations - */ - @GetMapping("/logs") - @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public List getList() { - LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); - return context.getLoggerList() - .stream() - .map(LoggerVM::new) - .toList(); - } - - /** - * Changes logger level. - * @param jsonLogger param - */ - @PutMapping("/logs") - @ResponseStatus(HttpStatus.NO_CONTENT) - @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public void changeLevel(@RequestBody LoggerVM jsonLogger) { - LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); - context.getLogger(jsonLogger.getName()).setLevel(Level.valueOf(jsonLogger.getLevel())); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/LogsResource.kt b/src/main/java/org/radarbase/management/web/rest/LogsResource.kt new file mode 100644 index 000000000..d5d8a93ad --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/LogsResource.kt @@ -0,0 +1,53 @@ +package org.radarbase.management.web.rest + +import ch.qos.logback.classic.Level +import ch.qos.logback.classic.Logger +import ch.qos.logback.classic.LoggerContext +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.web.rest.vm.LoggerVM +import org.slf4j.LoggerFactory +import org.springframework.http.HttpStatus +import org.springframework.security.access.annotation.Secured +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.ResponseStatus +import org.springframework.web.bind.annotation.RestController + +/** + * Controller for view and managing Log Level at runtime. + */ +@RestController +@RequestMapping("/management") +class LogsResource { + @get:Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + @get:Timed + @get:GetMapping("/logs") + val list: List + /** + * Returns all the logger configurations from current logger context. + * @return the logger configurations + */ + get() { + val context = LoggerFactory.getILoggerFactory() as LoggerContext + return context.getLoggerList() + .stream() + .map { logger: Logger -> LoggerVM(logger) } + .toList() + } + + /** + * Changes logger level. + * @param jsonLogger param + */ + @PutMapping("/logs") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Timed + @Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + fun changeLevel(@RequestBody jsonLogger: LoggerVM) { + val context = LoggerFactory.getILoggerFactory() as LoggerContext + context.getLogger(jsonLogger.name).setLevel(Level.valueOf(jsonLogger.level)) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt index efd23ea2e..71bdf0406 100644 --- a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt @@ -171,7 +171,7 @@ class OAuthClientsResource { @PostMapping("/oauth-clients") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createOAuthClient(@RequestBody clientDetailsDto: @Valid ClientDetailsDTO?): ResponseEntity { + fun createOAuthClient(@RequestBody clientDetailsDto: @Valid ClientDetailsDTO): ResponseEntity { authService!!.checkPermission(Permission.OAUTHCLIENTS_CREATE) val created = oAuthClientService!!.createClientDetail(clientDetailsDto) return ResponseEntity.created(ResourceUriService.getUri(clientDetailsDto)) @@ -202,11 +202,9 @@ class OAuthClientsResource { authService!!.checkScope(Permission.SUBJECT_UPDATE) val currentUser = userService!!.userWithAuthorities // We only allow this for actual logged in users for now, not for client_credentials - .orElseThrow { - AccessDeniedException( + ?: throw AccessDeniedException( "You must be a logged in user to access this resource" ) - } // lookup the subject val subject = subjectService!!.findOneByLogin(login) diff --git a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt index 582e81030..ad99b72e5 100644 --- a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt @@ -1,130 +1,124 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.OrganizationService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.dto.OrganizationDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.ORGANIZATION_CREATE; -import static org.radarbase.auth.authorization.Permission.ORGANIZATION_READ; -import static org.radarbase.auth.authorization.Permission.ORGANIZATION_UPDATE; -import static org.radarbase.auth.authorization.Permission.PROJECT_READ; -import static org.radarbase.management.web.rest.errors.EntityName.ORGANIZATION; +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.OrganizationService +import org.radarbase.management.service.ResourceUriService.getUri +import org.radarbase.management.service.dto.OrganizationDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityCreationAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createFailureAlert +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import java.net.URISyntaxException +import java.util.* +import javax.validation.Valid /** * REST controller for managing Organization. */ @RestController @RequestMapping("/api") -public class OrganizationResource { - - private static final Logger log = LoggerFactory.getLogger(OrganizationResource.class); - - private static final String ENTITY_NAME = "organization"; - +class OrganizationResource { @Autowired - private OrganizationService organizationService; + private val organizationService: OrganizationService? = null @Autowired - private AuthService authService; + private val authService: AuthService? = null /** * POST /organizations : Create a new organization. * * @param organizationDto the organizationDto to create * @return the ResponseEntity with status 201 (Created) - * and with body the new organizationDto, - * or with status 400 (Bad Request) if the organization already has an ID + * and with body the new organizationDto, + * or with status 400 (Bad Request) if the organization already has an ID * @throws URISyntaxException if the Location URI syntax is incorrect */ @PostMapping("/organizations") @Timed - public ResponseEntity createOrganization( - @Valid @RequestBody OrganizationDTO organizationDto - ) throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save Organization : {}", organizationDto); - authService.checkPermission(ORGANIZATION_CREATE); - if (organizationDto.getId() != null) { - var msg = "A new organization cannot already have an ID"; - var headers = HeaderUtil.createFailureAlert(ENTITY_NAME, "idexists", msg); - return ResponseEntity.badRequest().headers(headers).body(null); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createOrganization( + @RequestBody organizationDto: @Valid OrganizationDTO? + ): ResponseEntity { + log.debug("REST request to save Organization : {}", organizationDto) + authService!!.checkPermission(Permission.ORGANIZATION_CREATE) + if (organizationDto!!.id != null) { + val msg = "A new organization cannot already have an ID" + val headers = createFailureAlert(ENTITY_NAME, "idexists", msg) + return ResponseEntity.badRequest().headers(headers).body(null) } - var existingOrg = organizationService.findByName(organizationDto.getName()); - if (existingOrg.isPresent()) { - var msg = "An organization with this name already exists"; - var headers = HeaderUtil.createFailureAlert(ENTITY_NAME, "nameexists", msg); - return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers).body(null); + val existingOrg = organizationService!!.findByName(organizationDto.name) + if (existingOrg != null) { + val msg = "An organization with this name already exists" + val headers = createFailureAlert(ENTITY_NAME, "nameexists", msg) + return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers).body(null) } - var result = organizationService.save(organizationDto); - return ResponseEntity.created(ResourceUriService.getUri(result)) - .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getName())) - .body(result); + val result = organizationService.save(organizationDto) + return ResponseEntity.created(getUri(result)) + .headers(createEntityCreationAlert(ENTITY_NAME, result.name)) + .body(result) } - /** - * GET /organizations : get all the organizations. - * - * @return the ResponseEntity with status 200 (OK) - * and the list of organizations in body - */ - @GetMapping("/organizations") - @Timed - public ResponseEntity getAllOrganizations() throws NotAuthorizedException { - log.debug("REST request to get Organizations"); - authService.checkScope(ORGANIZATION_READ); - var orgs = organizationService.findAll(); - return new ResponseEntity<>(orgs, HttpStatus.OK); - } + @get:Throws(NotAuthorizedException::class) + @get:Timed + @get:GetMapping("/organizations") + val allOrganizations: ResponseEntity<*> + /** + * GET /organizations : get all the organizations. + * + * @return the ResponseEntity with status 200 (OK) + * and the list of organizations in body + */ + get() { + log.debug("REST request to get Organizations") + authService!!.checkScope(Permission.ORGANIZATION_READ) + val orgs = organizationService!!.findAll() + return ResponseEntity(orgs, HttpStatus.OK) + } /** * PUT /organizations : Updates an existing organization. * * @param organizationDto the organizationDto to update * @return the ResponseEntity - * with status 200 and with the updated organizationDto as body, - * or with status 400 if the organizationDto is not valid, - * or with status 500 if the organizationDto couldnt be updated + * with status 200 and with the updated organizationDto as body, + * or with status 400 if the organizationDto is not valid, + * or with status 500 if the organizationDto couldnt be updated * @throws URISyntaxException if the Location URI syntax is incorrect */ @PutMapping("/organizations") @Timed - public ResponseEntity updateOrganization( - @Valid @RequestBody OrganizationDTO organizationDto - ) throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update Organization : {}", organizationDto); - if (organizationDto.getId() == null) { - return createOrganization(organizationDto); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun updateOrganization( + @RequestBody organizationDto: @Valid OrganizationDTO? + ): ResponseEntity { + log.debug("REST request to update Organization : {}", organizationDto) + if (organizationDto!!.id == null) { + return createOrganization(organizationDto) } - var name = organizationDto.getName(); - authService.checkPermission(ORGANIZATION_UPDATE, e -> e.organization(name)); - var result = organizationService.save(organizationDto); + val name = organizationDto.name + authService!!.checkPermission(Permission.ORGANIZATION_UPDATE, { (organization): EntityDetails -> organization }) + val result = organizationService!!.save(organizationDto) return ResponseEntity.ok() - .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getName())) - .body(result); + .headers(createEntityCreationAlert(ENTITY_NAME, result.name)) + .body(result) } /** @@ -132,39 +126,53 @@ public class OrganizationResource { * * @param name the name of the organizationDTO to retrieve * @return the ResponseEntity with status 200 (OK) - * and with body the organizationDTO, - * or with status 404 (Not Found) + * and with body the organizationDTO, + * or with status 404 (Not Found) */ @GetMapping("/organizations/{name:" + Constants.ENTITY_ID_REGEX + "}") @Timed - public ResponseEntity getOrganization( - @PathVariable String name) throws NotAuthorizedException { - log.debug("REST request to get Organization : {}", name); - authService.checkPermission(ORGANIZATION_READ, e -> e.organization(name)); - var org = organizationService.findByName(name); - var dto = org.orElseThrow(() -> new NotFoundException( - "Organization not found with name " + name, - ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, - Collections.singletonMap("name", name))); - return ResponseEntity.ok(dto); + @Throws( + NotAuthorizedException::class + ) + fun getOrganization( + @PathVariable name: String + ): ResponseEntity { + log.debug("REST request to get Organization : {}", name) + authService!!.checkPermission(Permission.ORGANIZATION_READ, { (organization): EntityDetails -> organization }) + val org = organizationService!!.findByName(name) + val dto = org ?: throw NotFoundException( + "Organization not found with name $name", + EntityName.ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, + Collections.singletonMap("name", name) + ) + return ResponseEntity.ok(dto) } /** * GET /organizations/:organizationName/projects - * : get projects belonging to the organization with this name. + * : get projects belonging to the organization with this name. * * @param name the name of the organization * @return the ResponseEntity - * with status 200 (OK) and with body containing the project list, - * or with status 404 (Not Found) + * with status 200 (OK) and with body containing the project list, + * or with status 404 (Not Found) */ @GetMapping("/organizations/{name:" + Constants.ENTITY_ID_REGEX + "}/projects") @Timed - public ResponseEntity> getOrganizationProjects( - @PathVariable String name) throws NotAuthorizedException { - log.debug("REST request to get Projects of the Organization : {}", name); - authService.checkPermission(PROJECT_READ, e -> e.organization(name)); - var projects = organizationService.findAllProjectsByOrganizationName(name); - return ResponseEntity.ok(projects); + @Throws( + NotAuthorizedException::class + ) + fun getOrganizationProjects( + @PathVariable name: String? + ): ResponseEntity> { + log.debug("REST request to get Projects of the Organization : {}", name) + authService!!.checkPermission(Permission.PROJECT_READ, { (organization): EntityDetails -> organization }) + val projects = organizationService!!.findAllProjectsByOrganizationName(name!!) + return ResponseEntity.ok(projects) + } + + companion object { + private val log = LoggerFactory.getLogger(OrganizationResource::class.java) + private const val ENTITY_NAME = "organization" } } diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index d622155e6..842c51558 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -23,8 +23,11 @@ import org.radarbase.management.web.rest.criteria.SubjectCriteria import org.radarbase.management.web.rest.errors.BadRequestException import org.radarbase.management.web.rest.errors.ErrorConstants import org.radarbase.management.web.rest.errors.ErrorVM -import org.radarbase.management.web.rest.util.HeaderUtil -import org.radarbase.management.web.rest.util.HeaderUtil.* +import org.radarbase.management.web.rest.util.HeaderUtil.buildPath +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityCreationAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityDeletionAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityUpdateAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createFailureAlert import org.radarbase.management.web.rest.util.PaginationUtil import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired @@ -43,6 +46,7 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController import java.net.URISyntaxException +import java.util.NoSuchElementException import javax.validation.Valid /** @@ -105,7 +109,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, .headers( createEntityCreationAlert( ENTITY_NAME, - result.projectName + result?.projectName ) ) .body(result) @@ -139,8 +143,8 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, } // When clients want to transfer a project, // they must have permissions to modify both new & old organizations - val existingProject = projectService.findOne(projectDto.id) - if (existingProject.projectName != projectDto.projectName) { + val existingProject = projectService.findOne(projectDto.id!!) + if (existingProject?.projectName != projectDto.projectName) { throw BadRequestException( "The project name cannot be modified.", ENTITY_NAME, ErrorConstants.ERR_VALIDATION @@ -151,9 +155,9 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, Permission.PROJECT_UPDATE, { e: EntityDetails -> e.organization(newOrgName) - e.project(existingProject.projectName) + e.project(existingProject?.projectName) }) - val oldOrgName = existingProject.organization.name + val oldOrgName = existingProject?.organization?.name if (newOrgName != oldOrgName) { authService.checkPermission( Permission.PROJECT_UPDATE, @@ -179,8 +183,8 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, @Timed @Throws(NotAuthorizedException::class) fun getAllProjects( - @PageableDefault(size = Int.MAX_VALUE) pageable: Pageable?, - @RequestParam(name = "minimized", required = false, defaultValue = "false") minimized: Boolean? + @PageableDefault(size = Int.MAX_VALUE) pageable: Pageable, + @RequestParam(name = "minimized", required = false, defaultValue = "false") minimized: Boolean ): ResponseEntity<*> { log.debug("REST request to get Projects") authService.checkPermission(Permission.PROJECT_READ) @@ -207,7 +211,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, log.debug("REST request to get Project : {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> - e.organization(projectDto.organization.name) + e.organization(projectDto.organization?.name) e.project(projectDto.projectName) }) return ResponseEntity.ok(projectDto) @@ -230,10 +234,10 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, log.debug("REST request to get Project : {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> - e.organization(projectDto.organization.name) + e.organization(projectDto.organization?.name) e.project(projectDto.projectName) }) - return projectService.findSourceTypesByProjectId(projectDto.id) + return projectService.findSourceTypesByProjectId(projectDto.id!!) } /** @@ -252,11 +256,11 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, log.debug("REST request to delete Project : {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.PROJECT_DELETE, { e: EntityDetails -> - e.organization(projectDto.organization.name) + e.organization(projectDto.organization?.name) e.project(projectDto.projectName) }) return try { - projectService.delete(projectDto.id) + projectService.delete(projectDto.id!!) ResponseEntity.ok() .headers(createEntityDeletionAlert(ENTITY_NAME, projectName)) .build() @@ -281,7 +285,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, log.debug("REST request to get all Roles for project {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.ROLE_READ, { e: EntityDetails -> - e.organization(projectDto.organization.name) + e.organization(projectDto.organization?.name) e.project(projectDto.projectName) }) return ResponseEntity.ok(roleService.getRolesByProject(projectName)) @@ -298,16 +302,17 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, NotAuthorizedException::class ) fun getAllSourcesForProject( - @Parameter pageable: Pageable?, - @PathVariable projectName: String?, + @Parameter pageable: Pageable, + @PathVariable projectName: String, @RequestParam(value = "assigned", required = false) assigned: Boolean?, @RequestParam(name = "minimized", required = false, defaultValue = "false") minimized: Boolean ): ResponseEntity<*> { authService.checkScope(Permission.SOURCE_READ) log.debug("REST request to get all Sources") - val projectDto = projectService.findOneByName(projectName!!) + val projectDto = projectService.findOneByName(projectName) ?: throw NoSuchElementException() + authService.checkPermission(Permission.SOURCE_READ, { e: EntityDetails -> - e.organization(projectDto.organization.name) + e.organization(projectDto.organization?.name) e.project(projectDto.projectName) }) return if (assigned != null) { @@ -327,7 +332,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, } else { if (minimized) { val page = sourceService - .findAllMinimalSourceDetailsByProject(projectDto.id, pageable) + .findAllMinimalSourceDetailsByProject(projectDto.id!!, pageable) val headers = PaginationUtil .generatePaginationHttpHeaders( page, buildPath( @@ -338,7 +343,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, ResponseEntity(page.content, headers, HttpStatus.OK) } else { val page = sourceService - .findAllByProjectId(projectDto.id, pageable) + .findAllByProjectId(projectDto.id!!, pageable) val headers = PaginationUtil .generatePaginationHttpHeaders( page, buildPath( @@ -365,23 +370,27 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, subjectCriteria: @Valid SubjectCriteria? ): ResponseEntity> { authService.checkScope(Permission.SUBJECT_READ) - val projectName = subjectCriteria!!.projectName + + + val projectName = subjectCriteria!!.projectName ?: throw NoSuchElementException() // this checks if the project exists - val projectDto = projectService.findOneByName(projectName) + val projectDto = projectName.let { projectService.findOneByName(it) } authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> - e.organization(projectDto.organization.name) + e.organization(projectDto.organization?.name) e.project(projectDto.projectName) }) // this checks if the project exists projectService.findOneByName(projectName) + + subjectCriteria.projectName = projectName log.debug( "REST request to get all subjects for project {} using criteria {}", projectName, subjectCriteria ) val page = subjectService.findAll(subjectCriteria) - .map { subject: Subject? -> subjectMapper.subjectToSubjectWithoutProjectDTO(subject) } + .map { subject: Subject -> subjectMapper.subjectToSubjectWithoutProjectDTO(subject) } val baseUri = buildPath("api", "projects", projectName, "subjects") val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( page, baseUri, subjectCriteria diff --git a/src/main/java/org/radarbase/management/web/rest/RevisionResource.kt b/src/main/java/org/radarbase/management/web/rest/RevisionResource.kt index 2c7312f3b..235c2f6fe 100644 --- a/src/main/java/org/radarbase/management/web/rest/RevisionResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/RevisionResource.kt @@ -1,34 +1,27 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.service.RevisionService; -import org.radarbase.management.service.dto.RevisionInfoDTO; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.annotation.Secured; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.service.RevisionService +import org.radarbase.management.service.dto.RevisionInfoDTO +import org.radarbase.management.web.rest.util.PaginationUtil.generatePaginationHttpHeaders +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Pageable +import org.springframework.data.web.PageableDefault +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.security.access.annotation.Secured +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/api") -public class RevisionResource { - - private static final Logger log = LoggerFactory.getLogger(RevisionResource.class); - +class RevisionResource { @Autowired - private RevisionService revisionService; + private val revisionService: RevisionService? = null /** * Pageable API to get revisions. @@ -38,13 +31,13 @@ public class RevisionResource { */ @GetMapping("/revisions") @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public ResponseEntity> getRevisions( - @PageableDefault(page = 0, size = Integer.MAX_VALUE) Pageable pageable) { - log.debug("REST request to get page of revisions"); - Page page = revisionService.getRevisions(pageable); - return new ResponseEntity<>(page.getContent(), PaginationUtil - .generatePaginationHttpHeaders(page, "/api/revisions"), HttpStatus.OK); + @Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + fun getRevisions( + @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable? + ): ResponseEntity> { + log.debug("REST request to get page of revisions") + val page = revisionService!!.getRevisions(pageable!!) + return ResponseEntity(page.content, generatePaginationHttpHeaders(page, "/api/revisions"), HttpStatus.OK) } /** @@ -55,9 +48,13 @@ public class RevisionResource { */ @GetMapping("/revisions/{id}") @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public ResponseEntity getRevision(@PathVariable("id") Integer id) { - log.debug("REST request to get single revision: {}", id.toString()); - return ResponseEntity.ok(revisionService.getRevision(id)); + @Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + fun getRevision(@PathVariable("id") id: Int): ResponseEntity { + log.debug("REST request to get single revision: {}", id.toString()) + return ResponseEntity.ok(revisionService!!.getRevision(id)) + } + + companion object { + private val log = LoggerFactory.getLogger(RevisionResource::class.java) } } diff --git a/src/main/java/org/radarbase/management/web/rest/RoleResource.java b/src/main/java/org/radarbase/management/web/rest/RoleResource.java deleted file mode 100644 index 0593e7d80..000000000 --- a/src/main/java/org/radarbase/management/web/rest/RoleResource.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.RoleService; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.annotation.Secured; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import tech.jhipster.web.util.ResponseUtil; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.ROLE_CREATE; -import static org.radarbase.auth.authorization.Permission.ROLE_READ; -import static org.radarbase.auth.authorization.Permission.ROLE_UPDATE; - -/** - * REST controller for managing Role. - */ -@RestController -@RequestMapping("/api") -public class RoleResource { - - private static final Logger log = LoggerFactory.getLogger(RoleResource.class); - - private static final String ENTITY_NAME = "role"; - - @Autowired - private RoleService roleService; - @Autowired - private AuthService authService; - - /** - * POST /Roles : Create a new role. - * - * @param roleDto the roleDto to create - * @return the ResponseEntity with status 201 (Created) and with body the new RoleDTO, or with - * status 400 (Bad Request) if the Role has already an ID - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PostMapping("/roles") - @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public ResponseEntity createRole(@Valid @RequestBody RoleDTO roleDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save Role : {}", roleDto); - authService.checkPermission(ROLE_CREATE, e -> e - .organization(roleDto.getOrganizationName()) - .project(roleDto.getProjectName())); - if (roleDto.getId() != null) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, - "idexists", "A new role cannot already have an ID")).body(null); - } - RoleDTO result = roleService.save(roleDto); - return ResponseEntity.created(ResourceUriService.getUri(result)) - .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, displayName(result))) - .body(result); - } - - /** - * PUT /roles : Updates an existing role. - * - * @param roleDto the roleDto to update - * @return the ResponseEntity with status 200 (OK) and with body the updated roleDto, or with - * status 400 (Bad Request) if the roleDto is not valid, or with status 500 (Internal Server - * Error) if the roleDto couldnt be updated - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PutMapping("/roles") - @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public ResponseEntity updateRole(@Valid @RequestBody RoleDTO roleDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update Role : {}", roleDto); - if (roleDto.getId() == null) { - return createRole(roleDto); - } - authService.checkPermission(ROLE_UPDATE, e -> e - .organization(roleDto.getOrganizationName()) - .project(roleDto.getProjectName())); - RoleDTO result = roleService.save(roleDto); - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, displayName(roleDto))) - .body(result); - } - - /** - * GET /roles : get all the roles. - * - * @return the ResponseEntity with status 200 (OK) and the list of roles in body - */ - @GetMapping("/roles") - @Timed - public List getAllRoles() throws NotAuthorizedException { - log.debug("REST request to get all Roles"); - authService.checkPermission(ROLE_READ); - return roleService.findAll(); - } - - /** - * GET /roles : get all the roles. - * - * @return the ResponseEntity with status 200 (OK) and the list of roles in body - */ - @GetMapping("/roles/admin") - @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public List getAllAdminRoles() { - log.debug("REST request to get all Admin Roles"); - return roleService.findSuperAdminRoles(); - } - - /** - * GET /roles/:projectName/:authorityName : get the role of the specified project and - * authority. - * - * @param projectName The project name - * @param authorityName The authority name - * @return the ResponseEntity with status 200 (OK) and with body the roleDTO, or with status 404 - * (Not Found) - */ - @GetMapping("/roles/{projectName:" + Constants.ENTITY_ID_REGEX + "}/{authorityName:" - + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity getRole(@PathVariable String projectName, - @PathVariable String authorityName) throws NotAuthorizedException { - log.debug("REST request to get all Roles"); - authService.checkPermission(ROLE_READ, e -> e.project(projectName)); - return ResponseUtil.wrapOrNotFound(roleService - .findOneByProjectNameAndAuthorityName(projectName, authorityName)); - } - - /** - * Create a user-friendly display name for a given role. Useful for passing to the notification - * system - * - * @param role The role to create a user-friendly display for - * @return the display name - */ - private String displayName(RoleDTO role) { - return role.getProjectName() + ": " + role.getAuthorityName(); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/RoleResource.kt b/src/main/java/org/radarbase/management/web/rest/RoleResource.kt new file mode 100644 index 000000000..ed4cb384a --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/RoleResource.kt @@ -0,0 +1,174 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ResourceUriService +import org.radarbase.management.service.RoleService +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.web.rest.util.HeaderUtil +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.security.access.annotation.Secured +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.net.URISyntaxException +import java.util.* +import javax.validation.Valid + +/** + * REST controller for managing Role. + */ +@RestController +@RequestMapping("/api") +class RoleResource( + @Autowired private val roleService: RoleService, + @Autowired private val authService: AuthService +) { + + /** + * POST /Roles : Create a new role. + * + * @param roleDto the roleDto to create + * @return the ResponseEntity with status 201 (Created) and with body the new RoleDTO, or with + * status 400 (Bad Request) if the Role has already an ID + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/roles") + @Timed + @Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + @Throws( + URISyntaxException::class, NotAuthorizedException::class + ) + fun createRole(@RequestBody roleDto: @Valid RoleDTO): ResponseEntity { + log.debug("REST request to save Role : {}", roleDto) + authService.checkPermission(Permission.ROLE_CREATE, { e: EntityDetails -> + e.project = roleDto.projectName + }) + if (roleDto.id != null) { + return ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, + "idexists", "A new role cannot already have an ID" + ) + ).body(null) + } + val result = roleService.save(roleDto) + return ResponseEntity.created(ResourceUriService.getUri(result)) + .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, displayName(result))) + .body(result) + } + + /** + * PUT /roles : Updates an existing role. + * + * @param roleDto the roleDto to update + * @return the ResponseEntity with status 200 (OK) and with body the updated roleDto, or with + * status 400 (Bad Request) if the roleDto is not valid, or with status 500 (Internal Server + * Error) if the roleDto couldnt be updated + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PutMapping("/roles") + @Timed + @Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + @Throws( + URISyntaxException::class, NotAuthorizedException::class + ) + fun updateRole(@RequestBody roleDto: @Valid RoleDTO): ResponseEntity { + log.debug("REST request to update Role : {}", roleDto) + if (roleDto.id == null) { + return createRole(roleDto) + } + authService.checkPermission(Permission.ROLE_UPDATE, { e: EntityDetails -> + e.project = roleDto.projectName + }) + val result = roleService.save(roleDto) + return ResponseEntity.ok() + .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, displayName(roleDto))) + .body(result) + } + + @get:Throws(NotAuthorizedException::class) + @get:Timed + @get:GetMapping("/roles") + val allRoles: List + /** + * GET /roles : get all the roles. + * + * @return the ResponseEntity with status 200 (OK) and the list of roles in body + */ + get() { + log.debug("REST request to get all Roles") + authService.checkPermission(Permission.ROLE_READ) + return roleService.findAll() + } + + @get:Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + @get:Timed + @get:GetMapping("/roles/admin") + val allAdminRoles: List + /** + * GET /roles : get all the roles. + * + * @return the ResponseEntity with status 200 (OK) and the list of roles in body + */ + get() { + log.debug("REST request to get all Admin Roles") + return roleService.findSuperAdminRoles() + } + + /** + * GET /roles/:projectName/:authorityName : get the role of the specified project and + * authority. + * + * @param projectName The project name + * @param authorityName The authority name + * @return the ResponseEntity with status 200 (OK) and with body the roleDTO, or with status 404 + * (Not Found) + */ + @GetMapping( + "/roles/{projectName:" + Constants.ENTITY_ID_REGEX + "}/{authorityName:" + + Constants.ENTITY_ID_REGEX + "}" + ) + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getRole( + @PathVariable projectName: String?, + @PathVariable authorityName: String? + ): ResponseEntity { + log.debug("REST request to get all Roles") + authService.checkPermission(Permission.ROLE_READ, { e: EntityDetails -> e.project(projectName) }) + return ResponseUtil.wrapOrNotFound( + Optional.ofNullable(roleService.findOneByProjectNameAndAuthorityName(projectName, authorityName)) + ) + } + + /** + * Create a user-friendly display name for a given role. Useful for passing to the notification + * system + * + * @param role The role to create a user-friendly display for + * @return the display name + */ + private fun displayName(role: RoleDTO?): String { + return role?.projectName + ": " + role?.authorityName + } + + companion object { + private val log = LoggerFactory.getLogger(RoleResource::class.java) + private const val ENTITY_NAME = "role" + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt index f3709979e..10a99b4ff 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt @@ -1,88 +1,83 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.SourceDataService; -import org.radarbase.management.service.dto.SourceDataDTO; -import org.radarbase.management.web.rest.errors.ConflictException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import tech.jhipster.web.util.ResponseUtil; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -import static org.radarbase.auth.authorization.Permission.SOURCEDATA_CREATE; -import static org.radarbase.auth.authorization.Permission.SOURCEDATA_DELETE; -import static org.radarbase.auth.authorization.Permission.SOURCEDATA_READ; -import static org.radarbase.auth.authorization.Permission.SOURCEDATA_UPDATE; -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE_DATA; +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ResourceUriService.getUri +import org.radarbase.management.service.SourceDataService +import org.radarbase.management.service.dto.SourceDataDTO +import org.radarbase.management.web.rest.errors.ConflictException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityCreationAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityDeletionAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityUpdateAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createFailureAlert +import org.radarbase.management.web.rest.util.PaginationUtil.generatePaginationHttpHeaders +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Pageable +import org.springframework.data.web.PageableDefault +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.net.URISyntaxException +import java.util.* +import javax.validation.Valid /** * REST controller for managing SourceData. */ @RestController @RequestMapping("/api") -public class SourceDataResource { - - private static final Logger log = LoggerFactory.getLogger(SourceDataResource.class); - - @Autowired - private SourceDataService sourceDataService; - @Autowired - private AuthService authService; +class SourceDataResource( + @Autowired private val sourceDataService: SourceDataService, + @Autowired private val authService: AuthService +) { /** * POST /source-data : Create a new sourceData. * * @param sourceDataDto the sourceDataDto to create * @return the ResponseEntity with status 201 (Created) and with body the new sourceDataDto, or - * with status 400 (Bad Request) if the sourceData has already an ID + * with status 400 (Bad Request) if the sourceData has already an ID * @throws URISyntaxException if the Location URI syntax is incorrect */ @PostMapping("/source-data") @Timed - public ResponseEntity createSourceData(@Valid @RequestBody SourceDataDTO - sourceDataDto) throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save SourceData : {}", sourceDataDto); - authService.checkPermission(SOURCEDATA_CREATE); - if (sourceDataDto.getId() != null) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(SOURCE_DATA, - "idexists", "A new sourceData cannot already have an ID")).build(); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createSourceData(@RequestBody sourceDataDto: @Valid SourceDataDTO?): ResponseEntity { + log.debug("REST request to save SourceData : {}", sourceDataDto) + authService.checkPermission(Permission.SOURCEDATA_CREATE) + if (sourceDataDto!!.id != null) { + return ResponseEntity.badRequest().headers( + createFailureAlert( + EntityName.SOURCE_DATA, + "idexists", "A new sourceData cannot already have an ID" + ) + ).build() } - String name = sourceDataDto.getSourceDataName(); - if (sourceDataService.findOneBySourceDataName(name).isPresent()) { - throw new ConflictException("SourceData already available with source-name", - SOURCE_DATA, "error.sourceDataNameAvailable", - Collections.singletonMap("sourceDataName", name)); + val name = sourceDataDto.sourceDataName + if (sourceDataService.findOneBySourceDataName(name) != null) { + throw ConflictException( + "SourceData already available with source-name", + EntityName.SOURCE_DATA, "error.sourceDataNameAvailable", + Collections.singletonMap("sourceDataName", name) + ) } - SourceDataDTO result = sourceDataService.save(sourceDataDto); - return ResponseEntity.created(ResourceUriService.getUri(sourceDataDto)) - .headers(HeaderUtil.createEntityCreationAlert(SOURCE_DATA, name)) - .body(result); + val result = sourceDataService.save(sourceDataDto) + return ResponseEntity.created(getUri(sourceDataDto)) + .headers(createEntityCreationAlert(EntityName.SOURCE_DATA, name)) + .body(result) } /** @@ -90,23 +85,23 @@ public class SourceDataResource { * * @param sourceDataDto the sourceDataDto to update * @return the ResponseEntity with status 200 (OK) and with body the updated sourceDataDto, or - * with status 400 (Bad Request) if the sourceDataDto is not valid, or with status 500 - * (Internal Server Error) if the sourceDataDto couldnt be updated + * with status 400 (Bad Request) if the sourceDataDto is not valid, or with status 500 + * (Internal Server Error) if the sourceDataDto couldnt be updated * @throws URISyntaxException if the Location URI syntax is incorrect */ @PutMapping("/source-data") @Timed - public ResponseEntity updateSourceData(@Valid @RequestBody SourceDataDTO - sourceDataDto) throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update SourceData : {}", sourceDataDto); - if (sourceDataDto.getId() == null) { - return createSourceData(sourceDataDto); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun updateSourceData(@RequestBody sourceDataDto: @Valid SourceDataDTO?): ResponseEntity { + log.debug("REST request to update SourceData : {}", sourceDataDto) + if (sourceDataDto!!.id == null) { + return createSourceData(sourceDataDto) } - authService.checkPermission(SOURCEDATA_UPDATE); - SourceDataDTO result = sourceDataService.save(sourceDataDto); - return ResponseEntity.ok().headers(HeaderUtil - .createEntityUpdateAlert(SOURCE_DATA, sourceDataDto.getSourceDataName())) - .body(result); + authService.checkPermission(Permission.SOURCEDATA_UPDATE) + val result = sourceDataService.save(sourceDataDto) + return ResponseEntity.ok() + .headers(createEntityUpdateAlert(EntityName.SOURCE_DATA, sourceDataDto.sourceDataName)) + .body(result) } /** @@ -117,15 +112,15 @@ public class SourceDataResource { */ @GetMapping("/source-data") @Timed - public ResponseEntity> getAllSourceData( - @PageableDefault(page = 0, size = Integer.MAX_VALUE) Pageable pageable) - throws NotAuthorizedException { - log.debug("REST request to get all SourceData"); - authService.checkScope(SOURCEDATA_READ); - Page page = sourceDataService.findAll(pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/api/source-data"); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + @Throws(NotAuthorizedException::class) + fun getAllSourceData( + @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable? + ): ResponseEntity> { + log.debug("REST request to get all SourceData") + authService.checkScope(Permission.SOURCEDATA_READ) + val page = sourceDataService.findAll(pageable) + val headers = generatePaginationHttpHeaders(page, "/api/source-data") + return ResponseEntity(page.content, headers, HttpStatus.OK) } /** @@ -133,15 +128,21 @@ public class SourceDataResource { * * @param sourceDataName the sourceDataName of the sourceDataDTO to retrieve * @return the ResponseEntity with status 200 (OK) and with body the sourceDataDTO, or with - * status 404 (Not Found) + * status 404 (Not Found) */ @GetMapping("/source-data/{sourceDataName:" + Constants.ENTITY_ID_REGEX + "}") @Timed - public ResponseEntity getSourceData(@PathVariable String sourceDataName) - throws NotAuthorizedException { - authService.checkScope(SOURCEDATA_READ); - return ResponseUtil.wrapOrNotFound(sourceDataService - .findOneBySourceDataName(sourceDataName)); + @Throws( + NotAuthorizedException::class + ) + fun getSourceData(@PathVariable sourceDataName: String?): ResponseEntity { + authService.checkScope(Permission.SOURCEDATA_READ) + return ResponseUtil.wrapOrNotFound( + Optional.ofNullable( + sourceDataService + .findOneBySourceDataName(sourceDataName) + ) + ) } /** @@ -152,17 +153,18 @@ public class SourceDataResource { */ @DeleteMapping("/source-data/{sourceDataName:" + Constants.ENTITY_ID_REGEX + "}") @Timed - public ResponseEntity deleteSourceData(@PathVariable String sourceDataName) - throws NotAuthorizedException { - authService.checkPermission(SOURCEDATA_DELETE); - Optional sourceDataDto = sourceDataService - .findOneBySourceDataName(sourceDataName); - if (sourceDataDto.isEmpty()) { - return ResponseEntity.notFound().build(); - } - sourceDataService.delete(sourceDataDto.get().getId()); - return ResponseEntity.ok().headers(HeaderUtil - .createEntityDeletionAlert(SOURCE_DATA, sourceDataName)).build(); + @Throws( + NotAuthorizedException::class + ) + fun deleteSourceData(@PathVariable sourceDataName: String?): ResponseEntity { + authService.checkPermission(Permission.SOURCEDATA_DELETE) + val sourceDataDto = sourceDataService + .findOneBySourceDataName(sourceDataName) ?: return ResponseEntity.notFound().build() + sourceDataService.delete(sourceDataDto.id) + return ResponseEntity.ok().headers(createEntityDeletionAlert(EntityName.SOURCE_DATA, sourceDataName)).build() } + companion object { + private val log = LoggerFactory.getLogger(SourceDataResource::class.java) + } } diff --git a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt index e00a6714e..3e14ca0a5 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt @@ -55,53 +55,46 @@ class SourceResource( @PostMapping("/sources") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createSource(@RequestBody sourceDto: @Valid SourceDTO?): ResponseEntity { + fun createSource(@RequestBody sourceDto: @Valid SourceDTO?): ResponseEntity { log.debug("REST request to save Source : {}", sourceDto) val project = sourceDto!!.project - authService.checkPermission(Permission.SOURCE_CREATE, { (_, project1): EntityDetails -> + authService.checkPermission(Permission.SOURCE_CREATE, { e: EntityDetails -> if (project != null) { - project1 + e.project(project.projectName) } }) + return if (sourceDto.id != null) { ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( - ENTITY_NAME, - "idexists", "A new source cannot already have an ID" + ENTITY_NAME, "idexists", "A new source cannot already have an ID" ) ).build() - } else if (sourceDto.sourceId != null) { + } else if (sourceDto.sourceId != null) { ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( - ENTITY_NAME, - "sourceIdExists", "A new source cannot already have a Source ID" + ENTITY_NAME, "sourceIdExists", "A new source cannot already have a Source ID" ) ).build() - } else if (sourceRepository.findOneBySourceName(sourceDto.sourceName).isPresent) { + } else if (sourceRepository.findOneBySourceName(sourceDto.sourceName) != null) { ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( - ENTITY_NAME, - "sourceNameExists", "Source name already in use" + ENTITY_NAME, "sourceNameExists", "Source name already in use" ) ).build() } else if (sourceDto.assigned == null) { - ResponseEntity.badRequest() - .headers( - HeaderUtil.createFailureAlert( - ENTITY_NAME, "sourceAssignedRequired", - "A new source must have the 'assigned' field specified" - ) - ).body(null) + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, "sourceAssignedRequired", "A new source must have the 'assigned' field specified" + ) + ).body(null) } else { val result = sourceService.save(sourceDto) - ResponseEntity.created(ResourceUriService.getUri(result)) - .headers( + ResponseEntity.created(ResourceUriService.getUri(result)).headers( HeaderUtil.createEntityCreationAlert( - ENTITY_NAME, - result.sourceName + ENTITY_NAME, result.sourceName ) - ) - .body(result) + ).body(result) } } @@ -117,15 +110,15 @@ class SourceResource( @PutMapping("/sources") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun updateSource(@RequestBody sourceDto: @Valid SourceDTO?): ResponseEntity { + fun updateSource(@RequestBody sourceDto: @Valid SourceDTO): ResponseEntity { log.debug("REST request to update Source : {}", sourceDto) - if (sourceDto!!.id == null) { + if (sourceDto.id == null) { return createSource(sourceDto) } val project = sourceDto.project - authService.checkPermission(Permission.SOURCE_UPDATE, { (_, project1): EntityDetails -> + authService.checkPermission(Permission.SOURCE_UPDATE, { e: EntityDetails -> if (project != null) { - project1 + e.project(project.projectName) } }) val updatedSource: SourceDTO? = sourceService.updateSource(sourceDto) @@ -150,8 +143,7 @@ class SourceResource( authService.checkPermission(Permission.SUBJECT_READ) log.debug("REST request to get all Sources") val page = sourceService.findAll(pageable) - val headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/api/sources") + val headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/sources") return ResponseEntity(page!!.content, headers, HttpStatus.OK) } @@ -167,21 +159,19 @@ class SourceResource( @Throws( NotAuthorizedException::class ) - fun getSource(@PathVariable sourceName: String?): ResponseEntity { + fun getSource(@PathVariable sourceName: String): ResponseEntity { log.debug("REST request to get Source : {}", sourceName) authService.checkScope(Permission.SOURCE_READ) - val sourceOpt = sourceService.findOneByName(sourceName) - if (sourceOpt.isPresent) { - val source = sourceOpt.get() - authService.checkPermission(Permission.SOURCE_READ, { (_, project, subject): EntityDetails -> + val source = sourceService.findOneByName(sourceName) + if (source != null) { + authService.checkPermission(Permission.SOURCE_READ, { e: EntityDetails -> if (source.project != null) { - project + e.project(source.project!!.projectName) } - subject - //.source(source.sourceName) + e.subject(source.subjectLogin).source(source.sourceName) }) } - return ResponseUtil.wrapOrNotFound(sourceOpt) + return ResponseUtil.wrapOrNotFound(Optional.ofNullable(source)) } /** @@ -195,45 +185,40 @@ class SourceResource( @Throws( NotAuthorizedException::class ) - fun deleteSource(@PathVariable sourceName: String?): ResponseEntity { + fun deleteSource(@PathVariable sourceName: String): ResponseEntity { log.debug("REST request to delete Source : {}", sourceName) authService.checkScope(Permission.SOURCE_DELETE) - val sourceDtoOpt = sourceService.findOneByName(sourceName) - if (sourceDtoOpt.isEmpty) { - return ResponseEntity.notFound().build() - } - val sourceDto = sourceDtoOpt.get() - authService.checkPermission(Permission.SOURCE_DELETE, { (_, project, subject): EntityDetails -> + val sourceDto = sourceService.findOneByName(sourceName) + ?: return ResponseEntity.notFound().build() + authService.checkPermission(Permission.SOURCE_DELETE, { e: EntityDetails -> if (sourceDto.project != null) { - project + e.project(sourceDto.project!!.projectName); } - subject - //.source(sourceDto.sourceName) + e.subject(sourceDto.subjectLogin) + .source(sourceDto.sourceName) }) - if (sourceDto.assigned) { + if (sourceDto.assigned == true) { return ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( - ENTITY_NAME, - "sourceIsAssigned", "Cannot delete an assigned source" + ENTITY_NAME, "sourceIsAssigned", "Cannot delete an assigned source" ) ).build() } - val sourceId = sourceDtoOpt.get().id - val sourceHistory = sourceRepository.findRevisions(sourceId) - val sources = sourceHistory.content.mapNotNull { obj: Revision -> obj.entity } - .filter { it.isAssigned == true }.toList() - if (sources.isNotEmpty()) { + val sourceId = sourceDto.id + val sourceHistory = sourceId?.let { sourceRepository.findRevisions(it) } + val sources = + sourceHistory?.mapNotNull { obj: Revision -> obj.entity }?.filter { it.isAssigned == true } + ?.toList() + if (sources?.isNotEmpty() == true) { val failureAlert = HeaderUtil.createFailureAlert( - ENTITY_NAME, - "sourceRevisionIsAssigned", "Cannot delete a previously assigned source" + ENTITY_NAME, "sourceRevisionIsAssigned", "Cannot delete a previously assigned source" ) return ResponseEntity.status(HttpStatus.CONFLICT).headers(failureAlert).build() } - sourceService.delete(sourceId) + sourceId?.let { sourceService.delete(it) } return ResponseEntity.ok().headers( HeaderUtil.createEntityDeletionAlert( - ENTITY_NAME, - sourceName + ENTITY_NAME, sourceName ) ).build() } diff --git a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt index eb0bce7ee..5a34bac73 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt @@ -1,109 +1,97 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.repository.SourceTypeRepository; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.SourceTypeService; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.web.rest.errors.ConflictException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.InvalidRequestException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import tech.jhipster.web.util.ResponseUtil; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - -import static org.radarbase.auth.authorization.Permission.SOURCETYPE_CREATE; -import static org.radarbase.auth.authorization.Permission.SOURCETYPE_DELETE; -import static org.radarbase.auth.authorization.Permission.SOURCETYPE_READ; -import static org.radarbase.auth.authorization.Permission.SOURCETYPE_UPDATE; -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE_TYPE; +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.SourceType +import org.radarbase.management.repository.SourceTypeRepository +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ResourceUriService.getUri +import org.radarbase.management.service.SourceTypeService +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SourceTypeDTO +import org.radarbase.management.web.rest.errors.ConflictException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidRequestException +import org.radarbase.management.web.rest.util.HeaderUtil +import org.radarbase.management.web.rest.util.PaginationUtil +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Pageable +import org.springframework.data.web.PageableDefault +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.net.URISyntaxException +import java.util.* +import java.util.stream.Collectors +import javax.validation.Valid /** * REST controller for managing SourceType. */ @RestController @RequestMapping("/api") -public class SourceTypeResource { - private static final Logger log = LoggerFactory.getLogger(SourceTypeResource.class); - - @Autowired - private SourceTypeService sourceTypeService; - - @Autowired - private SourceTypeRepository sourceTypeRepository; - @Autowired - private AuthService authService; +class SourceTypeResource( + @Autowired private val sourceTypeService: SourceTypeService, + @Autowired private val sourceTypeRepository: SourceTypeRepository, + @Autowired private val authService: AuthService +) { /** * POST /source-types : Create a new sourceType. * * @param sourceTypeDto the sourceTypeDto to create * @return the ResponseEntity with status 201 (Created) and with body the new sourceTypeDto, or - * with status 400 (Bad Request) if the sourceType has already an ID + * with status 400 (Bad Request) if the sourceType has already an ID * @throws URISyntaxException if the Location URI syntax is incorrect */ @PostMapping("/source-types") @Timed - public ResponseEntity createSourceType(@Valid @RequestBody - SourceTypeDTO sourceTypeDto) throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save SourceType : {}", sourceTypeDto); - authService.checkPermission(SOURCETYPE_CREATE); - if (sourceTypeDto.getId() != null) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(SOURCE_TYPE, - "idexists", "A new sourceType cannot already have an ID")).build(); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createSourceType(@RequestBody sourceTypeDto: @Valid SourceTypeDTO?): ResponseEntity { + log.debug("REST request to save SourceType : {}", sourceTypeDto) + authService!!.checkPermission(Permission.SOURCETYPE_CREATE) + if (sourceTypeDto!!.id != null) { + return ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + EntityName.SOURCE_TYPE, + "idexists", "A new sourceType cannot already have an ID" + ) + ).build() } - Optional existing = sourceTypeRepository - .findOneWithEagerRelationshipsByProducerAndModelAndVersion( - sourceTypeDto.getProducer(), sourceTypeDto.getModel(), - sourceTypeDto.getCatalogVersion()); - - if (existing.isPresent()) { - Map errorParams = new HashMap<>(); - errorParams.put("message", "A SourceType with the specified producer, model and " - + "version already exists. This combination needs to be unique."); - errorParams.put("producer", sourceTypeDto.getProducer()); - errorParams.put("model", sourceTypeDto.getModel()); - errorParams.put("catalogVersion", sourceTypeDto.getCatalogVersion()); - throw new ConflictException("A SourceType with the specified producer, model and" - + "version already exists. This combination needs to be unique.", SOURCE_TYPE, - ErrorConstants.ERR_SOURCE_TYPE_EXISTS, errorParams); + val existing: SourceType? = sourceTypeRepository + .findOneWithEagerRelationshipsByProducerAndModelAndVersion( + sourceTypeDto.producer, sourceTypeDto.model, + sourceTypeDto.catalogVersion + ) + if (existing != null) { + val errorParams: MutableMap = HashMap() + errorParams["message"] = ("A SourceType with the specified producer, model and " + + "version already exists. This combination needs to be unique.") + errorParams["producer"] = sourceTypeDto.producer + errorParams["model"] = sourceTypeDto.model + errorParams["catalogVersion"] = sourceTypeDto.catalogVersion + throw ConflictException( + "A SourceType with the specified producer, model and" + + "version already exists. This combination needs to be unique.", EntityName.SOURCE_TYPE, + ErrorConstants.ERR_SOURCE_TYPE_EXISTS, errorParams + ) } - SourceTypeDTO result = sourceTypeService.save(sourceTypeDto); - return ResponseEntity.created(ResourceUriService.getUri(result)) - .headers(HeaderUtil.createEntityCreationAlert(SOURCE_TYPE, displayName(result))) - .body(result); + val result = sourceTypeService!!.save(sourceTypeDto) + return ResponseEntity.created(getUri(result)) + .headers(HeaderUtil.createEntityCreationAlert(EntityName.SOURCE_TYPE, displayName(result))) + .body(result) } /** @@ -111,24 +99,25 @@ public class SourceTypeResource { * * @param sourceTypeDto the sourceTypeDto to update * @return the ResponseEntity with status 200 (OK) and with body the updated sourceTypeDto, or - * with status 400 (Bad Request) if the sourceTypeDto is not valid, or with status 500 - * (Internal Server Error) if the sourceTypeDto couldnt be updated + * with status 400 (Bad Request) if the sourceTypeDto is not valid, or with status 500 + * (Internal Server Error) if the sourceTypeDto couldnt be updated * @throws URISyntaxException if the Location URI syntax is incorrect */ @PutMapping("/source-types") @Timed - public ResponseEntity updateSourceType(@Valid @RequestBody - SourceTypeDTO sourceTypeDto) throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update SourceType : {}", sourceTypeDto); - if (sourceTypeDto.getId() == null) { - return createSourceType(sourceTypeDto); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun updateSourceType(@RequestBody sourceTypeDto: @Valid SourceTypeDTO?): ResponseEntity { + log.debug("REST request to update SourceType : {}", sourceTypeDto) + if (sourceTypeDto!!.id == null) { + return createSourceType(sourceTypeDto) } - authService.checkPermission(SOURCETYPE_UPDATE); - SourceTypeDTO result = sourceTypeService.save(sourceTypeDto); + authService!!.checkPermission(Permission.SOURCETYPE_UPDATE) + val result = sourceTypeService!!.save(sourceTypeDto) return ResponseEntity.ok() - .headers( - HeaderUtil.createEntityUpdateAlert(SOURCE_TYPE, displayName(sourceTypeDto))) - .body(result); + .headers( + HeaderUtil.createEntityUpdateAlert(EntityName.SOURCE_TYPE, displayName(sourceTypeDto)) + ) + .body(result) } /** @@ -139,14 +128,15 @@ public class SourceTypeResource { */ @GetMapping("/source-types") @Timed - public ResponseEntity> getAllSourceTypes( - @PageableDefault(page = 0, size = Integer.MAX_VALUE) Pageable pageable) - throws NotAuthorizedException { - authService.checkPermission(SOURCETYPE_READ); - Page page = sourceTypeService.findAll(pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/api/source-types"); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + @Throws(NotAuthorizedException::class) + fun getAllSourceTypes( + @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable? + ): ResponseEntity> { + authService!!.checkPermission(Permission.SOURCETYPE_READ) + val page = sourceTypeService!!.findAll(pageable!!) + val headers = PaginationUtil + .generatePaginationHttpHeaders(page, "/api/source-types") + return ResponseEntity(page.content, headers, HttpStatus.OK) } /** @@ -157,10 +147,12 @@ public class SourceTypeResource { */ @GetMapping("/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}") @Timed - public ResponseEntity> getSourceTypes(@PathVariable String producer) - throws NotAuthorizedException { - authService.checkPermission(SOURCETYPE_READ); - return ResponseEntity.ok(sourceTypeService.findByProducer(producer)); + @Throws( + NotAuthorizedException::class + ) + fun getSourceTypes(@PathVariable producer: String?): ResponseEntity> { + authService!!.checkPermission(Permission.SOURCETYPE_READ) + return ResponseEntity.ok(sourceTypeService!!.findByProducer(producer!!)) } /** @@ -171,13 +163,24 @@ public class SourceTypeResource { * @param model The model * @return A list of objects matching the producer and model */ - @GetMapping("/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}/{model:" - + Constants.ENTITY_ID_REGEX + "}") + @GetMapping( + "/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}/{model:" + + Constants.ENTITY_ID_REGEX + "}" + ) @Timed - public ResponseEntity> getSourceTypes(@PathVariable String producer, - @PathVariable String model) throws NotAuthorizedException { - authService.checkPermission(SOURCETYPE_READ); - return ResponseEntity.ok(sourceTypeService.findByProducerAndModel(producer, model)); + @Throws( + NotAuthorizedException::class + ) + fun getSourceTypes( + @PathVariable producer: String?, + @PathVariable model: String? + ): ResponseEntity> { + authService!!.checkPermission(Permission.SOURCETYPE_READ) + return ResponseEntity.ok( + sourceTypeService!!.findByProducerAndModel( + producer!!, model!! + ) + ) } /** @@ -188,15 +191,24 @@ public class SourceTypeResource { * @param version The version * @return A single SourceType object matching the producer, model and version */ - @GetMapping("/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}/{model:" - + Constants.ENTITY_ID_REGEX + "}/{version:" + Constants.ENTITY_ID_REGEX + "}") + @GetMapping( + "/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}/{model:" + + Constants.ENTITY_ID_REGEX + "}/{version:" + Constants.ENTITY_ID_REGEX + "}" + ) @Timed - public ResponseEntity getSourceTypes(@PathVariable String producer, - @PathVariable String model, @PathVariable String version) - throws NotAuthorizedException { - authService.checkPermission(SOURCETYPE_READ); - return ResponseUtil.wrapOrNotFound(Optional.ofNullable( - sourceTypeService.findByProducerAndModelAndVersion(producer, model, version))); + @Throws( + NotAuthorizedException::class + ) + fun getSourceTypes( + @PathVariable producer: String?, + @PathVariable model: String?, @PathVariable version: String? + ): ResponseEntity { + authService!!.checkPermission(Permission.SOURCETYPE_READ) + return ResponseUtil.wrapOrNotFound( + Optional.ofNullable( + sourceTypeService!!.findByProducerAndModelAndVersion(producer!!, model!!, version!!) + ) + ) } /** @@ -208,37 +220,57 @@ public class SourceTypeResource { * @param version The version * @return the ResponseEntity with status 200 (OK) */ - @DeleteMapping("/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}/{model:" - + Constants.ENTITY_ID_REGEX + "}/{version:" + Constants.ENTITY_ID_REGEX + "}") + @DeleteMapping( + "/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}/{model:" + + Constants.ENTITY_ID_REGEX + "}/{version:" + Constants.ENTITY_ID_REGEX + "}" + ) @Timed - public ResponseEntity deleteSourceType(@PathVariable String producer, - @PathVariable String model, @PathVariable String version) - throws NotAuthorizedException { - authService.checkPermission(SOURCETYPE_DELETE); - SourceTypeDTO sourceTypeDto = sourceTypeService - .findByProducerAndModelAndVersion(producer, model, version); + @Throws( + NotAuthorizedException::class + ) + fun deleteSourceType( + @PathVariable producer: String?, + @PathVariable model: String?, @PathVariable version: String? + ): ResponseEntity { + authService!!.checkPermission(Permission.SOURCETYPE_DELETE) + val sourceTypeDto = sourceTypeService + .findByProducerAndModelAndVersion(producer!!, model!!, version!!) if (Objects.isNull(sourceTypeDto)) { - return ResponseEntity.notFound().build(); + return ResponseEntity.notFound().build() } - List projects = sourceTypeService.findProjectsBySourceType(producer, model, - version); + val projects = sourceTypeService!!.findProjectsBySourceType( + producer, model, + version + ) if (!projects.isEmpty()) { - throw new InvalidRequestException( - // we know the list is not empty so calling get() is safe here - "Cannot delete a source-type that " + "is being used by project(s)", SOURCE_TYPE, - ErrorConstants.ERR_SOURCE_TYPE_IN_USE, Collections.singletonMap("project-names", - projects + throw InvalidRequestException( // we know the list is not empty so calling get() is safe here + "Cannot delete a source-type that " + "is being used by project(s)", EntityName.SOURCE_TYPE, + ErrorConstants.ERR_SOURCE_TYPE_IN_USE, Collections.singletonMap( + "project-names", + projects .stream() - .map(ProjectDTO::getProjectName) - .collect(Collectors.joining("-")))); + .map(ProjectDTO::projectName) + .collect(Collectors.joining("-")) + ) + ) } - sourceTypeService.delete(sourceTypeDto.getId()); - return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(SOURCE_TYPE, - displayName(sourceTypeDto))).build(); + sourceTypeService.delete(sourceTypeDto.id!!) + return ResponseEntity.ok().headers( + HeaderUtil.createEntityDeletionAlert( + EntityName.SOURCE_TYPE, + displayName(sourceTypeDto) + ) + ).build() + } + + private fun displayName(sourceType: SourceTypeDTO?): String { + return java.lang.String.join( + " ", sourceType!!.producer, sourceType.model, + sourceType.catalogVersion + ) } - private String displayName(SourceTypeDTO sourceType) { - return String.join(" ", sourceType.getProducer(), sourceType.getModel(), - sourceType.getCatalogVersion()); + companion object { + private val log = LoggerFactory.getLogger(SourceTypeResource::class.java) } } diff --git a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt index 11b049d16..e83ff61fb 100644 --- a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt @@ -37,6 +37,7 @@ import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.actuate.audit.AuditEvent import org.springframework.boot.actuate.audit.AuditEventRepository +import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity @@ -94,13 +95,10 @@ class SubjectResource( EntityName.SUBJECT, "idexists" ) } - if (subjectDto.getLogin() == null) { - throw BadRequestException("A subject login is required", EntityName.SUBJECT, "loginrequired") - } - if (subjectDto.externalId != null && subjectDto.externalId.isNotEmpty() + if (!subjectDto.externalId.isNullOrEmpty() && subjectRepository.findOneByProjectNameAndExternalId( projectName, subjectDto.externalId - ).isPresent + ) != null ) { throw BadRequestException( "A subject with given project-id and" @@ -109,18 +107,18 @@ class SubjectResource( } val result = subjectService.createSubject(subjectDto) return ResponseEntity.created(ResourceUriService.getUri(subjectDto)) - .headers(HeaderUtil.createEntityCreationAlert(EntityName.SUBJECT, result?.getLogin())) + .headers(HeaderUtil.createEntityCreationAlert(EntityName.SUBJECT, result?.login)) .body(result) } private fun getProjectName(subjectDto: SubjectDTO): String { - if (subjectDto.project == null || subjectDto.project.id == null || subjectDto.project.projectName == null) { + if (subjectDto.project == null || subjectDto.project!!.id == null || subjectDto.project!!.projectName == null) { throw BadRequestException( "A subject should be assigned to a project", EntityName.SUBJECT, "projectrequired" ) } - return subjectDto.project.projectName + return subjectDto.project!!.projectName!! } /** @@ -144,11 +142,11 @@ class SubjectResource( authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> e .project(projectName) - .subject(subjectDto.getLogin()) + .subject(subjectDto.login) }) val result = subjectService.updateSubject(subjectDto) return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(EntityName.SUBJECT, subjectDto.getLogin())) + .headers(HeaderUtil.createEntityUpdateAlert(EntityName.SUBJECT, subjectDto.login)) .body(result) } @@ -159,7 +157,7 @@ class SubjectResource( * @param subjectDto the subjectDto to update * @return the ResponseEntity with status 200 (OK) and with body the updated subjectDto, or with * status 400 (Bad Request) if the subjectDto is not valid, or with status 500 (Internal - * Server Error) if the subjectDto couldnt be updated + * Server Error) if the subjectDto couldn't be updated */ @PutMapping("/subjects/discontinue") @Timed @@ -173,20 +171,20 @@ class SubjectResource( authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> e .project(projectName) - .subject(subjectDto.getLogin()) + .subject(subjectDto.login) }) // In principle this is already captured by the PostUpdate event listener, adding this // event just makes it more clear a subject was discontinued. eventRepository.add( AuditEvent( - SecurityUtils.getCurrentUserLogin().orElse(null), - "SUBJECT_DISCONTINUE", "subject_login=" + subjectDto.getLogin() + SecurityUtils.currentUserLogin, + "SUBJECT_DISCONTINUE", "subject_login=" + subjectDto.login ) ) val result = subjectService.discontinueSubject(subjectDto) return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(EntityName.SUBJECT, subjectDto.getLogin())) + .headers(HeaderUtil.createEntityUpdateAlert(EntityName.SUBJECT, subjectDto.login)) .body(result) } @@ -211,26 +209,26 @@ class SubjectResource( .map { obj: SubjectAuthority -> obj.name } .toList() return if (projectName != null && externalId != null) { - val subject = subjectRepository + val subject = Optional.ofNullable(subjectRepository .findOneByProjectNameAndExternalIdAndAuthoritiesIn( projectName, externalId, authoritiesToInclude ) - ?.map { s: Subject? -> + ?.let { s: Subject? -> listOf( subjectMapper.subjectToSubjectReducedProjectDTO(s) ) - } + }); ResponseUtil.wrapOrNotFound(subject) } else if (projectName == null && externalId != null) { val page = subjectService.findAll(subjectCriteria) - .map { s: Subject? -> subjectMapper.subjectToSubjectWithoutProjectDTO(s) } + .map { s: Subject -> subjectMapper.subjectToSubjectWithoutProjectDTO(s) } val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( page, "/api/subjects", subjectCriteria ) ResponseEntity(page.content, headers, HttpStatus.OK) } else { val page = subjectService.findAll(subjectCriteria) - .map { subject: Subject? -> subjectMapper.subjectToSubjectWithoutProjectDTO(subject) } + .map { subject: Subject -> subjectMapper.subjectToSubjectWithoutProjectDTO(subject) } val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( page, "/api/subjects", subjectCriteria ) @@ -255,7 +253,7 @@ class SubjectResource( authService.checkScope(Permission.SUBJECT_READ) val subject = subjectService.findOneByLogin(login) val project: Project? = subject.activeProject - ?.let { p -> projectRepository.findOneWithEagerRelationships(p.id) } + ?.let { p -> p.id?.let { projectRepository.findOneWithEagerRelationships(it) } } authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> if (project != null) { e.project(project.projectName) @@ -280,7 +278,7 @@ class SubjectResource( ) fun getSubjectRevisions( @Parameter pageable: Pageable?, - @PathVariable login: String? + @PathVariable login: String ): ResponseEntity> { authService.checkScope(Permission.SUBJECT_READ) log.debug("REST request to get revisions for Subject : {}", login) @@ -315,14 +313,14 @@ class SubjectResource( @Timed @Throws(NotAuthorizedException::class) fun getSubjectRevision( - @PathVariable login: String?, + @PathVariable login: String, @PathVariable revisionNb: Int? ): ResponseEntity { authService.checkScope(Permission.SUBJECT_READ) log.debug("REST request to get Subject : {}, for revisionNb: {}", login, revisionNb) val subjectDto = subjectService.findRevision(login, revisionNb) authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> - e.project(subjectDto.project.projectName) + e.project(subjectDto.project?.projectName) .subject(subjectDto.login) }) return ResponseEntity.ok(subjectDto) @@ -404,10 +402,10 @@ class SubjectResource( } sourceTypeId = sourceTypeService .findByProducerAndModelAndVersion( - sourceDto.sourceTypeProducer, - sourceDto.sourceTypeModel, - sourceDto.sourceTypeCatalogVersion - )?.id + sourceDto.sourceTypeProducer!!, + sourceDto.sourceTypeModel!!, + sourceDto.sourceTypeCatalogVersion!! + ).id // also update the sourceDto, since we pass it on to SubjectService later sourceDto.sourceTypeId = sourceTypeId } @@ -431,14 +429,12 @@ class SubjectResource( // find whether the relevant source-type is available in the subject's project val sourceType = projectRepository .findSourceTypeByProjectIdAndSourceTypeId(currentProject.id, sourceTypeId) - ?.orElseThrow { - BadRequestException( + ?: throw BadRequestException( "No valid source-type found for project." + " You must provide either valid source-type id or producer, model," + " version of a source-type that is assigned to project", EntityName.SUBJECT, ErrorConstants.ERR_SOURCE_TYPE_NOT_PROVIDED ) - } // check if any of id, sourceID, sourceName were non-null val existing = Stream.of( @@ -449,7 +445,7 @@ class SubjectResource( // handle the source registration val sourceRegistered = subjectService - .assignOrUpdateSource(sub, sourceType!!, currentProject, sourceDto) + .assignOrUpdateSource(sub, sourceType, currentProject, sourceDto) // Return the correct response type, either created if a new source was created, or ok if // an existing source was provided. If an existing source was given but not found, the @@ -494,7 +490,7 @@ class SubjectResource( val withInactiveSources = withInactiveSourcesParam != null && withInactiveSourcesParam // check the subject id val subject = subjectRepository.findOneWithEagerBySubjectLogin(login) - .orElseThrow { NoSuchElementException() } + ?: throw NoSuchElementException() authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> e .project(subject.associatedProject?.projectName) @@ -546,13 +542,11 @@ class SubjectResource( // check the subject id val subject = subjectRepository.findOneWithEagerBySubjectLogin(login) - .orElseThrow { - NotFoundException( - "Subject ID not found", - EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND, - Collections.singletonMap("subjectLogin", login) - ) - } + ?: throw NotFoundException( + "Subject ID not found", + EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> e .project(subject.associatedProject?.projectName) diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.kt b/src/main/java/org/radarbase/management/web/rest/UserResource.kt index bae3ea2e4..0c49f4aa1 100644 --- a/src/main/java/org/radarbase/management/web/rest/UserResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/UserResource.kt @@ -106,13 +106,13 @@ class UserResource( ) ).body(null) // Lowercase the user login before comparing with database - } else if (userRepository.findOneByLogin(managedUserVm.login.lowercase()).isPresent) { + } else if (managedUserVm.login.lowercase().let { userRepository.findOneByLogin(it) } != null) { ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( EntityName.USER, "userexists", "Login already in use" ) ).body(null) - } else if (userRepository.findOneByEmail(managedUserVm.email).isPresent) { + } else if (managedUserVm.email?.let { userRepository.findOneByEmail(it) } != null) { ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( EntityName.USER, "emailexists", "Email already in use" @@ -145,18 +145,20 @@ class UserResource( fun updateUser(@RequestBody managedUserVm: ManagedUserVM): ResponseEntity { log.debug("REST request to update User : {}", managedUserVm) authService.checkPermission(Permission.USER_UPDATE, { e: EntityDetails -> e.user(managedUserVm.login) }) - var existingUser = userRepository.findOneByEmail(managedUserVm.email) - if (existingUser.isPresent && existingUser.get().id != managedUserVm.id) { + var existingUser = managedUserVm.email?.let { userRepository.findOneByEmail(it) } + if (existingUser?.id != managedUserVm.id) { throw BadRequestException("Email already in use", EntityName.USER, "emailexists") } - existingUser = userRepository.findOneByLogin( - managedUserVm.login.lowercase() - ) - if (existingUser.isPresent && existingUser.get().id != managedUserVm.id) { + existingUser = managedUserVm.login.lowercase()?.let { + userRepository.findOneByLogin( + it + ) + } + if (existingUser != null && existingUser.id != managedUserVm.id) { throw BadRequestException("Login already in use", EntityName.USER, "emailexists") } val subject = subjectRepository.findOneWithEagerBySubjectLogin(managedUserVm.login) - if (subject.isPresent && managedUserVm.isActivated && subject.get().isRemoved!!) { + if (subject != null && managedUserVm.isActivated && subject.isRemoved!!) { // if the subject is also a user, check if the removed/activated states are valid throw InvalidRequestException( "Subject cannot be the user to request " + "this changes", EntityName.USER, "error.invalidsubjectstate" @@ -210,11 +212,11 @@ class UserResource( @Throws( NotAuthorizedException::class ) - fun getUser(@PathVariable login: String?): ResponseEntity { + fun getUser(@PathVariable login: String): ResponseEntity { log.debug("REST request to get User : {}", login) authService.checkPermission(Permission.USER_READ, { e: EntityDetails -> e.user(login) }) return ResponseUtil.wrapOrNotFound( - userService.getUserWithAuthoritiesByLogin(login) + Optional.ofNullable(userService.getUserWithAuthoritiesByLogin(login)) ) } @@ -229,7 +231,7 @@ class UserResource( @Throws( NotAuthorizedException::class ) - fun deleteUser(@PathVariable login: String?): ResponseEntity { + fun deleteUser(@PathVariable login: String): ResponseEntity { log.debug("REST request to delete User: {}", login) authService.checkPermission(Permission.USER_DELETE, { e: EntityDetails -> e.user(login) }) userService.deleteUser(login) @@ -247,11 +249,12 @@ class UserResource( @Throws( NotAuthorizedException::class ) - fun getUserRoles(@PathVariable login: String?): ResponseEntity> { + fun getUserRoles(@PathVariable login: String): ResponseEntity> { log.debug("REST request to read User roles: {}", login) authService.checkPermission(Permission.ROLE_READ, { e: EntityDetails -> e.user(login) }) - return ResponseUtil.wrapOrNotFound(userService.getUserWithAuthoritiesByLogin(login) - .map { obj: UserDTO -> obj.roles }) + return ResponseUtil.wrapOrNotFound( + Optional.ofNullable(userService.getUserWithAuthoritiesByLogin(login) + .let { obj: UserDTO? -> obj?.roles })) } /** diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.java b/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.java deleted file mode 100644 index 08bc8049a..000000000 --- a/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.web.rest.criteria; - -public class CriteriaRange> { - private T from = null; - private T to = null; - private T is = null; - - public T getFrom() { - return getIs() == null ? from : null; - } - - public void setFrom(T from) { - this.from = from; - } - - public T getTo() { - return getIs() == null ? to : null; - } - - public void setTo(T to) { - this.to = to; - } - - public void setIs(T is) { - this.is = is; - } - - /** Whether the criteria is equal to this value. */ - public T getIs() { - if (is != null) { - return is; - } else if (from != null && from.equals(to)) { - return from; - } else { - return null; - } - } - - /** - * Whether the criteria range contains any values at all. - */ - public boolean isEmpty() { - return from == null && to == null && is == null; - } - - /** - * Validate this criteria range whether the from and to ranges are in order. - */ - public void validate() { - if (is == null && from != null && to != null && from.compareTo(to) > 0) { - throw new IllegalArgumentException( - "CriteriaRange must have a from range that is smaller then the to range."); - } - } - - @Override - public String toString() { - return "CriteriaRange{" + "from=" + getFrom() - + ", to=" + getTo() - + ", is=" + getIs() - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt b/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt new file mode 100644 index 000000000..965f32fc0 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.web.rest.criteria + +open class CriteriaRange?>(var from: T? = null, var to: T? = null, + var iss: T? = null +) { + fun from(): T? { + return if (this.iss == null) from else null + } + + fun to(): T? { + return if (this.iss == null) to else null + } + + val isEmpty: Boolean + /** + * Whether the criteria range contains any values at all. + */ + get() = from == null && to == null && iss == null + + /** + * Validate this criteria range whether the from and to ranges are in order. + */ + fun validate() { + require(!(iss == null && from != null && to != null && from!!.compareTo(to!!) > 0)) { "CriteriaRange must have a from range that is smaller then the to range." } + } + + override fun toString(): String { + return ("CriteriaRange{" + "from=" + from() + + ", to=" + to() + + ", is=" + this.iss + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/LocalDateCriteriaRange.java b/src/main/java/org/radarbase/management/web/rest/criteria/LocalDateCriteriaRange.kt similarity index 60% rename from src/main/java/org/radarbase/management/web/rest/criteria/LocalDateCriteriaRange.java rename to src/main/java/org/radarbase/management/web/rest/criteria/LocalDateCriteriaRange.kt index ca032efef..9af9a1a4c 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/LocalDateCriteriaRange.java +++ b/src/main/java/org/radarbase/management/web/rest/criteria/LocalDateCriteriaRange.kt @@ -6,10 +6,8 @@ * * See the file LICENSE in the root of this repository. */ +package org.radarbase.management.web.rest.criteria -package org.radarbase.management.web.rest.criteria; +import java.time.LocalDate -import java.time.LocalDate; - -public class LocalDateCriteriaRange extends CriteriaRange { -} +class LocalDateCriteriaRange : CriteriaRange() diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectAuthority.java b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectAuthority.kt similarity index 69% rename from src/main/java/org/radarbase/management/web/rest/criteria/SubjectAuthority.java rename to src/main/java/org/radarbase/management/web/rest/criteria/SubjectAuthority.kt index 964674766..3b19818d2 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectAuthority.java +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectAuthority.kt @@ -6,10 +6,9 @@ * * See the file LICENSE in the root of this repository. */ +package org.radarbase.management.web.rest.criteria -package org.radarbase.management.web.rest.criteria; - -public enum SubjectAuthority { +enum class SubjectAuthority { ROLE_PARTICIPANT, - ROLE_INACTIVE_PARTICIPANT; + ROLE_INACTIVE_PARTICIPANT } diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.java b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.java deleted file mode 100644 index a13d3ddb2..000000000 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.java +++ /dev/null @@ -1,238 +0,0 @@ -package org.radarbase.management.web.rest.criteria; - -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.springframework.data.annotation.Transient; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; - -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.time.LocalDate; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_VALIDATION; - -public class SubjectCriteria { - private List authority = List.of(SubjectAuthority.ROLE_PARTICIPANT); - private LocalDateCriteriaRange dateOfBirth = null; - private ZonedDateTimeCriteriaRange enrollmentDate = null; - private Long groupId = null; - private String humanReadableIdentifier = null; - private SubjectCriteriaLast last = null; - @Min(0) - private int page = 0; - @Min(1) - private int size = 20; - private List sort; - private String personName = null; - private String projectName = null; - private String externalId = null; - private String login = null; - - @Transient - private List parsedSort = null; - - public List getAuthority() { - return authority; - } - - public void setAuthority(List authority) { - this.authority = authority; - } - - public CriteriaRange getDateOfBirth() { - return dateOfBirth; - } - - public void setDateOfBirth(LocalDateCriteriaRange dateOfBirth) { - this.dateOfBirth = dateOfBirth; - } - - public CriteriaRange getEnrollmentDate() { - return enrollmentDate; - } - - public void setEnrollmentDate(ZonedDateTimeCriteriaRange enrollmentDate) { - this.enrollmentDate = enrollmentDate; - } - - public Long getGroupId() { - return groupId; - } - - public void setGroupId(Long groupId) { - this.groupId = groupId; - } - - public String getHumanReadableIdentifier() { - return humanReadableIdentifier; - } - - public void setHumanReadableIdentifier(String humanReadableIdentifier) { - this.humanReadableIdentifier = humanReadableIdentifier; - } - - public SubjectCriteriaLast getLast() { - return last; - } - - public void setLast(SubjectCriteriaLast last) { - this.last = last; - } - - /** Get the criteria paging settings, excluding sorting. */ - @NotNull - public Pageable getPageable() { - return PageRequest.of(page, size); - } - - public int getPage() { - return page; - } - - public void setPage(int page) { - this.page = page; - } - - public int getSize() { - return size; - } - - public void setSize(int size) { - this.size = size; - } - - public String getPersonName() { - return personName; - } - - public void setPersonName(String personName) { - this.personName = personName; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - public String getExternalId() { - return externalId; - } - - public void setExternalId(String externalId) { - this.externalId = externalId; - } - - public String getLogin() { - return login; - } - - public void setLogin(String login) { - this.login = login; - } - - public List getSort() { - return sort; - } - - /** Parse the sort criteria. */ - public List getParsedSort() { - if (this.parsedSort == null) { - List flatSort = sort != null - ? sort.stream() - .flatMap(s -> Arrays.stream(s.split(","))) - .toList() - : List.of(); - - List parsedSort = new ArrayList<>(flatSort.size()); - - boolean hasDirection = true; - SubjectSortOrder previous = null; - for (String part : flatSort) { - if (!hasDirection) { - Optional direction = Sort.Direction.fromOptionalString(part); - if (direction.isPresent()) { - previous.setDirection(direction.get()); - hasDirection = true; - continue; - } - } else { - hasDirection = false; - } - previous = new SubjectSortOrder(getSubjectSortBy(part)); - parsedSort.add(previous); - } - - optimizeSortList(parsedSort); - this.parsedSort = Collections.unmodifiableList(parsedSort); - } - return this.parsedSort; - } - - /** - * Remove duplication and redundancy from sort list and make the result order consistent. - * @param sort modifiable ordered sort collection. - */ - private static void optimizeSortList(Collection sort) { - Set seenSortBy = EnumSet.noneOf(SubjectSortBy.class); - boolean hasUnique = false; - Iterator iterator = sort.iterator(); - while (iterator.hasNext()) { - SubjectSortOrder order = iterator.next(); - if (hasUnique || !seenSortBy.add(order.getSortBy())) { - iterator.remove(); - } - if (order.getSortBy().isUnique()) { - hasUnique = true; - } - } - if (!hasUnique) { - sort.add(new SubjectSortOrder(SubjectSortBy.ID)); - } - } - - private static SubjectSortBy getSubjectSortBy(String param) { - return Arrays.stream(SubjectSortBy.values()) - .filter(s -> s.getQueryParam().equalsIgnoreCase(param)) - .findAny() - .orElseThrow(() -> new BadRequestException( - "Cannot convert sort parameter " + param - + " to subject property", SUBJECT, ERR_VALIDATION)); - } - - public void setSort(List sort) { - this.parsedSort = null; - this.sort = sort; - } - - @Override - public String toString() { - return "SubjectCriteria{" + "authority=" + authority - + ", dateOfBirth=" + dateOfBirth - + ", enrollmentDate=" + enrollmentDate - + ", groupId='" + groupId + '\'' - + ", humanReadableIdentifier='" + humanReadableIdentifier + '\'' - + ", last=" + last - + ", page=" + page - + ", sort=" + sort - + ", personName='" + personName + '\'' - + ", projectName='" + projectName + '\'' - + ", externalId='" + externalId + '\'' - + ", login='" + login + '\'' - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt new file mode 100644 index 000000000..1ec053778 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt @@ -0,0 +1,125 @@ +package org.radarbase.management.web.rest.criteria + +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.springframework.data.annotation.Transient +import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Pageable +import org.springframework.data.domain.Sort +import java.util.* +import javax.validation.constraints.Min +import javax.validation.constraints.NotNull + +class SubjectCriteria { + var authority = listOf(SubjectAuthority.ROLE_PARTICIPANT) + var dateOfBirth: LocalDateCriteriaRange? = null + var enrollmentDate: ZonedDateTimeCriteriaRange? = null + var groupId: Long? = null + var humanReadableIdentifier: String? = null + var last: SubjectCriteriaLast? = null + var page: @Min(0) Int = 0 + var size: @Min(1) Int = 20 + private var sort: List? = null + var personName: String? = null + var projectName: String? = null + var externalId: String? = null + var login: String? = null + + @Transient + private var parsedSort: List? = null + + val pageable: @NotNull Pageable + /** Get the criteria paging settings, excluding sorting. */ + get() = PageRequest.of(page, size) + + fun getSort(): List? { + return sort + } + + /** Parse the sort criteria. */ + fun getParsedSort(): List? { + if (parsedSort == null) { + val flatSort = if (sort != null) sort!!.stream() + .flatMap { s: String -> + Arrays.stream(s.split(",".toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray()) + } + .toList() else listOf() + val parsedSort: MutableList = ArrayList(flatSort.size) + var hasDirection = true + var previous: SubjectSortOrder? = null + for (part in flatSort) { + if (!hasDirection) { + val direction = Sort.Direction.fromOptionalString(part) + if (direction.isPresent) { + previous?.direction = direction.get() + hasDirection = true + continue + } + } else { + hasDirection = false + } + previous = SubjectSortOrder(getSubjectSortBy(part)) + parsedSort.add(previous) + } + optimizeSortList(parsedSort) + this.parsedSort = Collections.unmodifiableList(parsedSort).filterNotNull() + } + return parsedSort + } + + override fun toString(): String { + return ("SubjectCriteria{" + "authority=" + authority + + ", dateOfBirth=" + dateOfBirth + + ", enrollmentDate=" + enrollmentDate + + ", groupId='" + groupId + '\'' + + ", humanReadableIdentifier='" + humanReadableIdentifier + '\'' + + ", last=" + last + + ", page=" + page + + ", sort=" + sort + + ", personName='" + personName + '\'' + + ", projectName='" + projectName + '\'' + + ", externalId='" + externalId + '\'' + + ", login='" + login + '\'' + + '}') + } + + companion object { + /** + * Remove duplication and redundancy from sort list and make the result order consistent. + * @param sort modifiable ordered sort collection. + */ + private fun optimizeSortList(sort: MutableCollection) { + val seenSortBy: EnumSet? = EnumSet.noneOf( + SubjectSortBy::class.java + ) + var hasUnique = false + val iterator = sort.iterator() + while (iterator.hasNext()) { + val order = iterator.next() + if (hasUnique || seenSortBy?.add(order?.sortBy) != true) { + iterator.remove() + } + if (order?.sortBy?.isUnique == true) { + hasUnique = true + } + } + if (!hasUnique) { + sort.add(SubjectSortOrder(SubjectSortBy.ID)) + } + } + + private fun getSubjectSortBy(param: String): SubjectSortBy { + return Arrays.stream(SubjectSortBy.values()) + .filter { s: SubjectSortBy -> s.queryParam.equals(param, ignoreCase = true) } + .findAny() + .orElseThrow { + BadRequestException( + "Cannot convert sort parameter " + param + + " to subject property", EntityName.Companion.SUBJECT, ErrorConstants.ERR_VALIDATION + ) + } + } + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.java b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.java deleted file mode 100644 index fde0bd62e..000000000 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.web.rest.criteria; - -public class SubjectCriteriaLast { - private String id = null; - private String externalId = null; - private String login = null; - private SubjectAuthority authority = null; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getExternalId() { - return externalId; - } - - public void setExternalId(String externalId) { - this.externalId = externalId; - } - - public String getLogin() { - return login; - } - - public void setLogin(String login) { - this.login = login; - } - - public SubjectAuthority getAuthority() { - return authority; - } - - public void setAuthority(SubjectAuthority authority) { - this.authority = authority; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.kt new file mode 100644 index 000000000..645016331 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.kt @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.web.rest.criteria + +class SubjectCriteriaLast { + var id: String? = null + var externalId: String? = null + var login: String? = null + var authority: SubjectAuthority? = null +} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.java b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.java deleted file mode 100644 index 0294239b3..000000000 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.web.rest.criteria; - -public enum SubjectSortBy { - ID("id", true), - EXTERNAL_ID("externalId", false), - USER_LOGIN("login", true); - - private final String queryParam; - private final boolean isUnique; - - SubjectSortBy(String queryParam, boolean isUnique) { - this.queryParam = queryParam; - this.isUnique = isUnique; - } - - /** Query parameter name. */ - public String getQueryParam() { - return this.queryParam; - } - - /** Whether this property is unique across all subjects. */ - public boolean isUnique() { - return isUnique; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.kt new file mode 100644 index 000000000..d9c85e74f --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.kt @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.web.rest.criteria + +enum class SubjectSortBy( + /** Query parameter name. */ + val queryParam: String, + /** Whether this property is unique across all subjects. */ + val isUnique: Boolean +) { + ID("id", true), + EXTERNAL_ID("externalId", false), + USER_LOGIN("login", true) + +} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.java b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.java deleted file mode 100644 index 47f8e368a..000000000 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.web.rest.criteria; - -import org.springframework.data.domain.Sort; - -import javax.validation.constraints.NotNull; -import java.util.Objects; - -public class SubjectSortOrder { - private Sort.Direction direction; - private final SubjectSortBy sortBy; - - public SubjectSortOrder(@NotNull SubjectSortBy sortBy, - @NotNull Sort.Direction direction) { - this.direction = direction; - this.sortBy = sortBy; - } - - public SubjectSortOrder(SubjectSortBy sortBy) { - this(sortBy, Sort.Direction.ASC); - } - - public void setDirection(@NotNull Sort.Direction direction) { - this.direction = direction; - } - - @NotNull - public Sort.Direction getDirection() { - return direction; - } - - @NotNull - public SubjectSortBy getSortBy() { - return sortBy; - } - - @Override - public String toString() { - return sortBy.name() + ',' + direction.name(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - SubjectSortOrder that = (SubjectSortOrder) o; - - return sortBy == that.sortBy && direction == that.direction; - } - - @Override - public int hashCode() { - return Objects.hash(direction, sortBy); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt new file mode 100644 index 000000000..c2cad7a04 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.web.rest.criteria + +import org.springframework.data.domain.Sort +import java.util.* +import javax.validation.constraints.NotNull + +class SubjectSortOrder @JvmOverloads constructor( + val sortBy: @NotNull SubjectSortBy, + var direction: @NotNull Sort.Direction = Sort.Direction.ASC +) { + + override fun toString(): String { + return sortBy.name + ',' + direction.name + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val that = o as SubjectSortOrder + return sortBy == that.sortBy && direction == that.direction + } + + override fun hashCode(): Int { + return Objects.hash(direction, sortBy) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/ZonedDateTimeCriteriaRange.java b/src/main/java/org/radarbase/management/web/rest/criteria/ZonedDateTimeCriteriaRange.kt similarity index 58% rename from src/main/java/org/radarbase/management/web/rest/criteria/ZonedDateTimeCriteriaRange.java rename to src/main/java/org/radarbase/management/web/rest/criteria/ZonedDateTimeCriteriaRange.kt index 33275bec6..6fe17fe94 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/ZonedDateTimeCriteriaRange.java +++ b/src/main/java/org/radarbase/management/web/rest/criteria/ZonedDateTimeCriteriaRange.kt @@ -6,10 +6,8 @@ * * See the file LICENSE in the root of this repository. */ +package org.radarbase.management.web.rest.criteria -package org.radarbase.management.web.rest.criteria; +import java.time.ZonedDateTime -import java.time.ZonedDateTime; - -public class ZonedDateTimeCriteriaRange extends CriteriaRange { -} +class ZonedDateTimeCriteriaRange : CriteriaRange() diff --git a/src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.java b/src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.java deleted file mode 100644 index 840c3e27e..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.springframework.http.HttpStatus; - -import java.util.Map; - -/** - * The request could not be understood by the server due to malformed syntax. - * The client SHOULD NOT repeat the request without modifications. - * (e.g. malformed request syntax, size too large, invalid request message framing, - * or deceptive request routing). - */ -public class BadRequestException extends RadarWebApplicationException { - - /** - * Create a BadRequestException with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - */ - public BadRequestException(String message, String entityName, String errorCode) { - super(HttpStatus.BAD_REQUEST, message, entityName, errorCode); - } - - /** - * Create a BadRequestException with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - * @param paramMap map of additional information. - */ - public BadRequestException(String message, String entityName, String errorCode, - Map paramMap) { - super(HttpStatus.BAD_REQUEST, message, entityName, errorCode, paramMap); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.kt b/src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.kt new file mode 100644 index 000000000..b69f5a6e2 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.kt @@ -0,0 +1,38 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus + +/** + * The request could not be understood by the server due to malformed syntax. + * The client SHOULD NOT repeat the request without modifications. + * (e.g. malformed request syntax, size too large, invalid request message framing, + * or deceptive request routing). + */ +class BadRequestException : RadarWebApplicationException { + /** + * Create a BadRequestException with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + */ + constructor(message: String?, entityName: String, errorCode: String?) : super( + HttpStatus.BAD_REQUEST, + message, + entityName, + errorCode + ) + + /** + * Create a BadRequestException with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + * @param paramMap map of additional information. + */ + constructor( + message: String?, entityName: String, errorCode: String?, + paramMap: Map? + ) : super(HttpStatus.BAD_REQUEST, message, entityName, errorCode, paramMap) +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ConflictException.java b/src/main/java/org/radarbase/management/web/rest/errors/ConflictException.java deleted file mode 100644 index b1a3c457b..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/ConflictException.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.springframework.http.HttpStatus; - -import java.util.Map; - - -/** - * Created by dverbeec on 13/09/2017. - *

- * The request could not be completed due to a conflict with the current state of the resource. - * This code is only allowed in situations where it is expected that the user might be able to - * resolve the conflict and resubmit the request. The response body SHOULD include enough - * information for the user to recognize the source of the conflict. Ideally, the response - * entity would include enough information for the user or user agent to fix the problem; - * however, that might not be possible and is not required. - *

- */ -public class ConflictException extends RadarWebApplicationException { - - /** - * Create a {@link ConflictException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - */ - public ConflictException(String message, String entityName, String errorCode) { - super(HttpStatus.CONFLICT, message, entityName, errorCode); - } - - /** - * Create a {@link ConflictException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - * @param paramMap map of additional information. - */ - public ConflictException(String message, String entityName, String errorCode, - Map paramMap) { - super(HttpStatus.CONFLICT, message, entityName, errorCode, paramMap); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ConflictException.kt b/src/main/java/org/radarbase/management/web/rest/errors/ConflictException.kt new file mode 100644 index 000000000..2dcbc7949 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/ConflictException.kt @@ -0,0 +1,44 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus + +/** + * Created by dverbeec on 13/09/2017. + * + * + * The request could not be completed due to a conflict with the current state of the resource. + * This code is only allowed in situations where it is expected that the user might be able to + * resolve the conflict and resubmit the request. The response body SHOULD include enough + * information for the user to recognize the source of the conflict. Ideally, the response + * entity would include enough information for the user or user agent to fix the problem; + * however, that might not be possible and is not required. + * + */ +class ConflictException : RadarWebApplicationException { + /** + * Create a [ConflictException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + */ + constructor(message: String?, entityName: String, errorCode: String?) : super( + HttpStatus.CONFLICT, + message, + entityName, + errorCode + ) + + /** + * Create a [ConflictException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + * @param paramMap map of additional information. + */ + constructor( + message: String?, entityName: String, errorCode: String?, + paramMap: Map? + ) : super(HttpStatus.CONFLICT, message, entityName, errorCode, paramMap) +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/EntityName.java b/src/main/java/org/radarbase/management/web/rest/errors/EntityName.java deleted file mode 100644 index a8dc96baf..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/EntityName.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -public interface EntityName { - - String OAUTH_CLIENT = "oauthClient"; - String SOURCE_DATA = "sourceData"; - String SOURCE_TYPE = "sourceType"; - String SUBJECT = "subject"; - String USER = "userManagement"; - String SOURCE = "source"; - String META_TOKEN = "meta-token"; - String ORGANIZATION = "organization"; - String PROJECT = "project"; - String REVISION = "revision"; - String GROUP = "group"; - -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/EntityName.kt b/src/main/java/org/radarbase/management/web/rest/errors/EntityName.kt new file mode 100644 index 000000000..786101b32 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/EntityName.kt @@ -0,0 +1,17 @@ +package org.radarbase.management.web.rest.errors + +interface EntityName { + companion object { + const val OAUTH_CLIENT = "oauthClient" + const val SOURCE_DATA = "sourceData" + const val SOURCE_TYPE = "sourceType" + const val SUBJECT = "subject" + const val USER = "userManagement" + const val SOURCE = "source" + const val META_TOKEN = "meta-token" + const val ORGANIZATION = "organization" + const val PROJECT = "project" + const val REVISION = "revision" + const val GROUP = "group" + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.java b/src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.java deleted file mode 100644 index 3719b57d6..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -public final class ErrorConstants { - - public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure"; - public static final String ERR_ACCESS_DENIED = "error.accessDenied"; - public static final String ERR_VALIDATION = "error.validation"; - public static final String ERR_METHOD_NOT_SUPPORTED = "error.methodNotSupported"; - public static final String ERR_MEDIA_TYPE_NOT_SUPPORTED = "error.mediaTypeNotSupported"; - public static final String ERR_INTERNAL_SERVER_ERROR = "error.internalServerError"; - public static final String ERR_SOURCE_TYPE_EXISTS = "error.sourceTypeExists"; - public static final String ERR_CLIENT_ID_EXISTS = "error.clientIdExists"; - public static final String ERR_OAUTH_CLIENT_PROTECTED = "error.oAuthClientProtected"; - public static final String ERR_OAUTH_CLIENT_ALREADY_EXISTS = "error.oAuthClientExists"; - public static final String ERR_OAUTH_CLIENT_ID_NOT_FOUND = "error.oAuthClientIdNotFound"; - public static final String ERR_SUBJECT_NOT_FOUND = "error.subjectNotFound"; - public static final String ERR_SOURCE_NAME_EXISTS = "error.sourceNameExists"; - public static final String ERR_SOURCE_NOT_FOUND = "error.sourceNotFound"; - public static final String ERR_SOURCE_TYPE_IN_USE = "error.sourceTypeInUse"; - public static final String ERR_SOURCE_TYPE_NOT_FOUND = "error.sourceTypeNotFound"; - public static final String ERR_GROUP_NOT_FOUND = "error.groupNotFound"; - public static final String ERR_GROUP_EXISTS = "error.groupExists"; - public static final String ERR_INVALID_AUTHORITY = "error.invalidAuthority"; - public static final String ERR_EMAIL_EXISTS = "error.emailexists"; - public static final String ERR_ORGANIZATION_NAME_NOT_FOUND = "error" - + ".organizationNameNotFound"; - public static final String ERR_PROJECT_ID_NOT_FOUND = "error.projectIdNotFound"; - public static final String ERR_PROJECT_NAME_NOT_FOUND = "error.projectNameNotFound"; - public static final String ERR_REVISIONS_NOT_FOUND = "error.revisionsNotFound"; - public static final String ERR_ENTITY_NOT_FOUND = "error.entityNotFound"; - public static final String ERR_TOKEN_NOT_FOUND = "error.tokenNotFound"; - public static final String ERR_SOURCE_TYPE_NOT_PROVIDED = "error.sourceTypeNotProvided"; - public static final String ERR_PERSISTENT_TOKEN_DISABLED = "error.persistentTokenDisabled"; - public static final String ERR_ACTIVE_PARTICIPANT_PROJECT_NOT_FOUND = "error" - + ".activeParticipantProjectNotFound"; - public static final String ERR_NO_VALID_PRIVACY_POLICY_URL_CONFIGURED = "error" - + ".noValidPrivacyPolicyUrl"; - public static final String ERR_NO_SUCH_CLIENT = "error.noSuchClient"; - public static final String ERR_PROJECT_NOT_EMPTY = "error.projectNotEmpty"; - public static final String ERR_PASSWORD_TOO_LONG = "error.longPassword"; - public static final String ERR_PASSWORD_TOO_WEAK = "error.weakPassword"; - - public static final String ERR_EMAIL_NOT_REGISTERED = "error.emailNotRegistered"; - - private ErrorConstants() { - } - -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.kt b/src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.kt new file mode 100644 index 000000000..3073a1102 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.kt @@ -0,0 +1,42 @@ +package org.radarbase.management.web.rest.errors + +object ErrorConstants { + const val ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure" + const val ERR_ACCESS_DENIED = "error.accessDenied" + const val ERR_VALIDATION = "error.validation" + const val ERR_METHOD_NOT_SUPPORTED = "error.methodNotSupported" + const val ERR_MEDIA_TYPE_NOT_SUPPORTED = "error.mediaTypeNotSupported" + const val ERR_INTERNAL_SERVER_ERROR = "error.internalServerError" + const val ERR_SOURCE_TYPE_EXISTS = "error.sourceTypeExists" + const val ERR_CLIENT_ID_EXISTS = "error.clientIdExists" + const val ERR_OAUTH_CLIENT_PROTECTED = "error.oAuthClientProtected" + const val ERR_OAUTH_CLIENT_ALREADY_EXISTS = "error.oAuthClientExists" + const val ERR_OAUTH_CLIENT_ID_NOT_FOUND = "error.oAuthClientIdNotFound" + const val ERR_SUBJECT_NOT_FOUND = "error.subjectNotFound" + const val ERR_SOURCE_NAME_EXISTS = "error.sourceNameExists" + const val ERR_SOURCE_NOT_FOUND = "error.sourceNotFound" + const val ERR_SOURCE_TYPE_IN_USE = "error.sourceTypeInUse" + const val ERR_SOURCE_TYPE_NOT_FOUND = "error.sourceTypeNotFound" + const val ERR_GROUP_NOT_FOUND = "error.groupNotFound" + const val ERR_GROUP_EXISTS = "error.groupExists" + const val ERR_INVALID_AUTHORITY = "error.invalidAuthority" + const val ERR_EMAIL_EXISTS = "error.emailexists" + const val ERR_ORGANIZATION_NAME_NOT_FOUND = ("error" + + ".organizationNameNotFound") + const val ERR_PROJECT_ID_NOT_FOUND = "error.projectIdNotFound" + const val ERR_PROJECT_NAME_NOT_FOUND = "error.projectNameNotFound" + const val ERR_REVISIONS_NOT_FOUND = "error.revisionsNotFound" + const val ERR_ENTITY_NOT_FOUND = "error.entityNotFound" + const val ERR_TOKEN_NOT_FOUND = "error.tokenNotFound" + const val ERR_SOURCE_TYPE_NOT_PROVIDED = "error.sourceTypeNotProvided" + const val ERR_PERSISTENT_TOKEN_DISABLED = "error.persistentTokenDisabled" + const val ERR_ACTIVE_PARTICIPANT_PROJECT_NOT_FOUND = ("error" + + ".activeParticipantProjectNotFound") + const val ERR_NO_VALID_PRIVACY_POLICY_URL_CONFIGURED = ("error" + + ".noValidPrivacyPolicyUrl") + const val ERR_NO_SUCH_CLIENT = "error.noSuchClient" + const val ERR_PROJECT_NOT_EMPTY = "error.projectNotEmpty" + const val ERR_PASSWORD_TOO_LONG = "error.longPassword" + const val ERR_PASSWORD_TOO_WEAK = "error.weakPassword" + const val ERR_EMAIL_NOT_REGISTERED = "error.emailNotRegistered" +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.java b/src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.java deleted file mode 100644 index 2c31c74bb..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -/** - * View Model for transferring error message with a list of field errors. - */ -public class ErrorVM implements Serializable { - - private static final long serialVersionUID = 1L; - - private final String message; - private final String description; - - private List fieldErrors; - - public ErrorVM(String message) { - this(message, null); - } - - public ErrorVM(String message, String description) { - this.message = message; - this.description = description; - } - - /** - * Add a field error. - * @param objectName the object name - * @param field the field name - * @param message the error message - */ - public void add(String objectName, String field, String message) { - if (fieldErrors == null) { - fieldErrors = new ArrayList<>(); - } - fieldErrors.add(new FieldErrorVM(objectName, field, message)); - } - - public String getMessage() { - return message; - } - - public String getDescription() { - return description; - } - - public List getFieldErrors() { - return fieldErrors; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.kt b/src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.kt new file mode 100644 index 000000000..39ae5c5cd --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.kt @@ -0,0 +1,31 @@ +package org.radarbase.management.web.rest.errors + +import java.io.Serializable + +/** + * View Model for transferring error message with a list of field errors. + */ +class ErrorVM @JvmOverloads constructor(val message: String?, val description: String? = null) : Serializable { + private var fieldErrors: MutableList? = null + + /** + * Add a field error. + * @param objectName the object name + * @param field the field name + * @param message the error message + */ + fun add(objectName: String?, field: String?, message: String?) { + if (fieldErrors == null) { + fieldErrors = ArrayList() + } + fieldErrors!!.add(FieldErrorVM(objectName, field, message)) + } + + fun getFieldErrors(): List? { + return fieldErrors + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.java b/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.java deleted file mode 100644 index 795beb9af..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.java +++ /dev/null @@ -1,209 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.dao.ConcurrencyFailureException; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.http.ResponseEntity.BodyBuilder; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.oauth2.provider.NoSuchClientException; -import org.springframework.transaction.TransactionSystemException; -import org.springframework.validation.BindingResult; -import org.springframework.validation.FieldError; -import org.springframework.web.HttpRequestMethodNotSupportedException; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; -import org.springframework.web.server.ResponseStatusException; - -import java.util.List; - -/** - * Controller advice to translate the server side exceptions to client-friendly json structures. - */ -@ControllerAdvice -@SuppressWarnings("PMD.CouplingBetweenObjects") -public class ExceptionTranslator { - - private static final Logger logger = LoggerFactory.getLogger(ExceptionTranslator.class); - - /** - * Translate a {@link ConcurrencyFailureException}. - * @param ex the exception - * @return the view-model for the translated exception - */ - @ExceptionHandler(ConcurrencyFailureException.class) - @ResponseStatus(HttpStatus.CONFLICT) - @ResponseBody - public ErrorVM processConcurrencyError(ConcurrencyFailureException ex) { - return new ErrorVM(ErrorConstants.ERR_CONCURRENCY_FAILURE); - } - - /** - * Translate a {@link TransactionSystemException}. - * @param ex the exception - * @return the view-model for the translated exception - */ - @ExceptionHandler(TransactionSystemException.class) - @ResponseStatus(HttpStatus.BAD_REQUEST) - @ResponseBody - public ErrorVM processValidationError(TransactionSystemException ex) { - // TODO: this is the top level exception that is thrown when e.g. a - // ConstraintValidationException occurs. Need to investigate what other exceptions result - // in this one and probably add a check for it. - return new ErrorVM(ErrorConstants.ERR_VALIDATION, ex.getMessage()); - } - - /** - * Translate a {@link MethodArgumentNotValidException}. - * @param ex the exception - * @return the view-model for the translated exception - */ - @ExceptionHandler(MethodArgumentNotValidException.class) - @ResponseStatus(HttpStatus.BAD_REQUEST) - @ResponseBody - public ErrorVM processValidationError(MethodArgumentNotValidException ex) { - BindingResult result = ex.getBindingResult(); - List fieldErrors = result.getFieldErrors(); - ErrorVM dto = new ErrorVM(ErrorConstants.ERR_VALIDATION); - for (FieldError fieldError : fieldErrors) { - dto.add(fieldError.getObjectName(), fieldError.getField(), - fieldError.getCode() + ": " + fieldError.getDefaultMessage()); - } - return dto; - } - - @ExceptionHandler(MethodArgumentTypeMismatchException.class) - @ResponseBody - public ErrorVM processValidationError(MethodArgumentTypeMismatchException ex) { - return new ErrorVM(ErrorConstants.ERR_VALIDATION, - ex.getName() + ": " + ex.getMessage()); - } - - @ExceptionHandler(RadarWebApplicationException.class) - public ResponseEntity processParameterizedValidationError( - RadarWebApplicationException ex) { - return processRadarWebApplicationException(ex); - } - - @ExceptionHandler(NotFoundException.class) - public ResponseEntity processNotFound(NotFoundException ex) { - return processRadarWebApplicationException(ex); - } - - @ExceptionHandler(InvalidStateException.class) - public ResponseEntity processNotFound( - InvalidStateException ex) { - return processRadarWebApplicationException(ex); - } - - @ExceptionHandler(RequestGoneException.class) - public ResponseEntity processNotFound(RequestGoneException ex) { - return processRadarWebApplicationException(ex); - } - - @ExceptionHandler(BadRequestException.class) - public ResponseEntity processNotFound(BadRequestException ex) { - return processRadarWebApplicationException(ex); - } - - @ExceptionHandler(InvalidRequestException.class) - public ResponseEntity processNotFound( - InvalidRequestException ex) { - return processRadarWebApplicationException(ex); - } - - - /** - * Translate a {@link ConflictException}. - * @param ex the exception - * @return the view-model for the translated exception - */ - @ExceptionHandler(ConflictException.class) - public ResponseEntity processConflict( - ConflictException ex) { - return processRadarWebApplicationException(ex); - } - - private ResponseEntity processRadarWebApplicationException( - RadarWebApplicationException exception) { - return ResponseEntity - .status(exception.getStatus()) - .headers(HeaderUtil.createExceptionAlert(exception.getEntityName(), - exception.getErrorCode(), exception.getMessage())) - .body(exception.getExceptionVM()); - } - - @ExceptionHandler(AccessDeniedException.class) - @ResponseStatus(HttpStatus.FORBIDDEN) - @ResponseBody - public ErrorVM processAccessDeniedException(AccessDeniedException e) { - return new ErrorVM(ErrorConstants.ERR_ACCESS_DENIED, e.getMessage()); - } - - @ExceptionHandler(NotAuthorizedException.class) - @ResponseStatus(HttpStatus.FORBIDDEN) - @ResponseBody - public ErrorVM processRadarNotAuthorizedException(NotAuthorizedException e) { - return new ErrorVM(ErrorConstants.ERR_ACCESS_DENIED, e.getMessage()); - } - - @ExceptionHandler(HttpRequestMethodNotSupportedException.class) - @ResponseBody - @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) - public ErrorVM processMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) { - return new ErrorVM(ErrorConstants.ERR_METHOD_NOT_SUPPORTED, ex.getMessage()); - } - - /** - * If a client tries to initiate an OAuth flow with a non-existing client, this will - * translate the error into a bad request status. Otherwise we return an internal server - * error status, but it is not a server error. - * - * @param ex the exception - * @return the view-model for the translated exception - */ - @ExceptionHandler(NoSuchClientException.class) - @ResponseBody - @ResponseStatus(HttpStatus.BAD_REQUEST) - public ErrorVM processNoSuchClientException(NoSuchClientException ex) { - return new ErrorVM(ErrorConstants.ERR_NO_SUCH_CLIENT, ex.getMessage()); - } - - @ExceptionHandler(ResponseStatusException.class) - public ResponseEntity responseStatusResponse(ResponseStatusException ex) { - return ResponseEntity.status(ex.getStatus()) - .body(new ErrorVM(null, ex.getMessage())); - } - - /** - * Generic exception translator. - * @param ex the exception - * @return the view-model for the translated exception - */ - @ExceptionHandler(Exception.class) - public ResponseEntity processRuntimeException(Exception ex) { - BodyBuilder builder; - ErrorVM errorVm; - logger.error("Failed to process message", ex); - ResponseStatus responseStatus = AnnotationUtils.findAnnotation(ex.getClass(), - ResponseStatus.class); - if (responseStatus != null) { - builder = ResponseEntity.status(responseStatus.value()); - errorVm = new ErrorVM("error." + responseStatus.value().value(), - responseStatus.reason()); - } else { - builder = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR); - errorVm = new ErrorVM(ErrorConstants.ERR_INTERNAL_SERVER_ERROR, - "Internal server error"); - } - return builder.body(errorVm); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt b/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt new file mode 100644 index 000000000..c405793cf --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt @@ -0,0 +1,224 @@ +package org.radarbase.management.web.rest.errors + +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.web.rest.errors.InvalidStateException +import org.radarbase.management.web.rest.errors.RadarWebApplicationException +import org.radarbase.management.web.rest.errors.RequestGoneException +import org.radarbase.management.web.rest.util.HeaderUtil +import org.slf4j.LoggerFactory +import org.springframework.core.annotation.AnnotationUtils +import org.springframework.dao.ConcurrencyFailureException +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.security.access.AccessDeniedException +import org.springframework.security.oauth2.provider.NoSuchClientException +import org.springframework.transaction.TransactionSystemException +import org.springframework.web.HttpRequestMethodNotSupportedException +import org.springframework.web.bind.MethodArgumentNotValidException +import org.springframework.web.bind.annotation.ControllerAdvice +import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.ResponseBody +import org.springframework.web.bind.annotation.ResponseStatus +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException +import org.springframework.web.server.ResponseStatusException + +/** + * Controller advice to translate the server side exceptions to client-friendly json structures. + */ +@ControllerAdvice +class ExceptionTranslator { + /** + * Translate a [ConcurrencyFailureException]. + * @param ex the exception + * @return the view-model for the translated exception + */ + @ExceptionHandler(ConcurrencyFailureException::class) + @ResponseStatus(HttpStatus.CONFLICT) + @ResponseBody + fun processConcurrencyError(ex: ConcurrencyFailureException?): ErrorVM { + return ErrorVM(ErrorConstants.ERR_CONCURRENCY_FAILURE) + } + + /** + * Translate a [TransactionSystemException]. + * @param ex the exception + * @return the view-model for the translated exception + */ + @ExceptionHandler(TransactionSystemException::class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ResponseBody + fun processValidationError(ex: TransactionSystemException): ErrorVM { + // TODO: this is the top level exception that is thrown when e.g. a + // ConstraintValidationException occurs. Need to investigate what other exceptions result + // in this one and probably add a check for it. + return ErrorVM(ErrorConstants.ERR_VALIDATION, ex.message) + } + + /** + * Translate a [MethodArgumentNotValidException]. + * @param ex the exception + * @return the view-model for the translated exception + */ + @ExceptionHandler(MethodArgumentNotValidException::class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ResponseBody + fun processValidationError(ex: MethodArgumentNotValidException): ErrorVM { + val result = ex.bindingResult + val fieldErrors = result.fieldErrors + val dto = ErrorVM(ErrorConstants.ERR_VALIDATION) + for (fieldError in fieldErrors) { + dto.add( + fieldError.objectName, fieldError.field, + fieldError.code + ": " + fieldError.defaultMessage + ) + } + return dto + } + + @ExceptionHandler(MethodArgumentTypeMismatchException::class) + @ResponseBody + fun processValidationError(ex: MethodArgumentTypeMismatchException): ErrorVM { + return ErrorVM( + ErrorConstants.ERR_VALIDATION, + ex.name + ": " + ex.message + ) + } + + @ExceptionHandler(RadarWebApplicationException::class) + fun processParameterizedValidationError( + ex: RadarWebApplicationException + ): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + @ExceptionHandler(NotFoundException::class) + fun processNotFound(ex: NotFoundException): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + @ExceptionHandler(InvalidStateException::class) + fun processNotFound( + ex: InvalidStateException + ): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + @ExceptionHandler(RequestGoneException::class) + fun processNotFound(ex: RequestGoneException): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + @ExceptionHandler(BadRequestException::class) + fun processNotFound(ex: BadRequestException): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + @ExceptionHandler(InvalidRequestException::class) + fun processNotFound( + ex: InvalidRequestException + ): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + /** + * Translate a [ConflictException]. + * @param ex the exception + * @return the view-model for the translated exception + */ + @ExceptionHandler(ConflictException::class) + fun processConflict( + ex: ConflictException + ): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + private fun processRadarWebApplicationException( + exception: RadarWebApplicationException + ): ResponseEntity { + return ResponseEntity + .status(exception.status) + .headers( + HeaderUtil.createExceptionAlert( + exception.entityName, + exception.errorCode, exception.message + ) + ) + .body(exception.exceptionVM) + } + + @ExceptionHandler(AccessDeniedException::class) + @ResponseStatus(HttpStatus.FORBIDDEN) + @ResponseBody + fun processAccessDeniedException(e: AccessDeniedException): ErrorVM { + return ErrorVM(ErrorConstants.ERR_ACCESS_DENIED, e.message) + } + + @ExceptionHandler(NotAuthorizedException::class) + @ResponseStatus(HttpStatus.FORBIDDEN) + @ResponseBody + fun processRadarNotAuthorizedException(e: NotAuthorizedException): ErrorVM { + return ErrorVM(ErrorConstants.ERR_ACCESS_DENIED, e.message) + } + + @ExceptionHandler(HttpRequestMethodNotSupportedException::class) + @ResponseBody + @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) + fun processMethodNotSupportedException(ex: HttpRequestMethodNotSupportedException): ErrorVM { + return ErrorVM(ErrorConstants.ERR_METHOD_NOT_SUPPORTED, ex.message) + } + + /** + * If a client tries to initiate an OAuth flow with a non-existing client, this will + * translate the error into a bad request status. Otherwise we return an internal server + * error status, but it is not a server error. + * + * @param ex the exception + * @return the view-model for the translated exception + */ + @ExceptionHandler(NoSuchClientException::class) + @ResponseBody + @ResponseStatus(HttpStatus.BAD_REQUEST) + fun processNoSuchClientException(ex: NoSuchClientException): ErrorVM { + return ErrorVM(ErrorConstants.ERR_NO_SUCH_CLIENT, ex.message) + } + + @ExceptionHandler(ResponseStatusException::class) + fun responseStatusResponse(ex: ResponseStatusException): ResponseEntity { + return ResponseEntity.status(ex.status) + .body(ErrorVM(null, ex.message)) + } + + /** + * Generic exception translator. + * @param ex the exception + * @return the view-model for the translated exception + */ + @ExceptionHandler(Exception::class) + fun processRuntimeException(ex: Exception): ResponseEntity { + val builder: ResponseEntity.BodyBuilder + val errorVm: ErrorVM + logger.error("Failed to process message", ex) + val responseStatus = AnnotationUtils.findAnnotation( + ex.javaClass, + ResponseStatus::class.java + ) + if (responseStatus != null) { + builder = ResponseEntity.status(responseStatus.value) + errorVm = ErrorVM( + "error." + responseStatus.value.value(), + responseStatus.reason + ) + } else { + builder = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + errorVm = ErrorVM( + ErrorConstants.ERR_INTERNAL_SERVER_ERROR, + "Internal server error" + ) + } + return builder.body(errorVm) + } + + companion object { + private val logger = LoggerFactory.getLogger(ExceptionTranslator::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.java b/src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.java deleted file mode 100644 index 81c580594..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import java.io.Serializable; - -public class FieldErrorVM implements Serializable { - - private static final long serialVersionUID = 1L; - - private final String objectName; - - private final String field; - - private final String message; - - /** - * Create a new field error view-model. - * @param dto the object name - * @param field the field name - * @param message the message - */ - public FieldErrorVM(String dto, String field, String message) { - this.objectName = dto; - this.field = field; - this.message = message; - } - - public String getObjectName() { - return objectName; - } - - public String getField() { - return field; - } - - public String getMessage() { - return message; - } - -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.kt b/src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.kt new file mode 100644 index 000000000..ca4f5cc3d --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.kt @@ -0,0 +1,16 @@ +package org.radarbase.management.web.rest.errors + +import java.io.Serializable + +class FieldErrorVM +/** + * Create a new field error view-model. + * @param dto the object name + * @param field the field name + * @param message the message + */(val objectName: String?, val field: String?, val message: String?) : Serializable { + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.java b/src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.java deleted file mode 100644 index 75c5420be..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.springframework.http.HttpStatus; - -import java.util.Map; - -/** - * The server understood the request, but is refusing to fulfill it. - * Authorization will not help and the request SHOULD NOT be repeated. - */ -public class InvalidRequestException extends RadarWebApplicationException { - - /** - * Create a {@link InvalidRequestException} with the given message, relatedEntityName,errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - */ - public InvalidRequestException(String message, String entityName, String errorCode) { - super(HttpStatus.FORBIDDEN, message, entityName, errorCode); - } - - /** - * Create a {@link InvalidRequestException} with the given message, relatedEntityName,errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - * @param params map of additional information. - */ - public InvalidRequestException(String message, String entityName, String errorCode, - Map params) { - super(HttpStatus.FORBIDDEN, message, entityName, errorCode, params); - } - -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.kt b/src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.kt new file mode 100644 index 000000000..85e344ef4 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.kt @@ -0,0 +1,36 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus + +/** + * The server understood the request, but is refusing to fulfill it. + * Authorization will not help and the request SHOULD NOT be repeated. + */ +class InvalidRequestException : RadarWebApplicationException { + /** + * Create a [InvalidRequestException] with the given message, relatedEntityName,errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + */ + constructor(message: String?, entityName: String, errorCode: String?) : super( + HttpStatus.FORBIDDEN, + message, + entityName, + errorCode + ) + + /** + * Create a [InvalidRequestException] with the given message, relatedEntityName,errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + * @param params map of additional information. + */ + constructor( + message: String?, entityName: String, errorCode: String?, + params: Map? + ) : super(HttpStatus.FORBIDDEN, message, entityName, errorCode, params) +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.java b/src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.java deleted file mode 100644 index f547e1d06..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.radarbase.management.web.rest.errors; - - -import org.springframework.http.HttpStatus; - -import java.util.Map; - -/** - * The server encountered an unexpected condition which prevented it from fulfilling the request. - */ -public class InvalidStateException extends RadarWebApplicationException { - - /** - * Create a {@link InvalidStateException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - */ - public InvalidStateException(String message, String entityName, String errorCode) { - super(HttpStatus.INTERNAL_SERVER_ERROR, message, entityName, errorCode); - } - - /** - * Create a {@link InvalidStateException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - * @param params map of additional information. - */ - public InvalidStateException(String message, String entityName, String errorCode, - Map params) { - super(HttpStatus.INTERNAL_SERVER_ERROR, message, entityName, errorCode, params); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.kt b/src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.kt new file mode 100644 index 000000000..4bf9d316d --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.kt @@ -0,0 +1,35 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus + +/** + * The server encountered an unexpected condition which prevented it from fulfilling the request. + */ +class InvalidStateException : RadarWebApplicationException { + /** + * Create a [InvalidStateException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + */ + constructor(message: String?, entityName: String, errorCode: String?) : super( + HttpStatus.INTERNAL_SERVER_ERROR, + message, + entityName, + errorCode + ) + + /** + * Create a [InvalidStateException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + * @param params map of additional information. + */ + constructor( + message: String?, entityName: String, errorCode: String?, + params: Map? + ) : super(HttpStatus.INTERNAL_SERVER_ERROR, message, entityName, errorCode, params) +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.java b/src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.java deleted file mode 100644 index 0c2330b24..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.springframework.http.HttpStatus; - -import java.util.Map; - -/** - * Created by dverbeec on 7/09/2017. - * Modified by nivethika on 2/08/2018. - *

The server has not found anything matching the Request-URI. - * No indication is given of whether the condition is temporary or permanent. - *

- */ -public class NotFoundException extends RadarWebApplicationException { - - /** - * Create a {@link NotFoundException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - */ - public NotFoundException(String message, String entityName, String errorCode) { - super(HttpStatus.NOT_FOUND, message, entityName, errorCode); - } - - /** - * Create a {@link NotFoundException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - * @param paramMap map of additional information. - */ - public NotFoundException(String message, String entityName, String errorCode, - Map paramMap) { - super(HttpStatus.NOT_FOUND, message, entityName, errorCode, paramMap); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.kt b/src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.kt new file mode 100644 index 000000000..4e071e791 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.kt @@ -0,0 +1,40 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus + +/** + * Created by dverbeec on 7/09/2017. + * Modified by nivethika on 2/08/2018. + * + * The server has not found anything matching the Request-URI. + * No indication is given of whether the condition is temporary or permanent. + * + */ +class NotFoundException : RadarWebApplicationException { + /** + * Create a [NotFoundException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + */ + constructor(message: String?, entityName: String, errorCode: String?) : super( + HttpStatus.NOT_FOUND, + message, + entityName, + errorCode + ) + + /** + * Create a [NotFoundException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + * @param paramMap map of additional information. + */ + constructor( + message: String, entityName: String, errorCode: String, + paramMap: Map? + ) : super(HttpStatus.NOT_FOUND, message, entityName, errorCode, paramMap) +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.java b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.java deleted file mode 100644 index 9c2ac3a87..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.springframework.http.HttpStatus; -import org.springframework.web.server.ResponseStatusException; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -import static java.util.Collections.emptyMap; - -/** - * A base parameterized exception, which can be translated on the client side. - * - *

For example:

- * - *

{@code throw new RadarWebApplicationException("Message to client", "entity", - * "error.errorCode")}

- * - *

can be translated with:

- * - *

{@code "error.myCustomError" : "The server says {{param0}} to {{param1}}"}

- */ -public class RadarWebApplicationException extends ResponseStatusException { - - private final String message; - - private final String entityName; - - private final String errorCode; - - private final Map paramMap = new HashMap<>(); - - /** - * Create an exception with the given parameters. This will be used to to create response - * body of the request. - * - * @param message Error message to the client - * @param entityName Entity related to the exception - * @param errorCode error code defined in MP if relevant. - */ - public RadarWebApplicationException(HttpStatus status, String message, String entityName, - String errorCode) { - this(status, message, entityName, errorCode, emptyMap()); - } - - - /** - * A base parameterized exception, which can be translated on the client side. - * @param status {@link HttpStatus} code. - * @param message message to client. - * @param entityName entityRelated from {@link EntityName} - * @param errorCode errorCode from {@link ErrorConstants} - * @param params map of optional information. - */ - public RadarWebApplicationException(HttpStatus status, String message, String entityName, - String errorCode, Map params) { - super(status, message, null); - // add default timestamp first, so a timestamp key in the paramMap will overwrite it - this.paramMap.put("timestamp", - new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US) - .format(new Date())); - this.paramMap.putAll(params); - this.message = message; - this.entityName = entityName; - this.errorCode = errorCode; - } - - @Override - public String getMessage() { - return message; - } - - public String getEntityName() { - return entityName; - } - - public String getErrorCode() { - return errorCode; - } - - protected RadarWebApplicationExceptionVM getExceptionVM() { - return new RadarWebApplicationExceptionVM(message, entityName, errorCode, paramMap); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.kt b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.kt new file mode 100644 index 000000000..088340c08 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.kt @@ -0,0 +1,60 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus +import org.springframework.web.server.ResponseStatusException +import java.text.SimpleDateFormat +import java.util.* + +/** + * A base parameterized exception, which can be translated on the client side. + * + * + * For example: + * + * + * `throw new RadarWebApplicationException("Message to client", "entity", + * "error.errorCode")` + * + * + * can be translated with: + * + * + * `"error.myCustomError" : "The server says {{param0}} to {{param1}}"` + */ +open class RadarWebApplicationException @JvmOverloads constructor( + status: HttpStatus?, message: String?, entityName: String, + errorCode: String?, params: Map? = emptyMap() +) : ResponseStatusException(status, message, null) { + override val message: String? + val entityName: String + val errorCode: String? + private val paramMap: MutableMap = HashMap() + /** + * A base parameterized exception, which can be translated on the client side. + * @param status [HttpStatus] code. + * @param message message to client. + * @param entityName entityRelated from [EntityName] + * @param errorCode errorCode from [ErrorConstants] + * @param params map of optional information. + */ + /** + * Create an exception with the given parameters. This will be used to to create response + * body of the request. + * + * @param message Error message to the client + * @param entityName Entity related to the exception + * @param errorCode error code defined in MP if relevant. + */ + init { + // add default timestamp first, so a timestamp key in the paramMap will overwrite it + paramMap["timestamp"] = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US) + .format(Date()) + paramMap.putAll(params!!) + this.message = message + this.entityName = entityName + this.errorCode = errorCode + } + + val exceptionVM: RadarWebApplicationExceptionVM + get() = RadarWebApplicationExceptionVM(message, entityName, errorCode, paramMap) +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.java b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.java deleted file mode 100644 index dfc438d55..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Map; -import java.util.Objects; - -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * View Model for sending a {@link RadarWebApplicationException}. - */ -public class RadarWebApplicationExceptionVM implements Serializable { - - private static final long serialVersionUID = 1L; - - @JsonProperty - private final String entityName; - - @JsonProperty - private final String errorCode; - - @JsonProperty - private final String message; - - @JsonProperty - private Map params; - - /** - * Creates an error view model with message, entityName and errorCode. - * - * @param message message to client. - * @param entityName entityRelated from {@link EntityName} - * @param errorCode errorCode from {@link ErrorConstants} - */ - protected RadarWebApplicationExceptionVM(String message, String entityName, String errorCode) { - this(message, entityName, errorCode, Collections.emptyMap()); - } - - /** - * Creates an error view model with message, entityName and errorCode. - * - * @param message message to client. - * @param entityName entityRelated from {@link EntityName} - * @param errorCode errorCode from {@link ErrorConstants} - * @param params map of optional information. - */ - protected RadarWebApplicationExceptionVM(String message, String entityName, String errorCode, - Map params) { - this.message = message; - this.entityName = entityName; - this.errorCode = errorCode; - this.params = params; - } - - public Map getParams() { - return params; - } - - public String getEntityName() { - return entityName; - } - - public String getErrorCode() { - return errorCode; - } - - public String getMessage() { - return message; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - RadarWebApplicationExceptionVM that = (RadarWebApplicationExceptionVM) o; - return Objects.equals(entityName, that.entityName) && Objects - .equals(errorCode, that.errorCode) && Objects.equals(message, that.message) && Objects - .equals(params, that.params); - } - - @Override - public int hashCode() { - - return Objects.hash(entityName, errorCode, message, params); - } - - @Override - public String toString() { - return "RadarWebApplicationExceptionVM{" + "entityName='" + entityName + '\'' - + ", errorCode='" + errorCode + '\'' + ", message='" + message + '\'' + ", params=" - + params + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt new file mode 100644 index 000000000..51d44586a --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt @@ -0,0 +1,63 @@ +package org.radarbase.management.web.rest.errors + +import com.fasterxml.jackson.annotation.JsonProperty +import java.io.Serializable +import java.util.* + +/** + * View Model for sending a [RadarWebApplicationException]. + */ +class RadarWebApplicationExceptionVM +/** + * Creates an error view model with message, entityName and errorCode. + * + * @param message message to client. + * @param entityName entityRelated from [EntityName] + * @param errorCode errorCode from [ErrorConstants] + * @param params map of optional information. + */( + @field:JsonProperty val message: String?, + @field:JsonProperty val entityName: String, + @field:JsonProperty val errorCode: String?, + @field:JsonProperty val params: Map +) : Serializable { + + /** + * Creates an error view model with message, entityName and errorCode. + * + * @param message message to client. + * @param entityName entityRelated from [EntityName] + * @param errorCode errorCode from [ErrorConstants] + */ + protected constructor(message: String?, entityName: String, errorCode: String?) : this( + message, + entityName, + errorCode, + emptyMap() + ) + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val that = o as RadarWebApplicationExceptionVM + return entityName == that.entityName && errorCode == that.errorCode && message == that.message && params == that.params + } + + override fun hashCode(): Int { + return Objects.hash(entityName, errorCode, message, params) + } + + override fun toString(): String { + return ("RadarWebApplicationExceptionVM{" + "entityName='" + entityName + '\'' + + ", errorCode='" + errorCode + '\'' + ", message='" + message + '\'' + ", params=" + + params + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.java b/src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.java deleted file mode 100644 index c9cf2aa39..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.springframework.http.HttpStatus; - -import java.util.Map; - -/** - * Throw when the requested resource is no longer available at the server and no forwarding - * address is known. This condition is expected to be considered permanent. Clients with - * link editing capabilities SHOULD delete references to the Request-URI after user approval. - */ -public class RequestGoneException extends RadarWebApplicationException { - - /** - * Create a {@link RequestGoneException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - */ - public RequestGoneException(String message, String entityName, String errorCode) { - super(HttpStatus.GONE, message, entityName, errorCode); - } - - - /** - * Create a {@link RequestGoneException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - * @param paramMap map of additional information. - */ - public RequestGoneException(String message, String entityName, String errorCode, - Map paramMap) { - super(HttpStatus.GONE, message, entityName, errorCode, paramMap); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.kt b/src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.kt new file mode 100644 index 000000000..622aff31c --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.kt @@ -0,0 +1,37 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus + +/** + * Throw when the requested resource is no longer available at the server and no forwarding + * address is known. This condition is expected to be considered permanent. Clients with + * link editing capabilities SHOULD delete references to the Request-URI after user approval. + */ +class RequestGoneException : RadarWebApplicationException { + /** + * Create a [RequestGoneException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + */ + constructor(message: String?, entityName: String, errorCode: String?) : super( + HttpStatus.GONE, + message, + entityName, + errorCode + ) + + /** + * Create a [RequestGoneException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + * @param paramMap map of additional information. + */ + constructor( + message: String?, entityName: String, errorCode: String?, + paramMap: Map? + ) : super(HttpStatus.GONE, message, entityName, errorCode, paramMap) +} diff --git a/src/main/java/org/radarbase/management/web/rest/package-info.java b/src/main/java/org/radarbase/management/web/rest/package-info.java deleted file mode 100644 index 6ae57b9cf..000000000 --- a/src/main/java/org/radarbase/management/web/rest/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Spring MVC REST controllers. - */ -package org.radarbase.management.web.rest; diff --git a/src/main/java/org/radarbase/management/web/rest/package-info.kt b/src/main/java/org/radarbase/management/web/rest/package-info.kt new file mode 100644 index 000000000..3dfc41d29 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/package-info.kt @@ -0,0 +1,5 @@ +/** + * Spring MVC REST controllers. + */ +package org.radarbase.management.web.rest + diff --git a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.java b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.java deleted file mode 100644 index e3855681e..000000000 --- a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.radarbase.management.web.rest.util; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.Arrays; -import java.util.Objects; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpHeaders; - -/** - * Utility class for HTTP headers creation. - */ -public final class HeaderUtil { - - private static final Logger log = LoggerFactory.getLogger(HeaderUtil.class); - - private static final String APPLICATION_NAME = "managementPortalApp"; - - private HeaderUtil() { - } - - /** - * Create the headers for displaying an alert in the frontend. - * @param message the message - * @param param the message parameters - * @return the {@link HttpHeaders} - */ - public static HttpHeaders createAlert(String message, String param) { - HttpHeaders headers = new HttpHeaders(); - headers.add("X-managementPortalApp-alert", message); - headers.add("X-managementPortalApp-params", param); - return headers; - } - - public static HttpHeaders createEntityCreationAlert(String entityName, String param) { - return createAlert(APPLICATION_NAME + "." + entityName + ".created", param); - } - - public static HttpHeaders createEntityUpdateAlert(String entityName, String param) { - return createAlert(APPLICATION_NAME + "." + entityName + ".updated", param); - } - - public static HttpHeaders createEntityDeletionAlert(String entityName, String param) { - return createAlert(APPLICATION_NAME + "." + entityName + ".deleted", param); - } - - /** - * Create headers to display a failure alert in the frontend. - * @param entityName the entity on which the failure occurred - * @param errorKey the error key in the translation dictionary - * @param defaultMessage the default message - * @return the {@link HttpHeaders} - */ - public static HttpHeaders createFailureAlert(String entityName, String errorKey, - String defaultMessage) { - log.error("Entity creation failed, {}", defaultMessage); - HttpHeaders headers = new HttpHeaders(); - headers.add("X-managementPortalApp-error", "error." + errorKey); - headers.add("X-managementPortalApp-params", entityName); - return headers; - } - - /** - * Create headers to display a failure alert in the frontend. - * @param entityName the entity on which the failure occurred - * @param errorKey the error key in the translation dictionary - * @param defaultMessage the default message - * @return the {@link HttpHeaders} - */ - public static HttpHeaders createExceptionAlert(String entityName, String errorKey, - String defaultMessage) { - //TODO: Replace createFailureAlert with error. addition - log.error("Entity creation failed, {}", defaultMessage); - HttpHeaders headers = new HttpHeaders(); - headers.add("X-managementPortalApp-error", errorKey); - headers.add("X-managementPortalApp-params", entityName); - return headers; - } - - /** - * URLEncode each component, prefix and join them by forward slashes. - * - *

E.g. buildPath("api", "projects", "radar/1") results in the string - * /api/projects/radar%2F1.

- * - * @param components The components of the path. - * @return A String where the components are URLEncoded and joined by forward slashes. - */ - public static String buildPath(String... components) { - return Arrays.stream(components) - .filter(Objects::nonNull) - .filter(c -> !c.isEmpty()) - .map(c -> { - // try-catch needs to be inside the lambda - try { - return URLEncoder.encode(c, "UTF-8"); - } catch (UnsupportedEncodingException ex) { - log.error(ex.getMessage()); - return ""; - } - }) - .reduce("", (a, b) -> String.join("/", a, b)); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt new file mode 100644 index 000000000..9fc6f8f50 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt @@ -0,0 +1,103 @@ +package org.radarbase.management.web.rest.util + +import org.slf4j.LoggerFactory +import org.springframework.http.HttpHeaders +import java.io.UnsupportedEncodingException +import java.net.URLEncoder +import java.util.* + +/** + * Utility class for HTTP headers creation. + */ +object HeaderUtil { + private val log = LoggerFactory.getLogger(HeaderUtil::class.java) + private const val APPLICATION_NAME = "managementPortalApp" + + /** + * Create the headers for displaying an alert in the frontend. + * @param message the message + * @param param the message parameters + * @return the [HttpHeaders] + */ + fun createAlert(message: String?, param: String?): HttpHeaders { + val headers = HttpHeaders() + headers.add("X-managementPortalApp-alert", message) + headers.add("X-managementPortalApp-params", param) + return headers + } + + fun createEntityCreationAlert(entityName: String, param: String?): HttpHeaders { + return createAlert(APPLICATION_NAME + "." + entityName + ".created", param) + } + + fun createEntityUpdateAlert(entityName: String, param: String?): HttpHeaders { + return createAlert(APPLICATION_NAME + "." + entityName + ".updated", param) + } + + fun createEntityDeletionAlert(entityName: String, param: String?): HttpHeaders { + return createAlert(APPLICATION_NAME + "." + entityName + ".deleted", param) + } + + /** + * Create headers to display a failure alert in the frontend. + * @param entityName the entity on which the failure occurred + * @param errorKey the error key in the translation dictionary + * @param defaultMessage the default message + * @return the [HttpHeaders] + */ + fun createFailureAlert( + entityName: String, errorKey: String, + defaultMessage: String? + ): HttpHeaders { + log.error("Entity creation failed, {}", defaultMessage) + val headers = HttpHeaders() + headers.add("X-managementPortalApp-error", "error.$errorKey") + headers.add("X-managementPortalApp-params", entityName) + return headers + } + + /** + * Create headers to display a failure alert in the frontend. + * @param entityName the entity on which the failure occurred + * @param errorKey the error key in the translation dictionary + * @param defaultMessage the default message + * @return the [HttpHeaders] + */ + fun createExceptionAlert( + entityName: String?, errorKey: String?, + defaultMessage: String? + ): HttpHeaders { + //TODO: Replace createFailureAlert with error. addition + log.error("Entity creation failed, {}", defaultMessage) + val headers = HttpHeaders() + headers.add("X-managementPortalApp-error", errorKey) + headers.add("X-managementPortalApp-params", entityName) + return headers + } + + /** + * URLEncode each component, prefix and join them by forward slashes. + * + * + * E.g. `buildPath("api", "projects", "radar/1")` results in the string + * `/api/projects/radar%2F1`. + * + * @param components The components of the path. + * @return A String where the components are URLEncoded and joined by forward slashes. + */ + fun buildPath(vararg components: String): String { + return Arrays.stream(components) + .filter { obj: String? -> Objects.nonNull(obj) } + .filter { c: String -> !c.isEmpty() } + .map { c: String? -> + // try-catch needs to be inside the lambda + try { + return@map URLEncoder.encode(c, "UTF-8") + } catch (ex: UnsupportedEncodingException) { + log.error(ex.message) + return@map "" + } + } + .reduce("") { a: String?, b: String? -> java.lang.String.join("/", a, b) } + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.java b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.java deleted file mode 100644 index ec5db882c..000000000 --- a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.radarbase.management.web.rest.util; - -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.web.rest.criteria.CriteriaRange; -import org.radarbase.management.web.rest.criteria.SubjectCriteria; -import org.springframework.data.domain.Page; -import org.springframework.http.HttpHeaders; -import org.springframework.web.util.UriComponentsBuilder; - -import javax.annotation.Nullable; -import java.util.Locale; - -/** - * Utility class for handling pagination. - * - *

- * Pagination uses the same principles as the - * GithubAPI, - * and follow RFC 5988 (Link header). - *

- */ -public final class PaginationUtil { - - private PaginationUtil() { - } - - /** - * Generate headers for pagination. - * @param page the page - * @param baseUrl the base URL - * @return the {@link HttpHeaders} - */ - public static HttpHeaders generatePaginationHttpHeaders(Page page, String baseUrl) { - HttpHeaders headers = new HttpHeaders(); - headers.add("X-Total-Count", Long.toString(page.getTotalElements())); - - StringBuilder link = new StringBuilder(256); - if ((page.getNumber() + 1) < page.getTotalPages()) { - link.append('<') - .append(generateUri(baseUrl, page.getNumber() + 1, page.getSize())) - .append(">; rel=\"next\","); - } - // prev link - if ((page.getNumber()) > 0) { - link.append('<') - .append(generateUri(baseUrl, page.getNumber() - 1, page.getSize())) - .append(">; rel=\"prev\","); - } - // last and first link - int lastPage = 0; - if (page.getTotalPages() > 0) { - lastPage = page.getTotalPages() - 1; - } - link.append('<') - .append(generateUri(baseUrl, lastPage, page.getSize())) - .append(">; rel=\"last\",<") - .append(generateUri(baseUrl, 0, page.getSize())) - .append(">; rel=\"first\""); - headers.add(HttpHeaders.LINK, link.toString()); - return headers; - } - - /** - * Generate pagination HTTP headers for subjects given a subject filter. - * @param page the page - * @param baseUrl the base URL - * @param criteria subject criteria - * @return the {@link HttpHeaders} - */ - public static HttpHeaders generateSubjectPaginationHttpHeaders( - Page page, String baseUrl, SubjectCriteria criteria - ) { - HttpHeaders headers = new HttpHeaders(); - headers.add("X-Total-Count", Long.toString(page.getTotalElements())); - if (!page.isEmpty()) { - String link = '<' - + generateUri(page, baseUrl, criteria) - + ">; rel=\"next\""; - headers.add(HttpHeaders.LINK, link); - } - return headers; - } - - private static String generateUri(String baseUrl, int page, int size) { - return UriComponentsBuilder.fromUriString(baseUrl) - .queryParam("page", page) - .queryParam("size", size) - .toUriString(); - } - - private static String generateUri(Page page, String baseUrl, - SubjectCriteria criteria) { - UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(baseUrl); - generateUriCriteriaRange(builder, "dateOfBirth", criteria.getDateOfBirth()); - generateUriCriteriaRange(builder, "enrollmentDate", criteria.getEnrollmentDate()); - generateUriParam(builder, "externalId", criteria.getExternalId()); - generateUriParam(builder, "groupId", criteria.getGroupId()); - generateUriParam(builder, "personName", criteria.getPersonName()); - generateUriParam(builder, "humanReadableIdentifier", - criteria.getHumanReadableIdentifier()); - generateUriParam(builder, "projectName", criteria.getProjectName()); - generateUriParam(builder, "login", criteria.getLogin()); - if (criteria.getAuthority() != null) { - criteria.getAuthority().forEach(a -> generateUriParam(builder, - "authority", a)); - } - generateUriParam(builder, "size", criteria.getSize()); - generateUriParam(builder, "page", criteria.getPage()); - if (criteria.getSort() != null) { - criteria.getParsedSort().forEach(order -> generateUriParam(builder, "sort", - order.getSortBy().getQueryParam() + ',' - + order.getDirection().name().toLowerCase(Locale.ROOT))); - } - SubjectDTO lastSubject = page.getContent().get(page.getNumberOfElements() - 1); - generateUriParam(builder, "last.id", lastSubject.getId()); - generateUriParam(builder, "last.login", lastSubject.getLogin()); - if (lastSubject.getExternalId() != null && !lastSubject.getExternalId().isEmpty()) { - generateUriParam(builder, "last.externalId", lastSubject.getExternalId()); - } - return builder.toUriString(); - } - - private static void generateUriCriteriaRange(UriComponentsBuilder builder, String prefix, - CriteriaRange range) { - if (range == null) { - return; - } - generateUriParam(builder, prefix + ".is", range.getIs()); - generateUriParam(builder, prefix + ".from", range.getFrom()); - generateUriParam(builder, prefix + ".to", range.getTo()); - } - - private static void generateUriParam(UriComponentsBuilder builder, String name, - @Nullable Object value) { - if (value != null) { - builder.queryParam(name, value); - } - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt new file mode 100644 index 000000000..bc27cdb8d --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt @@ -0,0 +1,151 @@ +package org.radarbase.management.web.rest.util + +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.web.rest.criteria.CriteriaRange +import org.radarbase.management.web.rest.criteria.SubjectAuthority +import org.radarbase.management.web.rest.criteria.SubjectCriteria +import org.radarbase.management.web.rest.criteria.SubjectSortOrder +import org.springframework.data.domain.Page +import org.springframework.http.HttpHeaders +import org.springframework.web.util.UriComponentsBuilder +import java.util.function.Consumer + +/** + * Utility class for handling pagination. + * + * + * + * Pagination uses the same principles as the + * [GithubAPI](https://developer.github.com/v3/#pagination), + * and follow [RFC 5988 (Link header)](http://tools.ietf.org/html/rfc5988). + * + */ +object PaginationUtil { + /** + * Generate headers for pagination. + * @param page the page + * @param baseUrl the base URL + * @return the [HttpHeaders] + */ + fun generatePaginationHttpHeaders(page: Page<*>?, baseUrl: String): HttpHeaders { + val headers = HttpHeaders() + headers.add("X-Total-Count", page!!.totalElements.toString()) + val link = StringBuilder(256) + if (page.number + 1 < page.totalPages) { + link.append('<') + .append(generateUri(baseUrl, page.number + 1, page.size)) + .append(">; rel=\"next\",") + } + // prev link + if (page.number > 0) { + link.append('<') + .append(generateUri(baseUrl, page.number - 1, page.size)) + .append(">; rel=\"prev\",") + } + // last and first link + var lastPage = 0 + if (page.totalPages > 0) { + lastPage = page.totalPages - 1 + } + link.append('<') + .append(generateUri(baseUrl, lastPage, page.size)) + .append(">; rel=\"last\",<") + .append(generateUri(baseUrl, 0, page.size)) + .append(">; rel=\"first\"") + headers.add(HttpHeaders.LINK, link.toString()) + return headers + } + + /** + * Generate pagination HTTP headers for subjects given a subject filter. + * @param page the page + * @param baseUrl the base URL + * @param criteria subject criteria + * @return the [HttpHeaders] + */ + fun generateSubjectPaginationHttpHeaders( + page: Page, baseUrl: String, criteria: SubjectCriteria + ): HttpHeaders { + val headers = HttpHeaders() + headers.add("X-Total-Count", page.totalElements.toString()) + if (!page.isEmpty) { + val link = ('<' + .toString() + generateUri(page, baseUrl, criteria) + + ">; rel=\"next\"") + headers.add(HttpHeaders.LINK, link) + } + return headers + } + + private fun generateUri(baseUrl: String, page: Int, size: Int): String { + return UriComponentsBuilder.fromUriString(baseUrl) + .queryParam("page", page) + .queryParam("size", size) + .toUriString() + } + + private fun generateUri( + page: Page, baseUrl: String, + criteria: SubjectCriteria + ): String { + val builder = UriComponentsBuilder.fromUriString(baseUrl) + generateUriCriteriaRange(builder, "dateOfBirth", criteria.dateOfBirth) + generateUriCriteriaRange(builder, "enrollmentDate", criteria.enrollmentDate) + generateUriParam(builder, "externalId", criteria.externalId) + generateUriParam(builder, "groupId", criteria.groupId) + generateUriParam(builder, "personName", criteria.personName) + generateUriParam( + builder, "humanReadableIdentifier", + criteria.humanReadableIdentifier + ) + generateUriParam(builder, "projectName", criteria.projectName) + generateUriParam(builder, "login", criteria.login) + if (criteria.authority != null) { + criteria.authority!!.forEach(Consumer { a: SubjectAuthority? -> + generateUriParam( + builder, + "authority", a + ) + }) + } + generateUriParam(builder, "size", criteria.size) + generateUriParam(builder, "page", criteria.page) + if (criteria.getSort() != null) { + criteria.getParsedSort()!!.forEach(Consumer { order: SubjectSortOrder? -> + generateUriParam( + builder, "sort", + order?.sortBy?.queryParam + ',' + + order?.direction?.name?.lowercase() + ) + }) + } + val lastSubject = page.content[page.numberOfElements - 1] + generateUriParam(builder, "last.id", lastSubject?.id) + generateUriParam(builder, "last.login", lastSubject?.login) + if (lastSubject?.externalId != null && !lastSubject.externalId.isNullOrEmpty()) { + generateUriParam(builder, "last.externalId", lastSubject.externalId) + } + return builder.toUriString() + } + + private fun generateUriCriteriaRange( + builder: UriComponentsBuilder, prefix: String, + range: CriteriaRange<*>? + ) { + if (range == null) { + return + } + generateUriParam(builder, "$prefix.is", range.iss) + generateUriParam(builder, "$prefix.from", range.from) + generateUriParam(builder, "$prefix.to", range.to) + } + + private fun generateUriParam( + builder: UriComponentsBuilder, name: String, + value: Any? + ) { + if (value != null) { + builder.queryParam(name, value) + } + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.kt b/src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.kt new file mode 100644 index 000000000..e39d1b04d --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.kt @@ -0,0 +1,19 @@ +package org.radarbase.management.web.rest.vm + +/** + * A POJO for PATCH .../groups/{groupName}/subjects + * [ + * {"op": "add", "value": [{"login": "sub1"}, {"id": 2}]}, + * {"op": "remove", "value": [{"login": "sub3"}]} + * ] + * request. + */ +class GroupPatchOperation { + var op: String? = null + var value: List? = null + + class SubjectPatchValue { + var id: Long? = null + var login: String? = null + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.kt b/src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.kt new file mode 100644 index 000000000..005cd097c --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.kt @@ -0,0 +1,9 @@ +package org.radarbase.management.web.rest.vm + +/** + * View Model object for storing the user's key and password. + */ +class KeyAndPasswordVM { + lateinit var key: String + lateinit var newPassword: String +} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.kt b/src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.kt new file mode 100644 index 000000000..596752026 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.kt @@ -0,0 +1,27 @@ +package org.radarbase.management.web.rest.vm + +import ch.qos.logback.classic.Logger +import com.fasterxml.jackson.annotation.JsonCreator + +/** + * View Model object for storing a Logback logger. + */ +class LoggerVM { + var name: String? = null + var level: String? = null + + constructor(logger: Logger) { + name = logger.name + level = logger.effectiveLevel.toString() + } + + @JsonCreator + constructor() + + override fun toString(): String { + return ("LoggerVM{" + + "name='" + name + '\'' + + ", level='" + level + '\'' + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.kt b/src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.kt new file mode 100644 index 000000000..831165595 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.kt @@ -0,0 +1,19 @@ +package org.radarbase.management.web.rest.vm + +import org.radarbase.management.service.dto.UserDTO +import javax.validation.constraints.Size + +/** + * View Model extending the UserDTO, which is meant to be used in the user management UI. + */ +class ManagedUserVM : UserDTO() { + var password: @Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH) String? = null + override fun toString(): String { + return "ManagedUserVM{} " + super.toString() + } + + companion object { + const val PASSWORD_MIN_LENGTH = 4 + const val PASSWORD_MAX_LENGTH = 100 + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/package-info.kt b/src/main/java/org/radarbase/management/web/rest/vm/package-info.kt new file mode 100644 index 000000000..52bd63ff5 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/vm/package-info.kt @@ -0,0 +1,5 @@ +/** + * View Models used by Spring MVC REST controllers. + */ +package org.radarbase.management.web.rest.vm + From c1979b1ccf66744fedbce270b803a9a55183ff89 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 30 Oct 2023 22:38:01 +0100 Subject: [PATCH 040/158] test compiles, not passing yet --- .../management/service/PasswordService.kt | 2 +- .../management/service/RoleService.kt | 12 +- .../management/service/UserService.kt | 11 +- .../service/dto/ClientDetailsDTO.kt | 2 +- .../management/service/dto/SourceTypeDTO.kt | 2 +- .../mapper/decorator/RoleMapperDecorator.kt | 14 +- .../management/web/rest/ProjectResource.kt | 8 +- .../management/web/rest/util/HeaderUtil.kt | 10 +- .../auth/authentication/OAuthHelper.kt | 6 +- .../security/SecurityUtilsUnitTest.kt | 2 +- .../service/MetaTokenServiceTest.kt | 2 +- ...apIntegrationWorkFlowOnServiceLevelTest.kt | 10 +- .../management/service/SubjectServiceTest.kt | 17 +- .../management/service/UserServiceIntTest.kt | 37 +-- .../web/rest/AccountResourceIntTest.kt | 43 ++-- .../web/rest/AuditResourceIntTest.kt | 61 ++--- .../web/rest/GroupResourceIntTest.kt | 209 ++++++--------- .../web/rest/OAuthClientsResourceIntTest.kt | 20 +- .../web/rest/OrganizationResourceIntTest.kt | 238 +++++++++--------- .../web/rest/ProfileInfoResourceIntTest.kt | 2 +- .../web/rest/SourceDataResourceIntTest.kt | 144 +++++------ .../web/rest/SourceTypeResourceIntTest.kt | 14 +- .../web/rest/SubjectResourceIntTest.kt | 34 +-- .../web/rest/UserResourceIntTest.kt | 10 +- 24 files changed, 417 insertions(+), 493 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/PasswordService.kt b/src/main/java/org/radarbase/management/service/PasswordService.kt index 9245e110e..abda1038f 100644 --- a/src/main/java/org/radarbase/management/service/PasswordService.kt +++ b/src/main/java/org/radarbase/management/service/PasswordService.kt @@ -17,7 +17,7 @@ import java.security.SecureRandom import java.util.* @Service -class PasswordService(private val passwordEncoder: PasswordEncoder) { +open class PasswordService(private val passwordEncoder: PasswordEncoder) { private val random: Random = SecureRandom() /** diff --git a/src/main/java/org/radarbase/management/service/RoleService.kt b/src/main/java/org/radarbase/management/service/RoleService.kt index 7bc960bd1..9074ceaf3 100644 --- a/src/main/java/org/radarbase/management/service/RoleService.kt +++ b/src/main/java/org/radarbase/management/service/RoleService.kt @@ -19,7 +19,6 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.util.* -import java.util.Map import java.util.function.Consumer /** @@ -144,8 +143,9 @@ open class RoleService( "Cannot find organization for authority", EntityName.USER, ErrorConstants.ERR_INVALID_AUTHORITY, - Map.of( - "authorityName", role.authority, "projectId", organizationId.toString() + mapOf( + Pair("authorityName", role.authority), + Pair("projectId", organizationId.toString()) ) ) } @@ -164,8 +164,10 @@ open class RoleService( ) ?: createNewRole(role) { r: Role -> r.project = projectRepository.findByIdWithOrganization(projectId) ?: throw NotFoundException( - "Cannot find project for authority", EntityName.USER, ErrorConstants.ERR_INVALID_AUTHORITY, Map.of( - "authorityName", role.authority, "projectId", projectId.toString() + "Cannot find project for authority", EntityName.USER, ErrorConstants.ERR_INVALID_AUTHORITY, + mapOf( + Pair("authorityName", role.authority), + Pair("projectId", projectId.toString()) ) ) } diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt index 3adcb8c2f..3f0dc91d6 100644 --- a/src/main/java/org/radarbase/management/service/UserService.kt +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -31,13 +31,10 @@ import org.springframework.transaction.annotation.Transactional import java.time.Period import java.time.ZonedDateTime import java.util.* -import java.util.Map import java.util.function.Function -import java.util.stream.Collectors import kotlin.collections.HashSet import kotlin.collections.MutableSet import kotlin.collections.Set -import kotlin.collections.setOf /** * Service class for managing users. @@ -72,7 +69,7 @@ open class UserService( "User with activation key $key not found", EntityName.USER, ErrorConstants.ERR_ENTITY_NOT_FOUND, - Map.of("activationKey", key) + mapOf(Pair("activationKey", key)) ) } @@ -235,7 +232,7 @@ open class UserService( "Email address $email already in use", EntityName.USER, ErrorConstants.ERR_EMAIL_EXISTS, - Map.of("email", email) + mapOf(Pair("email", email)) ) } } else { @@ -243,7 +240,7 @@ open class UserService( "User with login $userName not found", EntityName.USER, ErrorConstants.ERR_ENTITY_NOT_FOUND, - Map.of("user", userName) + mapOf(Pair("user", userName)) ) } user.firstName = firstName @@ -420,7 +417,7 @@ open class UserService( "User with login $login not found", EntityName.USER, ErrorConstants.ERR_ENTITY_NOT_FOUND, - Map.of("user", login) + mapOf(Pair("user", login)) ) val managedRoles = user.roles diff --git a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt index b2a19c2f6..98f7da1a6 100644 --- a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt @@ -16,5 +16,5 @@ class ClientDetailsDTO { var refreshTokenValiditySeconds: Long? = null var authorities: Set? = null var registeredRedirectUri: Set? = null - var additionalInformation: Map? = null + var additionalInformation: MutableMap? = null } diff --git a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt index 1eb8c3b85..ff5fe709e 100644 --- a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt @@ -25,7 +25,7 @@ class SourceTypeDTO : Serializable { @set:JsonSetter(nulls = Nulls.AS_EMPTY) @JsonInclude(JsonInclude.Include.NON_EMPTY) - var sourceData: Set = HashSet() + var sourceData: MutableSet = HashSet() override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt index 0fb761825..244965c2d 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt @@ -10,13 +10,9 @@ import org.springframework.beans.factory.annotation.Qualifier /** * Created by nivethika on 03-8-18. */ -abstract class RoleMapperDecorator : RoleMapper { - @Autowired - @Qualifier("delegate") - private val delegate: RoleMapper? = null - - @Autowired - private val authorityRepository: AuthorityRepository? = null +abstract class RoleMapperDecorator(@Autowired @Qualifier("delegate") private val delegate: RoleMapper, + @Autowired private val authorityRepository: AuthorityRepository +) : RoleMapper { /** * Overrides standard RoleMapperImpl and loads authority from repository if not specified. @@ -27,9 +23,9 @@ abstract class RoleMapperDecorator : RoleMapper { if (roleDto == null) { return null } - val role = delegate!!.roleDTOToRole(roleDto) + val role = delegate.roleDTOToRole(roleDto) if (role!!.authority == null) { - role.authority = roleDto.authorityName?.let { authorityRepository!!.getById(it) } + role.authority = roleDto.authorityName?.let { authorityRepository.getById(it) } } return role } diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index 842c51558..af751ea30 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -77,7 +77,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, fun createProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity { log.debug("REST request to save Project : {}", projectDto) val org = projectDto!!.organization - if (org == null || org.name == null) { + if (org?.name == null) { throw BadRequestException( "Organization must be provided", ENTITY_NAME, ErrorConstants.ERR_VALIDATION @@ -109,7 +109,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, .headers( createEntityCreationAlert( ENTITY_NAME, - result?.projectName + result.projectName ) ) .body(result) @@ -135,7 +135,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, // When a client wants to link the project to the default organization, // this must be done explicitly. val org = projectDto.organization - if (org == null || org.name == null) { + if (org?.name == null) { throw BadRequestException( "Organization must be provided", ENTITY_NAME, ErrorConstants.ERR_VALIDATION @@ -309,7 +309,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, ): ResponseEntity<*> { authService.checkScope(Permission.SOURCE_READ) log.debug("REST request to get all Sources") - val projectDto = projectService.findOneByName(projectName) ?: throw NoSuchElementException() + val projectDto = projectService.findOneByName(projectName) //?: throw NoSuchElementException() authService.checkPermission(Permission.SOURCE_READ, { e: EntityDetails -> e.organization(projectDto.organization?.name) diff --git a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt index 9fc6f8f50..888626811 100644 --- a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt +++ b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt @@ -4,7 +4,6 @@ import org.slf4j.LoggerFactory import org.springframework.http.HttpHeaders import java.io.UnsupportedEncodingException import java.net.URLEncoder -import java.util.* /** * Utility class for HTTP headers creation. @@ -85,10 +84,9 @@ object HeaderUtil { * @param components The components of the path. * @return A String where the components are URLEncoded and joined by forward slashes. */ - fun buildPath(vararg components: String): String { - return Arrays.stream(components) - .filter { obj: String? -> Objects.nonNull(obj) } - .filter { c: String -> !c.isEmpty() } + fun buildPath(vararg components: String?): String { + return components + .filterNotNull() .map { c: String? -> // try-catch needs to be inside the lambda try { @@ -98,6 +96,6 @@ object HeaderUtil { return@map "" } } - .reduce("") { a: String?, b: String? -> java.lang.String.join("/", a, b) } + .reduce { a: String, b: String -> java.lang.String.join("/", a, b) } } } diff --git a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt index 3c18fd705..e4779a75a 100644 --- a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt +++ b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt @@ -109,7 +109,7 @@ object OAuthHelper { val rsa = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey) validRsaToken = createValidToken(rsa) val verifierList = listOf(ecdsa, rsa) - .map{ alg: Algorithm? -> + .map { alg: Algorithm? -> alg?.toTokenVerifier(ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL) } .requireNoNulls() @@ -126,9 +126,7 @@ object OAuthHelper { fun createAuthenticationFilter(): JwtAuthenticationFilter { val userRepository = Mockito.mock(UserRepository::class.java) Mockito.`when`(userRepository.findOneByLogin(ArgumentMatchers.anyString())).thenReturn( - Optional.of( - createAdminUser() - ) + createAdminUser() ) return JwtAuthenticationFilter(createTokenValidator(), { auth: Authentication? -> auth }, userRepository) } diff --git a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt index 6bfdb36ce..e414e8506 100644 --- a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt +++ b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt @@ -19,7 +19,7 @@ internal class SecurityUtilsUnitTest { "admin" ) SecurityContextHolder.setContext(securityContext) - val login = SecurityUtils.getCurrentUserLogin().orElse(null) + val login = SecurityUtils.currentUserLogin Assertions.assertThat(login).isEqualTo("admin") } } diff --git a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt index b4f3f447d..5e167e471 100644 --- a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt @@ -42,7 +42,7 @@ internal open class MetaTokenServiceTest( fun setUp() { subjectDto = SubjectServiceTest.createEntityDTO() subjectDto = subjectService.createSubject(subjectDto)!! - clientDetails = oAuthClientService.createClientDetail(OAuthClientServiceTestUtil.createClient())!! + clientDetails = oAuthClientService.createClientDetail(OAuthClientServiceTestUtil.createClient()) } @Test diff --git a/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt b/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt index a4461d7cb..69a4efc1c 100644 --- a/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt +++ b/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt @@ -19,7 +19,7 @@ import java.util.* @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -internal class RedcapIntegrationWorkFlowOnServiceLevelTest { +internal open class RedcapIntegrationWorkFlowOnServiceLevelTest { @Autowired private val projectService: ProjectService? = null @@ -46,13 +46,13 @@ internal class RedcapIntegrationWorkFlowOnServiceLevelTest { // manually save val saved = projectService!!.save(projectDto) - val storedProjectId = saved.id + val storedProjectId = saved.id!! Assertions.assertTrue(storedProjectId > 0) // Use ROLE_EXTERNAL_ERF_INTEGRATOR authority in your oauth2 client config // GET api/projects/{storedProjectId} val retrievedById = projectService.findOne(storedProjectId) - Assertions.assertEquals(retrievedById.id, storedProjectId) + Assertions.assertEquals(retrievedById?.id, storedProjectId) // retrieve required details // location is part of project property @@ -64,7 +64,7 @@ internal class RedcapIntegrationWorkFlowOnServiceLevelTest { // redcap-id from trigger val redcapRecordId = "1" - for ((key, value) in retrievedById.attributes) { + for ((key, value) in retrievedById!!.attributes!!) { when (key) { ProjectDTO.WORK_PACKAGE_KEY -> workPackageRetrieved = value ProjectDTO.PHASE_KEY -> phaseRetrieved = value @@ -98,7 +98,7 @@ internal class RedcapIntegrationWorkFlowOnServiceLevelTest { // create/save a subject // PUT api/subjects/ val savedSubject = subjectService!!.createSubject(newSubject) - Assertions.assertTrue(savedSubject!!.id > 0) + Assertions.assertTrue(savedSubject!!.id!! > 0) // asset human-readable-id for ((key, value) in savedSubject.attributes) { diff --git a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt index 895b8ef2c..d1200bb68 100644 --- a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt @@ -21,19 +21,18 @@ import java.util.* @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -class SubjectServiceTest { - @Autowired - private val subjectService: SubjectService? = null +open class SubjectServiceTest( + @Autowired private val subjectService: SubjectService, + @Autowired private val projectService: ProjectService +) { - @Autowired - private val projectService: ProjectService? = null @Test @Transactional - fun testGetPrivacyPolicyUrl() { - projectService!!.save(createEntityDTO().project) - val created = subjectService!!.createSubject(createEntityDTO()) + open fun testGetPrivacyPolicyUrl() { + projectService.save(createEntityDTO().project!!) + val created = subjectService.createSubject(createEntityDTO()) Assertions.assertNotNull(created!!.id) - val subject = subjectService.findOneByLogin(created.getLogin()) + val subject = subjectService.findOneByLogin(created.login) Assertions.assertNotNull(subject) val privacyPolicyUrl = subjectService.getPrivacyPolicyUrl(subject) Assertions.assertNotNull(privacyPolicyUrl) diff --git a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt index 3fd29977a..eae6e9804 100644 --- a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt +++ b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt @@ -66,19 +66,20 @@ open class UserServiceIntTest( ReflectionTestUtils.setField(revisionService, "entityManager", entityManager) ReflectionTestUtils.setField(userService, "userMapper", userMapper) ReflectionTestUtils.setField(userService, "userRepository", userRepository) - userRepository.findOneByLogin(userDto!!.login) - .ifPresent { entity: User -> userRepository.delete(entity) } + + + userRepository.delete(userRepository.findOneByLogin(userDto!!.login)!!) } @Test fun assertThatUserMustExistToResetPassword() { var maybeUser = userService.requestPasswordReset("john.doe@localhost") - Assertions.assertThat(maybeUser).isNotPresent() + Assertions.assertThat(maybeUser).isNull() maybeUser = userService.requestPasswordReset("admin@localhost") - Assertions.assertThat(maybeUser).isPresent() - Assertions.assertThat(maybeUser.get().email).isEqualTo("admin@localhost") - Assertions.assertThat(maybeUser.get().resetDate).isNotNull() - Assertions.assertThat(maybeUser.get().resetKey).isNotNull() + Assertions.assertThat(maybeUser).isNotNull() + Assertions.assertThat(maybeUser?.email).isEqualTo("admin@localhost") + Assertions.assertThat(maybeUser?.resetDate).isNotNull() + Assertions.assertThat(maybeUser?.resetKey).isNotNull() } @Test @@ -86,9 +87,9 @@ open class UserServiceIntTest( fun assertThatOnlyActivatedUserCanRequestPasswordReset() { val user = userService.createUser(userDto!!) val maybeUser = userService.requestPasswordReset( - userDto?.email + userDto?.email!! ) - Assertions.assertThat(maybeUser).isNotPresent() + Assertions.assertThat(maybeUser).isNull() userRepository.delete(user) } @@ -104,9 +105,9 @@ open class UserServiceIntTest( userRepository.save(user) val maybeUser = userService.completePasswordReset( "johndoe2", - user.resetKey + user.resetKey!! ) - Assertions.assertThat(maybeUser).isNotPresent() + Assertions.assertThat(maybeUser).isNull() userRepository.delete(user) } @@ -121,9 +122,9 @@ open class UserServiceIntTest( userRepository.save(user) val maybeUser = userService.completePasswordReset( "johndoe2", - user.resetKey + user.resetKey!! ) - Assertions.assertThat(maybeUser).isNotPresent() + Assertions.assertThat(maybeUser).isNull() userRepository.delete(user) } @@ -140,12 +141,12 @@ open class UserServiceIntTest( userRepository.save(user) val maybeUser = userService.completePasswordReset( "johndoe2", - user.resetKey + user.resetKey!! ) - Assertions.assertThat(maybeUser).isPresent() - Assertions.assertThat(maybeUser.get().resetDate).isNull() - Assertions.assertThat(maybeUser.get().resetKey).isNull() - Assertions.assertThat(maybeUser.get().password).isNotEqualTo(oldPassword) + Assertions.assertThat(maybeUser).isNotNull() + Assertions.assertThat(maybeUser?.resetDate).isNull() + Assertions.assertThat(maybeUser?.resetKey).isNull() + Assertions.assertThat(maybeUser?.password).isNotEqualTo(oldPassword) userRepository.delete(user) } diff --git a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt index 1b8092117..d90d5bc7d 100644 --- a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt @@ -21,6 +21,7 @@ import org.radarbase.management.security.JwtAuthenticationFilter.Companion.radar import org.radarbase.management.security.RadarAuthentication import org.radarbase.management.service.AuthService import org.radarbase.management.service.MailService +import org.radarbase.management.service.PasswordService import org.radarbase.management.service.UserService import org.radarbase.management.service.dto.RoleDTO import org.radarbase.management.service.dto.UserDTO @@ -50,6 +51,7 @@ internal open class AccountResourceIntTest( @Autowired private val userRepository: UserRepository, @Autowired private val userService: UserService, @Autowired private val userMapper: UserMapper, + @Autowired private val passwordService: PasswordService, @Mock private val mockUserService: UserService, @Mock private val mockMailService: MailService, private var restUserMockMvc: MockMvc, @@ -67,25 +69,22 @@ internal open class AccountResourceIntTest( ) ) SecurityContextHolder.getContext().authentication = RadarAuthentication(radarToken) - val accountResource = AccountResource() - ReflectionTestUtils.setField(accountResource, "userService", userService) - ReflectionTestUtils.setField(accountResource, "userMapper", userMapper) - ReflectionTestUtils.setField(accountResource, "mailService", mockMailService) - ReflectionTestUtils.setField(accountResource, "authService", authService) - ReflectionTestUtils.setField(accountResource, "token", radarToken) - ReflectionTestUtils.setField( - accountResource, "managementPortalProperties", - managementPortalProperties + val accountResource = AccountResource( + userService, + mockMailService, + userMapper, + managementPortalProperties, + authService, + passwordService ) - val accountUserMockResource = AccountResource() - ReflectionTestUtils.setField(accountUserMockResource, "userService", mockUserService) - ReflectionTestUtils.setField(accountUserMockResource, "userMapper", userMapper) - ReflectionTestUtils.setField(accountUserMockResource, "mailService", mockMailService) - ReflectionTestUtils.setField(accountUserMockResource, "authService", authService) - ReflectionTestUtils.setField(accountUserMockResource, "token", radarToken) - ReflectionTestUtils.setField( - accountUserMockResource, "managementPortalProperties", - managementPortalProperties + ReflectionTestUtils.setField(accountResource, "token", radarToken) + val accountUserMockResource = AccountResource( + userService, + mockMailService, + userMapper, + managementPortalProperties, + authService, + passwordService ) restUserMockMvc = MockMvcBuilders.standaloneSetup(accountUserMockResource).build() } @@ -122,7 +121,7 @@ internal open class AccountResourceIntTest( user.email = "john.doe@jhipster.com" user.langKey = "en" user.roles = roles - Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(Optional.of(user)) + Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(user) restUserMockMvc.perform(MockMvcRequestBuilders.post("/api/login") .with { request: MockHttpServletRequest -> request.radarToken = token @@ -160,7 +159,7 @@ internal open class AccountResourceIntTest( user.email = "john.doe@jhipster.com" user.langKey = "en" user.roles = roles - Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(Optional.of(user)) + Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(user) restUserMockMvc.perform( MockMvcRequestBuilders.get("/api/account") .accept(MediaType.APPLICATION_JSON) @@ -182,7 +181,7 @@ internal open class AccountResourceIntTest( @Test @Throws(Exception::class) fun testGetUnknownAccount() { - Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(Optional.empty()) + Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(null) restUserMockMvc.perform( MockMvcRequestBuilders.get("/api/account") .accept(MediaType.APPLICATION_JSON) @@ -213,6 +212,6 @@ internal open class AccountResourceIntTest( ) .andExpect(MockMvcResultMatchers.status().isBadRequest()) val user = userRepository.findOneByEmail("funky@example.com") - Assertions.assertThat(user).isNotPresent() + Assertions.assertThat(user).isNull() } } diff --git a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt index 0c35a35e0..58f6f4b0e 100644 --- a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt @@ -38,37 +38,28 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -internal class AuditResourceIntTest { - @Autowired - private val auditEventRepository: PersistenceAuditEventRepository? = null +internal open class AuditResourceIntTest( + @Autowired private val auditEventRepository: PersistenceAuditEventRepository, + @Autowired private val auditEventConverter: AuditEventConverter, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val formattingConversionService: FormattingConversionService, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + private var auditEvent: PersistentAuditEvent, + private var restAuditMockMvc: MockMvc, + @Autowired private val authService: AuthService +) { - @Autowired - private val auditEventConverter: AuditEventConverter? = null - - @Autowired - private val jacksonMessageConverter: MappingJackson2HttpMessageConverter? = null - - @Autowired - private val formattingConversionService: FormattingConversionService? = null - - @Autowired - private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver? = null - private var auditEvent: PersistentAuditEvent? = null - private var restAuditMockMvc: MockMvc? = null - - @Autowired - private val authService: AuthService? = null @BeforeEach @Throws(ServletException::class) fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) val auditEventService = AuditEventService( auditEventRepository, auditEventConverter ) val auditResource = AuditResource(auditEventService, authService) val filter = OAuthHelper.createAuthenticationFilter() - filter!!.init(MockFilterConfig()) + filter.init(MockFilterConfig()) restAuditMockMvc = MockMvcBuilders.standaloneSetup(auditResource) .setCustomArgumentResolvers(pageableArgumentResolver) .setConversionService(formattingConversionService) @@ -80,11 +71,11 @@ internal class AuditResourceIntTest { @BeforeEach fun initTest() { - auditEventRepository!!.deleteAll() + auditEventRepository.deleteAll() auditEvent = PersistentAuditEvent() - auditEvent!!.auditEventType = SAMPLE_TYPE - auditEvent!!.principal = SAMPLE_PRINCIPAL - auditEvent!!.auditEventDate = SAMPLE_TIMESTAMP + auditEvent.auditEventType = SAMPLE_TYPE + auditEvent.principal = SAMPLE_PRINCIPAL + auditEvent.auditEventDate = SAMPLE_TIMESTAMP } @get:Throws(Exception::class) @@ -92,10 +83,10 @@ internal class AuditResourceIntTest { val allAudits: Unit get() { // Initialize the database - auditEventRepository!!.save(auditEvent) + auditEventRepository.save(auditEvent) // Get all the audits - restAuditMockMvc!!.perform(MockMvcRequestBuilders.get("/management/audits")) + restAuditMockMvc.perform(MockMvcRequestBuilders.get("/management/audits")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect( @@ -112,10 +103,10 @@ internal class AuditResourceIntTest { val audit: Unit get() { // Initialize the database - auditEventRepository!!.save(auditEvent) + auditEventRepository.save(auditEvent) // Get the audit - restAuditMockMvc!!.perform(MockMvcRequestBuilders.get("/management/audits/{id}", auditEvent!!.id)) + restAuditMockMvc.perform(MockMvcRequestBuilders.get("/management/audits/{id}", auditEvent.id)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$.principal").value(SAMPLE_PRINCIPAL)) @@ -123,17 +114,17 @@ internal class AuditResourceIntTest { @get:Throws(Exception::class) @get:Test - val auditsByDate: Unit + open val auditsByDate: Unit get() { // Initialize the database - auditEventRepository!!.save(auditEvent) + auditEventRepository.save(auditEvent) // Generate dates for selecting audits by date, making sure the period contains the audit val fromDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER) val toDate = SAMPLE_TIMESTAMP.plusDays(1).format(FORMATTER) // Get the audit - restAuditMockMvc!!.perform( + restAuditMockMvc.perform( MockMvcRequestBuilders.get( "/management/audits?fromDate=" + fromDate + "&toDate=" + toDate @@ -155,7 +146,7 @@ internal class AuditResourceIntTest { val nonExistingAuditsByDate: Unit get() { // Initialize the database - auditEventRepository!!.save(auditEvent) + auditEventRepository.save(auditEvent) // Generate dates for selecting audits by date, making sure the period will not contain the // sample audit @@ -163,7 +154,7 @@ internal class AuditResourceIntTest { val toDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER) // Query audits but expect no results - restAuditMockMvc!!.perform( + restAuditMockMvc.perform( MockMvcRequestBuilders.get( "/management/audits?fromDate=" + fromDate + "&toDate=" + toDate @@ -179,7 +170,7 @@ internal class AuditResourceIntTest { val nonExistingAudit: Unit get() { // Get the audit - restAuditMockMvc!!.perform(MockMvcRequestBuilders.get("/management/audits/{id}", Long.MAX_VALUE)) + restAuditMockMvc.perform(MockMvcRequestBuilders.get("/management/audits/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) } diff --git a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt index ca21e70f4..882b0afc1 100644 --- a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt @@ -53,39 +53,41 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal class GroupResourceIntTest(@Autowired private val groupService: GroupService, - @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, - @Autowired private val projectMapper: ProjectMapper, - @Autowired private val projectRepository: ProjectRepository, - @Autowired private val roleRepository: RoleRepository, - @Autowired private val subjectRepository: SubjectRepository, - @Autowired private val subjectService: SubjectService, - @Autowired private val groupMapper: GroupMapper, - @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, - @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val groupRepository: GroupRepository, - private var restGroupMockMvc: MockMvc, private var group: Group, - private var project: Project +internal class GroupResourceIntTest( + @Autowired private val groupService: GroupService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val roleRepository: RoleRepository, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val subjectService: SubjectService, + @Autowired private val groupMapper: GroupMapper, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val groupRepository: GroupRepository, + private var restGroupMockMvc: MockMvc, + private var group: Group, + private var project: Project ) { @Autowired private val authService: AuthService? = null + @BeforeEach @Throws(ServletException::class) fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) val groupResource = GroupResource() ReflectionTestUtils.setField(groupResource, "groupService", groupService) ReflectionTestUtils.setField(groupResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) - restGroupMockMvc = MockMvcBuilders.standaloneSetup(groupResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) - .build() + restGroupMockMvc = + MockMvcBuilders.standaloneSetup(groupResource).setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator).setMessageConverters(jacksonMessageConverter) + .addFilter(filter).defaultRequest( + MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken()) + ).build() project = ProjectResourceIntTest.Companion.createEntity() projectRepository.save(project) group = createEntity() @@ -95,7 +97,7 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe fun tearDown() { groupRepository.delete(group) val roles = roleRepository.findAllRolesByProjectName( - project.projectName + project.projectName!! ) roleRepository.deleteAll(roles) projectRepository.delete(project) @@ -118,13 +120,9 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe val groupDto = groupMapper.groupToGroupDTO(group) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + "/api/projects/{projectName}/groups", project.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(groupDto)) + ).andExpect(MockMvcResultMatchers.status().isCreated()) val savedGroup: Group? = groupRepository.findByProjectNameAndName( project.projectName, groupDto.name ) @@ -143,13 +141,9 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe val groupDto = groupMapper.groupToGroupDTO(group) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto)) - ) - .andExpect(MockMvcResultMatchers.status().isNotFound()) + "/api/projects/{projectName}/groups", project.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(groupDto)) + ).andExpect(MockMvcResultMatchers.status().isNotFound()) } @Test @@ -159,29 +153,20 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe val groupDto = groupMapper.groupToGroupDTO(group) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + "/api/projects/{projectName}/groups", project.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(groupDto)) + ).andExpect(MockMvcResultMatchers.status().isCreated()) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto)) - ) - .andExpect(MockMvcResultMatchers.status().isConflict()) + "/api/projects/{projectName}/groups", project.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(groupDto)) + ).andExpect(MockMvcResultMatchers.status().isConflict()) } @Test @Throws(Exception::class) fun createGroupWithExistingNameInDifferentProject() { - val project2: Project = ProjectResourceIntTest.Companion.createEntity() - .projectName(project.projectName + "2") + val project2: Project = ProjectResourceIntTest.Companion.createEntity().projectName(project.projectName + "2") projectRepository.saveAndFlush(project2) val group2 = Group() group2.name = group.name @@ -191,23 +176,15 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe val groupDto = groupMapper.groupToGroupDTO(group) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + "/api/projects/{projectName}/groups", project.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(groupDto)) + ).andExpect(MockMvcResultMatchers.status().isCreated()) val group2Dto = groupMapper.groupToGroupDTO(group2) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project2.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(group2Dto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + "/api/projects/{projectName}/groups", project2.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(group2Dto)) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate groups are saved for both projects val savedGroup1: Group? = groupRepository.findByProjectNameAndName( @@ -241,13 +218,9 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe val groupDto = groupMapper.groupToGroupDTO(group) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto)) - ) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) + "/api/projects/{projectName}/groups", project.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(groupDto)) + ).andExpect(MockMvcResultMatchers.status().isBadRequest()) } @get:Throws(Exception::class) @@ -260,18 +233,14 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get all the groups restGroupMockMvc.perform( MockMvcRequestBuilders.get( - "/api/projects/{projectName}/groups", - project.projectName + "/api/projects/{projectName}/groups", project.projectName ) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect( + ).andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)).andExpect( MockMvcResultMatchers.jsonPath("$.[*].projectId").value>( Matchers.hasItem(project.id!!.toInt()) ) - ) - .andExpect( + ).andExpect( MockMvcResultMatchers.jsonPath("$.[*].name").value>(Matchers.hasItem("group1")) ) } @@ -285,11 +254,9 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.get( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name + "/api/projects/{projectName}/groups/{groupName}", project.projectName, group.name ) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("group1")) .andExpect(MockMvcResultMatchers.jsonPath("$.projectId").value(project.id!!.toInt())) @@ -302,11 +269,9 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.get( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name + "/api/projects/{projectName}/groups/{groupName}", project.projectName, group.name ) - ) - .andExpect(MockMvcResultMatchers.status().isNotFound()) + ).andExpect(MockMvcResultMatchers.status().isNotFound()) } @Test @@ -318,12 +283,9 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name - ) - .accept(TestUtil.APPLICATION_JSON_UTF8) - ) - .andExpect(MockMvcResultMatchers.status().isNoContent()) + "/api/projects/{projectName}/groups/{groupName}", project.projectName, group.name + ).accept(TestUtil.APPLICATION_JSON_UTF8) + ).andExpect(MockMvcResultMatchers.status().isNoContent()) // Validate the Group is not present in the database val savedGroup = groupRepository.findByProjectNameAndName( @@ -349,30 +311,23 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Try to delete the Group (and fail) restGroupMockMvc.perform( MockMvcRequestBuilders.delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name - ) - .accept(TestUtil.APPLICATION_JSON_UTF8) - ) - .andExpect(MockMvcResultMatchers.status().isConflict()) + "/api/projects/{projectName}/groups/{groupName}", project.projectName, group.name + ).accept(TestUtil.APPLICATION_JSON_UTF8) + ).andExpect(MockMvcResultMatchers.status().isConflict()) // Delete the Group (and unlink the subjects) restGroupMockMvc.perform( MockMvcRequestBuilders.delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name - ) - .param("unlinkSubjects", "true") - .accept(TestUtil.APPLICATION_JSON_UTF8) - ) - .andExpect(MockMvcResultMatchers.status().isNoContent()) + "/api/projects/{projectName}/groups/{groupName}", project.projectName, group.name + ).param("unlinkSubjects", "true").accept(TestUtil.APPLICATION_JSON_UTF8) + ).andExpect(MockMvcResultMatchers.status().isNoContent()) // Validate the Group is not present in the database val savedGroup = groupRepository.findByProjectNameAndName( project.projectName, group.name ) Assertions.assertThat(savedGroup).isNull() - val storedSubject = subjectRepository.getOne(savedSubject!!.id) + val storedSubject = subjectRepository.getOne(savedSubject!!.id!!) subjectRepository.delete(storedSubject) } @@ -385,17 +340,14 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name + "2" - ) - .accept(TestUtil.APPLICATION_JSON_UTF8) - ) - .andExpect(MockMvcResultMatchers.status().isNotFound()) + "/api/projects/{projectName}/groups/{groupName}", project.projectName, group.name + "2" + ).accept(TestUtil.APPLICATION_JSON_UTF8) + ).andExpect(MockMvcResultMatchers.status().isNotFound()) // Validate the database still contains the group Assertions.assertThat( groupRepository.findById( - group.id + group.id!! ) ).isNotEmpty() } @@ -409,17 +361,14 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName + "2", group.name - ) - .accept(TestUtil.APPLICATION_JSON_UTF8) - ) - .andExpect(MockMvcResultMatchers.status().isNotFound()) + "/api/projects/{projectName}/groups/{groupName}", project.projectName + "2", group.name + ).accept(TestUtil.APPLICATION_JSON_UTF8) + ).andExpect(MockMvcResultMatchers.status().isNotFound()) // Validate the database still contains the group Assertions.assertThat( groupRepository.findById( - group.id + group.id!! ) ).isNotEmpty() } @@ -445,7 +394,7 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe val sub1Patch = SubjectPatchValue() sub1Patch.id = savedSub1!!.id val sub2Patch = SubjectPatchValue() - sub2Patch.login = savedSub2!!.getLogin() + sub2Patch.login = savedSub2!!.login val patchOp = GroupPatchOperation() patchOp.op = "add" val patchValue = ArrayList() @@ -458,16 +407,12 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.patch( - "/api/projects/{projectName}/groups/{groupName}/subjects", - project.projectName, group.name - ) - .contentType(TestUtil.APPLICATION_JSON_PATCH) - .content(TestUtil.convertObjectToJsonBytes(body)) - ) - .andExpect(MockMvcResultMatchers.status().isNoContent()) + "/api/projects/{projectName}/groups/{groupName}/subjects", project.projectName, group.name + ).contentType(TestUtil.APPLICATION_JSON_PATCH).content(TestUtil.convertObjectToJsonBytes(body)) + ).andExpect(MockMvcResultMatchers.status().isNoContent()) // Validate that the group was set for both subjects - val subjectLogins = listOf(savedSub1.getLogin(), savedSub2.getLogin()) + val subjectLogins = listOf(savedSub1.login!!, savedSub2.login!!) val subjects = subjectRepository.findAllBySubjectLogins(subjectLogins) Assertions.assertThat(subjects).hasSize(2) Assertions.assertThat(subjects).allSatisfy { s: Subject -> diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt index d319aeeee..16b8952af 100644 --- a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt @@ -131,7 +131,7 @@ internal open class OAuthClientsResourceIntTest( MockMvcResultMatchers.jsonPath("$.accessTokenValiditySeconds").value( Matchers.equalTo( details - .getAccessTokenValiditySeconds().toInt() + .accessTokenValiditySeconds?.toInt() ) ) ) @@ -139,34 +139,34 @@ internal open class OAuthClientsResourceIntTest( MockMvcResultMatchers.jsonPath("$.refreshTokenValiditySeconds").value( Matchers.equalTo( details - .refreshTokenValiditySeconds.toInt() + .refreshTokenValiditySeconds?.toInt() ) ) ) .andExpect( MockMvcResultMatchers.jsonPath("$.scope").value( Matchers.containsInAnyOrder( - *details.scope.toTypedArray() + details.scope?.toTypedArray() ) ) ) .andExpect( MockMvcResultMatchers.jsonPath("$.autoApproveScopes").value( Matchers.containsInAnyOrder( - *details.autoApproveScopes.toTypedArray() + details.autoApproveScopes?.toTypedArray() ) ) ) .andExpect( MockMvcResultMatchers.jsonPath("$.authorizedGrantTypes").value( Matchers.containsInAnyOrder( - *details.authorizedGrantTypes.toTypedArray() + details.authorizedGrantTypes?.toTypedArray() ) ) ) .andExpect( MockMvcResultMatchers.jsonPath("$.authorities").value( - Matchers.containsInAnyOrder(*details.authorities.toTypedArray()) + Matchers.containsInAnyOrder(details.authorities?.toTypedArray()) ) ) val testDetails = clientDetailsList.stream() @@ -183,7 +183,7 @@ internal open class OAuthClientsResourceIntTest( Assertions.assertThat(testDetails.authorizedGrantTypes).containsExactlyInAnyOrderElementsOf( details.authorizedGrantTypes ) - details.autoApproveScopes.forEach(Consumer { scope: String? -> + details.autoApproveScopes?.forEach(Consumer { scope: String? -> Assertions.assertThat( testDetails.isAutoApprove( scope @@ -191,10 +191,10 @@ internal open class OAuthClientsResourceIntTest( ).isTrue() }) Assertions.assertThat(testDetails.accessTokenValiditySeconds).isEqualTo( - details.accessTokenValiditySeconds.toInt() + details.accessTokenValiditySeconds?.toInt() ) Assertions.assertThat(testDetails.refreshTokenValiditySeconds).isEqualTo( - details.refreshTokenValiditySeconds.toInt() + details.refreshTokenValiditySeconds?.toInt() ) Assertions.assertThat(testDetails.authorities.stream().map { obj: GrantedAuthority -> obj.authority }) .containsExactlyInAnyOrderElementsOf(details.authorities) @@ -257,7 +257,7 @@ internal open class OAuthClientsResourceIntTest( @Throws(Exception::class) open fun cannotModifyProtected() { // first change our test client to be protected - details.additionalInformation["protected"] = "true" + details.additionalInformation!!["protected"] = "true" restOauthClientMvc.perform( MockMvcRequestBuilders.put("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index e650e923b..f1bc651d1 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -41,7 +41,7 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal class OrganizationResourceIntTest( +internal open class OrganizationResourceIntTest( @Autowired private val organizationMapper: OrganizationMapper, @Autowired private val organizationRepository: OrganizationRepository, @Autowired private val organizationService: OrganizationService, @@ -71,15 +71,7 @@ internal class OrganizationResourceIntTest( .addFilter(filter) .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) .build() - organization = createEntity() - } - - @AfterEach - fun tearDown() { - val testOrg = organizationRepository.findOneByName( - organization.name - ) - testOrg.ifPresent { entity: Organization -> organizationRepository.delete(entity) } + organization = this.createEntity() } /** @@ -93,54 +85,20 @@ internal class OrganizationResourceIntTest( return org } - @Test - @Throws(Exception::class) - fun createOrganization() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) - - // Validate the Organization in the database - val savedOrg = organizationRepository.findOneByName(orgDto.name) - Assertions.assertThat(savedOrg).isNotEmpty() - } - - @Test - @Throws(Exception::class) - fun createOrganizationWithExistingName() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) - - // Second request should fail - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isConflict()) - } - @Test - @Throws(Exception::class) - fun checkGroupNameIsRequired() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - orgDto.name = null - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - } + @get:Throws(Exception::class) + @get:Test + val nonExistingOrganization: Unit + get() { + // Get the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}", + organization.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @get:Throws(Exception::class) @get:Test @@ -158,57 +116,97 @@ internal class OrganizationResourceIntTest( ) } - @Test - @Throws(Exception::class) - fun getOrganization() { - // Initialize the database - organizationRepository.saveAndFlush(organization) - - // Get the organization - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/organizations/{name}", - organization.name + @get:Throws(Exception::class) + @get:Test + val projectsByOrganizationName: Unit + get() { + // Initialize the database + organizationRepository.saveAndFlush(organization) + val project: Project = ProjectResourceIntTest.Companion.createEntity() + .organization(organization) + .projectName("organization_project") + projectRepository.saveAndFlush(project) + + // Get projects of the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}/projects", + organization.name + ) ) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("org1")) - } + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].projectName").value("organization_project")) + projectRepository.delete(project) + } - @Test - @Throws(Exception::class) - fun editOrganization() { - // Initialize the database - organizationRepository.saveAndFlush(organization) - val updatedOrgDto = organizationMapper - .organizationToOrganizationDTO(organization) - updatedOrgDto?.location = "Other location" - - // Update the organization - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.put("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(updatedOrgDto)) + @AfterEach + fun tearDown() { + val testOrg = organizationRepository.findOneByName( + organization.name!! ) - .andExpect(MockMvcResultMatchers.status().isOk()) + if (testOrg != null) + organizationRepository.delete(testOrg) + - // Get the organization - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/organizations/{name}", - organization.name + @Test + @Throws(Exception::class) + fun createOrganization() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) ) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.location").value("Other location")) - } + .andExpect(MockMvcResultMatchers.status().isCreated()) + + // Validate the Organization in the database + val savedOrg = organizationRepository.findOneByName(orgDto.name) + Assertions.assertThat(savedOrg).isNotNull() + } + + @Test + @Throws(Exception::class) + fun createOrganizationWithExistingName() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) + + // Second request should fail + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isConflict()) + } + + + @Test + @Throws(Exception::class) + //TODO this is covered by not using a nullable type + fun checkGroupNameIsRequired() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + orgDto.name = "" + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + } + + + @Test + @Throws(Exception::class) + fun getOrganization() { + // Initialize the database + organizationRepository.saveAndFlush(organization) - @get:Throws(Exception::class) - @get:Test - val nonExistingOrganization: Unit - get() { // Get the organization restOrganizationMockMvc.perform( MockMvcRequestBuilders.get( @@ -216,30 +214,40 @@ internal class OrganizationResourceIntTest( organization.name ) ) - .andExpect(MockMvcResultMatchers.status().isNotFound()) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("org1")) } - @get:Throws(Exception::class) - @get:Test - val projectsByOrganizationName: Unit - get() { + @Test + @Throws(Exception::class) + fun editOrganization() { // Initialize the database organizationRepository.saveAndFlush(organization) - val project: Project = ProjectResourceIntTest.Companion.createEntity() - .organization(organization) - .projectName("organization_project") - projectRepository.saveAndFlush(project) + val updatedOrgDto = organizationMapper + .organizationToOrganizationDTO(organization) + updatedOrgDto?.location = "Other location" - // Get projects of the organization + // Update the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.put("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(updatedOrgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + + // Get the organization restOrganizationMockMvc.perform( MockMvcRequestBuilders.get( - "/api/organizations/{name}/projects", + "/api/organizations/{name}", organization.name ) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[*].projectName").value("organization_project")) - projectRepository.delete(project) + .andExpect(MockMvcResultMatchers.jsonPath("$.location").value("Other location")) } + + + } } diff --git a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt index 9851cc0ba..108c9644b 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt @@ -30,7 +30,7 @@ internal class ProfileInfoResourceIntTest { private var restProfileMockMvc: MockMvc? = null @BeforeEach fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) val activeProfiles = arrayOf("test") Mockito.`when`(environment!!.defaultProfiles).thenReturn(activeProfiles) Mockito.`when`(environment.activeProfiles).thenReturn(activeProfiles) diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt index 4db6c68a5..8ef5320d0 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt @@ -40,41 +40,31 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal class SourceDataResourceIntTest { - @Autowired - private val sourceDataRepository: SourceDataRepository? = null +internal open class SourceDataResourceIntTest( + @Autowired private val sourceDataRepository: SourceDataRepository, + @Autowired private val sourceDataMapper: SourceDataMapper, + @Autowired private val sourceDataService: SourceDataService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val em: EntityManager, + private var restSourceDataMockMvc: MockMvc, + private var sourceData: SourceData, + @Autowired private val authService: AuthService +) { - @Autowired - private val sourceDataMapper: SourceDataMapper? = null - - @Autowired - private val sourceDataService: SourceDataService? = null - - @Autowired - private val jacksonMessageConverter: MappingJackson2HttpMessageConverter? = null - - @Autowired - private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver? = null - - @Autowired - private val exceptionTranslator: ExceptionTranslator? = null - - @Autowired - private val em: EntityManager? = null - private var restSourceDataMockMvc: MockMvc? = null - private var sourceData: SourceData? = null - - @Autowired - private val authService: AuthService? = null @BeforeEach @Throws(ServletException::class) fun setUp() { - MockitoAnnotations.initMocks(this) - val sourceDataResource = SourceDataResource() + MockitoAnnotations.openMocks(this) + val sourceDataResource = SourceDataResource( + sourceDataService, + authService + ) ReflectionTestUtils.setField(sourceDataResource, "sourceDataService", sourceDataService) ReflectionTestUtils.setField(sourceDataResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() - filter!!.init(MockFilterConfig()) + filter.init(MockFilterConfig()) restSourceDataMockMvc = MockMvcBuilders.standaloneSetup(sourceDataResource) .setCustomArgumentResolvers(pageableArgumentResolver) .setControllerAdvice(exceptionTranslator) @@ -92,12 +82,12 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun createSourceData() { - val databaseSizeBeforeCreate = sourceDataRepository!!.findAll().size + open fun createSourceData() { + val databaseSizeBeforeCreate = sourceDataRepository.findAll().size // Create the SourceData - val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) - restSourceDataMockMvc!!.perform( + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) + restSourceDataMockMvc.perform( MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) @@ -121,15 +111,15 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun createSourceDataWithExistingId() { - val databaseSizeBeforeCreate = sourceDataRepository!!.findAll().size + open fun createSourceDataWithExistingId() { + val databaseSizeBeforeCreate = sourceDataRepository.findAll().size // Create the SourceData with an existing ID - sourceData!!.id = 1L - val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) + sourceData.id = 1L + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) // An entity with an existing ID cannot be created, so this API call must fail - restSourceDataMockMvc!!.perform( + restSourceDataMockMvc.perform( MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) @@ -144,14 +134,14 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun checkSourceDataTypeIsNotRequired() { - val databaseSizeBeforeTest = sourceDataRepository!!.findAll().size + open fun checkSourceDataTypeIsNotRequired() { + val databaseSizeBeforeTest = sourceDataRepository.findAll().size // set the field null - sourceData!!.sourceDataType = null + sourceData.sourceDataType = null // Create the SourceData, which fails. - val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) - restSourceDataMockMvc!!.perform( + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) + restSourceDataMockMvc.perform( MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) @@ -164,15 +154,15 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun checkSourceDataTypeOrTopicIsRequired() { - val databaseSizeBeforeTest = sourceDataRepository!!.findAll().size + open fun checkSourceDataTypeOrTopicIsRequired() { + val databaseSizeBeforeTest = sourceDataRepository.findAll().size // set the field null - sourceData!!.sourceDataType = null - sourceData!!.topic = null + sourceData.sourceDataType = null + sourceData.topic = null // Create the SourceData, which fails. - val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) - restSourceDataMockMvc!!.perform( + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) + restSourceDataMockMvc.perform( MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) @@ -185,19 +175,19 @@ internal class SourceDataResourceIntTest { @get:Throws(Exception::class) @get:Transactional @get:Test - val allSourceData: Unit + open val allSourceData: Unit get() { // Initialize the database - sourceDataRepository!!.saveAndFlush(sourceData) + sourceDataRepository.saveAndFlush(sourceData) // Get all the sourceDataList - restSourceDataMockMvc!!.perform(MockMvcRequestBuilders.get("/api/source-data?sort=id,desc")) + restSourceDataMockMvc.perform(MockMvcRequestBuilders.get("/api/source-data?sort=id,desc")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].id").value>( Matchers.hasItem( - sourceData!!.id!!.toInt() + sourceData.id!!.toInt() ) ) ) @@ -256,19 +246,19 @@ internal class SourceDataResourceIntTest { @get:Throws(Exception::class) @get:Transactional @get:Test - val allSourceDataWithPagination: Unit + open val allSourceDataWithPagination: Unit get() { // Initialize the database - sourceDataRepository!!.saveAndFlush(sourceData) + sourceDataRepository.saveAndFlush(sourceData) // Get all the sourceDataList - restSourceDataMockMvc!!.perform(MockMvcRequestBuilders.get("/api/source-data?page=0&size=5&sort=id,desc")) + restSourceDataMockMvc.perform(MockMvcRequestBuilders.get("/api/source-data?page=0&size=5&sort=id,desc")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].id").value>( Matchers.hasItem( - sourceData!!.id!!.toInt() + sourceData.id!!.toInt() ) ) ) @@ -327,20 +317,20 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun getSourceData() { + open fun getSourceData() { // Initialize the database - sourceDataRepository!!.saveAndFlush(sourceData) + sourceDataRepository.saveAndFlush(sourceData) // Get the sourceData - restSourceDataMockMvc!!.perform( + restSourceDataMockMvc.perform( MockMvcRequestBuilders.get( "/api/source-data/{sourceDataName}", - sourceData!!.sourceDataName + sourceData.sourceDataName ) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(sourceData!!.id!!.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(sourceData.id!!.toInt())) .andExpect(MockMvcResultMatchers.jsonPath("$.sourceDataType").value(DEFAULT_SOURCE_DATA_TYPE)) .andExpect(MockMvcResultMatchers.jsonPath("$.sourceDataName").value(DEFAULT_SOURCE_DATA_NAME)) .andExpect(MockMvcResultMatchers.jsonPath("$.processingState").value(DEFAULT_PROCESSING_STATE)) @@ -354,10 +344,10 @@ internal class SourceDataResourceIntTest { @get:Throws(Exception::class) @get:Transactional @get:Test - val nonExistingSourceData: Unit + open val nonExistingSourceData: Unit get() { // Get the sourceData - restSourceDataMockMvc!!.perform( + restSourceDataMockMvc.perform( MockMvcRequestBuilders.get( "/api/source-data/{sourceDataName}", DEFAULT_SOURCE_DATA_NAME + DEFAULT_SOURCE_DATA_NAME @@ -369,13 +359,13 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun updateSourceData() { + open fun updateSourceData() { // Initialize the database - sourceDataRepository!!.saveAndFlush(sourceData) + sourceDataRepository.saveAndFlush(sourceData) val databaseSizeBeforeUpdate = sourceDataRepository.findAll().size // Update the sourceData - val updatedSourceData = sourceDataRepository.findById(sourceData!!.id).get() + val updatedSourceData = sourceDataRepository.findById(sourceData.id).get() updatedSourceData .sourceDataType(UPDATED_SOURCE_DATA_TYPE) .sourceDataName(UPDATED_SOURCE_DATA_NAME) @@ -385,8 +375,8 @@ internal class SourceDataResourceIntTest { .topic(UPDATED_TOPIC) .unit(UPDATED_UNIT) .frequency(UPDATED_FREQUENCY) - val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(updatedSourceData) - restSourceDataMockMvc!!.perform( + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(updatedSourceData) + restSourceDataMockMvc.perform( MockMvcRequestBuilders.put("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) @@ -410,14 +400,14 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun updateNonExistingSourceData() { - val databaseSizeBeforeUpdate = sourceDataRepository!!.findAll().size + open fun updateNonExistingSourceData() { + val databaseSizeBeforeUpdate = sourceDataRepository.findAll().size // Create the SourceData - val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) // If the entity doesn't have an ID, it will be created instead of just being updated - restSourceDataMockMvc!!.perform( + restSourceDataMockMvc.perform( MockMvcRequestBuilders.put("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) @@ -432,16 +422,16 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun deleteSourceData() { + open fun deleteSourceData() { // Initialize the database - sourceDataRepository!!.saveAndFlush(sourceData) + sourceDataRepository.saveAndFlush(sourceData) val databaseSizeBeforeDelete = sourceDataRepository.findAll().size // Get the sourceData - restSourceDataMockMvc!!.perform( + restSourceDataMockMvc.perform( MockMvcRequestBuilders.delete( "/api/source-data/{sourceDataName}", - sourceData!!.sourceDataName + sourceData.sourceDataName ) .accept(TestUtil.APPLICATION_JSON_UTF8) ) @@ -455,7 +445,7 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun equalsVerifier() { + open fun equalsVerifier() { org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(SourceData::class.java)) } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt index 71ce2af6f..dc22d57e5 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt @@ -25,7 +25,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -62,13 +61,12 @@ internal open class SourceTypeResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val sourceTypeResource = SourceTypeResource() - ReflectionTestUtils.setField(sourceTypeResource, "sourceTypeService", sourceTypeService) - ReflectionTestUtils.setField( - sourceTypeResource, "sourceTypeRepository", - sourceTypeRepository + val sourceTypeResource = SourceTypeResource( + sourceTypeService, + sourceTypeRepository, + authService ) - ReflectionTestUtils.setField(sourceTypeResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) restSourceTypeMockMvc = MockMvcBuilders.standaloneSetup(sourceTypeResource) @@ -97,7 +95,7 @@ internal open class SourceTypeResourceIntTest( SourceDataResourceIntTest.Companion.createEntity(em) ) val sourceData = sourceTypeDto.sourceData - sourceData.add(sourceDataDto) + sourceData.add(sourceDataDto!!) restSourceTypeMockMvc.perform( MockMvcRequestBuilders.post("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index 623c78878..06c7e0d3a 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -147,7 +147,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit .andExpect( MockMvcResultMatchers.jsonPath("$.[*].id").value>( Matchers.hasItem( - subjectDto!!.id.toInt() + subjectDto!!.id!!.toInt() ) ) ) @@ -174,10 +174,10 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) // Get the subject - restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{login}", subjectDto!!.getLogin())) + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{login}", subjectDto!!.login)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(subjectDto.id.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(subjectDto.id!!.toInt())) .andExpect( MockMvcResultMatchers.jsonPath("$.externalLink") .value(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK) @@ -302,7 +302,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Get the subject restSubjectMockMvc.perform( - MockMvcRequestBuilders.delete("/api/subjects/{login}", subjectDto!!.getLogin()) + MockMvcRequestBuilders.delete("/api/subjects/{login}", subjectDto!!.login) .accept(TestUtil.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) @@ -404,7 +404,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Get all the subjectList restSubjectMockMvc - .perform(MockMvcRequestBuilders.get("/api/subjects/{login}/sources?sort=id,desc", subjectDto.getLogin())) + .perform(MockMvcRequestBuilders.get("/api/subjects/{login}/sources?sort=id,desc", subjectDto.login)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").isNotEmpty()) @@ -455,7 +455,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit .id(createdSource.id) .sourceName(createdSource.sourceName) .sourceTypeId(createdSource.sourceType.id) - .sourceId(createdSource.sourceId) + .sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) @@ -465,12 +465,12 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit restSubjectMockMvc.perform( MockMvcRequestBuilders.get( "/api/subjects/{login}/sources", - createdSubject.getLogin() + createdSubject.login ) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[0].id").value(createdSource.id.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.[0].id").value(createdSource.id!!.toInt())) .andExpect( MockMvcResultMatchers.jsonPath("$.[0].sourceId").value(createdSource.sourceId.toString()) ) @@ -488,22 +488,22 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit .id(createdSource.id) .sourceName(createdSource.sourceName) .sourceTypeId(createdSource.sourceType.id) - .sourceId(createdSource.sourceId) + .sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) TestUtil.commitTransactionAndStartNew() - org.junit.jupiter.api.Assertions.assertNotNull(createdSubject!!.getLogin()) + org.junit.jupiter.api.Assertions.assertNotNull(createdSubject!!.login) // Get the subject restSubjectMockMvc.perform( MockMvcRequestBuilders.get( "/api/subjects/{login}/sources?withInactiveSources=true", - createdSubject.getLogin() + createdSubject.login ) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id!!.toInt())) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) ) @@ -521,7 +521,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit .id(createdSource.id) .sourceName(createdSource.sourceName) .sourceTypeId(createdSource.sourceType.id) - .sourceId(createdSource.sourceId) + .sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) @@ -529,17 +529,17 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit createdSubject!!.sources = emptySet() val updatedSubject = subjectService.updateSubject(createdSubject) TestUtil.commitTransactionAndStartNew() - org.junit.jupiter.api.Assertions.assertNotNull(updatedSubject!!.getLogin()) + org.junit.jupiter.api.Assertions.assertNotNull(updatedSubject!!.login) // Get the subject restSubjectMockMvc.perform( MockMvcRequestBuilders.get( "/api/subjects/{login}/sources?withInactiveSources=true", - updatedSubject.getLogin() + updatedSubject.login ) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id!!.toInt())) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) ) @@ -549,7 +549,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit .perform( MockMvcRequestBuilders.get( "/api/subjects/{login}/sources?withInactiveSources=false", - updatedSubject.getLogin() + updatedSubject.login ) ) .andExpect(MockMvcResultMatchers.status().isOk()) diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt index 6f84bcf65..d0bb73db5 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt @@ -107,10 +107,12 @@ internal open class UserResourceIntTest( @BeforeEach fun initTest() { user = UserServiceIntTest.createEntity(passwordService) - userRepository.findOneByLogin(UserServiceIntTest.DEFAULT_LOGIN) - .ifPresent { entity: User -> userRepository.delete(entity) } - userRepository.findOneByLogin(UserServiceIntTest.UPDATED_LOGIN) - .ifPresent { entity: User -> userRepository.delete(entity) } + val default_user = userRepository.findOneByLogin(UserServiceIntTest.DEFAULT_LOGIN) + if (default_user != null) + userRepository.delete(default_user) + val updated_user = userRepository.findOneByLogin(UserServiceIntTest.UPDATED_LOGIN) + if (updated_user != null) + userRepository.delete(updated_user) val roles = roleRepository .findRolesByAuthorityName(RoleAuthority.PARTICIPANT.authority) .stream().filter { r: Role -> r.project == null } From 9810dcfec137c393cbd7763a7c3075fe6b425fc2 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 31 Oct 2023 09:39:14 +0100 Subject: [PATCH 041/158] Rename .java to .kt --- .../{ManagementPortalApp.java => ManagementPortalApp.kt} | 0 ...agementPortalProperties.java => ManagementPortalProperties.kt} | 0 ...yConfigLoader.java => ManagementPortalSecurityConfigLoader.kt} | 0 .../{OAuth2LoginUiWebConfig.java => OAuth2LoginUiWebConfig.kt} | 0 .../web/rest/{AuthorityResource.java => AuthorityResource.kt} | 0 .../rest/{SiteSettingsResource.java => SiteSettingsResource.kt} | 0 .../web/rest/{TokenKeyEndpoint.java => TokenKeyEndpoint.kt} | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/{ManagementPortalApp.java => ManagementPortalApp.kt} (100%) rename src/main/java/org/radarbase/management/config/{ManagementPortalProperties.java => ManagementPortalProperties.kt} (100%) rename src/main/java/org/radarbase/management/config/{ManagementPortalSecurityConfigLoader.java => ManagementPortalSecurityConfigLoader.kt} (100%) rename src/main/java/org/radarbase/management/config/{OAuth2LoginUiWebConfig.java => OAuth2LoginUiWebConfig.kt} (100%) rename src/main/java/org/radarbase/management/web/rest/{AuthorityResource.java => AuthorityResource.kt} (100%) rename src/main/java/org/radarbase/management/web/rest/{SiteSettingsResource.java => SiteSettingsResource.kt} (100%) rename src/main/java/org/radarbase/management/web/rest/{TokenKeyEndpoint.java => TokenKeyEndpoint.kt} (100%) diff --git a/src/main/java/org/radarbase/management/ManagementPortalApp.java b/src/main/java/org/radarbase/management/ManagementPortalApp.kt similarity index 100% rename from src/main/java/org/radarbase/management/ManagementPortalApp.java rename to src/main/java/org/radarbase/management/ManagementPortalApp.kt diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalProperties.java b/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/ManagementPortalProperties.java rename to src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.java b/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.java rename to src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt diff --git a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.java b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.java rename to src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt diff --git a/src/main/java/org/radarbase/management/web/rest/AuthorityResource.java b/src/main/java/org/radarbase/management/web/rest/AuthorityResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/AuthorityResource.java rename to src/main/java/org/radarbase/management/web/rest/AuthorityResource.kt diff --git a/src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.java b/src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.java rename to src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.kt diff --git a/src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.java b/src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.java rename to src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.kt From 230b791cb7a86f00949c4be0a4c5fffce9cb0b32 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 31 Oct 2023 09:39:15 +0100 Subject: [PATCH 042/158] test compiles, implemented joris' requested changes --- .../authorization/MPAuthorizationOracle.kt | 3 +- .../auth/authentication/TokenValidatorTest.kt | 10 +- .../management/ManagementPortalApp.kt | 154 +++++---- .../management/config/AsyncConfiguration.kt | 7 +- .../management/config/CacheConfiguration.kt | 2 +- .../config/DatabaseConfiguration.kt | 2 +- .../management/config/LoggingConfiguration.kt | 8 +- .../config/ManagementPortalProperties.kt | 327 +++--------------- .../ManagementPortalSecurityConfigLoader.kt | 271 +++++++-------- .../config/OAuth2LoginUiWebConfig.kt | 136 ++++---- .../radarbase/management/domain/Project.kt | 8 +- .../org/radarbase/management/domain/Source.kt | 9 +- .../management/repository/SourceRepository.kt | 4 +- .../security/JwtAuthenticationFilter.kt | 5 +- .../security/RadarAuthentication.kt | 2 +- .../management/security/SecurityUtils.kt | 34 +- .../ManagementPortalOauthKeyStoreHandler.kt | 16 +- .../algorithm/AsymmetricalJwtAlgorithm.java | 40 --- .../jwt/algorithm/EcdsaJwtAlgorithm.java | 41 --- .../security/jwt/algorithm/JwtAlgorithm.java | 26 -- .../jwt/algorithm/RsaJwtAlgorithm.java | 40 --- .../management/service/RoleService.kt | 1 - .../management/service/SiteSettingsService.kt | 8 +- .../management/service/SourceService.kt | 4 +- .../management/service/SubjectService.kt | 15 +- .../service/dto/MinimalSourceDetailsDTO.kt | 9 +- .../management/service/dto/SiteSettingsDto.kt | 8 +- .../mapper/decorator/SourceMapperDecorator.kt | 2 +- .../mapper/decorator/UserMapperDecorator.kt | 10 +- .../management/web/rest/AuthorityResource.kt | 88 ++--- .../web/rest/SiteSettingsResource.kt | 69 ++-- .../management/web/rest/SourceResource.kt | 2 +- .../management/web/rest/TokenKeyEndpoint.kt | 57 ++- .../errors/RadarWebApplicationExceptionVM.kt | 8 +- .../web/rest/OrganizationResourceIntTest.kt | 2 +- .../web/rest/SourceDataResourceIntTest.kt | 6 +- .../web/rest/SourceResourceIntTest.kt | 14 +- .../web/rest/SourceTypeResourceIntTest.kt | 4 +- .../web/rest/SubjectResourceIntTest.kt | 78 ++--- .../web/rest/UserResourceIntTest.kt | 2 +- 40 files changed, 569 insertions(+), 963 deletions(-) delete mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.java delete mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.java delete mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.java delete mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.java diff --git a/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt b/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt index 804470a50..ef7f0ad5d 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt @@ -26,8 +26,7 @@ class MPAuthorizationOracle( return identity.roles?.forkAny { it.hasPermission(identity, permission, entity, entityScope) - } - ?: false + } ?: false } /** diff --git a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt index 9b62292c8..9c35dc29e 100644 --- a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt +++ b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt @@ -20,7 +20,7 @@ import org.radarbase.auth.util.TokenTestUtils.WIREMOCK_PORT * Created by dverbeec on 24/04/2017. */ internal class TokenValidatorTest { - private var validator: TokenValidator? = null + private lateinit var validator: TokenValidator /** * Set up a stub public key endpoint and initialize a TokenValidator object. @@ -53,28 +53,28 @@ internal class TokenValidatorTest { @Test fun testValidToken() { - validator!!.validateBlocking(TokenTestUtils.VALID_RSA_TOKEN) + validator.validateBlocking(TokenTestUtils.VALID_RSA_TOKEN) } @Test fun testIncorrectAudienceToken() { Assertions.assertThrows( TokenValidationException::class.java - ) { validator!!.validateBlocking(TokenTestUtils.INCORRECT_AUDIENCE_TOKEN) } + ) { validator.validateBlocking(TokenTestUtils.INCORRECT_AUDIENCE_TOKEN) } } @Test fun testExpiredToken() { Assertions.assertThrows( TokenValidationException::class.java - ) { validator!!.validateBlocking(TokenTestUtils.EXPIRED_TOKEN) } + ) { validator.validateBlocking(TokenTestUtils.EXPIRED_TOKEN) } } @Test fun testIncorrectAlgorithmToken() { Assertions.assertThrows( TokenValidationException::class.java - ) { validator!!.validateBlocking(TokenTestUtils.INCORRECT_ALGORITHM_TOKEN) } + ) { validator.validateBlocking(TokenTestUtils.INCORRECT_ALGORITHM_TOKEN) } } companion object { diff --git a/src/main/java/org/radarbase/management/ManagementPortalApp.kt b/src/main/java/org/radarbase/management/ManagementPortalApp.kt index 7bfc158d2..2200a96d2 100644 --- a/src/main/java/org/radarbase/management/ManagementPortalApp.kt +++ b/src/main/java/org/radarbase/management/ManagementPortalApp.kt @@ -1,97 +1,105 @@ -package org.radarbase.management; +package org.radarbase.management -import tech.jhipster.config.DefaultProfileUtil; -import tech.jhipster.config.JHipsterConstants; -import java.net.InetAddress; -import java.net.UnknownHostException; -import javax.annotation.PostConstruct; -import org.radarbase.management.config.ApplicationProperties; -import org.radarbase.management.config.ManagementPortalProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.core.env.Environment; -import org.springframework.core.env.Profiles; +import org.radarbase.management.config.ApplicationProperties +import org.radarbase.management.config.ManagementPortalProperties +import org.slf4j.LoggerFactory +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.context.annotation.ComponentScan +import org.springframework.core.env.Environment +import org.springframework.core.env.Profiles +import tech.jhipster.config.DefaultProfileUtil +import tech.jhipster.config.JHipsterConstants +import java.net.InetAddress +import java.net.UnknownHostException +import javax.annotation.PostConstruct -@ComponentScan({ - "org.radarbase.management.config", - "org.radarbase.management.domain.support", - "org.radarbase.management.filters", - "org.radarbase.management.repository", - "org.radarbase.management.service", - "org.radarbase.management.security", - "org.radarbase.management.web" -}) +@ComponentScan( + "org.radarbase.management.config", + "org.radarbase.management.domain.support", + "org.radarbase.management.filters", + "org.radarbase.management.repository", + "org.radarbase.management.service", + "org.radarbase.management.security", + "org.radarbase.management.web" +) @EnableAutoConfiguration -@EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class, - ManagementPortalProperties.class}) -public class ManagementPortalApp { - - private static final Logger log = LoggerFactory.getLogger(ManagementPortalApp.class); - - private final Environment env; - - public ManagementPortalApp(Environment env) { - this.env = env; - } - +@EnableConfigurationProperties( + LiquibaseProperties::class, ApplicationProperties::class, ManagementPortalProperties::class +) +class ManagementPortalApp(private val env: Environment) { /** * Initializes ManagementPortal. * - *

Spring profiles can be configured with a program arguments - * --spring.profiles.active=your-active-profile

* - *

You can find more information on how profiles work with JHipster on - * - * http://jhipster.github.io/profiles/ - *

. + * Spring profiles can be configured with a program arguments + * --spring.profiles.active=your-active-profile + * + * + * You can find more information on how profiles work with JHipster on + * [ + * http://jhipster.github.io/profiles/ +](http://jhipster.github.io/profiles/) * . */ @PostConstruct - public void initApplication() { + fun initApplication() { if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) - && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_PRODUCTION))) { - log.error("You have misconfigured your application! It should not run " - + "with both the 'dev' and 'prod' profiles at the same time."); + && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) + ) { + log.error( + "You have misconfigured your application! It should not run " + + "with both the 'dev' and 'prod' profiles at the same time." + ) } if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) - && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_CLOUD))) { - log.error("You have misconfigured your application! It should not" - + "run with both the 'dev' and 'cloud' profiles at the same time."); + && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_CLOUD)) + ) { + log.error( + "You have misconfigured your application! It should not" + + "run with both the 'dev' and 'cloud' profiles at the same time." + ) } } - /** - * Main method, used to run the application. - * - * @param args the command line arguments - * @throws UnknownHostException if the local host name could not be resolved into an address - */ - public static void main(String[] args) throws UnknownHostException { - SpringApplication app = new SpringApplication(ManagementPortalApp.class); - DefaultProfileUtil.addDefaultProfile(app); - Environment env = app.run(args).getEnvironment(); - String protocol = "http"; - if (env.getProperty("server.ssl.key-store") != null) { - protocol = "https"; - } - log.info(""" + companion object { + private val log = LoggerFactory.getLogger(ManagementPortalApp::class.java) + /** + * Main method, used to run the application. + * + * @param args the command line arguments + * @throws UnknownHostException if the local host name could not be resolved into an address + */ + @Throws(UnknownHostException::class) + @JvmStatic + fun main(args: Array) { + val app = SpringApplication(ManagementPortalApp::class.java) + DefaultProfileUtil.addDefaultProfile(app) + val env: Environment = app.run(*args).environment + var protocol = "http" + if (env.getProperty("server.ssl.key-store") != null) { + protocol = "https" + } + log.info( + """ + + ----------------------------------------------------- + ${'\t'}Application '{}' is running! Access URLs: + ${'\t'}Local: ${'\t'}${'\t'}{}://localhost:{} + ${'\t'}External: ${'\t'}{}://{}:{} + ${'\t'}Profile(s): ${'\t'}{} ----------------------------------------------------- - \tApplication '{}' is running! Access URLs: - \tLocal: \t\t{}://localhost:{} - \tExternal: \t{}://{}:{} - \tProfile(s): \t{} - -----------------------------------------------------""", + """.trimIndent(), env.getProperty("spring.application.name"), protocol, env.getProperty("server.port"), protocol, - InetAddress.getLocalHost().getHostAddress(), + InetAddress.getLocalHost().hostAddress, env.getProperty("server.port"), - env.getActiveProfiles()); + env.activeProfiles + ) + } } } diff --git a/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt index 51e7aaf21..bca9e4d4f 100644 --- a/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt @@ -16,14 +16,13 @@ import tech.jhipster.config.JHipsterProperties @Configuration @EnableAsync @EnableScheduling -open class AsyncConfiguration : AsyncConfigurer { - @Autowired - private val jHipsterProperties: JHipsterProperties? = null +open class AsyncConfiguration( + @Autowired private val jHipsterProperties: JHipsterProperties) : AsyncConfigurer { @Bean(name = ["taskExecutor"]) override fun getAsyncExecutor(): ExceptionHandlingAsyncTaskExecutor { log.debug("Creating Async Task Executor") val executor = ThreadPoolTaskExecutor() - executor.corePoolSize = jHipsterProperties!!.async.corePoolSize + executor.corePoolSize = jHipsterProperties.async.corePoolSize executor.maxPoolSize = jHipsterProperties.async.maxPoolSize executor.queueCapacity = jHipsterProperties.async.queueCapacity executor.setThreadNamePrefix("management-portal-Executor-") diff --git a/src/main/java/org/radarbase/management/config/CacheConfiguration.kt b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt index 57b0cd25e..dcc1adbeb 100644 --- a/src/main/java/org/radarbase/management/config/CacheConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt @@ -37,7 +37,7 @@ open class CacheConfiguration { } @Bean - open fun HazelcastInstance?.cacheManager(): CacheManager { + open fun HazelcastInstance.cacheManager(): CacheManager { log.debug("Starting HazelcastCacheManager") return HazelcastCacheManager( this diff --git a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt index 752f96662..896feab14 100644 --- a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt @@ -28,7 +28,7 @@ open class DatabaseConfiguration { private val env: Environment? = null @Bean open fun liquibase( - dataSource: DataSource?, + dataSource: DataSource, liquibaseProperties: LiquibaseProperties ): SpringLiquibase { diff --git a/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt b/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt index 6e6651e07..0ef95ad72 100644 --- a/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt @@ -18,9 +18,11 @@ open class LoggingConfiguration( /** Logging configuration for JHipster. */ init { val context = LoggerFactory.getILoggerFactory() as LoggerContext - val map: MutableMap = HashMap() - map["app_name"] = appName - map["app_port"] = serverPort + val map: MutableMap = buildMap { + put("app_name", appName) + put("app_port", serverPort) + } as MutableMap + val customFields = mapper.writeValueAsString(map) val loggingProperties = jHipsterProperties.logging val logstashProperties = loggingProperties.logstash diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt b/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt index e478a0679..c9853ddbc 100644 --- a/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt +++ b/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt @@ -1,299 +1,68 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.springframework.boot.context.properties.ConfigurationProperties; - -import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties /** * Created by nivethika on 3-10-17. */ @ConfigurationProperties(prefix = "managementportal", ignoreUnknownFields = false) -public class ManagementPortalProperties { - - private final Mail mail = new Mail(); - - private final Frontend frontend = new Frontend(); - - private Oauth oauth = new Oauth(); - - private final Common common = new Common(); - - private final CatalogueServer catalogueServer = new CatalogueServer(); - - private final Account account = new Account(); - - private final SiteSettings siteSettings = new SiteSettings(); - - public ManagementPortalProperties.Frontend getFrontend() { - return frontend; +class ManagementPortalProperties { + val mail = Mail() + @JvmField + val frontend = Frontend() + @JvmField + var oauth = Oauth() + @JvmField + val common = Common() + val catalogueServer = CatalogueServer() + val account = Account() + val siteSettings = SiteSettings() + + class Account { + var enableExposeToken = false } - public ManagementPortalProperties.Mail getMail() { - return mail; + class Common { + var baseUrl = "" + var managementPortalBaseUrl = "" + var privacyPolicyUrl = "" + @JvmField + var adminPassword = "" + var activationKeyTimeoutInSeconds = 24 * 60 * 60 // 1 day } - public ManagementPortalProperties.Oauth getOauth() { - return oauth; + class Mail { + var from = "" } - public void setOauth(ManagementPortalProperties.Oauth oauth) { - this.oauth = oauth; + class Frontend { + @JvmField + var clientId = "" + var clientSecret = "" + @JvmField + var accessTokenValiditySeconds = 4 * 60 * 60 + @JvmField + var refreshTokenValiditySeconds = 72 * 60 * 60 + var sessionTimeout = 24 * 60 * 60 // a day } - public CatalogueServer getCatalogueServer() { - return catalogueServer; - } - - public Common getCommon() { - return common; - } - - public Account getAccount() { - return account; - } - - public SiteSettings getSiteSettings() { - return siteSettings; - } - - public static class Account { - private boolean enableExposeToken = false; - - public boolean getEnableExposeToken() { - return enableExposeToken; - } - - public void setEnableExposeToken(boolean enableExposeToken) { - this.enableExposeToken = enableExposeToken; - } - } - - public static class Common { - - private String baseUrl = ""; - - private String managementPortalBaseUrl = ""; - - private String privacyPolicyUrl = ""; - - private String adminPassword = ""; - - private Integer activationKeyTimeoutInSeconds = 24 * 60 * 60; // 1 day - - public String getBaseUrl() { - return baseUrl; - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } - - public String getPrivacyPolicyUrl() { - return privacyPolicyUrl; - } - - public void setPrivacyPolicyUrl(String privacyPolicyUrl) { - this.privacyPolicyUrl = privacyPolicyUrl; - } - - public String getAdminPassword() { - return adminPassword; - } - - public void setAdminPassword(String adminPassword) { - this.adminPassword = adminPassword; - } - - public String getManagementPortalBaseUrl() { - return managementPortalBaseUrl; - } - - public void setManagementPortalBaseUrl(String managementPortalBaseUrl) { - this.managementPortalBaseUrl = managementPortalBaseUrl; - } - - public Integer getActivationKeyTimeoutInSeconds() { - return activationKeyTimeoutInSeconds; - } - - public void setActivationKeyTimeoutInSeconds(Integer activationKeyTimeoutInSeconds) { - this.activationKeyTimeoutInSeconds = activationKeyTimeoutInSeconds; - } + class Oauth { + @JvmField + var clientsFile: String? = null + var signingKeyAlias: String? = null + var checkingKeyAliases: List? = null + lateinit var keyStorePassword: String + var metaTokenTimeout: String? = null + var persistentMetaTokenTimeout: String? = null + var enablePublicKeyVerifiers = false } - public static class Mail { - - private String from = ""; - - public String getFrom() { - return from; - } - - public void setFrom(String from) { - this.from = from; - } - + class CatalogueServer { + var isEnableAutoImport = false + var serverUrl: String? = null } - public static class Frontend { - - private String clientId = ""; - - private String clientSecret = ""; - - private Integer accessTokenValiditySeconds = 4 * 60 * 60; - - private Integer refreshTokenValiditySeconds = 72 * 60 * 60; - - private Integer sessionTimeout = 24 * 60 * 60; // a day - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public String getClientSecret() { - return clientSecret; - } - - public void setClientSecret(String clientSecret) { - this.clientSecret = clientSecret; - } - - public Integer getSessionTimeout() { - return sessionTimeout; - } - - public void setSessionTimeout(Integer sessionTimeout) { - this.sessionTimeout = sessionTimeout; - } - - public Integer getAccessTokenValiditySeconds() { - return accessTokenValiditySeconds; - } - - public void setAccessTokenValiditySeconds(Integer accessTokenValiditySeconds) { - this.accessTokenValiditySeconds = accessTokenValiditySeconds; - } - - public Integer getRefreshTokenValiditySeconds() { - return refreshTokenValiditySeconds; - } - - public void setRefreshTokenValiditySeconds(Integer refreshTokenValiditySeconds) { - this.refreshTokenValiditySeconds = refreshTokenValiditySeconds; - } - } - - public static class Oauth { - - private String clientsFile; - - private String signingKeyAlias; - - private List checkingKeyAliases; - - private String keyStorePassword; - - private String metaTokenTimeout; - - private String persistentMetaTokenTimeout; - - private Boolean enablePublicKeyVerifiers = false; - - public String getClientsFile() { - return clientsFile; - } - - public void setClientsFile(String clientsFile) { - this.clientsFile = clientsFile; - } - - public String getSigningKeyAlias() { - return signingKeyAlias; - } - - public void setSigningKeyAlias(String signingKeyAlias) { - this.signingKeyAlias = signingKeyAlias; - } - - public List getCheckingKeyAliases() { - return checkingKeyAliases; - } - - public void setCheckingKeyAliases(List checkingKeyAliases) { - this.checkingKeyAliases = checkingKeyAliases; - } - - public String getKeyStorePassword() { - return keyStorePassword; - } - - public void setKeyStorePassword(String keyStorePassword) { - this.keyStorePassword = keyStorePassword; - } - - public String getMetaTokenTimeout() { - return metaTokenTimeout; - } - - public void setMetaTokenTimeout(String metaTokenTimeout) { - this.metaTokenTimeout = metaTokenTimeout; - } - - public String getPersistentMetaTokenTimeout() { - return persistentMetaTokenTimeout; - } - - public void setPersistentMetaTokenTimeout(String persistentMetaTokenTimeout) { - this.persistentMetaTokenTimeout = persistentMetaTokenTimeout; - } - - public Boolean getEnablePublicKeyVerifiers() { - return enablePublicKeyVerifiers; - } - - public void setEnablePublicKeyVerifiers(Boolean enablePublicKeyVerifiers) { - this.enablePublicKeyVerifiers = enablePublicKeyVerifiers; - } - } - - public static class CatalogueServer { - - private boolean enableAutoImport = false; - - private String serverUrl; - - public String getServerUrl() { - return serverUrl; - } - - public void setServerUrl(String serverUrl) { - this.serverUrl = serverUrl; - } - - public boolean isEnableAutoImport() { - return enableAutoImport; - } - - public void setEnableAutoImport(boolean enableAutoImport) { - this.enableAutoImport = enableAutoImport; - } - } - - public static class SiteSettings { - - private List hiddenSubjectFields; - - public void setHiddenSubjectFields(List hiddenSubjectFields) { - this.hiddenSubjectFields = hiddenSubjectFields; - } - - public List getHiddenSubjectFields() { - return hiddenSubjectFields; - } + class SiteSettings { + var hiddenSubjectFields: List = listOf() } } diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt b/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt index aa1f15116..b12b7ce13 100644 --- a/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt +++ b/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt @@ -1,198 +1,199 @@ -package org.radarbase.management.config; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.MappingIterator; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.dataformat.csv.CsvMapper; -import com.fasterxml.jackson.dataformat.csv.CsvSchema; -import org.radarbase.auth.authorization.Permission; -import org.radarbase.management.service.UserService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.context.event.EventListener; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.security.oauth2.provider.NoSuchClientException; -import org.springframework.security.oauth2.provider.client.BaseClientDetails; -import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; -import org.springframework.stereotype.Component; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +package org.radarbase.management.config + +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.dataformat.csv.CsvMapper +import org.radarbase.auth.authorization.Permission.Companion.scopes +import org.radarbase.management.service.UserService +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.event.ContextRefreshedEvent +import org.springframework.context.event.EventListener +import org.springframework.security.oauth2.provider.ClientDetails +import org.springframework.security.oauth2.provider.NoSuchClientException +import org.springframework.security.oauth2.provider.client.BaseClientDetails +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService +import org.springframework.stereotype.Component +import java.lang.Boolean +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import java.util.* +import kotlin.Any +import kotlin.Array +import kotlin.Exception +import kotlin.String /** * Loads security configs such as oauth-clients, and overriding admin password if specified. * Created by dverbeec on 20/11/2017. */ @Component -public class ManagementPortalSecurityConfigLoader { - +class ManagementPortalSecurityConfigLoader { @Autowired - private JdbcClientDetailsService clientDetailsService; + private val clientDetailsService: JdbcClientDetailsService? = null @Autowired - private ManagementPortalProperties managementPortalProperties; + private val managementPortalProperties: ManagementPortalProperties? = null @Autowired - private UserService userService; - - private static final Logger logger = - LoggerFactory.getLogger(ManagementPortalSecurityConfigLoader.class); - - private static final Character SEPARATOR = ';'; + private val userService: UserService? = null /** * Resets the admin password to the value of managementportal.common.adminPassword value if * exists. */ - @EventListener(ContextRefreshedEvent.class) - public void overrideAdminPassword() { - String adminPassword = managementPortalProperties.getCommon().getAdminPassword(); - + @EventListener(ContextRefreshedEvent::class) + fun overrideAdminPassword() { + val adminPassword = managementPortalProperties!!.common.adminPassword if (adminPassword != null && !adminPassword.isEmpty()) { - logger.info("Overriding admin password to configured password"); - userService.changePassword("admin", adminPassword); + logger.info("Overriding admin password to configured password") + userService!!.changePassword("admin", adminPassword) } else { - logger.info("AdminPassword property is empty. Using default password..."); + logger.info("AdminPassword property is empty. Using default password...") } } - /** * Build the ClientDetails for the ManagementPortal frontend and load it to the database. */ - @EventListener(ContextRefreshedEvent.class) - public void loadFrontendOauthClient() { - logger.info("Loading ManagementPortal frontend client"); - ManagementPortalProperties.Frontend frontend = managementPortalProperties.getFrontend(); - BaseClientDetails details = new BaseClientDetails(); - details.setClientId(frontend.getClientId()); - details.setClientSecret(null); - details.setAccessTokenValiditySeconds(frontend.getAccessTokenValiditySeconds()); - details.setRefreshTokenValiditySeconds(frontend.getRefreshTokenValiditySeconds()); - details.setResourceIds(List.of("res_ManagementPortal", "res_appconfig", "res_upload", - "res_restAuthorizer")); - details.setAuthorizedGrantTypes(Arrays.asList("password", "refresh_token", - "authorization_code")); - details.setAdditionalInformation(Collections.singletonMap("protected", Boolean.TRUE)); - List allScopes = Arrays.asList(Permission.scopes()); - details.setScope(allScopes); - details.setAutoApproveScopes(allScopes); - loadOAuthClient(details); + @EventListener(ContextRefreshedEvent::class) + fun loadFrontendOauthClient() { + logger.info("Loading ManagementPortal frontend client") + val frontend = managementPortalProperties!!.frontend + val details = BaseClientDetails() + details.clientId = frontend.clientId + details.clientSecret = null + details.accessTokenValiditySeconds = frontend.accessTokenValiditySeconds + details.refreshTokenValiditySeconds = frontend.refreshTokenValiditySeconds + details.setResourceIds( + listOf( + "res_ManagementPortal", "res_appconfig", "res_upload", + "res_restAuthorizer" + ) + ) + details.setAuthorizedGrantTypes( + mutableListOf( + "password", "refresh_token", + "authorization_code" + ) + ) + details.setAdditionalInformation(Collections.singletonMap("protected", Boolean.TRUE)) + val allScopes = Arrays.asList(*scopes()) + details.setScope(allScopes) + details.setAutoApproveScopes(allScopes) + loadOAuthClient(details) } /** * Event listener method that loads OAuth clients from file as soon as the application * context is refreshed. This happens at least once, on application startup. */ - @EventListener(ContextRefreshedEvent.class) - public void loadOAuthClientsFromFile() { - String path = managementPortalProperties.getOauth().getClientsFile(); - if (Objects.isNull(path) || path.equals("")) { - logger.info("No OAuth clients file specified, not loading additional clients"); - return; + @EventListener(ContextRefreshedEvent::class) + fun loadOAuthClientsFromFile() { + val path = managementPortalProperties!!.oauth.clientsFile + if (Objects.isNull(path) || path == "") { + logger.info("No OAuth clients file specified, not loading additional clients") + return } - Path file = Paths.get(path); + val file = Paths.get(path) // CsvSchema uses the @JsonPropertyOrder to define column order, it does not // read the header. Let's read the header ourselves and provide that as // column order - String[] columnOrder = getCsvFileColumnOrder(file); - if (columnOrder == null) { - return; - } - CsvMapper mapper = new CsvMapper(); - CsvSchema schema = mapper.schemaFor(CustomBaseClientDetails.class) - .withColumnReordering(true) - .sortedBy(columnOrder) - .withColumnSeparator(SEPARATOR) - .withHeader(); - ObjectReader reader = mapper - .readerFor(CustomBaseClientDetails.class) - .with(schema); - try (InputStream inputStream = Files.newInputStream(file); - MappingIterator iterator = reader.readValues(inputStream)) { - logger.info("Loading OAuth clients from {}", file.toAbsolutePath()); - while (iterator.hasNext()) { - loadOAuthClient(iterator.nextValue()); + val columnOrder = getCsvFileColumnOrder(file) ?: return + val mapper = CsvMapper() + val schema = mapper.schemaFor(CustomBaseClientDetails::class.java) + .withColumnReordering(true) + .sortedBy(*columnOrder) + .withColumnSeparator(SEPARATOR) + .withHeader() + val reader = mapper + .readerFor(CustomBaseClientDetails::class.java) + .with(schema) + try { + Files.newInputStream(file).use { inputStream -> + reader.readValues(inputStream).use { iterator -> + logger.info("Loading OAuth clients from {}", file.toAbsolutePath()) + while (iterator.hasNext()) { + loadOAuthClient(iterator.nextValue()) + } + } } - } catch (Exception ex) { - logger.error("Unable to load OAuth clients from file: " + ex.getMessage(), ex); + } catch (ex: Exception) { + logger.error("Unable to load OAuth clients from file: " + ex.message, ex) } } - private void loadOAuthClient(ClientDetails details) { + private fun loadOAuthClient(details: ClientDetails) { try { - ClientDetails client = clientDetailsService.loadClientByClientId(details.getClientId()); + val client = clientDetailsService!!.loadClientByClientId(details.clientId) // we delete the existing client and reload it in the next try block - clientDetailsService.removeClientDetails(client.getClientId()); - logger.info("Removed existing OAuth client: " + details.getClientId()); - } catch (NoSuchClientException ex) { + clientDetailsService.removeClientDetails(client.clientId) + logger.info("Removed existing OAuth client: " + details.clientId) + } catch (ex: NoSuchClientException) { // the client is not in the databse yet, this is ok - } catch (Exception ex) { + } catch (ex: Exception) { // other error, e.g. database issue - logger.error(ex.getMessage(), ex); + logger.error(ex.message, ex) } try { - clientDetailsService.addClientDetails(details); - logger.info("OAuth client loaded: " + details.getClientId()); - } catch (Exception ex) { - logger.error("Unable to load OAuth client " + details.getClientId() + ": " - + ex.getMessage(), ex); + clientDetailsService!!.addClientDetails(details) + logger.info("OAuth client loaded: " + details.clientId) + } catch (ex: Exception) { + logger.error( + "Unable to load OAuth client " + details.clientId + ": " + + ex.message, ex + ) } } - private String[] getCsvFileColumnOrder(Path csvFile) { - try (BufferedReader bufferedReader = Files.newBufferedReader(csvFile)) { - return bufferedReader.readLine().split(SEPARATOR.toString()); - } catch (Exception ex) { - logger.error("Unable to read header from OAuth clients file: " + ex.getMessage(), ex); - return null; + private fun getCsvFileColumnOrder(csvFile: Path): Array? { + try { + Files.newBufferedReader(csvFile).use { bufferedReader -> + return bufferedReader.readLine().split(SEPARATOR.toString().toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray() + } + } catch (ex: Exception) { + logger.error("Unable to read header from OAuth clients file: " + ex.message, ex) + return null } } /** * Custom class that will also deserialize the additional_information field. This field holds a - * JSON structure that needs to be converted to a {@code Map}. This field is - * {@link com.fasterxml.jackson.annotation.JsonIgnore}d in BaseClientDetails but we need it. + * JSON structure that needs to be converted to a `Map`. This field is + * [com.fasterxml.jackson.annotation.JsonIgnore]d in BaseClientDetails but we need it. */ - private static class CustomBaseClientDetails extends BaseClientDetails { - + private class CustomBaseClientDetails : BaseClientDetails() { @JsonProperty("additional_information") - private Map additionalInformation = new LinkedHashMap<>(); - - @Override - public Map getAdditionalInformation() { - return additionalInformation; + private var additionalInformation: Map = LinkedHashMap() + override fun getAdditionalInformation(): Map { + return additionalInformation } @JsonSetter("additional_information") - public void setAdditionalInformation(String additionalInformation) { - if (Objects.isNull(additionalInformation) || additionalInformation.equals("")) { - this.additionalInformation = Collections.emptyMap(); - return; + fun setAdditionalInformation(additionalInformation: String) { + if (Objects.isNull(additionalInformation) || additionalInformation == "") { + this.additionalInformation = emptyMap() + return } - ObjectMapper mapper = new ObjectMapper(); + val mapper = ObjectMapper() try { - this.additionalInformation = mapper.readValue(additionalInformation, - new TypeReference>() { - }); - } catch (Exception ex) { - logger.error("Unable to parse additional_information field for client " - + getClientId() + ": " + ex.getMessage(), ex); + this.additionalInformation = mapper.readValue>(additionalInformation, + object : TypeReference>() {}) + } catch (ex: Exception) { + logger.error( + "Unable to parse additional_information field for client " + + clientId + ": " + ex.message, ex + ) } } } + + companion object { + private val logger = LoggerFactory.getLogger(ManagementPortalSecurityConfigLoader::class.java) + private const val SEPARATOR = ';' + } } diff --git a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt index dae7d135d..741e9d882 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt @@ -1,39 +1,34 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; -import org.springframework.security.oauth2.common.util.OAuth2Utils; -import org.springframework.security.oauth2.provider.AuthorizationRequest; -import org.springframework.security.oauth2.provider.ClientDetailsService; -import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.SessionAttributes; -import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.util.HtmlUtils; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.text.SimpleDateFormat; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.TreeMap; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception +import org.springframework.security.oauth2.common.util.OAuth2Utils +import org.springframework.security.oauth2.provider.ClientDetailsService +import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.SessionAttributes +import org.springframework.web.servlet.ModelAndView +import org.springframework.web.util.HtmlUtils +import java.lang.Boolean +import java.text.SimpleDateFormat +import java.util.* +import java.util.function.Function +import java.util.stream.Collectors +import java.util.stream.Stream +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse +import kotlin.Any +import kotlin.String /** * Created by dverbeec on 6/07/2017. */ @Controller @SessionAttributes("authorizationRequest") -public class OAuth2LoginUiWebConfig { - +class OAuth2LoginUiWebConfig { @Autowired - private ClientDetailsService clientDetailsService; + private val clientDetailsService: ClientDetailsService? = null /** * Login form for OAuth2 auhorization flows. @@ -42,12 +37,12 @@ public class OAuth2LoginUiWebConfig { * @return a ModelAndView to render the form */ @RequestMapping("/login") - public ModelAndView getLogin(HttpServletRequest request, HttpServletResponse response) { - TreeMap model = new TreeMap<>(); - if (request.getParameterMap().containsKey("error")) { - model.put("loginError", Boolean.TRUE); + fun getLogin(request: HttpServletRequest, response: HttpServletResponse?): ModelAndView { + val model = TreeMap() + if (request.parameterMap.containsKey("error")) { + model["loginError"] = Boolean.TRUE } - return new ModelAndView("login", model); + return ModelAndView("login", model) } /** @@ -57,23 +52,25 @@ public class OAuth2LoginUiWebConfig { * @return a ModelAndView to render the form */ @RequestMapping("/oauth/confirm_access") - public ModelAndView getAccessConfirmation(HttpServletRequest request, - HttpServletResponse response) { - - Map params = request.getParameterMap(); - - Map authorizationParameters = Stream.of( - OAuth2Utils.CLIENT_ID, OAuth2Utils.REDIRECT_URI, OAuth2Utils.STATE, - OAuth2Utils.SCOPE, OAuth2Utils.RESPONSE_TYPE) - .filter(params::containsKey) - .collect(Collectors.toMap(Function.identity(), p -> params.get(p)[0])); - - AuthorizationRequest authorizationRequest = new DefaultOAuth2RequestFactory( - clientDetailsService).createAuthorizationRequest(authorizationParameters); - - Map model = Collections.singletonMap("authorizationRequest", - authorizationRequest); - return new ModelAndView("authorize", model); + fun getAccessConfirmation( + request: HttpServletRequest, + response: HttpServletResponse? + ): ModelAndView { + val params = request.parameterMap + val authorizationParameters = Stream.of( + OAuth2Utils.CLIENT_ID, OAuth2Utils.REDIRECT_URI, OAuth2Utils.STATE, + OAuth2Utils.SCOPE, OAuth2Utils.RESPONSE_TYPE + ) + .filter { key: String -> params.containsKey(key) } + .collect(Collectors.toMap(Function.identity(), Function { p: String -> params[p]!![0] })) + val authorizationRequest = DefaultOAuth2RequestFactory( + clientDetailsService + ).createAuthorizationRequest(authorizationParameters) + val model = Collections.singletonMap( + "authorizationRequest", + authorizationRequest + ) + return ModelAndView("authorize", model) } /** @@ -82,34 +79,33 @@ public class OAuth2LoginUiWebConfig { * @return a ModelAndView to render the page */ @RequestMapping("/oauth/error") - public ModelAndView handleOAuthClientError(HttpServletRequest req) { - TreeMap model = new TreeMap<>(); - Object error = req.getAttribute("error"); + fun handleOAuthClientError(req: HttpServletRequest): ModelAndView { + val model = TreeMap() + val error = req.getAttribute("error") // The error summary may contain malicious user input, // it needs to be escaped to prevent XSS - Map errorParams = new HashMap<>(); - errorParams.put("date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US) - .format(new Date())); - if (error instanceof OAuth2Exception) { - OAuth2Exception oauthError = (OAuth2Exception) error; - errorParams.put("status", String.format("%d", oauthError.getHttpErrorCode())); - errorParams.put("code", oauthError.getOAuth2ErrorCode()); - errorParams.put("message", HtmlUtils.htmlEscape(oauthError.getMessage())); + val errorParams: MutableMap = HashMap() + errorParams["date"] = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US) + .format(Date()) + if (error is OAuth2Exception) { + val oauthError = error + errorParams["status"] = String.format("%d", oauthError.httpErrorCode) + errorParams["code"] = oauthError.oAuth2ErrorCode + errorParams["message"] = HtmlUtils.htmlEscape(oauthError.message) // transform the additionalInfo map to a comma seperated list of key: value pairs - if (oauthError.getAdditionalInformation() != null) { - errorParams.put("additionalInfo", HtmlUtils.htmlEscape( - oauthError.getAdditionalInformation().entrySet().stream() - .map(entry -> entry.getKey() + ": " + entry.getValue()) - .collect(Collectors.joining(", ")))); + if (oauthError.additionalInformation != null) { + errorParams["additionalInfo"] = HtmlUtils.htmlEscape( + oauthError.additionalInformation.entries.joinToString(", ") { entry -> entry.key + ": " + entry.value } + ) } } // Copy non-empty entries to the model. Empty entries will not be present in the model, // so the default value will be rendered in the view. - for (Map.Entry entry : errorParams.entrySet()) { - if (!entry.getValue().equals("")) { - model.put(entry.getKey(), entry.getValue()); + for ((key, value) in errorParams) { + if (value != "") { + model[key] = value } } - return new ModelAndView("error", model); + return ModelAndView("error", model) } } diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index bc36271a5..faa6b7cbd 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -169,14 +169,14 @@ class Project : AbstractEntity(), Serializable { return this } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val project = o as Project + val project = other as Project return if (project.id == null || id == null) { false } else id == project.id diff --git a/src/main/java/org/radarbase/management/domain/Source.kt b/src/main/java/org/radarbase/management/domain/Source.kt index 241f4a5b4..53d1287c3 100644 --- a/src/main/java/org/radarbase/management/domain/Source.kt +++ b/src/main/java/org/radarbase/management/domain/Source.kt @@ -58,7 +58,7 @@ class Source : AbstractEntity, Serializable { var expectedSourceName: String? = null @Column(name = "assigned", nullable = false) - var isAssigned: @NotNull Boolean? = false + var assigned: @NotNull Boolean? = false @Column(name = "deleted", nullable = false) var isDeleted: @NotNull Boolean = false @@ -125,11 +125,6 @@ class Source : AbstractEntity, Serializable { } } - fun assigned(assigned: Boolean): Source { - isAssigned = assigned - return this - } - fun deleted(deleted: Boolean): Source { isDeleted = deleted return this @@ -177,7 +172,7 @@ class Source : AbstractEntity, Serializable { + "id=" + id + ", sourceId='" + sourceId + '\'' + ", sourceName='" + sourceName + '\'' - + ", assigned=" + isAssigned + + ", assigned=" + assigned + ", sourceType=" + sourceType + ", project=" + project + '}') diff --git a/src/main/java/org/radarbase/management/repository/SourceRepository.kt b/src/main/java/org/radarbase/management/repository/SourceRepository.kt index a11861da6..094d95d46 100644 --- a/src/main/java/org/radarbase/management/repository/SourceRepository.kt +++ b/src/main/java/org/radarbase/management/repository/SourceRepository.kt @@ -35,10 +35,10 @@ interface SourceRepository : JpaRepository, RevisionRepository? + val User.authorityReferences: Set get() = roles?.mapTo(HashSet()) { role: Role? -> val auth = role?.role val referent = when (auth?.scope) { @@ -195,7 +195,8 @@ class JwtAuthenticationFilter @JvmOverloads constructor( null -> null } AuthorityReference(auth!!, referent) - } + } ?: setOf() + @get:JvmStatic diff --git a/src/main/java/org/radarbase/management/security/RadarAuthentication.kt b/src/main/java/org/radarbase/management/security/RadarAuthentication.kt index 26df1809d..3f6be9708 100644 --- a/src/main/java/org/radarbase/management/security/RadarAuthentication.kt +++ b/src/main/java/org/radarbase/management/security/RadarAuthentication.kt @@ -79,7 +79,7 @@ class RadarAuthentication(@param:Nonnull private val token: RadarToken) : Authen } override fun hashCode(): Int { - var result = token?.hashCode() ?: 0 + var result = token.hashCode() result = 31 * result + if (isAuthenticated) 1 else 0 return result } diff --git a/src/main/java/org/radarbase/management/security/SecurityUtils.kt b/src/main/java/org/radarbase/management/security/SecurityUtils.kt index 0b6b66f42..309c52ecc 100644 --- a/src/main/java/org/radarbase/management/security/SecurityUtils.kt +++ b/src/main/java/org/radarbase/management/security/SecurityUtils.kt @@ -25,27 +25,25 @@ object SecurityUtils { * @param authentication context authentication * @return user name if present */ - fun getUserName(authentication: Authentication): String? { - return authentication - .let { obj: Authentication -> obj.principal } - .let { principal: Any? -> - when (principal) { - is UserDetails -> { - return (authentication.principal as UserDetails).username - } + fun getUserName(authentication: Authentication): String? = authentication + .let { obj: Authentication -> obj.principal } + .let { principal: Any? -> + when (principal) { + is UserDetails -> { + return (authentication.principal as UserDetails).username + } - is String -> { - return authentication.principal as String - } + is String -> { + return authentication.principal as String + } - is Authentication -> { - return principal.name - } + is Authentication -> { + return principal.name + } - else -> { - return null - } + else -> { + return null } } - } + } } diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt index 7fae1aed9..57625c3f4 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt @@ -112,9 +112,9 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( private fun loadVerifiersPublicKeyAliasList(): List { val publicKeyAliases: MutableList = ArrayList() - publicKeyAliases.add(oauthConfig.signingKeyAlias) + oauthConfig.signingKeyAlias?.let { publicKeyAliases.add(it) } if (oauthConfig.checkingKeyAliases != null) { - publicKeyAliases.addAll(oauthConfig.checkingKeyAliases) + publicKeyAliases.addAll(oauthConfig.checkingKeyAliases!!) } return publicKeyAliases } @@ -230,23 +230,17 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( private val logger = LoggerFactory.getLogger( ManagementPortalOauthKeyStoreHandler::class.java ) - private val KEYSTORE_PATHS = Arrays.asList( + private val KEYSTORE_PATHS = listOf( ClassPathResource("/config/keystore.p12"), ClassPathResource("/config/keystore.jks") ) private fun checkOAuthConfig(managementPortalProperties: ManagementPortalProperties) { val oauthConfig = managementPortalProperties.oauth - if (oauthConfig == null) { - logger.error( - "Could not find valid Oauth Config. Please configure compulsary " + "properties of Oauth configs of Management Portal" - ) - throw IllegalArgumentException("OauthConfig is not provided") - } - if (oauthConfig.keyStorePassword == null || oauthConfig.keyStorePassword.isEmpty()) { + if (oauthConfig.keyStorePassword.isEmpty()) { logger.error("oauth.keyStorePassword is empty") throw IllegalArgumentException("oauth.keyStorePassword is empty") } - if (oauthConfig.signingKeyAlias == null || oauthConfig.signingKeyAlias.isEmpty()) { + if (oauthConfig.signingKeyAlias == null || oauthConfig.signingKeyAlias!!.isEmpty()) { logger.error("oauth.signingKeyAlias is empty") throw IllegalArgumentException("OauthConfig is not provided") } diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.java b/src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.java deleted file mode 100644 index a0145c422..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.radarbase.management.security.jwt.algorithm; - -import java.security.KeyPair; -import java.util.Base64; - -import org.radarbase.auth.jwks.JsonWebKey; -import org.radarbase.auth.jwks.MPJsonWebKey; - -public abstract class AsymmetricalJwtAlgorithm implements JwtAlgorithm { - - protected final KeyPair keyPair; - - protected AsymmetricalJwtAlgorithm(KeyPair keyPair) { - this.keyPair = keyPair; - } - - /** Header used for encoding public keys. */ - protected abstract String getEncodedStringHeader(); - - /** Footer used for encoding public keys. */ - protected abstract String getEncodedStringFooter(); - - /** The family of cryptographic algorithms used with the key. */ - protected abstract String getKeyType(); - - @Override - public String getVerifierKeyEncodedString() { - return getEncodedStringHeader() + '\n' - + new String(Base64.getEncoder().encode(keyPair.getPublic().getEncoded())) - + '\n' + getEncodedStringFooter(); - } - - @Override - public JsonWebKey getJwk() { - return new MPJsonWebKey( - this.getAlgorithm().getName(), - this.getKeyType(), - this.getVerifierKeyEncodedString()); - } -} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.java b/src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.java deleted file mode 100644 index 2ab3931e1..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.radarbase.management.security.jwt.algorithm; - -import com.auth0.jwt.algorithms.Algorithm; - -import java.security.KeyPair; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; - -public class EcdsaJwtAlgorithm extends AsymmetricalJwtAlgorithm { - /** ECDSA JWT algorithm. */ - public EcdsaJwtAlgorithm(KeyPair keyPair) { - super(keyPair); - if (!(keyPair.getPrivate() instanceof ECPrivateKey)) { - throw new IllegalArgumentException( - "Cannot make EcdsaJwtAlgorithm with " + keyPair.getPrivate().getClass()); - } - } - - @Override - public Algorithm getAlgorithm() { - return Algorithm.ECDSA256( - (ECPublicKey)keyPair.getPublic(), - (ECPrivateKey)keyPair.getPrivate()); - } - - @Override - public String getEncodedStringHeader() { - return "-----BEGIN EC PUBLIC KEY-----"; - } - - @Override - public String getEncodedStringFooter() { - return "-----END EC PUBLIC KEY-----"; - } - - @Override - public String getKeyType() { - return "EC"; - } - -} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.java b/src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.java deleted file mode 100644 index d7d026371..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.radarbase.management.security.jwt.algorithm; - -import com.auth0.jwt.algorithms.Algorithm; -import org.radarbase.auth.jwks.JsonWebKey; - -/** - * Encodes a signing and verification algorithm for JWT. - */ -public interface JwtAlgorithm { - - /** - * Auth0 Algorithm used in JWTs. - */ - Algorithm getAlgorithm(); - - /** - * Encoded public key for storage or transmission. - */ - String getVerifierKeyEncodedString(); - - /** - * JavaWebKey for given algorithm for token verification. - * @return instance of {@link JsonWebKey} - */ - JsonWebKey getJwk(); -} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.java b/src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.java deleted file mode 100644 index 10d1aedde..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.radarbase.management.security.jwt.algorithm; - -import com.auth0.jwt.algorithms.Algorithm; - -import java.security.KeyPair; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; - -public class RsaJwtAlgorithm extends AsymmetricalJwtAlgorithm { - /** RSA JWT algorithm. */ - public RsaJwtAlgorithm(KeyPair keyPair) { - super(keyPair); - if (!(keyPair.getPrivate() instanceof RSAPrivateKey)) { - throw new IllegalArgumentException( - "Cannot make RsaJwtAlgorithm with " + keyPair.getPrivate().getClass()); - } - } - - @Override - public Algorithm getAlgorithm() { - return Algorithm.RSA256( - (RSAPublicKey)keyPair.getPublic(), - (RSAPrivateKey)keyPair.getPrivate()); - } - - @Override - public String getEncodedStringHeader() { - return "-----BEGIN PUBLIC KEY-----"; - } - - @Override - public String getEncodedStringFooter() { - return "-----END PUBLIC KEY-----"; - } - - @Override - public String getKeyType() { - return "RSA"; - } -} diff --git a/src/main/java/org/radarbase/management/service/RoleService.kt b/src/main/java/org/radarbase/management/service/RoleService.kt index 9074ceaf3..239dcf59a 100644 --- a/src/main/java/org/radarbase/management/service/RoleService.kt +++ b/src/main/java/org/radarbase/management/service/RoleService.kt @@ -35,7 +35,6 @@ open class RoleService( @Autowired private val userService: UserService ) { - private val log = LoggerFactory.getLogger(RoleService::class.java) /** * Save a role. diff --git a/src/main/java/org/radarbase/management/service/SiteSettingsService.kt b/src/main/java/org/radarbase/management/service/SiteSettingsService.kt index 9226f49a1..cabb2e47e 100644 --- a/src/main/java/org/radarbase/management/service/SiteSettingsService.kt +++ b/src/main/java/org/radarbase/management/service/SiteSettingsService.kt @@ -12,9 +12,8 @@ import org.springframework.transaction.annotation.Transactional */ @Service @Transactional -class SiteSettingsService { - @Autowired - private val managementPortalProperties: ManagementPortalProperties? = null +open class SiteSettingsService( + @Autowired private val managementPortalProperties: ManagementPortalProperties) { /** * Convert a [SiteSettings] to a [SiteSettingsDto] object. @@ -28,6 +27,5 @@ class SiteSettingsService { } val siteSettingsDto: SiteSettingsDto - // NAMING! - get() = createSiteSettingsDto(managementPortalProperties!!.siteSettings) + get() = createSiteSettingsDto(managementPortalProperties.siteSettings) } diff --git a/src/main/java/org/radarbase/management/service/SourceService.kt b/src/main/java/org/radarbase/management/service/SourceService.kt index ccf937a07..eb21d13e9 100644 --- a/src/main/java/org/radarbase/management/service/SourceService.kt +++ b/src/main/java/org/radarbase/management/service/SourceService.kt @@ -117,7 +117,7 @@ open class SourceService( val sourceHistory = sourceRepository.findRevisions(id) val sources = sourceHistory.content .mapNotNull { obj -> obj.entity } - .filter{ it.isAssigned + .filter{ it.assigned ?: false } .toList() if (sources.isEmpty()) { @@ -228,7 +228,7 @@ open class SourceService( // if the source is being transferred to another project. if (existingSource.project?.id != sourceDto.project?.id) { - if (existingSource.isAssigned!!) { + if (existingSource.assigned!!) { throw InvalidRequestException( "Cannot transfer an assigned source", EntityName.SOURCE, "error.sourceIsAssigned" diff --git a/src/main/java/org/radarbase/management/service/SubjectService.kt b/src/main/java/org/radarbase/management/service/SubjectService.kt index 84dcd8ec1..2a2bec776 100644 --- a/src/main/java/org/radarbase/management/service/SubjectService.kt +++ b/src/main/java/org/radarbase/management/service/SubjectService.kt @@ -98,7 +98,10 @@ open class SubjectService( user.activated = true //set if any devices are set as assigned if (subject.sources.isNotEmpty()) { - subject.sources.forEach(Consumer { s: Source -> s.assigned(true).subject(subject) }) + subject.sources.forEach(Consumer { s: Source -> + s.assigned = true + s.subject(subject) + }) } if (subject.enrollmentDate == null) { subject.enrollmentDate = ZonedDateTime.now() @@ -157,7 +160,8 @@ open class SubjectService( //set only the devices assigned to a subject as assigned subjectMapper.safeUpdateSubjectFromDTO(newSubjectDto, subjectFromDb) sourcesToUpdate.addAll(subjectFromDb.sources) - subjectFromDb.sources.forEach(Consumer { s: Source -> s.subject(subjectFromDb).assigned(true) }) + subjectFromDb.sources.forEach(Consumer { s: Source -> + s.subject(subjectFromDb).assigned = true }) sourceRepository.saveAll(sourcesToUpdate) // update participant role subjectFromDb.user!!.roles = updateParticipantRoles(subjectFromDb, newSubjectDto) @@ -233,7 +237,7 @@ open class SubjectService( */ private fun unassignAllSources(subject: Subject) { subject.sources.forEach(Consumer { source: Source -> - source.isAssigned = false + source.assigned = false source.subject = null source.isDeleted = true sourceRepository.save(source) @@ -262,7 +266,8 @@ open class SubjectService( // create a source and register metadata // we allow only one source of a source-type per subject if (sources.isNullOrEmpty()) { - var source = Source(sourceType).project(project).assigned(true).sourceType(sourceType).subject(subject) + var source = Source(sourceType).project(project).sourceType(sourceType).subject(subject) + source.assigned = true source.attributes += sourceRegistrationDto.attributes // if source name is provided update source name if (sourceRegistrationDto.sourceName != null) { @@ -332,7 +337,7 @@ open class SubjectService( source.sourceName = sourceRegistrationDto.sourceName } source.attributes += sourceRegistrationDto.attributes - source.isAssigned = true + source.assigned = true source.subject = subject return sourceRepository.save(source) } diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt index fe111ae5b..56eb19894 100644 --- a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt @@ -16,7 +16,7 @@ class MinimalSourceDetailsDTO { lateinit var sourceId: UUID var sourceName: String? = null var isAssigned: Boolean? = null - var attributes: Map = HashMap() + var attributes: MutableMap = HashMap() fun id(id: Long?): MinimalSourceDetailsDTO { this.id = id return this @@ -27,11 +27,6 @@ class MinimalSourceDetailsDTO { return this } - fun setExpectedSourceName(expectedSourceName: String?): MinimalSourceDetailsDTO { - this.expectedSourceName = expectedSourceName - return this - } - fun sourceId(sourceId: UUID): MinimalSourceDetailsDTO { this.sourceId = sourceId return this @@ -47,7 +42,7 @@ class MinimalSourceDetailsDTO { return this } - fun attributes(attributes: Map): MinimalSourceDetailsDTO { + fun attributes(attributes: MutableMap): MinimalSourceDetailsDTO { this.attributes = attributes return this } diff --git a/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt b/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt index b45250e80..b4fba3a0d 100644 --- a/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt +++ b/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt @@ -9,14 +9,14 @@ import java.util.* */ class SiteSettingsDto : Serializable { var hiddenSubjectFields = listOf() - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val that = o as SiteSettingsDto + val that = other as SiteSettingsDto return hiddenSubjectFields == that.hiddenSubjectFields } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt index eb418185c..518f91360 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt @@ -31,7 +31,7 @@ abstract class SourceMapperDecorator( EntityName.Companion.SOURCE, ErrorConstants.ERR_SOURCE_NOT_FOUND, Map.of("sourceId", minimalSourceDetailsDto.sourceId.toString()) ) - source.isAssigned = minimalSourceDetailsDto.isAssigned + source.assigned = minimalSourceDetailsDto.isAssigned return source } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt index 02f4fa2eb..163eda4ee 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt @@ -7,13 +7,11 @@ import org.radarbase.management.service.mapper.UserMapper import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Qualifier -abstract class UserMapperDecorator : UserMapper { - @Autowired - @Qualifier("delegate") - private val delegate: UserMapper? = null +abstract class UserMapperDecorator( + @Autowired @Qualifier("delegate") private val delegate: UserMapper? = null, + @Autowired private val revisionService: RevisionService? = null +) : UserMapper { - @Autowired - private val revisionService: RevisionService? = null override fun userToUserDTO(user: User?): UserDTO? { if (user == null) { return null diff --git a/src/main/java/org/radarbase/management/web/rest/AuthorityResource.kt b/src/main/java/org/radarbase/management/web/rest/AuthorityResource.kt index e47911788..231e4395b 100644 --- a/src/main/java/org/radarbase/management/web/rest/AuthorityResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/AuthorityResource.kt @@ -1,53 +1,57 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.dto.AuthorityDTO; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; -import java.util.stream.Stream; - -import static org.radarbase.auth.authorization.Permission.AUTHORITY_READ; +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.Permission +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.dto.AuthorityDTO +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import java.util.stream.Stream /** * REST controller for managing Authority. */ @RestController @RequestMapping("/api") -public class AuthorityResource { - private static final Logger log = LoggerFactory.getLogger(AuthorityResource.class); - - private static final List ALL_AUTHORITIES = Stream.of( - RoleAuthority.SYS_ADMIN, - RoleAuthority.ORGANIZATION_ADMIN, - RoleAuthority.PROJECT_ADMIN, - RoleAuthority.PROJECT_OWNER, - RoleAuthority.PROJECT_AFFILIATE, - RoleAuthority.PROJECT_ANALYST) - .map(AuthorityDTO::new) - .toList(); - +class AuthorityResource { @Autowired - private AuthService authService; + private val authService: AuthService? = null + + @get:Throws(NotAuthorizedException::class) + @get:Timed + @get:GetMapping("/authorities") + val allAuthorities: List + /** + * GET /authorities : get all the authorities. + * + * @return the ResponseEntity with status 200 (OK) and the list of authorities in body + */ + get() { + log.debug("REST request to get all Authorities") + authService!!.checkScope(Permission.AUTHORITY_READ) + return ALL_AUTHORITIES + } - /** - * GET /authorities : get all the authorities. - * - * @return the ResponseEntity with status 200 (OK) and the list of authorities in body - */ - @GetMapping("/authorities") - @Timed - public List getAllAuthorities() throws NotAuthorizedException { - log.debug("REST request to get all Authorities"); - authService.checkScope(AUTHORITY_READ); - return ALL_AUTHORITIES; + companion object { + private val log = LoggerFactory.getLogger(AuthorityResource::class.java) + private val ALL_AUTHORITIES = Stream.of( + RoleAuthority.SYS_ADMIN, + RoleAuthority.ORGANIZATION_ADMIN, + RoleAuthority.PROJECT_ADMIN, + RoleAuthority.PROJECT_OWNER, + RoleAuthority.PROJECT_AFFILIATE, + RoleAuthority.PROJECT_ANALYST + ) + .map { role: RoleAuthority? -> + AuthorityDTO( + role!! + ) + } + .toList() } } diff --git a/src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.kt b/src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.kt index a4ba51d05..71d872714 100644 --- a/src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.kt @@ -1,49 +1,44 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.service.SiteSettingsService; -import org.radarbase.management.service.dto.SiteSettingsDto; -import org.radarbase.management.config.ManagementPortalProperties.SiteSettings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import io.micrometer.core.annotation.Timed +import org.radarbase.management.service.SiteSettingsService +import org.radarbase.management.service.dto.SiteSettingsDto +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController /** * REST controller for managing site settings. * - *

This class accesses {@link SiteSettings} entity as a means of defining configurations - * before authentication.

+ * + * This class accesses [SiteSettings] entity as a means of defining configurations + * before authentication. * */ @RestController @RequestMapping("/api") -public class SiteSettingsResource { - - private static final Logger log = LoggerFactory.getLogger(SiteSettingsResource.class); - - private final SiteSettingsService siteSettingsService; - - public SiteSettingsResource( - @Autowired SiteSettingsService siteSettingsService) { - this.siteSettingsService = siteSettingsService; - } - - /** - * GET /SiteSettings : Gets the current SiteSettings as a DTO. - * - * @return the ResponseEntity with status 200 (Ok) and with body {@link SiteSettingsDto}. - */ - @GetMapping("/sitesettings") - @Timed - public ResponseEntity getDisabledSubjectFields() { - log.debug("REST request to get sitesettings"); - - return ResponseEntity +class SiteSettingsResource( + @param:Autowired private val siteSettingsService: SiteSettingsService +) { + @get:Timed + @get:GetMapping("/sitesettings") + val disabledSubjectFields: ResponseEntity + /** + * GET /SiteSettings : Gets the current SiteSettings as a DTO. + * + * @return the ResponseEntity with status 200 (Ok) and with body [SiteSettingsDto]. + */ + get() { + log.debug("REST request to get sitesettings") + return ResponseEntity .ok() - .body(siteSettingsService.getSiteSettingsDto()); + .body(siteSettingsService.siteSettingsDto) + } + + companion object { + private val log = LoggerFactory.getLogger(SiteSettingsResource::class.java) } } diff --git a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt index 3e14ca0a5..856c3b61b 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt @@ -207,7 +207,7 @@ class SourceResource( val sourceId = sourceDto.id val sourceHistory = sourceId?.let { sourceRepository.findRevisions(it) } val sources = - sourceHistory?.mapNotNull { obj: Revision -> obj.entity }?.filter { it.isAssigned == true } + sourceHistory?.mapNotNull { obj: Revision -> obj.entity }?.filter { it.assigned == true } ?.toList() if (sources?.isNotEmpty() == true) { val failureAlert = HeaderUtil.createFailureAlert( diff --git a/src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.kt b/src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.kt index fed32de5c..c4fc357ee 100644 --- a/src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.kt +++ b/src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.kt @@ -1,37 +1,32 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.auth.jwks.JsonWebKeySet; -import org.radarbase.management.security.jwt.ManagementPortalOauthKeyStoreHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.jwks.JsonWebKeySet +import org.radarbase.management.security.jwt.ManagementPortalOauthKeyStoreHandler +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController @RestController -public class TokenKeyEndpoint { - private static final Logger logger = LoggerFactory.getLogger(TokenKeyEndpoint.class); +class TokenKeyEndpoint @Autowired constructor( + private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler +) { + @get:Timed + @get:GetMapping("/oauth/token_key") + val key: JsonWebKeySet + /** + * Get the verification key for the token signatures. The principal has to + * be provided only if the key is secret + * + * @return the key used to verify tokens + */ + get() { + logger.debug("Requesting verifier public keys...") + return keyStoreHandler.loadJwks() + } - private final ManagementPortalOauthKeyStoreHandler keyStoreHandler; - - @Autowired - public TokenKeyEndpoint( - ManagementPortalOauthKeyStoreHandler keyStoreHandler - ) { - this.keyStoreHandler = keyStoreHandler; - } - - /** - * Get the verification key for the token signatures. The principal has to - * be provided only if the key is secret - * - * @return the key used to verify tokens - */ - @GetMapping("/oauth/token_key") - @Timed - public JsonWebKeySet getKey() { - logger.debug("Requesting verifier public keys..."); - return keyStoreHandler.loadJwks(); + companion object { + private val logger = LoggerFactory.getLogger(TokenKeyEndpoint::class.java) } } diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt index 51d44586a..6fc2c2404 100644 --- a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt +++ b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt @@ -36,14 +36,14 @@ class RadarWebApplicationExceptionVM emptyMap() ) - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val that = o as RadarWebApplicationExceptionVM + val that = other as RadarWebApplicationExceptionVM return entityName == that.entityName && errorCode == that.errorCode && message == that.message && params == that.params } diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index f1bc651d1..78ec5fa9a 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -226,7 +226,7 @@ internal open class OrganizationResourceIntTest( organizationRepository.saveAndFlush(organization) val updatedOrgDto = organizationMapper .organizationToOrganizationDTO(organization) - updatedOrgDto?.location = "Other location" + updatedOrgDto.location = "Other location" // Update the organization restOrganizationMockMvc.perform( diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt index 8ef5320d0..804292021 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt @@ -76,7 +76,7 @@ internal open class SourceDataResourceIntTest( @BeforeEach fun initTest() { - sourceData = createEntity(em) + sourceData = createEntity() } @Test @@ -365,7 +365,7 @@ internal open class SourceDataResourceIntTest( val databaseSizeBeforeUpdate = sourceDataRepository.findAll().size // Update the sourceData - val updatedSourceData = sourceDataRepository.findById(sourceData.id).get() + val updatedSourceData = sourceDataRepository.findById(sourceData.id!!).get() updatedSourceData .sourceDataType(UPDATED_SOURCE_DATA_TYPE) .sourceDataName(UPDATED_SOURCE_DATA_NAME) @@ -474,7 +474,7 @@ internal open class SourceDataResourceIntTest( * This is a static method, as tests for other entities might also need it, * if they test an entity which requires the current entity. */ - fun createEntity(em: EntityManager?): SourceData { + fun createEntity(): SourceData { return SourceData() .sourceDataType(DEFAULT_SOURCE_DATA_TYPE) .sourceDataName(DEFAULT_SOURCE_DATA_NAME) diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt index 04f5133ef..80033e65a 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt @@ -109,7 +109,7 @@ internal open class SourceResourceIntTest( val sourceList = sourceRepository.findAll() Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeCreate + 1) val testSource = sourceList[sourceList.size - 1] - Assertions.assertThat(testSource.isAssigned).isEqualTo(DEFAULT_ASSIGNED) + Assertions.assertThat(testSource.assigned).isEqualTo(DEFAULT_ASSIGNED) Assertions.assertThat(testSource.sourceName).isEqualTo(DEFAULT_SOURCE_NAME) Assertions.assertThat(testSource.project!!.projectName).isEqualTo(project.projectName) } @@ -173,7 +173,7 @@ internal open class SourceResourceIntTest( open fun checkAssignedIsRequired() { val databaseSizeBeforeTest = sourceRepository.findAll().size // set the field null - source.isAssigned = null + source.assigned = null // Create the Source, which fails. val sourceDto = sourceMapper.sourceToSourceDTO(source) @@ -254,7 +254,7 @@ internal open class SourceResourceIntTest( val updatedSource = sourceRepository.findById(source.id!!).get() updatedSource .sourceId(UPDATED_SOURCE_PHYSICAL_ID) - .assigned(UPDATED_ASSIGNED) + .assigned = UPDATED_ASSIGNED val sourceDto = sourceMapper.sourceToSourceDTO(updatedSource) restDeviceMockMvc.perform( MockMvcRequestBuilders.put("/api/sources") @@ -268,7 +268,7 @@ internal open class SourceResourceIntTest( Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeUpdate) val testSource = sourceList[sourceList.size - 1] Assertions.assertThat(testSource.sourceId).isEqualTo(UPDATED_SOURCE_PHYSICAL_ID) - Assertions.assertThat(testSource.isAssigned).isEqualTo(UPDATED_ASSIGNED) + Assertions.assertThat(testSource.assigned).isEqualTo(UPDATED_ASSIGNED) } @Test @@ -335,9 +335,11 @@ internal open class SourceResourceIntTest( * if they test an entity which requires the current entity. */ fun createEntity(): Source { - return Source() - .assigned(DEFAULT_ASSIGNED) + val s = Source() .sourceName(DEFAULT_SOURCE_NAME) + + s.assigned = DEFAULT_ASSIGNED + return s } } } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt index dc22d57e5..2981eb2ad 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt @@ -92,7 +92,7 @@ internal open class SourceTypeResourceIntTest( // Create the SourceType val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO( - SourceDataResourceIntTest.Companion.createEntity(em) + SourceDataResourceIntTest.Companion.createEntity() ) val sourceData = sourceTypeDto.sourceData sourceData.add(sourceDataDto!!) @@ -431,7 +431,7 @@ internal open class SourceTypeResourceIntTest( open fun idempotentPutWithoutId() { val databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size val sensorsSizeBeforeUpdate = sourceDataRepository.findAll().size - sourceType.sourceData = setOf(SourceDataResourceIntTest.Companion.createEntity(em)) + sourceType.sourceData = setOf(SourceDataResourceIntTest.Companion.createEntity()) // Create the SourceType val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index 06c7e0d3a..e93558545 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -93,7 +93,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -105,9 +105,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val subjectList = subjectRepository.findAll() Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) val testSubject = subjectList[subjectList.size - 1] - Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK) - Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.Companion.DEFAULT_ENTERNAL_ID) - Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.Companion.DEFAULT_REMOVED) + Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) + Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.DEFAULT_ENTERNAL_ID) + Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.DEFAULT_REMOVED) org.junit.jupiter.api.Assertions.assertEquals(1, testSubject.user!!.roles!!.size) } @@ -116,7 +116,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit @Throws(Exception::class) open fun createSubjectWithExistingId() { // Create a Subject - val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeCreate = subjectRepository.findAll().size // An entity with an existing ID cannot be created, so this API call must fail @@ -138,7 +138,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit open val allSubjects: Unit get() { // Initialize the database - val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) // Get all the subjectList restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects?sort=id,desc")) @@ -153,15 +153,15 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit ) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].externalLink") - .value>(Matchers.hasItem(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK)) + .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_EXTERNAL_LINK)) ) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].externalId") - .value>(Matchers.hasItem(SubjectServiceTest.Companion.DEFAULT_ENTERNAL_ID)) + .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_ENTERNAL_ID)) ) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].status") - .value>(Matchers.hasItem(SubjectServiceTest.Companion.DEFAULT_STATUS.toString())) + .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_STATUS.toString())) ) } @@ -171,7 +171,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit open val subject: Unit get() { // Initialize the database - val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) // Get the subject restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{login}", subjectDto!!.login)) @@ -180,15 +180,15 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(subjectDto.id!!.toInt())) .andExpect( MockMvcResultMatchers.jsonPath("$.externalLink") - .value(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK) + .value(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) ) .andExpect( MockMvcResultMatchers.jsonPath("$.externalId") - .value(SubjectServiceTest.Companion.DEFAULT_ENTERNAL_ID) + .value(SubjectServiceTest.DEFAULT_ENTERNAL_ID) ) .andExpect( MockMvcResultMatchers.jsonPath("$.status") - .value(SubjectServiceTest.Companion.DEFAULT_STATUS.toString()) + .value(SubjectServiceTest.DEFAULT_STATUS.toString()) ) } @@ -207,15 +207,15 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit @Throws(Exception::class) open fun updateSubject() { // Initialize the database - var subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + var subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Update the subject - val updatedSubject = subjectRepository.findById(subjectDto!!.id).get() + val updatedSubject = subjectRepository.findById(subjectDto!!.id!!).get() updatedSubject - .externalLink(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) - .externalId(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) - .removed(SubjectServiceTest.Companion.UPDATED_REMOVED) + .externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) + .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID) + .removed(SubjectServiceTest.UPDATED_REMOVED) subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) restSubjectMockMvc.perform( MockMvcRequestBuilders.put("/api/subjects") @@ -228,9 +228,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val subjectList = subjectRepository.findAll() Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeUpdate) val testSubject = subjectList[subjectList.size - 1] - Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) - Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) - Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.Companion.UPDATED_REMOVED) + Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.UPDATED_EXTERNAL_LINK) + Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.UPDATED_ENTERNAL_ID) + Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) } @Test @@ -238,15 +238,15 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit @Throws(Exception::class) open fun updateSubjectWithNewProject() { // Initialize the database - var subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + var subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Update the subject - val updatedSubject = subjectRepository.findById(subjectDto!!.id).get() + val updatedSubject = subjectRepository.findById(subjectDto!!.id!!).get() updatedSubject - .externalLink(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) - .externalId(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) - .removed(SubjectServiceTest.Companion.UPDATED_REMOVED) + .externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) + .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID) + .removed(SubjectServiceTest.UPDATED_REMOVED) subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) val newProject = ProjectDTO() newProject.id = 2L @@ -264,9 +264,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val subjectList = subjectRepository.findAll() Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeUpdate) val testSubject = subjectList[subjectList.size - 1] - Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) - Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) - Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.Companion.UPDATED_REMOVED) + Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.UPDATED_EXTERNAL_LINK) + Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.UPDATED_ENTERNAL_ID) + Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) Assertions.assertThat(testSubject.user!!.roles!!.size).isEqualTo(2) } @@ -277,7 +277,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Create the Subject - val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() // If the entity doesn't have an ID, it will be created instead of just being updated restSubjectMockMvc.perform( @@ -297,7 +297,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit @Throws(Exception::class) open fun deleteSubject() { // Initialize the database - val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeDelete = subjectRepository.findAll().size // Get the subject @@ -326,7 +326,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -368,7 +368,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -417,7 +417,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -449,7 +449,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit open val subjectSources: Unit get() { // Initialize the database - val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) val sourceDto = MinimalSourceDetailsDTO() .id(createdSource.id) @@ -482,7 +482,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit open val subjectSourcesWithQueryParam: Unit get() { // Initialize the database - val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) val sourceDto = MinimalSourceDetailsDTO() .id(createdSource.id) @@ -515,7 +515,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit open val inactiveSubjectSourcesWithQueryParam: Unit get() { // Initialize the database - val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) val sourceDto = MinimalSourceDetailsDTO() .id(createdSource.id) @@ -602,7 +602,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit private val source: MinimalSourceDetailsDTO get() { val sourceRegistrationDto = MinimalSourceDetailsDTO() - .sourceName(SubjectServiceTest.Companion.PRODUCER + "-" + SubjectServiceTest.Companion.MODEL) + .sourceName(SubjectServiceTest.PRODUCER + "-" + SubjectServiceTest.MODEL) .attributes(Collections.singletonMap("something", "value")) Assertions.assertThat(sourceRegistrationDto.sourceId).isNull() return sourceRegistrationDto @@ -615,7 +615,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt index d0bb73db5..9d0a54a50 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt @@ -100,7 +100,7 @@ internal open class UserResourceIntTest( @AfterEach fun tearDown() { if (project != null) { - projectRepository.delete(project) + projectRepository.delete(project!!) } } From 99dab911a4f058295bba3764667812a211aaa9b3 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 31 Oct 2023 10:12:58 +0100 Subject: [PATCH 043/158] properties back to java class for simplicities' sake --- .../config/ManagementPortalProperties.java | 299 ++++++++++++++++++ .../config/ManagementPortalProperties.kt | 68 ---- 2 files changed, 299 insertions(+), 68 deletions(-) create mode 100644 src/main/java/org/radarbase/management/config/ManagementPortalProperties.java delete mode 100644 src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalProperties.java b/src/main/java/org/radarbase/management/config/ManagementPortalProperties.java new file mode 100644 index 000000000..e478a0679 --- /dev/null +++ b/src/main/java/org/radarbase/management/config/ManagementPortalProperties.java @@ -0,0 +1,299 @@ +package org.radarbase.management.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.List; + +/** + * Created by nivethika on 3-10-17. + */ +@ConfigurationProperties(prefix = "managementportal", ignoreUnknownFields = false) +public class ManagementPortalProperties { + + private final Mail mail = new Mail(); + + private final Frontend frontend = new Frontend(); + + private Oauth oauth = new Oauth(); + + private final Common common = new Common(); + + private final CatalogueServer catalogueServer = new CatalogueServer(); + + private final Account account = new Account(); + + private final SiteSettings siteSettings = new SiteSettings(); + + public ManagementPortalProperties.Frontend getFrontend() { + return frontend; + } + + public ManagementPortalProperties.Mail getMail() { + return mail; + } + + public ManagementPortalProperties.Oauth getOauth() { + return oauth; + } + + public void setOauth(ManagementPortalProperties.Oauth oauth) { + this.oauth = oauth; + } + + public CatalogueServer getCatalogueServer() { + return catalogueServer; + } + + public Common getCommon() { + return common; + } + + public Account getAccount() { + return account; + } + + public SiteSettings getSiteSettings() { + return siteSettings; + } + + public static class Account { + private boolean enableExposeToken = false; + + public boolean getEnableExposeToken() { + return enableExposeToken; + } + + public void setEnableExposeToken(boolean enableExposeToken) { + this.enableExposeToken = enableExposeToken; + } + } + + public static class Common { + + private String baseUrl = ""; + + private String managementPortalBaseUrl = ""; + + private String privacyPolicyUrl = ""; + + private String adminPassword = ""; + + private Integer activationKeyTimeoutInSeconds = 24 * 60 * 60; // 1 day + + public String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public String getPrivacyPolicyUrl() { + return privacyPolicyUrl; + } + + public void setPrivacyPolicyUrl(String privacyPolicyUrl) { + this.privacyPolicyUrl = privacyPolicyUrl; + } + + public String getAdminPassword() { + return adminPassword; + } + + public void setAdminPassword(String adminPassword) { + this.adminPassword = adminPassword; + } + + public String getManagementPortalBaseUrl() { + return managementPortalBaseUrl; + } + + public void setManagementPortalBaseUrl(String managementPortalBaseUrl) { + this.managementPortalBaseUrl = managementPortalBaseUrl; + } + + public Integer getActivationKeyTimeoutInSeconds() { + return activationKeyTimeoutInSeconds; + } + + public void setActivationKeyTimeoutInSeconds(Integer activationKeyTimeoutInSeconds) { + this.activationKeyTimeoutInSeconds = activationKeyTimeoutInSeconds; + } + } + + public static class Mail { + + private String from = ""; + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + } + + public static class Frontend { + + private String clientId = ""; + + private String clientSecret = ""; + + private Integer accessTokenValiditySeconds = 4 * 60 * 60; + + private Integer refreshTokenValiditySeconds = 72 * 60 * 60; + + private Integer sessionTimeout = 24 * 60 * 60; // a day + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + public Integer getSessionTimeout() { + return sessionTimeout; + } + + public void setSessionTimeout(Integer sessionTimeout) { + this.sessionTimeout = sessionTimeout; + } + + public Integer getAccessTokenValiditySeconds() { + return accessTokenValiditySeconds; + } + + public void setAccessTokenValiditySeconds(Integer accessTokenValiditySeconds) { + this.accessTokenValiditySeconds = accessTokenValiditySeconds; + } + + public Integer getRefreshTokenValiditySeconds() { + return refreshTokenValiditySeconds; + } + + public void setRefreshTokenValiditySeconds(Integer refreshTokenValiditySeconds) { + this.refreshTokenValiditySeconds = refreshTokenValiditySeconds; + } + } + + public static class Oauth { + + private String clientsFile; + + private String signingKeyAlias; + + private List checkingKeyAliases; + + private String keyStorePassword; + + private String metaTokenTimeout; + + private String persistentMetaTokenTimeout; + + private Boolean enablePublicKeyVerifiers = false; + + public String getClientsFile() { + return clientsFile; + } + + public void setClientsFile(String clientsFile) { + this.clientsFile = clientsFile; + } + + public String getSigningKeyAlias() { + return signingKeyAlias; + } + + public void setSigningKeyAlias(String signingKeyAlias) { + this.signingKeyAlias = signingKeyAlias; + } + + public List getCheckingKeyAliases() { + return checkingKeyAliases; + } + + public void setCheckingKeyAliases(List checkingKeyAliases) { + this.checkingKeyAliases = checkingKeyAliases; + } + + public String getKeyStorePassword() { + return keyStorePassword; + } + + public void setKeyStorePassword(String keyStorePassword) { + this.keyStorePassword = keyStorePassword; + } + + public String getMetaTokenTimeout() { + return metaTokenTimeout; + } + + public void setMetaTokenTimeout(String metaTokenTimeout) { + this.metaTokenTimeout = metaTokenTimeout; + } + + public String getPersistentMetaTokenTimeout() { + return persistentMetaTokenTimeout; + } + + public void setPersistentMetaTokenTimeout(String persistentMetaTokenTimeout) { + this.persistentMetaTokenTimeout = persistentMetaTokenTimeout; + } + + public Boolean getEnablePublicKeyVerifiers() { + return enablePublicKeyVerifiers; + } + + public void setEnablePublicKeyVerifiers(Boolean enablePublicKeyVerifiers) { + this.enablePublicKeyVerifiers = enablePublicKeyVerifiers; + } + } + + public static class CatalogueServer { + + private boolean enableAutoImport = false; + + private String serverUrl; + + public String getServerUrl() { + return serverUrl; + } + + public void setServerUrl(String serverUrl) { + this.serverUrl = serverUrl; + } + + public boolean isEnableAutoImport() { + return enableAutoImport; + } + + public void setEnableAutoImport(boolean enableAutoImport) { + this.enableAutoImport = enableAutoImport; + } + } + + public static class SiteSettings { + + private List hiddenSubjectFields; + + public void setHiddenSubjectFields(List hiddenSubjectFields) { + this.hiddenSubjectFields = hiddenSubjectFields; + } + + public List getHiddenSubjectFields() { + return hiddenSubjectFields; + } + } +} diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt b/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt deleted file mode 100644 index c9853ddbc..000000000 --- a/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt +++ /dev/null @@ -1,68 +0,0 @@ -package org.radarbase.management.config - -import org.springframework.boot.context.properties.ConfigurationProperties - -/** - * Created by nivethika on 3-10-17. - */ -@ConfigurationProperties(prefix = "managementportal", ignoreUnknownFields = false) -class ManagementPortalProperties { - val mail = Mail() - @JvmField - val frontend = Frontend() - @JvmField - var oauth = Oauth() - @JvmField - val common = Common() - val catalogueServer = CatalogueServer() - val account = Account() - val siteSettings = SiteSettings() - - class Account { - var enableExposeToken = false - } - - class Common { - var baseUrl = "" - var managementPortalBaseUrl = "" - var privacyPolicyUrl = "" - @JvmField - var adminPassword = "" - var activationKeyTimeoutInSeconds = 24 * 60 * 60 // 1 day - } - - class Mail { - var from = "" - } - - class Frontend { - @JvmField - var clientId = "" - var clientSecret = "" - @JvmField - var accessTokenValiditySeconds = 4 * 60 * 60 - @JvmField - var refreshTokenValiditySeconds = 72 * 60 * 60 - var sessionTimeout = 24 * 60 * 60 // a day - } - - class Oauth { - @JvmField - var clientsFile: String? = null - var signingKeyAlias: String? = null - var checkingKeyAliases: List? = null - lateinit var keyStorePassword: String - var metaTokenTimeout: String? = null - var persistentMetaTokenTimeout: String? = null - var enablePublicKeyVerifiers = false - } - - class CatalogueServer { - var isEnableAutoImport = false - var serverUrl: String? = null - } - - class SiteSettings { - var hiddenSubjectFields: List = listOf() - } -} From 90a53b2dfcda166b01dcc9cff725949cc54f41d2 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 31 Oct 2023 10:13:27 +0100 Subject: [PATCH 044/158] change the renamed boolean properties back so hibernate plays nice --- .../org/radarbase/management/domain/Source.kt | 8 +------- .../radarbase/management/domain/SourceData.kt | 12 +++++------ .../radarbase/management/domain/Subject.kt | 9 ++------- .../management/repository/SourceRepository.kt | 20 +++++++++---------- .../management/service/SubjectService.kt | 4 ++-- .../management/service/dto/SourceDataDTO.kt | 8 ++++---- .../decorator/SubjectMapperDecorator.kt | 14 ++++++------- .../management/web/rest/UserResource.kt | 2 +- .../web/rest/SubjectResourceIntTest.kt | 10 +++++----- 9 files changed, 38 insertions(+), 49 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Source.kt b/src/main/java/org/radarbase/management/domain/Source.kt index 53d1287c3..c409cca9e 100644 --- a/src/main/java/org/radarbase/management/domain/Source.kt +++ b/src/main/java/org/radarbase/management/domain/Source.kt @@ -61,7 +61,7 @@ class Source : AbstractEntity, Serializable { var assigned: @NotNull Boolean? = false @Column(name = "deleted", nullable = false) - var isDeleted: @NotNull Boolean = false + var deleted: @NotNull Boolean = false @JvmField @ManyToOne(fetch = FetchType.EAGER) @@ -124,12 +124,6 @@ class Source : AbstractEntity, Serializable { ) } } - - fun deleted(deleted: Boolean): Source { - isDeleted = deleted - return this - } - fun sourceType(sourceType: SourceType?): Source { this.sourceType = sourceType return this diff --git a/src/main/java/org/radarbase/management/domain/SourceData.kt b/src/main/java/org/radarbase/management/domain/SourceData.kt index 28a8805b3..ce73c1df6 100644 --- a/src/main/java/org/radarbase/management/domain/SourceData.kt +++ b/src/main/java/org/radarbase/management/domain/SourceData.kt @@ -86,7 +86,7 @@ class SourceData : AbstractEntity(), Serializable { var provider: String? = null @Column(name = "enabled") - var isEnabled = true + var enabled = true @JvmField @ManyToOne(fetch = FetchType.LAZY) @@ -137,14 +137,14 @@ class SourceData : AbstractEntity(), Serializable { return this } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val sourceData = o as SourceData + val sourceData = other as SourceData return if (sourceData.id == null || id == null) { false } else id == sourceData.id @@ -162,7 +162,7 @@ class SourceData : AbstractEntity(), Serializable { + ", dataClass='" + dataClass + '\'' + ", keySchema='" + keySchema + '\'' + ", valueSchema='" + valueSchema + '\'' + ", topic='" + topic + '\'' + ", provider='" - + provider + '\'' + ", enabled=" + isEnabled + '}') + + provider + '\'' + ", enabled=" + enabled + '}') } companion object { diff --git a/src/main/java/org/radarbase/management/domain/Subject.kt b/src/main/java/org/radarbase/management/domain/Subject.kt index e5e1217e7..4fecfdce7 100644 --- a/src/main/java/org/radarbase/management/domain/Subject.kt +++ b/src/main/java/org/radarbase/management/domain/Subject.kt @@ -64,7 +64,7 @@ class Subject( var externalId: String? = null @Column(name = "removed", nullable = false) - var isRemoved: @NotNull Boolean? = false + var removed: @NotNull Boolean = false @JvmField @OneToOne @@ -124,11 +124,6 @@ class Subject( return this } - fun removed(removed: Boolean?): Subject { - isRemoved = removed - return this - } - fun user(usr: User?): Subject { user = usr return this @@ -189,7 +184,7 @@ class Subject( + "id=" + id + ", externalLink='" + externalLink + '\'' + ", externalId='" + externalId + '\'' - + ", removed=" + isRemoved + + ", removed=" + removed + ", user=" + user + ", sources=" + sources + ", attributes=" + attributes diff --git a/src/main/java/org/radarbase/management/repository/SourceRepository.kt b/src/main/java/org/radarbase/management/repository/SourceRepository.kt index 094d95d46..4b5946480 100644 --- a/src/main/java/org/radarbase/management/repository/SourceRepository.kt +++ b/src/main/java/org/radarbase/management/repository/SourceRepository.kt @@ -17,26 +17,26 @@ import java.util.* interface SourceRepository : JpaRepository, RevisionRepository { @Query( value = "select source from Source source " - + "WHERE source.isDeleted = false", countQuery = "select count(source) from Source source " - + "WHERE source.isDeleted = false" + + "WHERE source.deleted = false", countQuery = "select count(source) from Source source " + + "WHERE source.deleted = false" ) override fun findAll(pageable: Pageable): Page @Query( value = "select source from Source source " - + "WHERE source.isDeleted = false " + + "WHERE source.deleted = false " + "AND source.project.id = :projectId", countQuery = "select count(source) from Source source " - + "WHERE source.isDeleted = false " + + "WHERE source.deleted = false " + "AND source.project.id = :projectId" ) fun findAllSourcesByProjectId(pageable: Pageable, @Param("projectId") projectId: Long): Page @Query( value = "select source from Source source " - + "WHERE source.isDeleted = false " + + "WHERE source.deleted = false " + "AND source.project.id = :projectId " + "AND source.assigned = :assigned", countQuery = "select count(source) from Source source " - + "WHERE source.isDeleted = false " + + "WHERE source.deleted = false " + "AND source.project.id = :projectId " + "AND source.assigned = :assigned" ) @@ -47,18 +47,18 @@ interface SourceRepository : JpaRepository, RevisionRepository source.assigned = false source.subject = null - source.isDeleted = true + source.deleted = true sourceRepository.save(source) }) subject.sources.clear() diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt index 187af33bd..0bf175343 100644 --- a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt @@ -34,14 +34,14 @@ class SourceDataDTO : Serializable { @JsonInclude(JsonInclude.Include.NON_NULL) var sourceType: MinimalSourceTypeDTO? = null - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val sourceDataDto = o as SourceDataDTO + val sourceDataDto = other as SourceDataDTO return if (sourceDataDto.id == null || id == null) { false } else id == sourceDataDto.id diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt index 19ece43e4..94face2c9 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt @@ -108,11 +108,11 @@ abstract class SubjectMapperDecorator( } private fun getSubjectStatus(subject: Subject): SubjectStatus { - if (!subject.user!!.activated && !subject.isRemoved!!) { + if (!subject.user!!.activated && !subject.removed!!) { return SubjectStatus.DEACTIVATED - } else if (subject.user!!.activated && !subject.isRemoved!!) { + } else if (subject.user!!.activated && !subject.removed!!) { return SubjectStatus.ACTIVATED - } else if (!subject.user!!.activated && subject.isRemoved!!) { + } else if (!subject.user!!.activated && subject.removed!!) { return SubjectStatus.DISCONTINUED } return SubjectStatus.INVALID @@ -122,22 +122,22 @@ abstract class SubjectMapperDecorator( when (subjectDto!!.status) { SubjectStatus.DEACTIVATED -> { subject!!.user!!.activated = false - subject.isRemoved = false + subject.removed = false } SubjectStatus.ACTIVATED -> { subject!!.user!!.activated = true - subject.isRemoved = false + subject.removed = false } SubjectStatus.DISCONTINUED -> { subject!!.user!!.activated = false - subject.isRemoved = true + subject.removed = true } SubjectStatus.INVALID -> { subject!!.user!!.activated = true - subject.isRemoved = true + subject.removed = true } else -> {} diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.kt b/src/main/java/org/radarbase/management/web/rest/UserResource.kt index 0c49f4aa1..39fdbcc49 100644 --- a/src/main/java/org/radarbase/management/web/rest/UserResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/UserResource.kt @@ -158,7 +158,7 @@ class UserResource( throw BadRequestException("Login already in use", EntityName.USER, "emailexists") } val subject = subjectRepository.findOneWithEagerBySubjectLogin(managedUserVm.login) - if (subject != null && managedUserVm.isActivated && subject.isRemoved!!) { + if (subject != null && managedUserVm.isActivated && subject.removed!!) { // if the subject is also a user, check if the removed/activated states are valid throw InvalidRequestException( "Subject cannot be the user to request " + "this changes", EntityName.USER, "error.invalidsubjectstate" diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index e93558545..c024bcd1a 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -107,7 +107,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val testSubject = subjectList[subjectList.size - 1] Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.DEFAULT_ENTERNAL_ID) - Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.DEFAULT_REMOVED) + Assertions.assertThat(testSubject.removed).isEqualTo(SubjectServiceTest.DEFAULT_REMOVED) org.junit.jupiter.api.Assertions.assertEquals(1, testSubject.user!!.roles!!.size) } @@ -215,7 +215,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit updatedSubject .externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID) - .removed(SubjectServiceTest.UPDATED_REMOVED) + .removed = SubjectServiceTest.UPDATED_REMOVED subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) restSubjectMockMvc.perform( MockMvcRequestBuilders.put("/api/subjects") @@ -230,7 +230,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val testSubject = subjectList[subjectList.size - 1] Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.UPDATED_EXTERNAL_LINK) Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.UPDATED_ENTERNAL_ID) - Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) + Assertions.assertThat(testSubject.removed).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) } @Test @@ -246,7 +246,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit updatedSubject .externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID) - .removed(SubjectServiceTest.UPDATED_REMOVED) + .removed = SubjectServiceTest.UPDATED_REMOVED subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) val newProject = ProjectDTO() newProject.id = 2L @@ -266,7 +266,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val testSubject = subjectList[subjectList.size - 1] Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.UPDATED_EXTERNAL_LINK) Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.UPDATED_ENTERNAL_ID) - Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) + Assertions.assertThat(testSubject.removed).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) Assertions.assertThat(testSubject.user!!.roles!!.size).isEqualTo(2) } From 20d292f40a0ba9893bc15b7cf3f519bc49d12ff0 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 31 Oct 2023 14:59:22 +0100 Subject: [PATCH 045/158] structmap issues solved by reverting back to some java classes and using kapt --- build.gradle | 1 + gradle/mapstruct.gradle | 2 +- .../management/service/OAuthClientService.kt | 31 ++++--- .../service/mapper/ClientDetailsMapper.java | 80 +++++++++++++++++++ .../service/mapper/ClientDetailsMapper.kt | 72 ----------------- .../management/service/mapper/UserMapper.kt | 10 ++- .../ClientDetailsMapperDecorator.java | 44 ++++++++++ .../decorator/ClientDetailsMapperDecorator.kt | 36 --------- .../decorator/ProjectMapperDecorator.kt | 24 +++--- .../mapper/decorator/RoleMapperDecorator.kt | 12 +-- .../mapper/decorator/SourceMapperDecorator.kt | 26 +++--- .../decorator/SubjectMapperDecorator.kt | 47 +++++------ .../web/rest/vm/GroupPatchOperation.java | 53 ------------ .../web/rest/vm/KeyAndPasswordVM.java | 27 ------- .../management/web/rest/vm/LoggerVM.java | 48 ----------- .../management/web/rest/vm/ManagedUserVM.java | 31 ------- 16 files changed, 201 insertions(+), 343 deletions(-) create mode 100644 src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java delete mode 100644 src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.java delete mode 100644 src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.java delete mode 100644 src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.java delete mode 100644 src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.java diff --git a/build.gradle b/build.gradle index 24c364e83..2b480b1a6 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,7 @@ plugins { id "io.github.gradle-nexus.publish-plugin" version "1.3.0" id("com.github.ben-manes.versions") version "0.47.0" id 'org.jetbrains.kotlin.jvm' version "1.9.10" + id "org.jetbrains.kotlin.kapt" version "1.9.10" id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.10' apply false id 'org.jetbrains.dokka' version "1.8.20" } diff --git a/gradle/mapstruct.gradle b/gradle/mapstruct.gradle index b267a55f5..10a398198 100644 --- a/gradle/mapstruct.gradle +++ b/gradle/mapstruct.gradle @@ -1,5 +1,5 @@ dependencies { implementation group: 'org.mapstruct', name: 'mapstruct', version: mapstruct_version - annotationProcessor group: 'org.mapstruct', name: 'mapstruct-processor', version: mapstruct_version + kapt group: 'org.mapstruct', name: 'mapstruct-processor', version: mapstruct_version } diff --git a/src/main/java/org/radarbase/management/service/OAuthClientService.kt b/src/main/java/org/radarbase/management/service/OAuthClientService.kt index a0d6fd53f..9268d5d5e 100644 --- a/src/main/java/org/radarbase/management/service/OAuthClientService.kt +++ b/src/main/java/org/radarbase/management/service/OAuthClientService.kt @@ -30,17 +30,14 @@ import java.util.* * Created by nivethika on 03/08/2018. */ @Service -class OAuthClientService { - @Autowired - private val clientDetailsService: JdbcClientDetailsService? = null +class OAuthClientService( + @Autowired private val clientDetailsService: JdbcClientDetailsService, + @Autowired private val clientDetailsMapper: ClientDetailsMapper, + @Autowired private val authorizationServerEndpointsConfiguration: AuthorizationServerEndpointsConfiguration +) { - @Autowired - private val clientDetailsMapper: ClientDetailsMapper? = null - - @Autowired - private val authorizationServerEndpointsConfiguration: AuthorizationServerEndpointsConfiguration? = null fun findAllOAuthClients(): List { - return clientDetailsService!!.listClientDetails() + return clientDetailsService.listClientDetails() } /** @@ -52,7 +49,7 @@ class OAuthClientService { */ fun findOneByClientId(clientId: String?): ClientDetails { return try { - clientDetailsService!!.loadClientByClientId(clientId) + clientDetailsService.loadClientByClientId(clientId) } catch (e: NoSuchClientException) { log.error("Pair client request for unknown client id: {}", clientId) val errorParams: MutableMap = HashMap() @@ -71,9 +68,9 @@ class OAuthClientService { * @return Updated [ClientDetails] instance. */ fun updateOauthClient(clientDetailsDto: ClientDetailsDTO): ClientDetails { - val details: ClientDetails? = clientDetailsMapper!!.clientDetailsDTOToClientDetails(clientDetailsDto) + val details: ClientDetails? = clientDetailsMapper.clientDetailsDTOToClientDetails(clientDetailsDto) // update client. - clientDetailsService!!.updateClientDetails(details) + clientDetailsService.updateClientDetails(details) val updated = findOneByClientId(clientDetailsDto.clientId) // updateClientDetails does not update secret, so check for it separately if (clientDetailsDto.clientSecret != null && clientDetailsDto.clientSecret != updated.clientSecret) { @@ -90,7 +87,7 @@ class OAuthClientService { * @param clientId of the auth-client to delete. */ fun deleteClientDetails(clientId: String?) { - clientDetailsService!!.removeClientDetails(clientId) + clientDetailsService.removeClientDetails(clientId) } /** @@ -102,7 +99,7 @@ class OAuthClientService { fun createClientDetail(clientDetailsDto: ClientDetailsDTO): ClientDetails { // check if the client id exists try { - val existingClient = clientDetailsService!!.loadClientByClientId(clientDetailsDto.clientId) + val existingClient = clientDetailsService.loadClientByClientId(clientDetailsDto.clientId) if (existingClient != null) { throw ConflictException( "OAuth client already exists with this id", @@ -117,9 +114,9 @@ class OAuthClientService { clientDetailsDto.clientId ) } - val details: ClientDetails? = clientDetailsMapper!!.clientDetailsDTOToClientDetails(clientDetailsDto) + val details: ClientDetails? = clientDetailsMapper.clientDetailsDTOToClientDetails(clientDetailsDto) // create oauth client. - clientDetailsService!!.addClientDetails(details) + clientDetailsService.addClientDetails(details) return findOneByClientId(clientDetailsDto.clientId) } @@ -149,7 +146,7 @@ class OAuthClientService { val authenticationToken: Authentication = UsernamePasswordAuthenticationToken( user.login, null, authorities ) - return authorizationServerEndpointsConfiguration!!.getEndpointsConfigurer() + return authorizationServerEndpointsConfiguration.getEndpointsConfigurer() .tokenServices .createAccessToken(OAuth2Authentication(oAuth2Request, authenticationToken)) } diff --git a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java new file mode 100644 index 000000000..10c1b1ad8 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java @@ -0,0 +1,80 @@ +package org.radarbase.management.service.mapper; + +import org.mapstruct.DecoratedWith; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.radarbase.management.service.dto.ClientDetailsDTO; +import org.radarbase.management.service.mapper.decorator.ClientDetailsMapperDecorator; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.provider.ClientDetails; +import org.springframework.security.oauth2.provider.client.BaseClientDetails; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Created by dverbeec on 7/09/2017. + */ +@Mapper(componentModel = "spring", uses = {BaseClientDetails.class}) +@DecoratedWith(ClientDetailsMapperDecorator.class) + public interface ClientDetailsMapper { + + @Mapping(target = "clientSecret", ignore = true) + @Mapping(target = "autoApproveScopes", ignore = true) + ClientDetailsDTO clientDetailsToClientDetailsDTO(ClientDetails details); + + List clientDetailsToClientDetailsDTO(List detailsList); + + BaseClientDetails clientDetailsDTOToClientDetails(ClientDetailsDTO detailsDto); + + List clientDetailsDTOToClientDetails(List detailsDtoList); + + /** + * Map a set of authorities represented as strings to a collection of {@link GrantedAuthority}s. + * @param authorities the set of authorities to be mapped + * @return a collection of {@link GrantedAuthority}s + */ + default Collection map(Set authorities) { + if (Objects.isNull(authorities)) { + return Collections.emptySet(); + } + return authorities.stream() + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + } + + /** + * Map a collection of authorities represented as {@link GrantedAuthority}s to a set of strings. + * @param authorities the collection of {@link GrantedAuthority}s to be mapped + * @return the set of strings + */ + default Set map(Collection authorities) { + if (Objects.isNull(authorities)) { + return Collections.emptySet(); + } + return authorities.stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.toSet()); + } + + /** + * Transforms the values in the input map to strings so the result is a + * {@link Map}. + * @param additionalInformation a {@link Map} to be transformed + * @return a new map with the same keys as the input map, but the values are transformed to + * strings using their {@link Object#toString()} method + */ + default Map map(Map additionalInformation) { + if (Objects.isNull(additionalInformation)) { + return Collections.emptyMap(); + } + return additionalInformation.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString())); + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt deleted file mode 100644 index 7d4258077..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt +++ /dev/null @@ -1,72 +0,0 @@ -package org.radarbase.management.service.mapper - -import org.mapstruct.DecoratedWith -import org.mapstruct.Mapper -import org.mapstruct.Mapping -import org.radarbase.management.service.dto.ClientDetailsDTO -import org.radarbase.management.service.mapper.decorator.ClientDetailsMapperDecorator -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.core.authority.SimpleGrantedAuthority -import org.springframework.security.oauth2.provider.ClientDetails -import org.springframework.security.oauth2.provider.client.BaseClientDetails -import java.util.* -import java.util.stream.Collectors - -/** - * Created by dverbeec on 7/09/2017. - */ -@Mapper(componentModel = "spring", uses = [BaseClientDetails::class]) -@DecoratedWith( - ClientDetailsMapperDecorator::class -) -interface ClientDetailsMapper { - @Mapping(target = "clientSecret", ignore = true) - @Mapping(target = "autoApproveScopes", ignore = true) - fun clientDetailsToClientDetailsDTO(details: ClientDetails): ClientDetailsDTO - fun clientDetailsToClientDetailsDTO(detailsList: List): List? - fun clientDetailsDTOToClientDetails(detailsDto: ClientDetailsDTO?): BaseClientDetails - fun clientDetailsDTOToClientDetails(detailsDtoList: List): List - - /** - * Map a set of authorities represented as strings to a collection of [GrantedAuthority]s. - * @param authorities the set of authorities to be mapped - * @return a collection of [GrantedAuthority]s - */ - fun map(authorities: Set): Collection? { - return if (Objects.isNull(authorities)) { - emptySet() - } else authorities.stream() - .map { role: String? -> SimpleGrantedAuthority(role) } - .collect(Collectors.toList()) - } - - /** - * Map a collection of authorities represented as [GrantedAuthority]s to a set of strings. - * @param authorities the collection of [GrantedAuthority]s to be mapped - * @return the set of strings - */ - fun map(authorities: Collection): Set? { - return if (Objects.isNull(authorities)) { - emptySet() - } else authorities.stream() - .map { obj: GrantedAuthority -> obj.authority } - .collect(Collectors.toSet()) - } - - /** - * Transforms the values in the input map to strings so the result is a - * [Map]. - * @param additionalInformation a [Map] to be transformed - * @return a new map with the same keys as the input map, but the values are transformed to - * strings using their [Object.toString] method - */ - fun map(additionalInformation: Map): Map? { - return if (Objects.isNull(additionalInformation)) { - emptyMap() - } else additionalInformation.entries - .associateBy( - { it.key }, - { e -> e.value.toString() } - ) - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt index affe9f120..d5e652f2d 100644 --- a/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt +++ b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt @@ -46,10 +46,14 @@ interface UserMapper { * @param authorities the authorities to map * @return the set of strings if authorities is not null, null otherwise */ - fun stringsFromAuthorities(authorities: Set?): Set<@NotNull @Size( + fun map(authorities: Set): Set<@NotNull @Size( max = 50, min = 0 - ) @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") String?>? { - return authorities?.map{ it?.name }?.toSet() + ) @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") String> { + return authorities.mapNotNull { it.name }.toSet() + } + + fun map(authority: Authority): String { + return authority.name!! } } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java new file mode 100644 index 000000000..119bdea64 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java @@ -0,0 +1,44 @@ +package org.radarbase.management.service.mapper.decorator; + + +import org.radarbase.management.service.dto.ClientDetailsDTO; +import org.radarbase.management.service.mapper.ClientDetailsMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.security.oauth2.provider.ClientDetails; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Decorator for ClientDetailsMapper. The ClientDetails interface does not expose a method to get + * all auto-approve scopes, instead it only has a method to check if a given scope is auto-approve. + * This decorator adds the subset of scopes for which isAutoApprove returns true to the DTO. + */ +public abstract class ClientDetailsMapperDecorator implements ClientDetailsMapper { + + @Autowired + @Qualifier("delegate") + private ClientDetailsMapper delegate; + + @Override + public ClientDetailsDTO clientDetailsToClientDetailsDTO(ClientDetails details) { + ClientDetailsDTO clientDetailsDto = delegate.clientDetailsToClientDetailsDTO(details); + // collect the scopes that are auto-approve and set them in our DTO + clientDetailsDto.setAutoApproveScopes(details.getScope().stream() + .filter(details::isAutoApprove) + .collect(Collectors.toSet())); + return clientDetailsDto; + } + + @Override + public List clientDetailsToClientDetailsDTO(List details) { + if (Objects.isNull(details)) { + return null; + } + return details.stream() + .map(this::clientDetailsToClientDetailsDTO) + .toList(); + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt deleted file mode 100644 index e0e6217cf..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.radarbase.management.service.mapper.decorator - -import org.radarbase.management.service.dto.ClientDetailsDTO -import org.radarbase.management.service.mapper.ClientDetailsMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Qualifier -import org.springframework.security.oauth2.provider.ClientDetails -import java.util.* -import java.util.stream.Collectors - -/** - * Decorator for ClientDetailsMapper. The ClientDetails interface does not expose a method to get - * all auto-approve scopes, instead it only has a method to check if a given scope is auto-approve. - * This decorator adds the subset of scopes for which isAutoApprove returns true to the DTO. - */ -abstract class ClientDetailsMapperDecorator : ClientDetailsMapper { - @Autowired - @Qualifier("delegate") - private val delegate: ClientDetailsMapper? = null - override fun clientDetailsToClientDetailsDTO(details: ClientDetails): ClientDetailsDTO { - val clientDetailsDto = delegate!!.clientDetailsToClientDetailsDTO(details) - // collect the scopes that are auto-approve and set them in our DTO - clientDetailsDto.autoApproveScopes = details.scope.stream() - .filter { scope: String? -> details.isAutoApprove(scope) } - .collect(Collectors.toSet()) - return clientDetailsDto - } - - override fun clientDetailsToClientDetailsDTO(detailsList: List): List? { - return if (Objects.isNull(detailsList)) { - null - } else detailsList.stream() - .map { details: ClientDetails -> this.clientDetailsToClientDetailsDTO(details) } - .toList() - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt index 48d862398..a023f87d1 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt @@ -18,18 +18,18 @@ import java.util.* /** * Created by nivethika on 30-8-17. */ -abstract class ProjectMapperDecorator( - @Autowired @Qualifier("delegate") private val delegate: ProjectMapper, - @Autowired private val organizationRepository: OrganizationRepository, - @Autowired private val projectRepository: ProjectRepository, - @Autowired private val metaTokenService: MetaTokenService -) : ProjectMapper { +abstract class ProjectMapperDecorator() : ProjectMapper { + + @Autowired @Qualifier("delegate") private val delegate: ProjectMapper? = null + private val organizationRepository: OrganizationRepository? = null + private val projectRepository: ProjectRepository? = null + private val metaTokenService: MetaTokenService? = null override fun projectToProjectDTO(project: Project?): ProjectDTO? { - val dto = delegate.projectToProjectDTO(project) + val dto = delegate?.projectToProjectDTO(project) dto?.humanReadableProjectName = project?.attributes?.get(ProjectDTO.HUMAN_READABLE_PROJECT_NAME) try { - dto?.persistentTokenTimeout = metaTokenService.getMetaTokenTimeout(true, project).toMillis() + dto?.persistentTokenTimeout = metaTokenService?.getMetaTokenTimeout(true, project)?.toMillis() } catch (ex: BadRequestException) { dto?.persistentTokenTimeout = null } @@ -40,7 +40,7 @@ abstract class ProjectMapperDecorator( if (project == null) { return null } - val dto = delegate.projectToProjectDTOReduced(project) + val dto = delegate?.projectToProjectDTOReduced(project) dto?.humanReadableProjectName = project.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] dto?.sourceTypes = null return dto @@ -50,14 +50,14 @@ abstract class ProjectMapperDecorator( if (projectDto == null) { return null } - val project = delegate.projectDTOToProject(projectDto) + val project = delegate?.projectDTOToProject(projectDto) val projectName = projectDto.humanReadableProjectName if (!projectName.isNullOrEmpty()) { project!!.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] = projectName } val orgDto = projectDto.organization if (orgDto?.name != null) { - val org = organizationRepository.findOneByName(orgDto.name) + val org = organizationRepository?.findOneByName(orgDto.name) ?: throw NotFoundException( "Organization not found with name", EntityName.Companion.ORGANIZATION, @@ -72,6 +72,6 @@ abstract class ProjectMapperDecorator( override fun descriptiveDTOToProject(minimalProjectDetailsDto: MinimalProjectDetailsDTO?): Project? { return if (minimalProjectDetailsDto == null) { null - } else minimalProjectDetailsDto.id?.let { projectRepository.getById(it) } + } else minimalProjectDetailsDto.id?.let { projectRepository?.getById(it) } } } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt index 244965c2d..6ea4a059c 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt @@ -10,9 +10,11 @@ import org.springframework.beans.factory.annotation.Qualifier /** * Created by nivethika on 03-8-18. */ -abstract class RoleMapperDecorator(@Autowired @Qualifier("delegate") private val delegate: RoleMapper, - @Autowired private val authorityRepository: AuthorityRepository -) : RoleMapper { +abstract class RoleMapperDecorator() : RoleMapper { + +// constructor(roleMapper: RoleMapper, authorityRepository: AuthorityRepository?) : this(roleMapper) + @Autowired @Qualifier("delegate") private val delegate: RoleMapper? = null + private var authorityRepository: AuthorityRepository? = null; /** * Overrides standard RoleMapperImpl and loads authority from repository if not specified. @@ -23,9 +25,9 @@ abstract class RoleMapperDecorator(@Autowired @Qualifier("delegate") private val if (roleDto == null) { return null } - val role = delegate.roleDTOToRole(roleDto) + val role = delegate?.roleDTOToRole(roleDto) if (role!!.authority == null) { - role.authority = roleDto.authorityName?.let { authorityRepository.getById(it) } + role.authority = roleDto.authorityName?.let { authorityRepository?.getById(it) } } return role } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt index 518f91360..6a1136560 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt @@ -16,15 +16,15 @@ import java.util.Map /** * Created by nivethika on 13-6-17. */ -abstract class SourceMapperDecorator( - @Autowired @Qualifier("delegate") private val delegate: SourceMapper, - @Autowired private val sourceRepository: SourceRepository, - @Autowired private val subjectRepository: SubjectRepository -) : SourceMapper { +abstract class SourceMapperDecorator() : SourceMapper { + + @Autowired @Qualifier("delegate") private val delegate: SourceMapper? = null + private val sourceRepository: SourceRepository? = null + private val subjectRepository: SubjectRepository? = null override fun minimalSourceDTOToSource(minimalSourceDetailsDto: MinimalSourceDetailsDTO): Source? { val source = sourceRepository - .findOneBySourceId(minimalSourceDetailsDto.sourceId) + ?.findOneBySourceId(minimalSourceDetailsDto.sourceId) ?: throw NotFoundException( "Source ID " + minimalSourceDetailsDto.sourceId + " not found", @@ -36,11 +36,11 @@ abstract class SourceMapperDecorator( } override fun sourceDTOToSource(sourceDto: SourceDTO): Source { - val source = delegate.sourceDTOToSource(sourceDto) + val source = delegate?.sourceDTOToSource(sourceDto) if (sourceDto.id != null) { val existingSource = sourceDto.id?.let { - sourceRepository.findById(it) - .orElseThrow { + sourceRepository?.findById(it) + ?.orElseThrow { NotFoundException( "Source ID " + sourceDto.id + " not found", EntityName.Companion.SOURCE, ErrorConstants.ERR_SOURCE_NOT_FOUND, @@ -49,13 +49,13 @@ abstract class SourceMapperDecorator( } }!! if (sourceDto.subjectLogin == null) { - source.subject = existingSource.subject + source?.subject = existingSource.subject } else { - source.subject = subjectRepository - .findOneWithEagerBySubjectLogin(sourceDto.subjectLogin) + source?.subject = subjectRepository + ?.findOneWithEagerBySubjectLogin(sourceDto.subjectLogin) ?: throw NoSuchElementException() } } - return source + return source!! } } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt index 94face2c9..6396b670a 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt @@ -19,22 +19,21 @@ import org.springframework.beans.factory.annotation.Qualifier /** * Created by nivethika on 30-8-17. */ -abstract class SubjectMapperDecorator( - @Autowired @Qualifier("delegate") private val delegate: SubjectMapper, - @Autowired private val projectMapper: ProjectMapper, - @Autowired private val revisionService: RevisionService, - @Autowired private val projectRepository: ProjectRepository, - @Autowired private val groupRepository: GroupRepository -) : SubjectMapper { +abstract class SubjectMapperDecorator() : SubjectMapper { + @Autowired @Qualifier("delegate") private val delegate: SubjectMapper? = null + private var groupRepository: GroupRepository? = null + private var projectRepository: ProjectRepository? = null + private var revisionService: RevisionService? = null + private var projectMapper: ProjectMapper? = null override fun subjectToSubjectDTO(subject: Subject?): SubjectDTO? { if (subject == null) { return null } val dto = subjectToSubjectWithoutProjectDTO(subject) val project = subject.activeProject - .let { p -> projectRepository.findOneWithEagerRelationships(p?.id!!) } - dto?.project = projectMapper.projectToProjectDTO(project) + .let { p -> projectRepository?.findOneWithEagerRelationships(p?.id!!) } + dto?.project = projectMapper?.projectToProjectDTO(project) addAuditInfo(subject, dto) return dto } @@ -44,24 +43,24 @@ abstract class SubjectMapperDecorator( return null } val dto = subjectToSubjectWithoutProjectDTO(subject) - subject.activeProject?.let { project -> dto?.project = projectMapper.projectToProjectDTOReduced(project) } + subject.activeProject?.let { project -> dto?.project = projectMapper?.projectToProjectDTOReduced(project) } addAuditInfo(subject, dto) return dto } private fun addAuditInfo(subject: Subject, dto: SubjectDTO?) { - val auditInfo = revisionService.getAuditInfo(subject) - dto!!.createdDate = auditInfo.createdAt - dto.createdBy = auditInfo.createdBy - dto.lastModifiedDate = auditInfo.lastModifiedAt - dto.lastModifiedBy = auditInfo.lastModifiedBy + val auditInfo = revisionService?.getAuditInfo(subject) + dto!!.createdDate = auditInfo?.createdAt + dto.createdBy = auditInfo?.createdBy + dto.lastModifiedDate = auditInfo?.lastModifiedAt + dto.lastModifiedBy = auditInfo?.lastModifiedBy } override fun subjectToSubjectWithoutProjectDTO(subject: Subject?): SubjectDTO? { if (subject == null) { return null } - val dto = delegate.subjectToSubjectWithoutProjectDTO(subject) + val dto = delegate?.subjectToSubjectWithoutProjectDTO(subject) dto?.status = getSubjectStatus(subject) return dto } @@ -70,7 +69,7 @@ abstract class SubjectMapperDecorator( if (subjectDto == null) { return null } - val subject = delegate.subjectDTOToSubject(subjectDto) + val subject = delegate?.subjectDTOToSubject(subjectDto) setSubjectStatus(subjectDto, subject) subject?.group = getGroup(subjectDto) return subject @@ -80,13 +79,13 @@ abstract class SubjectMapperDecorator( return if (subjectDto!!.group == null) { null } else if (subjectDto.project?.id != null) { - groupRepository.findByProjectIdAndName(subjectDto.project?.id, subjectDto.group) + groupRepository?.findByProjectIdAndName(subjectDto.project?.id, subjectDto.group) ?: throw BadRequestException( "Group " + subjectDto.group + " not found in project " + subjectDto.project?.id, EntityName.SUBJECT, ErrorConstants.ERR_GROUP_NOT_FOUND) } else if (subjectDto.project?.projectName != null) { - groupRepository.findByProjectNameAndName(subjectDto.project?.projectName, subjectDto.group) + groupRepository?.findByProjectNameAndName(subjectDto.project?.projectName, subjectDto.group) ?: throw BadRequestException( "Group " + subjectDto.group + " not found in project " + subjectDto.project?.projectName, @@ -101,18 +100,18 @@ abstract class SubjectMapperDecorator( } override fun safeUpdateSubjectFromDTO(subjectDto: SubjectDTO?, @MappingTarget subject: Subject?): Subject? { - val subjectRetrieved = delegate.safeUpdateSubjectFromDTO(subjectDto, subject) + val subjectRetrieved = delegate?.safeUpdateSubjectFromDTO(subjectDto, subject) setSubjectStatus(subjectDto, subjectRetrieved) subject!!.group = getGroup(subjectDto) return subjectRetrieved } private fun getSubjectStatus(subject: Subject): SubjectStatus { - if (!subject.user!!.activated && !subject.removed!!) { + if (!subject.user!!.activated && !subject.removed) { return SubjectStatus.DEACTIVATED - } else if (subject.user!!.activated && !subject.removed!!) { + } else if (subject.user!!.activated && !subject.removed) { return SubjectStatus.ACTIVATED - } else if (!subject.user!!.activated && subject.removed!!) { + } else if (!subject.user!!.activated && subject.removed) { return SubjectStatus.DISCONTINUED } return SubjectStatus.INVALID @@ -139,8 +138,6 @@ abstract class SubjectMapperDecorator( subject!!.user!!.activated = true subject.removed = true } - - else -> {} } } } diff --git a/src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.java b/src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.java deleted file mode 100644 index 9e8614504..000000000 --- a/src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.radarbase.management.web.rest.vm; - -import java.util.List; - -/** - * A POJO for PATCH .../groups/{groupName}/subjects - * [ - * {"op": "add", "value": [{"login": "sub1"}, {"id": 2}]}, - * {"op": "remove", "value": [{"login": "sub3"}]} - * ] - * request. - */ -public class GroupPatchOperation { - private String op; - private List value; - - public String getOp() { - return op; - } - - public void setOp(String op) { - this.op = op; - } - - public List getValue() { - return value; - } - - public void setValue(List value) { - this.value = value; - } - - public static class SubjectPatchValue { - private Long id; - private String login; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getLogin() { - return login; - } - - public void setLogin(String login) { - this.login = login; - } - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.java b/src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.java deleted file mode 100644 index 5625aea90..000000000 --- a/src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.radarbase.management.web.rest.vm; - -/** - * View Model object for storing the user's key and password. - */ -public class KeyAndPasswordVM { - - private String key; - - private String newPassword; - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public String getNewPassword() { - return newPassword; - } - - public void setNewPassword(String newPassword) { - this.newPassword = newPassword; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.java b/src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.java deleted file mode 100644 index 11e736fe7..000000000 --- a/src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.radarbase.management.web.rest.vm; - -import ch.qos.logback.classic.Logger; -import com.fasterxml.jackson.annotation.JsonCreator; - -/** - * View Model object for storing a Logback logger. - */ -public class LoggerVM { - - private String name; - - private String level; - - public LoggerVM(Logger logger) { - this.name = logger.getName(); - this.level = logger.getEffectiveLevel().toString(); - } - - @JsonCreator - public LoggerVM() { - // Empty public constructor used by Jackson. - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getLevel() { - return level; - } - - public void setLevel(String level) { - this.level = level; - } - - @Override - public String toString() { - return "LoggerVM{" - + "name='" + name + '\'' - + ", level='" + level + '\'' - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.java b/src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.java deleted file mode 100644 index 21a4f299a..000000000 --- a/src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.radarbase.management.web.rest.vm; - -import org.radarbase.management.service.dto.UserDTO; - -import javax.validation.constraints.Size; - -/** - * View Model extending the UserDTO, which is meant to be used in the user management UI. - */ -public class ManagedUserVM extends UserDTO { - - public static final int PASSWORD_MIN_LENGTH = 4; - - public static final int PASSWORD_MAX_LENGTH = 100; - - @Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH) - private String password; - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - @Override - public String toString() { - return "ManagedUserVM{} " + super.toString(); - } -} From 903575ae6eff7ed0cc4bf225d39f6a710bac9b22 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 31 Oct 2023 22:40:29 +0100 Subject: [PATCH 046/158] fixed updateproject test --- build.gradle | 8 + .../radarbase/management/domain/Project.kt | 9 +- .../management/service/ProjectService.kt | 2 +- .../management/service/RoleService.kt | 5 +- .../management/service/UserService.kt | 21 +- .../management/service/dto/GroupDTO.kt | 8 +- .../management/service/dto/OrganizationDTO.kt | 3 +- .../management/service/dto/ProjectDTO.kt | 12 +- .../decorator/ProjectMapperDecorator.kt | 12 +- .../management/web/rest/ProjectResource.kt | 21 +- .../management/web/rest/util/HeaderUtil.kt | 3 +- .../web/rest/AccountResourceIntTest.kt | 3 +- .../web/rest/AuditResourceIntTest.kt | 40 +- .../web/rest/GroupResourceIntTest.kt | 24 +- .../web/rest/LogsResourceIntTest.kt | 9 +- .../web/rest/OAuthClientsResourceIntTest.kt | 29 +- .../web/rest/OrganizationResourceIntTest.kt | 25 +- .../web/rest/ProfileInfoResourceIntTest.kt | 14 +- .../web/rest/ProjectResourceIntTest.kt | 79 ++- .../web/rest/SourceDataResourceIntTest.kt | 33 +- .../web/rest/SourceResourceIntTest.kt | 24 +- .../web/rest/SourceTypeResourceIntTest.kt | 33 +- .../web/rest/SubjectResourceIntTest.kt | 511 ++++++++---------- .../web/rest/UserResourceIntTest.kt | 6 +- 24 files changed, 420 insertions(+), 514 deletions(-) diff --git a/build.gradle b/build.gradle index 2b480b1a6..e03b2b71a 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,7 @@ plugins { id "org.jetbrains.kotlin.kapt" version "1.9.10" id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.10' apply false id 'org.jetbrains.dokka' version "1.8.20" + id "org.jetbrains.kotlin.plugin.allopen" version "1.9.10" } apply plugin: 'org.springframework.boot' @@ -172,6 +173,7 @@ dependencies { exclude group: 'org.hibernate', module: 'hibernate-entitymanager' } implementation "org.hibernate:hibernate-core" + implementation "org.hibernate:hibernate-core" implementation "org.hibernate:hibernate-envers" implementation 'org.hibernate:hibernate-validator:8.0.0.Final' @@ -227,6 +229,12 @@ dependencies { annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") } +allOpen { + annotation("org.springframework.stereotype.Component") + annotation("org.springframework.boot.test.context.SpringBootTest") + annotation("org.springframework.web.bind.annotation.RestController") +} + dependencyManagement { imports { mavenBom "com.fasterxml.jackson:jackson-bom:$jackson_version" diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index faa6b7cbd..b6c57b4f7 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -12,7 +12,6 @@ import org.hibernate.envers.Audited import org.hibernate.envers.NotAudited import org.radarbase.management.domain.enumeration.ProjectStatus import org.radarbase.management.domain.support.AbstractEntityListener -import org.radarbase.management.security.Constants import java.io.Serializable import java.time.ZonedDateTime import java.util.* @@ -57,7 +56,7 @@ class Project : AbstractEntity(), Serializable { override var id: Long? = null @Column(name = "project_name", nullable = false, unique = true) - var projectName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + var projectName: @NotNull @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") String? = null @Column(name = "description", nullable = false) var description: @NotNull String? = null @@ -124,17 +123,17 @@ class Project : AbstractEntity(), Serializable { ) @OrderBy("name ASC") var groups: MutableSet = HashSet() - fun projectName(projectName: String?): Project { + fun projectName(projectName: String): Project { this.projectName = projectName return this } - fun description(description: String?): Project { + fun description(description: String): Project { this.description = description return this } - fun organizationName(organizationName: String?): Project { + fun organizationName(organizationName: String): Project { this.organizationName = organizationName return this } diff --git a/src/main/java/org/radarbase/management/service/ProjectService.kt b/src/main/java/org/radarbase/management/service/ProjectService.kt index 5856587f0..adaaaa547 100644 --- a/src/main/java/org/radarbase/management/service/ProjectService.kt +++ b/src/main/java/org/radarbase/management/service/ProjectService.kt @@ -39,7 +39,7 @@ open class ProjectService( */ fun save(projectDto: ProjectDTO): ProjectDTO { log.debug("Request to save Project : {}", projectDto) - var project = projectMapper.projectDTOToProject(projectDto) + var project: Project? = projectMapper.projectDTOToProject(projectDto) project = project?.let { projectRepository.save(it) } return projectMapper.projectToProjectDTO(project)!! } diff --git a/src/main/java/org/radarbase/management/service/RoleService.kt b/src/main/java/org/radarbase/management/service/RoleService.kt index 239dcf59a..6f167e446 100644 --- a/src/main/java/org/radarbase/management/service/RoleService.kt +++ b/src/main/java/org/radarbase/management/service/RoleService.kt @@ -31,10 +31,9 @@ open class RoleService( @Autowired private val authorityRepository: AuthorityRepository, @Autowired private val organizationRepository: OrganizationRepository, @Autowired private val projectRepository: ProjectRepository, - @Autowired private val roleMapper: RoleMapper, - @Autowired private val userService: UserService + @Autowired private val roleMapper: RoleMapper ) { - + @Autowired lateinit private var userService: UserService /** * Save a role. diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt index 3f0dc91d6..7f332f726 100644 --- a/src/main/java/org/radarbase/management/service/UserService.kt +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -32,24 +32,21 @@ import java.time.Period import java.time.ZonedDateTime import java.util.* import java.util.function.Function -import kotlin.collections.HashSet -import kotlin.collections.MutableSet -import kotlin.collections.Set /** * Service class for managing users. */ @Service @Transactional -open class UserService( - @Autowired private val userRepository: UserRepository, - @Autowired private val passwordService: PasswordService, - @Autowired private val roleService: RoleService, - @Autowired private val userMapper: UserMapper, - @Autowired private val revisionService: RevisionService, - @Autowired private val managementPortalProperties: ManagementPortalProperties, - @Autowired private val authService: AuthService +open class UserService @Autowired constructor( + private val userRepository: UserRepository, + private val passwordService: PasswordService, + private val userMapper: UserMapper, + private val revisionService: RevisionService, + private val managementPortalProperties: ManagementPortalProperties, + private val authService: AuthService ) { + @Autowired lateinit var roleService: RoleService /** * Activate a user with the given activation key. @@ -312,7 +309,7 @@ open class UserService( * @param password the new password * @param login of the user to change password */ - fun changePassword(login: String, password: String) { + open fun changePassword(login: String, password: String) { val user = userRepository.findOneByLogin(login) if (user != null) diff --git a/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt b/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt index 7daa3ba88..02463bb31 100644 --- a/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt @@ -12,14 +12,14 @@ class GroupDTO { var id: Long? = null var projectId: Long? = null var name: @NotNull String? = null - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val groupDto = o as GroupDTO + val groupDto = other as GroupDTO return if (id == null || groupDto.id == null) { false } else id == groupDto.id diff --git a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt index 00aab1319..44a5e8ada 100644 --- a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt @@ -14,7 +14,8 @@ class OrganizationDTO : Serializable { lateinit var name: @NotNull String lateinit var description: @NotNull String lateinit var location: @NotNull String - var projects: List? = null + + var projects: List = emptyList() override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt index 3d4655f89..c5f9b7421 100644 --- a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt @@ -18,26 +18,26 @@ class ProjectDTO : Serializable { var description: @NotNull String? = null var organization: OrganizationDTO? = null var organizationName: String? = null - var location: @NotNull String? = null + lateinit var location: @NotNull String var startDate: ZonedDateTime? = null var projectStatus: ProjectStatus? = null var endDate: ZonedDateTime? = null @JsonInclude(JsonInclude.Include.NON_EMPTY) - var sourceTypes: Set? = null + var sourceTypes: Set = emptySet() var attributes: Map? = null @JsonInclude(JsonInclude.Include.NON_EMPTY) var groups: Set? = null var persistentTokenTimeout: Long? = null - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val projectDto = o as ProjectDTO + val projectDto = other as ProjectDTO return if (id == null || projectDto.id == null) { false } else id == projectDto.id diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt index a023f87d1..41e988a82 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt @@ -21,9 +21,9 @@ import java.util.* abstract class ProjectMapperDecorator() : ProjectMapper { @Autowired @Qualifier("delegate") private val delegate: ProjectMapper? = null - private val organizationRepository: OrganizationRepository? = null - private val projectRepository: ProjectRepository? = null - private val metaTokenService: MetaTokenService? = null + @Autowired private lateinit var organizationRepository: OrganizationRepository + @Autowired private lateinit var projectRepository: ProjectRepository + @Autowired private lateinit var metaTokenService: MetaTokenService override fun projectToProjectDTO(project: Project?): ProjectDTO? { val dto = delegate?.projectToProjectDTO(project) @@ -41,8 +41,8 @@ abstract class ProjectMapperDecorator() : ProjectMapper { return null } val dto = delegate?.projectToProjectDTOReduced(project) - dto?.humanReadableProjectName = project.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] - dto?.sourceTypes = null + dto?.humanReadableProjectName = project.attributes[ProjectDTO.HUMAN_READABLE_PROJECT_NAME] + dto?.sourceTypes = emptySet() return dto } @@ -57,7 +57,7 @@ abstract class ProjectMapperDecorator() : ProjectMapper { } val orgDto = projectDto.organization if (orgDto?.name != null) { - val org = organizationRepository?.findOneByName(orgDto.name) + val org = organizationRepository.findOneByName(orgDto.name) ?: throw NotFoundException( "Organization not found with name", EntityName.Companion.ORGANIZATION, diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index af751ea30..2f9b0a775 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -46,7 +46,6 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController import java.net.URISyntaxException -import java.util.NoSuchElementException import javax.validation.Valid /** @@ -54,13 +53,14 @@ import javax.validation.Valid */ @RestController @RequestMapping("/api") -class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, - @Autowired private val projectRepository: ProjectRepository, - @Autowired private val projectService: ProjectService, - @Autowired private val roleService: RoleService, - @Autowired private val subjectService: SubjectService, - @Autowired private val sourceService: SourceService, - @Autowired private val authService: AuthService +class ProjectResource( + @Autowired private val subjectMapper: SubjectMapper, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val projectService: ProjectService, + @Autowired private val roleService: RoleService, + @Autowired private val subjectService: SubjectService, + @Autowired private val sourceService: SourceService, + @Autowired private val authService: AuthService ) { /** @@ -127,9 +127,8 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, @PutMapping("/projects") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun updateProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity { - log.debug("REST request to update Project : {}", projectDto) - if (projectDto!!.id == null) { + fun updateProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity {log.debug("REST request to update Project : {}", projectDto) + if (projectDto?.id == null) { return createProject(projectDto) } // When a client wants to link the project to the default organization, diff --git a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt index 888626811..a6104569c 100644 --- a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt +++ b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt @@ -85,8 +85,9 @@ object HeaderUtil { * @return A String where the components are URLEncoded and joined by forward slashes. */ fun buildPath(vararg components: String?): String { - return components + return "/" + components .filterNotNull() + .filter { it != "" } .map { c: String? -> // try-catch needs to be inside the lambda try { diff --git a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt index d90d5bc7d..442093261 100644 --- a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt @@ -54,12 +54,11 @@ internal open class AccountResourceIntTest( @Autowired private val passwordService: PasswordService, @Mock private val mockUserService: UserService, @Mock private val mockMailService: MailService, - private var restUserMockMvc: MockMvc, @Autowired private val radarToken: RadarToken, @Autowired private val authService: AuthService, @Autowired private val managementPortalProperties: ManagementPortalProperties ) { - + private lateinit var restUserMockMvc: MockMvc @BeforeEach fun setUp() { MockitoAnnotations.openMocks(this) diff --git a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt index 58f6f4b0e..3924e62f3 100644 --- a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt @@ -44,11 +44,10 @@ internal open class AuditResourceIntTest( @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val formattingConversionService: FormattingConversionService, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, - private var auditEvent: PersistentAuditEvent, - private var restAuditMockMvc: MockMvc, @Autowired private val authService: AuthService ) { - + private lateinit var auditEvent: PersistentAuditEvent + private lateinit var restAuditMockMvc: MockMvc @BeforeEach @Throws(ServletException::class) fun setUp() { @@ -78,10 +77,9 @@ internal open class AuditResourceIntTest( auditEvent.auditEventDate = SAMPLE_TIMESTAMP } - @get:Throws(Exception::class) - @get:Test - val allAudits: Unit - get() { + @Throws(Exception::class) + @Test + fun allAudits() { // Initialize the database auditEventRepository.save(auditEvent) @@ -98,10 +96,9 @@ internal open class AuditResourceIntTest( ) } - @get:Throws(Exception::class) - @get:Test - val audit: Unit - get() { + @Throws(Exception::class) + @Test + fun audit() { // Initialize the database auditEventRepository.save(auditEvent) @@ -112,10 +109,9 @@ internal open class AuditResourceIntTest( .andExpect(MockMvcResultMatchers.jsonPath("$.principal").value(SAMPLE_PRINCIPAL)) } - @get:Throws(Exception::class) - @get:Test - open val auditsByDate: Unit - get() { + @Throws(Exception::class) + @Test + fun auditsByDate() { // Initialize the database auditEventRepository.save(auditEvent) @@ -141,10 +137,9 @@ internal open class AuditResourceIntTest( ) } - @get:Throws(Exception::class) - @get:Test - val nonExistingAuditsByDate: Unit - get() { + @Throws(Exception::class) + @Test + fun nonExistingAuditsByDate() { // Initialize the database auditEventRepository.save(auditEvent) @@ -165,10 +160,9 @@ internal open class AuditResourceIntTest( .andExpect(MockMvcResultMatchers.header().string("X-Total-Count", "0")) } - @get:Throws(Exception::class) - @get:Test - val nonExistingAudit: Unit - get() { + @Throws(Exception::class) + @Test + fun nonExistingAudit() { // Get the audit restAuditMockMvc.perform(MockMvcRequestBuilders.get("/management/audits/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) diff --git a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt index 882b0afc1..113b59f30 100644 --- a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt @@ -65,13 +65,13 @@ internal class GroupResourceIntTest( @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, @Autowired private val groupRepository: GroupRepository, - private var restGroupMockMvc: MockMvc, - private var group: Group, - private var project: Project + @Autowired private val authService: AuthService ) { + private lateinit var restGroupMockMvc: MockMvc + private lateinit var group: Group + private lateinit var project: Project + - @Autowired - private val authService: AuthService? = null @BeforeEach @Throws(ServletException::class) @@ -223,10 +223,9 @@ internal class GroupResourceIntTest( ).andExpect(MockMvcResultMatchers.status().isBadRequest()) } - @get:Throws(Exception::class) - @get:Test - val allGroups: Unit - get() { + @Throws(Exception::class) + @Test + fun allGroups() { // Initialize the database groupRepository.saveAndFlush(group) @@ -262,10 +261,9 @@ internal class GroupResourceIntTest( .andExpect(MockMvcResultMatchers.jsonPath("$.projectId").value(project.id!!.toInt())) } - @get:Throws(Exception::class) - @get:Test - val nonExistingGroup: Unit - get() { + @Throws(Exception::class) + @Test + fun nonExistingGroup() { // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.get( diff --git a/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt index 65a4f2fa8..bf268ac6a 100644 --- a/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt @@ -25,17 +25,16 @@ internal class LogsResourceIntTest { private var restLogsMockMvc: MockMvc? = null @BeforeEach fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) val logsResource = LogsResource() restLogsMockMvc = MockMvcBuilders .standaloneSetup(logsResource) .build() } - @get:Throws(Exception::class) - @get:Test - val allLogs: Unit - get() { + @Throws(Exception::class) + @Test + fun allLogs() { restLogsMockMvc!!.perform(MockMvcRequestBuilders.get("/management/logs")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt index 16b8952af..7d196a709 100644 --- a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt @@ -42,22 +42,21 @@ import java.util.function.Consumer */ @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalApp::class]) -internal open class OAuthClientsResourceIntTest( - @Autowired private val clientDetailsService: JdbcClientDetailsService, - @Autowired private val clientDetailsMapper: ClientDetailsMapper, - @Autowired private val subjectService: SubjectService, - @Autowired private val userService: UserService, - @Autowired private val oAuthClientService: OAuthClientService, - @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, - @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, - @Autowired private val exceptionTranslator: ExceptionTranslator, - private var restOauthClientMvc: MockMvc, - private var details: ClientDetailsDTO, - private var clientDetailsList: List, - private var databaseSizeBeforeCreate: Int = 0, - @Autowired private val authService: AuthService +internal open class OAuthClientsResourceIntTest @Autowired constructor ( + private val clientDetailsService: JdbcClientDetailsService, + private val clientDetailsMapper: ClientDetailsMapper, + private val subjectService: SubjectService, + private val userService: UserService, + private val oAuthClientService: OAuthClientService, + private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + private val exceptionTranslator: ExceptionTranslator, + private val authService: AuthService ) { - + private lateinit var restOauthClientMvc: MockMvc + private lateinit var details: ClientDetailsDTO + private var databaseSizeBeforeCreate: Int = 0 + private lateinit var clientDetailsList: List @BeforeEach @Throws(Exception::class) diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index 78ec5fa9a..63870f3e9 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -49,10 +49,10 @@ internal open class OrganizationResourceIntTest( @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - private var restOrganizationMockMvc: MockMvc, - private var organization: Organization, @Autowired private val authService: AuthService ) { + private lateinit var restOrganizationMockMvc: MockMvc + private lateinit var organization: Organization @BeforeEach @Throws(ServletException::class) @@ -86,10 +86,9 @@ internal open class OrganizationResourceIntTest( } - @get:Throws(Exception::class) - @get:Test - val nonExistingOrganization: Unit - get() { + @Throws(Exception::class) + @Test + fun nonExistingOrganization() { // Get the organization restOrganizationMockMvc.perform( MockMvcRequestBuilders.get( @@ -100,10 +99,9 @@ internal open class OrganizationResourceIntTest( .andExpect(MockMvcResultMatchers.status().isNotFound()) } - @get:Throws(Exception::class) - @get:Test - val allOrganizations: Unit - get() { + @Throws(Exception::class) + @Test + fun allOrganizations() { // Initialize the database organizationRepository.saveAndFlush(organization) @@ -116,10 +114,9 @@ internal open class OrganizationResourceIntTest( ) } - @get:Throws(Exception::class) - @get:Test - val projectsByOrganizationName: Unit - get() { + @Throws(Exception::class) + @Test + fun projectsByOrganizationName() { // Initialize the database organizationRepository.saveAndFlush(organization) val project: Project = ProjectResourceIntTest.Companion.createEntity() diff --git a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt index 108c9644b..ba9b4e2fa 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt @@ -41,19 +41,17 @@ internal class ProfileInfoResourceIntTest { .build() } - @get:Throws(Exception::class) - @get:Test - val profileInfo: Unit - get() { + @Throws(Exception::class) + @Test + fun profileInfo() { restProfileMockMvc!!.perform(MockMvcRequestBuilders.get("/api/profile-info")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) } - @get:Throws(Exception::class) - @get:Test - val profileInfoWithoutActiveProfiles: Unit - get() { + @Throws(Exception::class) + @Test + fun profileInfoWithoutActiveProfiles() { val emptyProfile = arrayOf() Mockito.`when`(environment!!.defaultProfiles).thenReturn(emptyProfile) Mockito.`when`(environment.activeProfiles).thenReturn(emptyProfile) diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt index b75f57972..9a1decae5 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt @@ -1,6 +1,5 @@ package org.radarbase.management.web.rest -import org.assertj.core.api.Assertions import org.assertj.core.api.Assertions.assertThat import org.hamcrest.Matchers import org.junit.jupiter.api.BeforeEach @@ -14,8 +13,6 @@ import org.radarbase.management.domain.Project import org.radarbase.management.domain.enumeration.ProjectStatus import org.radarbase.management.repository.OrganizationRepository import org.radarbase.management.repository.ProjectRepository -import org.radarbase.management.service.AuthService -import org.radarbase.management.service.ProjectService import org.radarbase.management.service.mapper.ProjectMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired @@ -26,7 +23,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -48,26 +44,30 @@ import javax.servlet.ServletException @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser internal open class ProjectResourceIntTest( - @Autowired private val organizationRepository: OrganizationRepository, + @Autowired private val projectResource: ProjectResource, + +// @Autowired private val subjectMapper: SubjectMapper, @Autowired private val projectRepository: ProjectRepository, - @Autowired private val projectMapper: ProjectMapper, - @Autowired private val projectService: ProjectService, - @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, +// @Autowired private val projectService: ProjectService, +// @Autowired private val roleService: RoleService, +// @Autowired private val subjectService: SubjectService, +// @Autowired private val sourceService: SourceService, +// @Autowired private val authService: AuthService, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val exceptionTranslator: ExceptionTranslator, - private var restProjectMockMvc: MockMvc, - private var project: Project, - @Autowired private val authService: AuthService + + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val organizationRepository: OrganizationRepository, ) { + private lateinit var restProjectMockMvc: MockMvc + private lateinit var project: Project @BeforeEach @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val projectResource = ProjectResource - ReflectionTestUtils.setField(projectResource, "projectRepository", projectRepository) - ReflectionTestUtils.setField(projectResource, "projectService", projectService) - ReflectionTestUtils.setField(projectResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) restProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) @@ -101,15 +101,15 @@ internal open class ProjectResourceIntTest( // Validate the Project in the database val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeCreate + 1) + assertThat(projectList).hasSize(databaseSizeBeforeCreate + 1) val testProject = projectList[projectList.size - 1] - Assertions.assertThat(testProject!!.projectName).isEqualTo(DEFAULT_PROJECT_NAME) - Assertions.assertThat(testProject.description).isEqualTo(DEFAULT_DESCRIPTION) - Assertions.assertThat(testProject.organizationName).isEqualTo(DEFAULT_ORGANIZATION) - Assertions.assertThat(testProject.location).isEqualTo(DEFAULT_LOCATION) - Assertions.assertThat(testProject.startDate).isEqualTo(DEFAULT_START_DATE) - Assertions.assertThat(testProject.projectStatus).isEqualTo(DEFAULT_PROJECT_STATUS) - Assertions.assertThat(testProject.endDate).isEqualTo(DEFAULT_END_DATE) + assertThat(testProject!!.projectName).isEqualTo(DEFAULT_PROJECT_NAME) + assertThat(testProject.description).isEqualTo(DEFAULT_DESCRIPTION) + assertThat(testProject.organizationName).isEqualTo(DEFAULT_ORGANIZATION) + assertThat(testProject.location).isEqualTo(DEFAULT_LOCATION) + assertThat(testProject.startDate).isEqualTo(DEFAULT_START_DATE) + assertThat(testProject.projectStatus).isEqualTo(DEFAULT_PROJECT_STATUS) + assertThat(testProject.endDate).isEqualTo(DEFAULT_END_DATE) } @Test @@ -132,7 +132,7 @@ internal open class ProjectResourceIntTest( // Validate the Alice in the database val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeCreate) + assertThat(projectList).hasSize(databaseSizeBeforeCreate) } @Test @@ -152,7 +152,7 @@ internal open class ProjectResourceIntTest( ) .andExpect(MockMvcResultMatchers.status().isBadRequest()) val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeTest) + assertThat(projectList).hasSize(databaseSizeBeforeTest) } @Test @@ -172,7 +172,7 @@ internal open class ProjectResourceIntTest( ) .andExpect(MockMvcResultMatchers.status().isBadRequest()) val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeTest) + assertThat(projectList).hasSize(databaseSizeBeforeTest) } @Test @@ -192,14 +192,13 @@ internal open class ProjectResourceIntTest( ) .andExpect(MockMvcResultMatchers.status().isBadRequest()) val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeTest) + assertThat(projectList).hasSize(databaseSizeBeforeTest) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allProjects: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun allProjects() { // Initialize the database projectRepository.saveAndFlush(project) @@ -284,11 +283,10 @@ internal open class ProjectResourceIntTest( .andExpect(MockMvcResultMatchers.jsonPath("$.endDate").value(TestUtil.sameInstant(DEFAULT_END_DATE))) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val nonExistingProject: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun nonExistingProject() { // Get the project restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) @@ -324,8 +322,7 @@ internal open class ProjectResourceIntTest( MockMvcRequestBuilders.put("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(projectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Project in the database val projectList = projectRepository.findAll() @@ -363,7 +360,7 @@ internal open class ProjectResourceIntTest( // Validate the Project in the database val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeUpdate + 1) + assertThat(projectList).hasSize(databaseSizeBeforeUpdate + 1) } @Test @@ -383,7 +380,7 @@ internal open class ProjectResourceIntTest( // Validate the database is empty val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeDelete - 1) + assertThat(projectList).hasSize(databaseSizeBeforeDelete - 1) } @Test diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt index 804292021..87bd2cff6 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt @@ -29,7 +29,6 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers import org.springframework.test.web.servlet.setup.MockMvcBuilders import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder import org.springframework.transaction.annotation.Transactional -import javax.persistence.EntityManager import javax.servlet.ServletException /** @@ -47,11 +46,10 @@ internal open class SourceDataResourceIntTest( @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val em: EntityManager, - private var restSourceDataMockMvc: MockMvc, - private var sourceData: SourceData, @Autowired private val authService: AuthService ) { + private lateinit var restSourceDataMockMvc: MockMvc + private lateinit var sourceData: SourceData @BeforeEach @Throws(ServletException::class) @@ -172,11 +170,10 @@ internal open class SourceDataResourceIntTest( Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeTest) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allSourceData: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun allSourceData() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) @@ -243,11 +240,10 @@ internal open class SourceDataResourceIntTest( ) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allSourceDataWithPagination: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun allSourceDataWithPagination() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) @@ -341,11 +337,10 @@ internal open class SourceDataResourceIntTest( .andExpect(MockMvcResultMatchers.jsonPath("$.frequency").value(DEFAULT_FREQUENCY)) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val nonExistingSourceData: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun nonExistingSourceData() { // Get the sourceData restSourceDataMockMvc.perform( MockMvcRequestBuilders.get( diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt index 80033e65a..6c4ed5696 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt @@ -55,11 +55,11 @@ internal open class SourceResourceIntTest( @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, @Autowired private val projectRepository: ProjectRepository, - private var restDeviceMockMvc: MockMvc, - private var source: Source, - private var project: Project, @Autowired private val authService: AuthService ) { + private lateinit var restDeviceMockMvc: MockMvc + private lateinit var source: Source + private lateinit var project: Project @BeforeEach @Throws(ServletException::class) @@ -187,11 +187,10 @@ internal open class SourceResourceIntTest( Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeTest) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allSources: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun allSources() { // Initialize the database sourceRepository.saveAndFlush(source) @@ -232,11 +231,10 @@ internal open class SourceResourceIntTest( .andExpect(MockMvcResultMatchers.jsonPath("$.assigned").value(DEFAULT_ASSIGNED)) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val nonExistingSource: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun nonExistingSource() { // Get the source restDeviceMockMvc.perform(MockMvcRequestBuilders.get("/api/sources/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt index 2981eb2ad..ad2dbf537 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt @@ -31,7 +31,6 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers import org.springframework.test.web.servlet.setup.MockMvcBuilders import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder import org.springframework.transaction.annotation.Transactional -import javax.persistence.EntityManager import javax.servlet.ServletException /** @@ -51,11 +50,10 @@ internal open class SourceTypeResourceIntTest( @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val em: EntityManager, - private var restSourceTypeMockMvc: MockMvc, - private var sourceType: SourceType, @Autowired private val authService: AuthService ) { + private lateinit var restSourceTypeMockMvc: MockMvc + private lateinit var sourceType: SourceType @BeforeEach @Throws(ServletException::class) @@ -205,11 +203,10 @@ internal open class SourceTypeResourceIntTest( Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allSourceTypes: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun allSourceTypes() { // Initialize the database sourceTypeRepository.saveAndFlush(sourceType) @@ -252,11 +249,10 @@ internal open class SourceTypeResourceIntTest( ) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allSourceTypesWithPagination: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun allSourceTypesWithPagination() { // Initialize the database sourceTypeRepository.saveAndFlush(sourceType) @@ -325,11 +321,10 @@ internal open class SourceTypeResourceIntTest( ) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val nonExistingSourceType: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun nonExistingSourceType() { // Get the sourceType restSourceTypeMockMvc.perform( MockMvcRequestBuilders.get( diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index c024bcd1a..4b48e9a80 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -12,6 +12,7 @@ import org.radarbase.management.domain.Subject import org.radarbase.management.repository.ProjectRepository import org.radarbase.management.repository.SubjectRepository import org.radarbase.management.service.AuthService +import org.radarbase.management.service.RevisionService import org.radarbase.management.service.SourceService import org.radarbase.management.service.SourceTypeService import org.radarbase.management.service.SubjectService @@ -24,6 +25,7 @@ import org.radarbase.management.service.dto.SubjectDTO import org.radarbase.management.service.mapper.SubjectMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.actuate.audit.AuditEventRepository import org.springframework.boot.test.context.SpringBootTest import org.springframework.data.web.PageableHandlerMethodArgumentResolver import org.springframework.http.MediaType @@ -31,7 +33,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -50,40 +51,47 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class SubjectResourceIntTest(@Autowired private val subjectRepository: SubjectRepository, - @Autowired private val subjectMapper: SubjectMapper, - @Autowired private val subjectService: SubjectService, - @Autowired private val sourceService: SourceService, - @Autowired private val sourceTypeService: SourceTypeService, - @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, - @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, - @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val projectRepository: ProjectRepository, - private var restSubjectMockMvc: MockMvc, - @Autowired private val authService: AuthService +internal open class SubjectResourceIntTest( + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val subjectMapper: SubjectMapper, + @Autowired private val subjectService: SubjectService, + @Autowired private val sourceService: SourceService, + @Autowired private val sourceTypeService: SourceTypeService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val authService: AuthService, + @Autowired private val revisionService: RevisionService, + @Autowired private val eventRepository: AuditEventRepository ) { + private lateinit var restSubjectMockMvc: MockMvc @BeforeEach @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val subjectResource = SubjectResource - ReflectionTestUtils.setField(subjectResource, "subjectService", subjectService) - ReflectionTestUtils.setField(subjectResource, "subjectRepository", subjectRepository) - ReflectionTestUtils.setField(subjectResource, "subjectMapper", subjectMapper) - ReflectionTestUtils.setField(subjectResource, "projectRepository", projectRepository) - ReflectionTestUtils.setField(subjectResource, "sourceTypeService", sourceTypeService) - ReflectionTestUtils.setField(subjectResource, "authService", authService) - ReflectionTestUtils.setField(subjectResource, "sourceService", sourceService) + val subjectResource = SubjectResource( + subjectService, + subjectRepository, + subjectMapper, + projectRepository, + sourceTypeService, + eventRepository, + revisionService, + sourceService, + authService + ) + val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) - restSubjectMockMvc = MockMvcBuilders.standaloneSetup(subjectResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) // add the oauth token by default to all requests for this mockMvc - .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) - .build() + restSubjectMockMvc = + MockMvcBuilders.standaloneSetup(subjectResource).setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator).setMessageConverters(jacksonMessageConverter) + .addFilter(filter) // add the oauth token by default to all requests for this mockMvc + .defaultRequest( + MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken()) + ).build() } @Test @@ -95,11 +103,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Create the Subject val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( - MockMvcRequestBuilders.post("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -121,86 +127,71 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // An entity with an existing ID cannot be created, so this API call must fail restSubjectMockMvc.perform( - MockMvcRequestBuilders.post("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) + ).andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the Alice in the database val subjectList = subjectRepository.findAll() Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allSubjects: Unit - get() { - // Initialize the database - val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) - - // Get all the subjectList - restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects?sort=id,desc")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[*].id").value>( - Matchers.hasItem( - subjectDto!!.id!!.toInt() - ) + @Throws(Exception::class) + @Transactional + @Test + open fun allSubjects() { + // Initialize the database + val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) + + // Get all the subjectList + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)).andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + subjectDto!!.id!!.toInt() ) ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[*].externalLink") - .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_EXTERNAL_LINK)) - ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[*].externalId") - .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_ENTERNAL_ID)) - ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[*].status") - .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_STATUS.toString())) - ) - } + ).andExpect( + MockMvcResultMatchers.jsonPath("$.[*].externalLink") + .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_EXTERNAL_LINK)) + ).andExpect( + MockMvcResultMatchers.jsonPath("$.[*].externalId") + .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_ENTERNAL_ID)) + ).andExpect( + MockMvcResultMatchers.jsonPath("$.[*].status") + .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_STATUS.toString())) + ) + } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val subject: Unit - get() { - // Initialize the database - val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) - - // Get the subject - restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{login}", subjectDto!!.login)) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(subjectDto.id!!.toInt())) - .andExpect( - MockMvcResultMatchers.jsonPath("$.externalLink") - .value(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) - ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.externalId") - .value(SubjectServiceTest.DEFAULT_ENTERNAL_ID) - ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.status") - .value(SubjectServiceTest.DEFAULT_STATUS.toString()) - ) - } + @Throws(Exception::class) + @Transactional + @Test + open fun subject() { + // Initialize the database + val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val nonExistingSubject: Unit - get() { - // Get the subject - restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{id}", Long.MAX_VALUE)) - .andExpect(MockMvcResultMatchers.status().isNotFound()) - } + // Get the subject + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{login}", subjectDto!!.login)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(subjectDto.id!!.toInt())).andExpect( + MockMvcResultMatchers.jsonPath("$.externalLink").value(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) + ).andExpect( + MockMvcResultMatchers.jsonPath("$.externalId").value(SubjectServiceTest.DEFAULT_ENTERNAL_ID) + ).andExpect( + MockMvcResultMatchers.jsonPath("$.status").value(SubjectServiceTest.DEFAULT_STATUS.toString()) + ) + } + + @Throws(Exception::class) + @Transactional + @Test + open fun nonExistingSubject() { + // Get the subject + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{id}", Long.MAX_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional @@ -212,17 +203,13 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Update the subject val updatedSubject = subjectRepository.findById(subjectDto!!.id!!).get() - updatedSubject - .externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) - .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID) - .removed = SubjectServiceTest.UPDATED_REMOVED + updatedSubject.externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) + .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID).removed = SubjectServiceTest.UPDATED_REMOVED subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) restSubjectMockMvc.perform( - MockMvcRequestBuilders.put("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.put("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -243,10 +230,8 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Update the subject val updatedSubject = subjectRepository.findById(subjectDto!!.id!!).get() - updatedSubject - .externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) - .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID) - .removed = SubjectServiceTest.UPDATED_REMOVED + updatedSubject.externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) + .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID).removed = SubjectServiceTest.UPDATED_REMOVED subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) val newProject = ProjectDTO() newProject.id = 2L @@ -254,11 +239,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit newProject.location = "new location" subjectDto!!.project = newProject restSubjectMockMvc.perform( - MockMvcRequestBuilders.put("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.put("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -281,11 +264,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // If the entity doesn't have an ID, it will be created instead of just being updated restSubjectMockMvc.perform( - MockMvcRequestBuilders.put("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.put("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -304,8 +285,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit restSubjectMockMvc.perform( MockMvcRequestBuilders.delete("/api/subjects/{login}", subjectDto!!.login) .accept(TestUtil.APPLICATION_JSON_UTF8) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty val subjectList = subjectRepository.findAll() @@ -328,11 +308,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Create the Subject val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( - MockMvcRequestBuilders.post("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -347,8 +325,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.sourceId").isNotEmpty()) // A source can not be assigned twice to a subject, so this call must fail @@ -357,8 +334,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) - ) - .andExpect(MockMvcResultMatchers.status().is4xxClientError()) + ).andExpect(MockMvcResultMatchers.status().is4xxClientError()) } @Test @@ -370,11 +346,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Create the Subject val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( - MockMvcRequestBuilders.post("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -389,8 +363,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.sourceId").isNotEmpty()) // A source can not be assigned twice to a subject, so this call must fail @@ -399,13 +372,15 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) - ) - .andExpect(MockMvcResultMatchers.status().is4xxClientError()) + ).andExpect(MockMvcResultMatchers.status().is4xxClientError()) // Get all the subjectList - restSubjectMockMvc - .perform(MockMvcRequestBuilders.get("/api/subjects/{login}/sources?sort=id,desc", subjectDto.login)) - .andExpect(MockMvcResultMatchers.status().isOk()) + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?sort=id,desc", + subjectDto.login + ) + ).andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").isNotEmpty()) } @@ -419,11 +394,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Create the Subject val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( - MockMvcRequestBuilders.post("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -438,124 +411,98 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) - ) - .andExpect(MockMvcResultMatchers.status().is4xxClientError()) + ).andExpect(MockMvcResultMatchers.status().is4xxClientError()) .andExpect(MockMvcResultMatchers.jsonPath("$.message").isNotEmpty()) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val subjectSources: Unit - get() { - // Initialize the database - val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() - val createdSource = sourceService.save(createSource()) - val sourceDto = MinimalSourceDetailsDTO() - .id(createdSource.id) - .sourceName(createdSource.sourceName) - .sourceTypeId(createdSource.sourceType.id) - .sourceId(createdSource.sourceId!!) - subjectDtoToCreate.sources = setOf(sourceDto) - org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) - val createdSubject = subjectService.createSubject(subjectDtoToCreate) - org.junit.jupiter.api.Assertions.assertFalse(createdSubject!!.sources.isEmpty()) - - // Get the subject - restSubjectMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/subjects/{login}/sources", - createdSubject.login - ) + @Throws(Exception::class) + @Transactional + @Test + open fun subjectSources() { + // Initialize the database + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() + val createdSource = sourceService.save(createSource()) + val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) + .sourceTypeId(createdSource.sourceType.id).sourceId(createdSource.sourceId!!) + subjectDtoToCreate.sources = setOf(sourceDto) + org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + val createdSubject = subjectService.createSubject(subjectDtoToCreate) + org.junit.jupiter.api.Assertions.assertFalse(createdSubject!!.sources.isEmpty()) + + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources", createdSubject.login ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[0].id").value(createdSource.id!!.toInt())) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[0].sourceId").value(createdSource.sourceId.toString()) - ) - } + ).andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[0].id").value(createdSource.id!!.toInt())).andExpect( + MockMvcResultMatchers.jsonPath("$.[0].sourceId").value(createdSource.sourceId.toString()) + ) + } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val subjectSourcesWithQueryParam: Unit - get() { - // Initialize the database - val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() - val createdSource = sourceService.save(createSource()) - val sourceDto = MinimalSourceDetailsDTO() - .id(createdSource.id) - .sourceName(createdSource.sourceName) - .sourceTypeId(createdSource.sourceType.id) - .sourceId(createdSource.sourceId!!) - subjectDtoToCreate.sources = setOf(sourceDto) - org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) - val createdSubject = subjectService.createSubject(subjectDtoToCreate) - TestUtil.commitTransactionAndStartNew() - org.junit.jupiter.api.Assertions.assertNotNull(createdSubject!!.login) - // Get the subject - restSubjectMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/subjects/{login}/sources?withInactiveSources=true", - createdSubject.login - ) + @Throws(Exception::class) + @Transactional + @Test + open fun subjectSourcesWithQueryParam() { + // Initialize the database + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() + val createdSource = sourceService.save(createSource()) + val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) + .sourceTypeId(createdSource.sourceType.id).sourceId(createdSource.sourceId!!) + subjectDtoToCreate.sources = setOf(sourceDto) + org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + val createdSubject = subjectService.createSubject(subjectDtoToCreate) + TestUtil.commitTransactionAndStartNew() + org.junit.jupiter.api.Assertions.assertNotNull(createdSubject!!.login) + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?withInactiveSources=true", createdSubject.login ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id!!.toInt())) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) - ) - } + ).andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id!!.toInt())).andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) + ) + } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val inactiveSubjectSourcesWithQueryParam: Unit - get() { - // Initialize the database - val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() - val createdSource = sourceService.save(createSource()) - val sourceDto = MinimalSourceDetailsDTO() - .id(createdSource.id) - .sourceName(createdSource.sourceName) - .sourceTypeId(createdSource.sourceType.id) - .sourceId(createdSource.sourceId!!) - subjectDtoToCreate.sources = setOf(sourceDto) - org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) - val createdSubject = subjectService.createSubject(subjectDtoToCreate) - TestUtil.commitTransactionAndStartNew() - createdSubject!!.sources = emptySet() - val updatedSubject = subjectService.updateSubject(createdSubject) - TestUtil.commitTransactionAndStartNew() - org.junit.jupiter.api.Assertions.assertNotNull(updatedSubject!!.login) - // Get the subject - restSubjectMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/subjects/{login}/sources?withInactiveSources=true", - updatedSubject.login - ) + @Throws(Exception::class) + @Transactional + @Test + open fun inactiveSubjectSourcesWithQueryParam() { + // Initialize the database + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() + val createdSource = sourceService.save(createSource()) + val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) + .sourceTypeId(createdSource.sourceType.id).sourceId(createdSource.sourceId!!) + subjectDtoToCreate.sources = setOf(sourceDto) + org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + val createdSubject = subjectService.createSubject(subjectDtoToCreate) + TestUtil.commitTransactionAndStartNew() + createdSubject!!.sources = emptySet() + val updatedSubject = subjectService.updateSubject(createdSubject) + TestUtil.commitTransactionAndStartNew() + org.junit.jupiter.api.Assertions.assertNotNull(updatedSubject!!.login) + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?withInactiveSources=true", updatedSubject.login + ) + ).andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id!!.toInt())).andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id!!.toInt())) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) - ) - // Get the subject - restSubjectMockMvc - .perform( - MockMvcRequestBuilders.get( - "/api/subjects/{login}/sources?withInactiveSources=false", - updatedSubject.login - ) + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?withInactiveSources=false", updatedSubject.login ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andReturn() - } + ).andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)).andReturn() + } private fun createSource(): SourceDTO { val sourceDto = SourceDTO() @@ -567,43 +514,39 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit } private fun createSourceWithSourceTypeId(): MinimalSourceDetailsDTO { - val sourceTypes = sourceTypeService.findAll().stream() - .filter { obj: SourceTypeDTO -> obj.canRegisterDynamically } - .collect(Collectors.toList()) + val sourceTypes = + sourceTypeService.findAll().stream().filter { obj: SourceTypeDTO -> obj.canRegisterDynamically } + .collect(Collectors.toList()) Assertions.assertThat(sourceTypes.size).isPositive() val sourceType = sourceTypes[0] return source.sourceTypeId(sourceType.id) } private fun createSourceWithoutSourceTypeId(): MinimalSourceDetailsDTO { - val sourceTypes = sourceTypeService.findAll().stream() - .filter { obj: SourceTypeDTO -> obj.canRegisterDynamically } - .collect(Collectors.toList()) + val sourceTypes = + sourceTypeService.findAll().stream().filter { obj: SourceTypeDTO -> obj.canRegisterDynamically } + .collect(Collectors.toList()) Assertions.assertThat(sourceTypes.size).isPositive() val sourceType = sourceTypes[0] - return source - .sourceTypeCatalogVersion(sourceType.catalogVersion) - .sourceTypeModel(sourceType.model) + return source.sourceTypeCatalogVersion(sourceType.catalogVersion).sourceTypeModel(sourceType.model) .sourceTypeProducer(sourceType.producer) } private fun createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration(): MinimalSourceDetailsDTO { - val sourceTypes = sourceTypeService.findAll().stream() - .filter { it: SourceTypeDTO -> !it.canRegisterDynamically } - .collect(Collectors.toList()) + val sourceTypes = + sourceTypeService.findAll().stream().filter { it: SourceTypeDTO -> !it.canRegisterDynamically } + .collect(Collectors.toList()) Assertions.assertThat(sourceTypes.size).isPositive() val sourceType = sourceTypes[0] - return source - .sourceTypeCatalogVersion(sourceType.catalogVersion) - .sourceTypeModel(sourceType.model) + return source.sourceTypeCatalogVersion(sourceType.catalogVersion).sourceTypeModel(sourceType.model) .sourceTypeProducer(sourceType.producer) } private val source: MinimalSourceDetailsDTO get() { - val sourceRegistrationDto = MinimalSourceDetailsDTO() - .sourceName(SubjectServiceTest.PRODUCER + "-" + SubjectServiceTest.MODEL) - .attributes(Collections.singletonMap("something", "value")) + val sourceRegistrationDto = + MinimalSourceDetailsDTO().sourceName(SubjectServiceTest.PRODUCER + "-" + SubjectServiceTest.MODEL) + .attributes(Collections.singletonMap("something", "value")) Assertions.assertThat(sourceRegistrationDto.sourceId).isNull() return sourceRegistrationDto } @@ -617,11 +560,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Create the Subject val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( - MockMvcRequestBuilders.post("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -634,17 +575,12 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val sourceRegistrationDto = createSourceWithoutSourceTypeId() val result = restSubjectMockMvc.perform( MockMvcRequestBuilders.post( - "/api/subjects/{login}/sources", - subjectLogin - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) + "/api/subjects/{login}/sources", subjectLogin + ).contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andReturn() + ).andExpect(MockMvcResultMatchers.status().isOk()).andReturn() val value = TestUtil.convertJsonStringToObject( - result - .response.contentAsString, MinimalSourceDetailsDTO::class.java + result.response.contentAsString, MinimalSourceDetailsDTO::class.java ) as MinimalSourceDetailsDTO org.junit.jupiter.api.Assertions.assertNotNull(value.sourceName) val attributes: MutableMap = HashMap() @@ -654,11 +590,8 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit restSubjectMockMvc.perform( MockMvcRequestBuilders.post( "/api/subjects/{login}/sources/{sourceName}", subjectLogin, value.sourceName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(attributes)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(attributes)) + ).andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.attributes").isNotEmpty()) } } diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt index 9d0a54a50..5949207d7 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt @@ -66,10 +66,10 @@ internal open class UserResourceIntTest( @Autowired private val authService: AuthService, @Autowired private val passwordService: PasswordService, @Autowired private val projectRepository: ProjectRepository, - private var restUserMockMvc: MockMvc, - private var user: User, - private var project: Project? ) { + private lateinit var restUserMockMvc: MockMvc + private lateinit var user: User + private var project: Project? = null @BeforeEach @Throws(ServletException::class) From c9fefe83eebd91f8caf764c697303929ffafda48 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 11:30:12 +0100 Subject: [PATCH 047/158] misc fixes --- .../management/domain/Organization.kt | 8 ++--- .../org/radarbase/management/domain/Role.kt | 8 ++--- .../web/rest/OrganizationResource.kt | 30 +++++++++---------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Organization.kt b/src/main/java/org/radarbase/management/domain/Organization.kt index 479a0f708..44b94d2d4 100644 --- a/src/main/java/org/radarbase/management/domain/Organization.kt +++ b/src/main/java/org/radarbase/management/domain/Organization.kt @@ -49,14 +49,14 @@ class Organization : AbstractEntity() { @JvmField @OneToMany(mappedBy = "organization") var projects: List? = null - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val org = o as Organization + val org = other as Organization return if (org.id == null || id == null) { false } else id == org.id diff --git a/src/main/java/org/radarbase/management/domain/Role.kt b/src/main/java/org/radarbase/management/domain/Role.kt index b71751401..010af8aca 100644 --- a/src/main/java/org/radarbase/management/domain/Role.kt +++ b/src/main/java/org/radarbase/management/domain/Role.kt @@ -99,14 +99,14 @@ class Role : AbstractEntity, Serializable { return this } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val role = o as Role + val role = other as Role return authority == role.authority && project == role.project && organization == role.organization } diff --git a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt index ad99b72e5..53071da24 100644 --- a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt @@ -35,12 +35,10 @@ import javax.validation.Valid */ @RestController @RequestMapping("/api") -class OrganizationResource { - @Autowired - private val organizationService: OrganizationService? = null - - @Autowired - private val authService: AuthService? = null +class OrganizationResource( + @Autowired private val organizationService: OrganizationService, + @Autowired private val authService: AuthService +) { /** * POST /organizations : Create a new organization. @@ -58,13 +56,13 @@ class OrganizationResource { @RequestBody organizationDto: @Valid OrganizationDTO? ): ResponseEntity { log.debug("REST request to save Organization : {}", organizationDto) - authService!!.checkPermission(Permission.ORGANIZATION_CREATE) + authService.checkPermission(Permission.ORGANIZATION_CREATE) if (organizationDto!!.id != null) { val msg = "A new organization cannot already have an ID" val headers = createFailureAlert(ENTITY_NAME, "idexists", msg) return ResponseEntity.badRequest().headers(headers).body(null) } - val existingOrg = organizationService!!.findByName(organizationDto.name) + val existingOrg = organizationDto.name?.let { organizationService.findByName(it) } if (existingOrg != null) { val msg = "An organization with this name already exists" val headers = createFailureAlert(ENTITY_NAME, "nameexists", msg) @@ -88,8 +86,8 @@ class OrganizationResource { */ get() { log.debug("REST request to get Organizations") - authService!!.checkScope(Permission.ORGANIZATION_READ) - val orgs = organizationService!!.findAll() + authService.checkScope(Permission.ORGANIZATION_READ) + val orgs = organizationService.findAll() return ResponseEntity(orgs, HttpStatus.OK) } @@ -114,8 +112,8 @@ class OrganizationResource { return createOrganization(organizationDto) } val name = organizationDto.name - authService!!.checkPermission(Permission.ORGANIZATION_UPDATE, { (organization): EntityDetails -> organization }) - val result = organizationService!!.save(organizationDto) + authService.checkPermission(Permission.ORGANIZATION_UPDATE, { (organization): EntityDetails -> organization }) + val result = organizationService.save(organizationDto) return ResponseEntity.ok() .headers(createEntityCreationAlert(ENTITY_NAME, result.name)) .body(result) @@ -138,8 +136,8 @@ class OrganizationResource { @PathVariable name: String ): ResponseEntity { log.debug("REST request to get Organization : {}", name) - authService!!.checkPermission(Permission.ORGANIZATION_READ, { (organization): EntityDetails -> organization }) - val org = organizationService!!.findByName(name) + authService.checkPermission(Permission.ORGANIZATION_READ, { (organization): EntityDetails -> organization }) + val org = organizationService.findByName(name) val dto = org ?: throw NotFoundException( "Organization not found with name $name", EntityName.ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, @@ -166,8 +164,8 @@ class OrganizationResource { @PathVariable name: String? ): ResponseEntity> { log.debug("REST request to get Projects of the Organization : {}", name) - authService!!.checkPermission(Permission.PROJECT_READ, { (organization): EntityDetails -> organization }) - val projects = organizationService!!.findAllProjectsByOrganizationName(name!!) + authService.checkPermission(Permission.PROJECT_READ, { (organization): EntityDetails -> organization }) + val projects = organizationService.findAllProjectsByOrganizationName(name!!) return ResponseEntity.ok(projects) } From 72e36ca85fda675770afd735eb16a25b9b2d407f Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 11:33:17 +0100 Subject: [PATCH 048/158] all tests in ProjectResourceIntTest.kt passing. --- .../radarbase/management/domain/Project.kt | 6 +- .../repository/ProjectRepository.kt | 4 +- .../management/service/dto/OrganizationDTO.kt | 6 +- .../management/service/dto/ProjectDTO.kt | 6 +- .../decorator/ProjectMapperDecorator.kt | 23 +- .../management/web/rest/ProjectResource.kt | 14 +- .../web/rest/OrganizationResourceIntTest.kt | 201 +++++++++--------- .../web/rest/ProjectResourceIntTest.kt | 7 +- 8 files changed, 136 insertions(+), 131 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index b6c57b4f7..f9c607091 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -123,17 +123,17 @@ class Project : AbstractEntity(), Serializable { ) @OrderBy("name ASC") var groups: MutableSet = HashSet() - fun projectName(projectName: String): Project { + fun projectName(projectName: String?): Project { this.projectName = projectName return this } - fun description(description: String): Project { + fun description(description: String?): Project { this.description = description return this } - fun organizationName(organizationName: String): Project { + fun organizationName(organizationName: String?): Project { this.organizationName = organizationName return this } diff --git a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt index 9dfd6b7be..2eb10938f 100644 --- a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt +++ b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt @@ -15,7 +15,7 @@ import org.springframework.data.repository.query.Param */ @Suppress("unused") @RepositoryDefinition(domainClass = Project::class, idClass = Long::class) -interface ProjectRepository : JpaRepository, RevisionRepository { +interface ProjectRepository : JpaRepository, RevisionRepository { @Query( value = "select distinct project from Project project " + "left join fetch project.sourceTypes", @@ -53,7 +53,7 @@ interface ProjectRepository : JpaRepository, RevisionRepository

= emptyList() override fun equals(other: Any?): Boolean { diff --git a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt index c5f9b7421..0955cec77 100644 --- a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt @@ -13,12 +13,12 @@ import javax.validation.constraints.NotNull @JsonInclude(JsonInclude.Include.NON_NULL) class ProjectDTO : Serializable { var id: Long? = null - var projectName: @NotNull String? = null + @NotNull var projectName: String? = null var humanReadableProjectName: String? = null - var description: @NotNull String? = null + @NotNull var description: String? = null var organization: OrganizationDTO? = null var organizationName: String? = null - lateinit var location: @NotNull String + @NotNull var location: String? = null var startDate: ZonedDateTime? = null var projectStatus: ProjectStatus? = null var endDate: ZonedDateTime? = null diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt index 41e988a82..9f7811647 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt @@ -18,18 +18,18 @@ import java.util.* /** * Created by nivethika on 30-8-17. */ -abstract class ProjectMapperDecorator() : ProjectMapper { +abstract class ProjectMapperDecorator : ProjectMapper { - @Autowired @Qualifier("delegate") private val delegate: ProjectMapper? = null + @Autowired @Qualifier("delegate") private lateinit var delegate: ProjectMapper @Autowired private lateinit var organizationRepository: OrganizationRepository @Autowired private lateinit var projectRepository: ProjectRepository @Autowired private lateinit var metaTokenService: MetaTokenService override fun projectToProjectDTO(project: Project?): ProjectDTO? { - val dto = delegate?.projectToProjectDTO(project) + val dto = delegate.projectToProjectDTO(project) dto?.humanReadableProjectName = project?.attributes?.get(ProjectDTO.HUMAN_READABLE_PROJECT_NAME) try { - dto?.persistentTokenTimeout = metaTokenService?.getMetaTokenTimeout(true, project)?.toMillis() + dto?.persistentTokenTimeout = metaTokenService.getMetaTokenTimeout(true, project).toMillis() } catch (ex: BadRequestException) { dto?.persistentTokenTimeout = null } @@ -40,7 +40,7 @@ abstract class ProjectMapperDecorator() : ProjectMapper { if (project == null) { return null } - val dto = delegate?.projectToProjectDTOReduced(project) + val dto = delegate.projectToProjectDTOReduced(project) dto?.humanReadableProjectName = project.attributes[ProjectDTO.HUMAN_READABLE_PROJECT_NAME] dto?.sourceTypes = emptySet() return dto @@ -50,19 +50,20 @@ abstract class ProjectMapperDecorator() : ProjectMapper { if (projectDto == null) { return null } - val project = delegate?.projectDTOToProject(projectDto) + val project = delegate.projectDTOToProject(projectDto) val projectName = projectDto.humanReadableProjectName if (!projectName.isNullOrEmpty()) { project!!.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] = projectName } - val orgDto = projectDto.organization - if (orgDto?.name != null) { - val org = organizationRepository.findOneByName(orgDto.name) + + val name = projectDto.organization?.name + if (name != null) { + val org = organizationRepository.findOneByName(name) ?: throw NotFoundException( "Organization not found with name", EntityName.Companion.ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, - Collections.singletonMap("name", orgDto.name) + Collections.singletonMap("name", name) ) project!!.organization = org } @@ -72,6 +73,6 @@ abstract class ProjectMapperDecorator() : ProjectMapper { override fun descriptiveDTOToProject(minimalProjectDetailsDto: MinimalProjectDetailsDTO?): Project? { return if (minimalProjectDetailsDto == null) { null - } else minimalProjectDetailsDto.id?.let { projectRepository?.getById(it) } + } else minimalProjectDetailsDto.id?.let { projectRepository.getById(it) } } } diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index 2f9b0a775..2a0dd330f 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -74,9 +74,9 @@ class ProjectResource( @PostMapping("/projects") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity { + fun createProject(@RequestBody @Valid projectDto: ProjectDTO?): ResponseEntity { log.debug("REST request to save Project : {}", projectDto) - val org = projectDto!!.organization + val org = projectDto?.organization if (org?.name == null) { throw BadRequestException( "Organization must be provided", @@ -93,7 +93,7 @@ class ProjectResource( ENTITY_NAME, "idexists", "A new project cannot already have an ID" ) ) - .body(null) + .body(null) } if (projectRepository.findOneWithEagerRelationshipsByName(projectDto.projectName) != null) { return ResponseEntity.badRequest() @@ -102,7 +102,7 @@ class ProjectResource( ENTITY_NAME, "nameexists", "A project with this name already exists" ) ) - .body(null) + .body(null) } val result = projectService.save(projectDto) return ResponseEntity.created(ResourceUriService.getUri(result)) @@ -112,7 +112,7 @@ class ProjectResource( result.projectName ) ) - .body(result) + .body(result) } /** @@ -127,7 +127,7 @@ class ProjectResource( @PutMapping("/projects") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun updateProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity {log.debug("REST request to update Project : {}", projectDto) + fun updateProject(@RequestBody @Valid projectDto: ProjectDTO?): ResponseEntity {log.debug("REST request to update Project : {}", projectDto) if (projectDto?.id == null) { return createProject(projectDto) } @@ -366,7 +366,7 @@ class ProjectResource( NotAuthorizedException::class ) fun getAllSubjects( - subjectCriteria: @Valid SubjectCriteria? + @Valid subjectCriteria: SubjectCriteria? ): ResponseEntity> { authService.checkScope(Permission.SUBJECT_READ) diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index 63870f3e9..6a3815e9b 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -25,7 +25,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -42,14 +41,17 @@ import javax.servlet.ServletException @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser internal open class OrganizationResourceIntTest( + @Autowired private val organizationResource: OrganizationResource, + + @Autowired private val organizationService: OrganizationService, + @Autowired private val authService: AuthService, + @Autowired private val organizationMapper: OrganizationMapper, @Autowired private val organizationRepository: OrganizationRepository, - @Autowired private val organizationService: OrganizationService, @Autowired private val projectRepository: ProjectRepository, @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val authService: AuthService ) { private lateinit var restOrganizationMockMvc: MockMvc private lateinit var organization: Organization @@ -58,19 +60,16 @@ internal open class OrganizationResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val orgResource = OrganizationResource() - ReflectionTestUtils - .setField(orgResource, "organizationService", organizationService) - ReflectionTestUtils.setField(orgResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) - restOrganizationMockMvc = MockMvcBuilders.standaloneSetup(orgResource) + restOrganizationMockMvc = MockMvcBuilders.standaloneSetup(organizationResource) .setCustomArgumentResolvers(pageableArgumentResolver) .setControllerAdvice(exceptionTranslator) .setMessageConverters(jacksonMessageConverter) .addFilter(filter) .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) .build() + organization = this.createEntity() } @@ -137,113 +136,115 @@ internal open class OrganizationResourceIntTest( projectRepository.delete(project) } - @AfterEach - fun tearDown() { - val testOrg = organizationRepository.findOneByName( - organization.name!! + @Test + @Throws(Exception::class) + fun createOrganization() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) ) - if (testOrg != null) - organizationRepository.delete(testOrg) + .andExpect(MockMvcResultMatchers.status().isCreated()) + // Validate the Organization in the database + val savedOrg = orgDto.name?.let { organizationRepository.findOneByName(it) } + Assertions.assertThat(savedOrg).isNotNull() + } - @Test - @Throws(Exception::class) - fun createOrganization() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + @Test + @Throws(Exception::class) + fun createOrganizationWithExistingName() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) - // Validate the Organization in the database - val savedOrg = organizationRepository.findOneByName(orgDto.name) - Assertions.assertThat(savedOrg).isNotNull() - } + // Second request should fail + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isConflict()) + } - @Test - @Throws(Exception::class) - fun createOrganizationWithExistingName() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) - // Second request should fail - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isConflict()) - } + @Test + @Throws(Exception::class) + //TODO this is covered by not using a nullable type + fun checkGroupNameIsRequired() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + orgDto.name = "" + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + } - @Test - @Throws(Exception::class) - //TODO this is covered by not using a nullable type - fun checkGroupNameIsRequired() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - orgDto.name = "" - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) + @Test + @Throws(Exception::class) + fun getOrganization() { + // Initialize the database + organizationRepository.saveAndFlush(organization) + + // Get the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}", + organization.name ) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - } - + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("org1")) + } - @Test - @Throws(Exception::class) - fun getOrganization() { - // Initialize the database - organizationRepository.saveAndFlush(organization) + @Test + @Throws(Exception::class) + fun editOrganization() { + // Initialize the database + organizationRepository.saveAndFlush(organization) + val updatedOrgDto = organizationMapper + .organizationToOrganizationDTO(organization) + updatedOrgDto.location = "Other location" + + // Update the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.put("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(updatedOrgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) - // Get the organization - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/organizations/{name}", - organization.name - ) + // Get the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}", + organization.name ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("org1")) - } + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.location").value("Other location")) + } + + @AfterEach + fun tearDown() { + val testOrg = organizationRepository.findOneByName( + organization.name!! + ) + if (testOrg != null) + organizationRepository.delete(testOrg) - @Test - @Throws(Exception::class) - fun editOrganization() { - // Initialize the database - organizationRepository.saveAndFlush(organization) - val updatedOrgDto = organizationMapper - .organizationToOrganizationDTO(organization) - updatedOrgDto.location = "Other location" - // Update the organization - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.put("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(updatedOrgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - // Get the organization - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/organizations/{name}", - organization.name - ) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.location").value("Other location")) - } } diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt index 9a1decae5..a2d835205 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt @@ -13,6 +13,7 @@ import org.radarbase.management.domain.Project import org.radarbase.management.domain.enumeration.ProjectStatus import org.radarbase.management.repository.OrganizationRepository import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.dto.ProjectDTO import org.radarbase.management.service.mapper.ProjectMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired @@ -144,7 +145,8 @@ internal open class ProjectResourceIntTest( project.projectName = null // Create the Project, which fails. - val projectDto = projectMapper.projectToProjectDTO(project) + val projectDto: ProjectDTO? = projectMapper.projectToProjectDTO(project) + val projectt: Project? = projectMapper.projectDTOToProject(projectDto) restProjectMockMvc.perform( MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -184,7 +186,7 @@ internal open class ProjectResourceIntTest( project.location = null // Create the Project, which fails. - val projectDto = projectMapper.projectToProjectDTO(project) + val projectDto: ProjectDTO? = projectMapper.projectToProjectDTO(project) restProjectMockMvc.perform( MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -425,6 +427,7 @@ internal open class ProjectResourceIntTest( val organization = Organization() organization.id = 1L organization.name = "main" + organization.description = "test" return Project() .projectName(DEFAULT_PROJECT_NAME) .description(DEFAULT_DESCRIPTION) From 20bfc8ff2f43a9b1a1a53166844105fca3085c13 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 12:01:54 +0100 Subject: [PATCH 049/158] move validation annotations and constraint annotations so that they actually annotate the fields/parameters rather than the types (?) --- .../radarbase/management/domain/Authority.kt | 10 +++--- .../org/radarbase/management/domain/Group.kt | 2 +- .../radarbase/management/domain/MetaToken.kt | 10 +++--- .../management/domain/Organization.kt | 6 ++-- .../management/domain/PersistentAuditEvent.kt | 2 +- .../radarbase/management/domain/Project.kt | 6 ++-- .../org/radarbase/management/domain/Source.kt | 8 ++--- .../radarbase/management/domain/SourceData.kt | 4 +-- .../radarbase/management/domain/SourceType.kt | 10 +++--- .../radarbase/management/domain/Subject.kt | 2 +- .../org/radarbase/management/domain/User.kt | 18 +++++----- .../management/repository/SourceRepository.kt | 2 +- .../management/service/RevisionService.kt | 2 +- .../management/service/SourceTypeService.kt | 4 +-- .../management/service/dto/AttributeMapDTO.kt | 8 ++--- .../service/dto/ClientDetailsDTO.kt | 2 +- .../management/service/dto/GroupDTO.kt | 2 +- .../management/service/dto/OrganizationDTO.kt | 6 ++-- .../management/service/dto/SourceDTO.kt | 6 ++-- .../management/service/dto/SourceTypeDTO.kt | 10 +++--- .../management/service/mapper/UserMapper.kt | 4 +-- .../management/web/rest/AccountResource.kt | 2 +- .../management/web/rest/GroupResource.kt | 2 +- .../web/rest/OAuthClientsResource.kt | 2 +- .../web/rest/OrganizationResource.kt | 4 +-- .../management/web/rest/ProjectResource.kt | 4 +-- .../management/web/rest/RoleResource.kt | 4 +-- .../management/web/rest/SourceDataResource.kt | 4 +-- .../management/web/rest/SourceResource.kt | 4 +-- .../management/web/rest/SourceTypeResource.kt | 36 +++++++++---------- .../management/web/rest/SubjectResource.kt | 2 +- .../web/rest/criteria/SubjectCriteria.kt | 3 +- .../web/rest/criteria/SubjectSortOrder.kt | 12 +++---- .../web/rest/ProjectResourceIntTest.kt | 10 +++--- .../web/rest/SubjectResourceIntTest.kt | 6 ++-- 35 files changed, 110 insertions(+), 109 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Authority.kt b/src/main/java/org/radarbase/management/domain/Authority.kt index 773957f64..a98a1b664 100644 --- a/src/main/java/org/radarbase/management/domain/Authority.kt +++ b/src/main/java/org/radarbase/management/domain/Authority.kt @@ -25,7 +25,7 @@ class Authority : Serializable { @JvmField @Id @Column(length = 50) - var name: @NotNull @Size(min = 0, max = 50) @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Size(min = 0, max = 50) @Pattern(regexp = Constants.ENTITY_ID_REGEX) var name: String? = null constructor() @@ -36,14 +36,14 @@ class Authority : Serializable { constructor(role: RoleAuthority) : this(role.authority) - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val authority = o as Authority + val authority = other as Authority return if (name == null || authority.name == null) { false } else name == authority.name diff --git a/src/main/java/org/radarbase/management/domain/Group.kt b/src/main/java/org/radarbase/management/domain/Group.kt index 1f527bdf9..71d2810e3 100644 --- a/src/main/java/org/radarbase/management/domain/Group.kt +++ b/src/main/java/org/radarbase/management/domain/Group.kt @@ -40,7 +40,7 @@ class Group : AbstractEntity(), Serializable { @JvmField @Column(name = "name", length = 50, nullable = false) - var name: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) var name: String? = null @JvmField @JsonIgnore diff --git a/src/main/java/org/radarbase/management/domain/MetaToken.kt b/src/main/java/org/radarbase/management/domain/MetaToken.kt index 5980d8329..8cc4e0e45 100644 --- a/src/main/java/org/radarbase/management/domain/MetaToken.kt +++ b/src/main/java/org/radarbase/management/domain/MetaToken.kt @@ -36,7 +36,7 @@ class MetaToken : AbstractEntity() { override var id: Long? = null @Column(name = "token_name", nullable = false, unique = true) - var tokenName: @NotNull @Pattern(regexp = Constants.TOKEN_NAME_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.TOKEN_NAME_REGEX) var tokenName: String? = null private set @Column(name = "fetched", nullable = false) @@ -109,14 +109,14 @@ class MetaToken : AbstractEntity() { val isValid: Boolean get() = (persistent!! || !fetched!!) && Instant.now().isBefore(expiryDate) - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val metaToken = o as MetaToken + val metaToken = other as MetaToken return id == metaToken.id && tokenName == metaToken.tokenName && fetched == metaToken.fetched && expiryDate == metaToken.expiryDate && clientId == metaToken.clientId && subject == metaToken.subject && persistent == metaToken.persistent } diff --git a/src/main/java/org/radarbase/management/domain/Organization.kt b/src/main/java/org/radarbase/management/domain/Organization.kt index 44b94d2d4..283450a18 100644 --- a/src/main/java/org/radarbase/management/domain/Organization.kt +++ b/src/main/java/org/radarbase/management/domain/Organization.kt @@ -36,15 +36,15 @@ class Organization : AbstractEntity() { @JvmField @Column(name = "name", nullable = false, unique = true) - var name: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) var name: String? = null @JvmField @Column(name = "description", nullable = false) - var description: @NotNull String? = null + @NotNull var description: String? = null @JvmField @Column(name = "location", nullable = false) - var location: @NotNull String? = null + @NotNull var location: String? = null @JvmField @OneToMany(mappedBy = "organization") diff --git a/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt b/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt index 9f04a713f..7f58cfab1 100644 --- a/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt +++ b/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt @@ -34,7 +34,7 @@ class PersistentAuditEvent : Serializable { @JvmField @Column(nullable = false) - var principal: @NotNull String? = null + @NotNull var principal: String? = null @JvmField @Column(name = "event_date") diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index f9c607091..3c142bc38 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -56,10 +56,10 @@ class Project : AbstractEntity(), Serializable { override var id: Long? = null @Column(name = "project_name", nullable = false, unique = true) - var projectName: @NotNull @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") String? = null + @NotNull @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") var projectName: String? = null @Column(name = "description", nullable = false) - var description: @NotNull String? = null + @NotNull var description: String? = null @JvmField @Column(name = "jhi_organization") @@ -72,7 +72,7 @@ class Project : AbstractEntity(), Serializable { @JvmField @Column(name = "location", nullable = false) - var location: @NotNull String? = null + @NotNull var location: String? = null @JvmField @Column(name = "start_date") diff --git a/src/main/java/org/radarbase/management/domain/Source.kt b/src/main/java/org/radarbase/management/domain/Source.kt index c409cca9e..15ea02d99 100644 --- a/src/main/java/org/radarbase/management/domain/Source.kt +++ b/src/main/java/org/radarbase/management/domain/Source.kt @@ -47,21 +47,21 @@ class Source : AbstractEntity, Serializable { // pass @JvmField @Column(name = "source_id", nullable = false, unique = true) - var sourceId: @NotNull UUID? = null + @NotNull var sourceId: UUID? = null @JvmField @Column(name = "source_name", nullable = false, unique = true) - var sourceName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) var sourceName: String? = null @JvmField @Column(name = "expected_source_name") var expectedSourceName: String? = null @Column(name = "assigned", nullable = false) - var assigned: @NotNull Boolean? = false + @NotNull var assigned: Boolean? = false @Column(name = "deleted", nullable = false) - var deleted: @NotNull Boolean = false + @NotNull var deleted: Boolean = false @JvmField @ManyToOne(fetch = FetchType.EAGER) diff --git a/src/main/java/org/radarbase/management/domain/SourceData.kt b/src/main/java/org/radarbase/management/domain/SourceData.kt index ce73c1df6..7ff379940 100644 --- a/src/main/java/org/radarbase/management/domain/SourceData.kt +++ b/src/main/java/org/radarbase/management/domain/SourceData.kt @@ -40,12 +40,12 @@ class SourceData : AbstractEntity(), Serializable { //SourceData type e.g. ACCELEROMETER, TEMPERATURE. @JvmField @Column(name = "source_data_type", nullable = false) - var sourceDataType: @NotNull String? = null + @NotNull var sourceDataType: String? = null // this will be the unique human readable identifier of @JvmField @Column(name = "source_data_name", nullable = false, unique = true) - var sourceDataName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) var sourceDataName: String? = null //Default data frequency @JvmField diff --git a/src/main/java/org/radarbase/management/domain/SourceType.kt b/src/main/java/org/radarbase/management/domain/SourceType.kt index cb89cefd7..5e64cbfd4 100644 --- a/src/main/java/org/radarbase/management/domain/SourceType.kt +++ b/src/main/java/org/radarbase/management/domain/SourceType.kt @@ -44,7 +44,7 @@ class SourceType : AbstractEntity(), Serializable { @JvmField @Column(name = "producer") - var producer: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) var producer: String? = null @JvmField @Column(name = "name") @@ -64,19 +64,19 @@ class SourceType : AbstractEntity(), Serializable { @JvmField @Column(name = "model", nullable = false) - var model: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) var model: String? = null @JvmField @Column(name = "catalog_version", nullable = false) - var catalogVersion: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) var catalogVersion: String? = null @JvmField @Column(name = "source_type_scope", nullable = false) - var sourceTypeScope: @NotNull String? = null + @NotNull var sourceTypeScope: String? = null @JvmField @Column(name = "dynamic_registration", nullable = false) - var canRegisterDynamically: @NotNull Boolean? = false + @NotNull var canRegisterDynamically: Boolean? = false @JvmField @set:JsonSetter(nulls = Nulls.AS_EMPTY) diff --git a/src/main/java/org/radarbase/management/domain/Subject.kt b/src/main/java/org/radarbase/management/domain/Subject.kt index 4fecfdce7..a86d547e7 100644 --- a/src/main/java/org/radarbase/management/domain/Subject.kt +++ b/src/main/java/org/radarbase/management/domain/Subject.kt @@ -64,7 +64,7 @@ class Subject( var externalId: String? = null @Column(name = "removed", nullable = false) - var removed: @NotNull Boolean = false + @NotNull var removed: Boolean = false @JvmField @OneToOne diff --git a/src/main/java/org/radarbase/management/domain/User.kt b/src/main/java/org/radarbase/management/domain/User.kt index a0bcd307b..a09bff588 100644 --- a/src/main/java/org/radarbase/management/domain/User.kt +++ b/src/main/java/org/radarbase/management/domain/User.kt @@ -47,42 +47,42 @@ class User : AbstractEntity(), Serializable { override var id: Long? = null @Column(length = 50, unique = true, nullable = false) - lateinit var login: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) String + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) lateinit var login: String private set @JvmField @JsonIgnore @Column(name = "password_hash", length = 60) - var password: @NotNull @Size(min = 60, max = 60) String? = null + @NotNull @Size(min = 60, max = 60) var password: String? = null @JvmField @Column(name = "first_name", length = 50) - var firstName: @Size(max = 50) String? = null + @Size(max = 50) var firstName: String? = null @JvmField @Column(name = "last_name", length = 50) - var lastName: @Size(max = 50) String? = null + @Size(max = 50) var lastName: String? = null @JvmField @Column(length = 100, unique = true, nullable = true) - var email: @Email @Size(min = 5, max = 100) String? = null + @Email @Size(min = 5, max = 100) var email: String? = null @JvmField @Column(nullable = false) - var activated: @NotNull Boolean = false + @NotNull var activated: Boolean = false @JvmField @Column(name = "lang_key", length = 5) - var langKey: @Size(min = 2, max = 5) String? = null + @Size(min = 2, max = 5) var langKey: String? = null @JvmField @Column(name = "activation_key", length = 20) @JsonIgnore - var activationKey: @Size(max = 20) String? = null + @Size(max = 20) var activationKey: String? = null @JvmField @Column(name = "reset_key", length = 20) - var resetKey: @Size(max = 20) String? = null + @Size(max = 20) var resetKey: String? = null @JvmField @Column(name = "reset_date") diff --git a/src/main/java/org/radarbase/management/repository/SourceRepository.kt b/src/main/java/org/radarbase/management/repository/SourceRepository.kt index 4b5946480..fa23af0b9 100644 --- a/src/main/java/org/radarbase/management/repository/SourceRepository.kt +++ b/src/main/java/org/radarbase/management/repository/SourceRepository.kt @@ -61,5 +61,5 @@ interface SourceRepository : JpaRepository, RevisionRepository?): Function { + private fun getDtoMapper(@NotNull entity: Class<*>?): Function { return dtoMapperMap.computeIfAbsent(entity) { clazz: Class<*>? -> addMapperForClass(clazz) } } diff --git a/src/main/java/org/radarbase/management/service/SourceTypeService.kt b/src/main/java/org/radarbase/management/service/SourceTypeService.kt index f0025ff43..bc2c42ed6 100644 --- a/src/main/java/org/radarbase/management/service/SourceTypeService.kt +++ b/src/main/java/org/radarbase/management/service/SourceTypeService.kt @@ -95,8 +95,8 @@ open class SourceTypeService( * Fetch SourceType by producer and model. */ fun findByProducerAndModelAndVersion( - producer: @NotNull String, - model: @NotNull String, version: @NotNull String + @NotNull producer: String, + @NotNull model: String, @NotNull version: String ): SourceTypeDTO { log.debug( "Request to get SourceType by producer and model and version: {}, {}, {}", diff --git a/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt b/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt index 7f54176ee..1d8a01441 100644 --- a/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt @@ -7,14 +7,14 @@ import java.util.* */ class AttributeMapDTO @JvmOverloads constructor(var key: String? = null, var value: String? = null) { - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val attributeMapDto = o as AttributeMapDTO + val attributeMapDto = other as AttributeMapDTO return key == attributeMapDto.key && value == attributeMapDto.value } diff --git a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt index 98f7da1a6..1992b14e4 100644 --- a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt @@ -6,7 +6,7 @@ import javax.validation.constraints.NotNull * Created by dverbeec on 7/09/2017. */ class ClientDetailsDTO { - lateinit var clientId: @NotNull String + @NotNull var clientId: String? = null var clientSecret: String? = null var scope: Set? = null var resourceIds: Set? = null diff --git a/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt b/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt index 02463bb31..ca53db0a4 100644 --- a/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt @@ -11,7 +11,7 @@ import javax.validation.constraints.NotNull class GroupDTO { var id: Long? = null var projectId: Long? = null - var name: @NotNull String? = null + @NotNull var name: String? = null override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt index 849448f77..06d2ef19e 100644 --- a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt @@ -11,9 +11,9 @@ import javax.validation.constraints.NotNull @JsonInclude(JsonInclude.Include.NON_NULL) class OrganizationDTO : Serializable { var id: Long? = null - var name: @NotNull String? = null - var description: @NotNull String? = null - var location: @NotNull String? = null + @NotNull var name: String? = null + @NotNull var description: String? = null + @NotNull var location: String? = null var projects: List = emptyList() override fun equals(other: Any?): Boolean { diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt index b7ff95330..c54f245d5 100644 --- a/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt @@ -11,10 +11,10 @@ import javax.validation.constraints.NotNull class SourceDTO : Serializable { var id: Long? = null var sourceId: UUID? = null - lateinit var sourceName: @NotNull String + @NotNull var sourceName: String? = null var expectedSourceName: String? = null - var assigned: @NotNull Boolean? = null - lateinit var sourceType: @NotNull SourceTypeDTO + @NotNull var assigned: Boolean? = null + @NotNull var sourceType: SourceTypeDTO? = null var subjectLogin: String? = null @JsonInclude(JsonInclude.Include.NON_NULL) diff --git a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt index ff5fe709e..0168170e2 100644 --- a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt @@ -13,11 +13,11 @@ import javax.validation.constraints.NotNull @JsonInclude(JsonInclude.Include.NON_NULL) class SourceTypeDTO : Serializable { var id: Long? = null - lateinit var producer: @NotNull String - lateinit var model: @NotNull String - lateinit var catalogVersion: @NotNull String - lateinit var sourceTypeScope: @NotNull String - var canRegisterDynamically: @NotNull Boolean = false + @NotNull var producer: String? = null + @NotNull var model: String? = null + @NotNull var catalogVersion: String? = null + @NotNull var sourceTypeScope: String? = null + @NotNull var canRegisterDynamically: Boolean = false var name: String? = null var description: String? = null var assessmentType: String? = null diff --git a/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt index d5e652f2d..8296a076f 100644 --- a/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt +++ b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt @@ -46,10 +46,10 @@ interface UserMapper { * @param authorities the authorities to map * @return the set of strings if authorities is not null, null otherwise */ - fun map(authorities: Set): Set<@NotNull @Size( + fun map(authorities: Set): @NotNull @Size( max = 50, min = 0 - ) @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") String> { + ) @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") Set { return authorities.mapNotNull { it.name }.toSet() } diff --git a/src/main/java/org/radarbase/management/web/rest/AccountResource.kt b/src/main/java/org/radarbase/management/web/rest/AccountResource.kt index 852d433a1..d747595c6 100644 --- a/src/main/java/org/radarbase/management/web/rest/AccountResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/AccountResource.kt @@ -139,7 +139,7 @@ class AccountResource( @Timed @Throws(NotAuthorizedException::class) fun saveAccount( - @RequestBody userDto: @Valid UserDTO, + @RequestBody @Valid userDto: UserDTO, authentication: Authentication ): ResponseEntity { authService.checkPermission(Permission.USER_UPDATE, { e: EntityDetails -> diff --git a/src/main/java/org/radarbase/management/web/rest/GroupResource.kt b/src/main/java/org/radarbase/management/web/rest/GroupResource.kt index 22ab46839..dbd0ef7df 100644 --- a/src/main/java/org/radarbase/management/web/rest/GroupResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/GroupResource.kt @@ -54,7 +54,7 @@ class GroupResource { @Throws(NotAuthorizedException::class) fun createGroup( @PathVariable projectName: String?, - @RequestBody groupDto: @Valid GroupDTO? + @RequestBody @Valid groupDto: GroupDTO? ): ResponseEntity { authService!!.checkPermission(Permission.PROJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) val groupDtoResult = groupService!!.createGroup(projectName!!, groupDto!!) diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt index 71bdf0406..600db7e5f 100644 --- a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt @@ -120,7 +120,7 @@ class OAuthClientsResource { @PutMapping("/oauth-clients") @Timed @Throws(NotAuthorizedException::class) - fun updateOAuthClient(@RequestBody clientDetailsDto: @Valid ClientDetailsDTO?): ResponseEntity { + fun updateOAuthClient(@RequestBody @Valid clientDetailsDto: ClientDetailsDTO?): ResponseEntity { authService!!.checkPermission(Permission.OAUTHCLIENTS_UPDATE) // getOAuthClient checks if the id exists OAuthClientService.checkProtected(oAuthClientService!!.findOneByClientId(clientDetailsDto!!.clientId)) diff --git a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt index 53071da24..7f87ab0cc 100644 --- a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt @@ -53,7 +53,7 @@ class OrganizationResource( @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) fun createOrganization( - @RequestBody organizationDto: @Valid OrganizationDTO? + @RequestBody @Valid organizationDto: OrganizationDTO? ): ResponseEntity { log.debug("REST request to save Organization : {}", organizationDto) authService.checkPermission(Permission.ORGANIZATION_CREATE) @@ -105,7 +105,7 @@ class OrganizationResource( @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) fun updateOrganization( - @RequestBody organizationDto: @Valid OrganizationDTO? + @RequestBody @Valid organizationDto: OrganizationDTO? ): ResponseEntity { log.debug("REST request to update Organization : {}", organizationDto) if (organizationDto!!.id == null) { diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index 2a0dd330f..725e15a88 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -367,7 +367,7 @@ class ProjectResource( ) fun getAllSubjects( @Valid subjectCriteria: SubjectCriteria? - ): ResponseEntity> { + ): ResponseEntity> { authService.checkScope(Permission.SUBJECT_READ) @@ -394,7 +394,7 @@ class ProjectResource( val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( page, baseUri, subjectCriteria ) - return ResponseEntity(page.content, headers, HttpStatus.OK) + return ResponseEntity(page.content.filterNotNull(), headers, HttpStatus.OK) } companion object { diff --git a/src/main/java/org/radarbase/management/web/rest/RoleResource.kt b/src/main/java/org/radarbase/management/web/rest/RoleResource.kt index ed4cb384a..930f5dcf1 100644 --- a/src/main/java/org/radarbase/management/web/rest/RoleResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/RoleResource.kt @@ -51,7 +51,7 @@ class RoleResource( @Throws( URISyntaxException::class, NotAuthorizedException::class ) - fun createRole(@RequestBody roleDto: @Valid RoleDTO): ResponseEntity { + fun createRole(@RequestBody @Valid roleDto: RoleDTO): ResponseEntity { log.debug("REST request to save Role : {}", roleDto) authService.checkPermission(Permission.ROLE_CREATE, { e: EntityDetails -> e.project = roleDto.projectName @@ -85,7 +85,7 @@ class RoleResource( @Throws( URISyntaxException::class, NotAuthorizedException::class ) - fun updateRole(@RequestBody roleDto: @Valid RoleDTO): ResponseEntity { + fun updateRole(@RequestBody @Valid roleDto: RoleDTO): ResponseEntity { log.debug("REST request to update Role : {}", roleDto) if (roleDto.id == null) { return createRole(roleDto) diff --git a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt index 10a99b4ff..cbbbc6090 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt @@ -55,7 +55,7 @@ class SourceDataResource( @PostMapping("/source-data") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createSourceData(@RequestBody sourceDataDto: @Valid SourceDataDTO?): ResponseEntity { + fun createSourceData(@RequestBody @Valid sourceDataDto: SourceDataDTO?): ResponseEntity { log.debug("REST request to save SourceData : {}", sourceDataDto) authService.checkPermission(Permission.SOURCEDATA_CREATE) if (sourceDataDto!!.id != null) { @@ -92,7 +92,7 @@ class SourceDataResource( @PutMapping("/source-data") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun updateSourceData(@RequestBody sourceDataDto: @Valid SourceDataDTO?): ResponseEntity { + fun updateSourceData(@RequestBody @Valid sourceDataDto: SourceDataDTO?): ResponseEntity { log.debug("REST request to update SourceData : {}", sourceDataDto) if (sourceDataDto!!.id == null) { return createSourceData(sourceDataDto) diff --git a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt index 856c3b61b..bcfcad5d0 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt @@ -55,7 +55,7 @@ class SourceResource( @PostMapping("/sources") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createSource(@RequestBody sourceDto: @Valid SourceDTO?): ResponseEntity { + fun createSource(@RequestBody @Valid sourceDto: SourceDTO?): ResponseEntity { log.debug("REST request to save Source : {}", sourceDto) val project = sourceDto!!.project authService.checkPermission(Permission.SOURCE_CREATE, { e: EntityDetails -> @@ -110,7 +110,7 @@ class SourceResource( @PutMapping("/sources") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun updateSource(@RequestBody sourceDto: @Valid SourceDTO): ResponseEntity { + fun updateSource(@RequestBody @Valid sourceDto: SourceDTO): ResponseEntity { log.debug("REST request to update Source : {}", sourceDto) if (sourceDto.id == null) { return createSource(sourceDto) diff --git a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt index 5a34bac73..b94d22046 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt @@ -59,9 +59,9 @@ class SourceTypeResource( @PostMapping("/source-types") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createSourceType(@RequestBody sourceTypeDto: @Valid SourceTypeDTO?): ResponseEntity { + fun createSourceType(@RequestBody @Valid sourceTypeDto: SourceTypeDTO?): ResponseEntity { log.debug("REST request to save SourceType : {}", sourceTypeDto) - authService!!.checkPermission(Permission.SOURCETYPE_CREATE) + authService.checkPermission(Permission.SOURCETYPE_CREATE) if (sourceTypeDto!!.id != null) { return ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( @@ -72,8 +72,8 @@ class SourceTypeResource( } val existing: SourceType? = sourceTypeRepository .findOneWithEagerRelationshipsByProducerAndModelAndVersion( - sourceTypeDto.producer, sourceTypeDto.model, - sourceTypeDto.catalogVersion + sourceTypeDto.producer!!, sourceTypeDto.model!!, + sourceTypeDto.catalogVersion!! ) if (existing != null) { val errorParams: MutableMap = HashMap() @@ -88,7 +88,7 @@ class SourceTypeResource( ErrorConstants.ERR_SOURCE_TYPE_EXISTS, errorParams ) } - val result = sourceTypeService!!.save(sourceTypeDto) + val result = sourceTypeService.save(sourceTypeDto) return ResponseEntity.created(getUri(result)) .headers(HeaderUtil.createEntityCreationAlert(EntityName.SOURCE_TYPE, displayName(result))) .body(result) @@ -106,13 +106,13 @@ class SourceTypeResource( @PutMapping("/source-types") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun updateSourceType(@RequestBody sourceTypeDto: @Valid SourceTypeDTO?): ResponseEntity { + fun updateSourceType(@RequestBody @Valid sourceTypeDto: SourceTypeDTO?): ResponseEntity { log.debug("REST request to update SourceType : {}", sourceTypeDto) if (sourceTypeDto!!.id == null) { return createSourceType(sourceTypeDto) } - authService!!.checkPermission(Permission.SOURCETYPE_UPDATE) - val result = sourceTypeService!!.save(sourceTypeDto) + authService.checkPermission(Permission.SOURCETYPE_UPDATE) + val result = sourceTypeService.save(sourceTypeDto) return ResponseEntity.ok() .headers( HeaderUtil.createEntityUpdateAlert(EntityName.SOURCE_TYPE, displayName(sourceTypeDto)) @@ -132,8 +132,8 @@ class SourceTypeResource( fun getAllSourceTypes( @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable? ): ResponseEntity> { - authService!!.checkPermission(Permission.SOURCETYPE_READ) - val page = sourceTypeService!!.findAll(pageable!!) + authService.checkPermission(Permission.SOURCETYPE_READ) + val page = sourceTypeService.findAll(pageable!!) val headers = PaginationUtil .generatePaginationHttpHeaders(page, "/api/source-types") return ResponseEntity(page.content, headers, HttpStatus.OK) @@ -151,8 +151,8 @@ class SourceTypeResource( NotAuthorizedException::class ) fun getSourceTypes(@PathVariable producer: String?): ResponseEntity> { - authService!!.checkPermission(Permission.SOURCETYPE_READ) - return ResponseEntity.ok(sourceTypeService!!.findByProducer(producer!!)) + authService.checkPermission(Permission.SOURCETYPE_READ) + return ResponseEntity.ok(sourceTypeService.findByProducer(producer!!)) } /** @@ -175,9 +175,9 @@ class SourceTypeResource( @PathVariable producer: String?, @PathVariable model: String? ): ResponseEntity> { - authService!!.checkPermission(Permission.SOURCETYPE_READ) + authService.checkPermission(Permission.SOURCETYPE_READ) return ResponseEntity.ok( - sourceTypeService!!.findByProducerAndModel( + sourceTypeService.findByProducerAndModel( producer!!, model!! ) ) @@ -203,10 +203,10 @@ class SourceTypeResource( @PathVariable producer: String?, @PathVariable model: String?, @PathVariable version: String? ): ResponseEntity { - authService!!.checkPermission(Permission.SOURCETYPE_READ) + authService.checkPermission(Permission.SOURCETYPE_READ) return ResponseUtil.wrapOrNotFound( Optional.ofNullable( - sourceTypeService!!.findByProducerAndModelAndVersion(producer!!, model!!, version!!) + sourceTypeService.findByProducerAndModelAndVersion(producer!!, model!!, version!!) ) ) } @@ -232,13 +232,13 @@ class SourceTypeResource( @PathVariable producer: String?, @PathVariable model: String?, @PathVariable version: String? ): ResponseEntity { - authService!!.checkPermission(Permission.SOURCETYPE_DELETE) + authService.checkPermission(Permission.SOURCETYPE_DELETE) val sourceTypeDto = sourceTypeService .findByProducerAndModelAndVersion(producer!!, model!!, version!!) if (Objects.isNull(sourceTypeDto)) { return ResponseEntity.notFound().build() } - val projects = sourceTypeService!!.findProjectsBySourceType( + val projects = sourceTypeService.findProjectsBySourceType( producer, model, version ) diff --git a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt index e83ff61fb..13aede526 100644 --- a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt @@ -197,7 +197,7 @@ class SubjectResource( @Timed @Throws(NotAuthorizedException::class) fun getAllSubjects( - subjectCriteria: @Valid SubjectCriteria? + @Valid subjectCriteria: SubjectCriteria? ): ResponseEntity>? { val projectName = subjectCriteria!!.projectName authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> e.project(projectName) }) diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt index 1ec053778..312a35231 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt @@ -29,7 +29,8 @@ class SubjectCriteria { @Transient private var parsedSort: List? = null - val pageable: @NotNull Pageable + @get:NotNull + val pageable: Pageable /** Get the criteria paging settings, excluding sorting. */ get() = PageRequest.of(page, size) diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt index c2cad7a04..69932d4fa 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt @@ -13,22 +13,22 @@ import java.util.* import javax.validation.constraints.NotNull class SubjectSortOrder @JvmOverloads constructor( - val sortBy: @NotNull SubjectSortBy, - var direction: @NotNull Sort.Direction = Sort.Direction.ASC + @NotNull val sortBy: SubjectSortBy, + @NotNull var direction: Sort.Direction = Sort.Direction.ASC ) { override fun toString(): String { return sortBy.name + ',' + direction.name } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val that = o as SubjectSortOrder + val that = other as SubjectSortOrder return sortBy == that.sortBy && direction == that.direction } diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt index a2d835205..230042584 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt @@ -202,7 +202,7 @@ internal open class ProjectResourceIntTest( @Test open fun allProjects() { // Initialize the database - projectRepository.saveAndFlush(project) + projectRepository.saveAndFlush(project) // Get all the projectList restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects?sort=id,desc")) @@ -269,7 +269,7 @@ internal open class ProjectResourceIntTest( @Throws(Exception::class) open fun getProject() { // Initialize the database - projectRepository.saveAndFlush(project) + projectRepository.saveAndFlush(project) // Get the project restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects/{projectName}", project.projectName)) @@ -299,7 +299,7 @@ internal open class ProjectResourceIntTest( @Throws(Exception::class) open fun updateProject() { // Initialize the database - projectRepository.saveAndFlush(project) + projectRepository.saveAndFlush(project) val org = Organization() org.name = "org1" org.description = "Test Organization 1" @@ -328,7 +328,7 @@ internal open class ProjectResourceIntTest( // Validate the Project in the database val projectList = projectRepository.findAll() - assertThat(projectList).hasSize(databaseSizeBeforeUpdate) + assertThat(projectList).hasSize(databaseSizeBeforeUpdate) val testProject = projectList[projectList.size - 1] assertThat(testProject!!.projectName).isEqualTo(UPDATED_PROJECT_NAME) assertThat(testProject.description).isEqualTo(UPDATED_DESCRIPTION) @@ -370,7 +370,7 @@ internal open class ProjectResourceIntTest( @Throws(Exception::class) open fun deleteProject() { // Initialize the database - projectRepository.saveAndFlush(project) + projectRepository.saveAndFlush(project) val databaseSizeBeforeDelete = projectRepository.findAll().size // Get the project diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index 4b48e9a80..be76669ca 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -423,7 +423,7 @@ internal open class SubjectResourceIntTest( val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) - .sourceTypeId(createdSource.sourceType.id).sourceId(createdSource.sourceId!!) + .sourceTypeId(createdSource.sourceType?.id).sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) @@ -449,7 +449,7 @@ internal open class SubjectResourceIntTest( val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) - .sourceTypeId(createdSource.sourceType.id).sourceId(createdSource.sourceId!!) + .sourceTypeId(createdSource.sourceType?.id).sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) @@ -475,7 +475,7 @@ internal open class SubjectResourceIntTest( val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) - .sourceTypeId(createdSource.sourceType.id).sourceId(createdSource.sourceId!!) + .sourceTypeId(createdSource.sourceType?.id).sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) From 102b4d53ba3809911351c39011b16b667abe2964 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 21:57:00 +0100 Subject: [PATCH 050/158] simplification of Authority.kt. all AccountResourceIntTest.kt tests passing --- build.gradle | 5 +- gradle.properties | 1 + managementportal-client/build.gradle | 2 +- .../radarbase/management/domain/Authority.kt | 24 +++----- .../org/radarbase/management/domain/User.kt | 18 +++--- .../management/repository/UserRepository.kt | 2 +- .../security/DomainUserDetailsService.kt | 3 +- .../management/service/MailService.kt | 47 +++++++-------- .../management/service/OAuthClientService.kt | 3 +- .../management/service/RoleService.kt | 10 ++-- .../management/service/SubjectService.kt | 8 +-- .../management/service/dto/UserDTO.kt | 10 ++-- .../management/service/mapper/UserMapper.kt | 20 ------- .../mapper/decorator/UserMapperDecorator.kt | 8 +-- .../management/web/rest/AccountResource.kt | 9 +-- .../management/web/rest/UserResource.kt | 4 +- .../JwtAuthenticationFilterIntTest.kt | 13 ++--- .../security/SecurityUtilsUnitTest.kt | 8 +++ .../service/MetaTokenServiceTest.kt | 4 +- .../management/service/SubjectServiceTest.kt | 4 +- .../management/service/UserServiceIntTest.kt | 30 ++++------ .../web/rest/AccountResourceIntTest.kt | 58 ++++++++++--------- .../web/rest/OrganizationResourceIntTest.kt | 2 +- .../web/rest/ProfileInfoResourceIntTest.kt | 23 ++++---- .../web/rest/SourceResourceIntTest.kt | 32 +++++----- .../web/rest/UserResourceIntTest.kt | 44 ++++++-------- 26 files changed, 174 insertions(+), 218 deletions(-) diff --git a/build.gradle b/build.gradle index e03b2b71a..3ddc5d791 100644 --- a/build.gradle +++ b/build.gradle @@ -205,6 +205,9 @@ dependencies { implementation project(':radar-auth') implementation "org.springframework.data:spring-data-envers" + implementation "org.mockito:mockito-core:$mockito_version" + implementation "org.mockito.kotlin:mockito-kotlin:${mockito_kotlin_version}" + runtimeOnly("jakarta.xml.bind:jakarta.xml.bind-api:${javax_xml_bind_version}") runtimeOnly("org.glassfish.jaxb:jaxb-core:${javax_jaxb_core_version}") runtimeOnly("org.glassfish.jaxb:jaxb-runtime:${javax_jaxb_runtime_version}") @@ -221,7 +224,7 @@ dependencies { testImplementation "org.springframework.boot:spring-boot-test" testImplementation "org.assertj:assertj-core:${assertj_version}" testImplementation "org.junit.jupiter:junit-jupiter-api" - testImplementation "org.mockito:mockito-core:$mockito_version" + testImplementation "org.mockito.kotlin:mockito-kotlin:${mockito_kotlin_version}" testImplementation "com.mattbertolini:liquibase-slf4j:${liquibase_slf4j_version}" testImplementation "org.hamcrest:hamcrest-library" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" diff --git a/gradle.properties b/gradle.properties index d36af40f2..cfedaf791 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,6 +22,7 @@ javax_jaxb_core_version=2.3.0.1 javax_jaxb_runtime_version=2.3.8 javax_activation=1.1.1 mockito_version=4.8.1 +mockito_kotlin_version=5.1.0 slf4j_version=2.0.7 logback_version=1.4.11 oauth_jwt_version=4.4.0 diff --git a/managementportal-client/build.gradle b/managementportal-client/build.gradle index 4e01cb691..17811d741 100644 --- a/managementportal-client/build.gradle +++ b/managementportal-client/build.gradle @@ -39,7 +39,7 @@ dependencies { testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test") testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junit_version testImplementation group: 'com.github.tomakehurst', name: 'wiremock', version: '2.27.2' - testImplementation group: 'org.mockito', name: 'mockito-core', version: mockito_version + testImplementation group: 'org.mockito.kotlin', name: 'mockito-kotlin', version: mockito_kotlin_version testImplementation group: 'org.hamcrest', name: 'hamcrest', version: '2.2' testRuntimeOnly group: 'org.slf4j', name: 'slf4j-simple', version: slf4j_version diff --git a/src/main/java/org/radarbase/management/domain/Authority.kt b/src/main/java/org/radarbase/management/domain/Authority.kt index a98a1b664..7a67aae0a 100644 --- a/src/main/java/org/radarbase/management/domain/Authority.kt +++ b/src/main/java/org/radarbase/management/domain/Authority.kt @@ -21,18 +21,10 @@ import javax.validation.constraints.Size @Audited @Table(name = "radar_authority") @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -class Authority : Serializable { - @JvmField - @Id - @Column(length = 50) - @NotNull @Size(min = 0, max = 50) @Pattern(regexp = Constants.ENTITY_ID_REGEX) var name: String? = null - - constructor() - - constructor(authorityName: String?) { - name = authorityName - this.name = authorityName - } +data class Authority(@JvmField + @Id + @Column(length = 50) + @NotNull @Size(min = 0, max = 50) @Pattern(regexp = Constants.ENTITY_ID_REGEX) var name: String? = null) : Serializable { constructor(role: RoleAuthority) : this(role.authority) @@ -54,12 +46,14 @@ class Authority : Serializable { } override fun toString(): String { - return ("Authority{" - + "name='" + name + '\'' - + "}") + return name.toString() } companion object { private const val serialVersionUID = 1L } + + fun asString() : String? { + return name + } } diff --git a/src/main/java/org/radarbase/management/domain/User.kt b/src/main/java/org/radarbase/management/domain/User.kt index a09bff588..a780da221 100644 --- a/src/main/java/org/radarbase/management/domain/User.kt +++ b/src/main/java/org/radarbase/management/domain/User.kt @@ -47,7 +47,7 @@ class User : AbstractEntity(), Serializable { override var id: Long? = null @Column(length = 50, unique = true, nullable = false) - @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) lateinit var login: String + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) var login: String? = null private set @JvmField @@ -88,8 +88,14 @@ class User : AbstractEntity(), Serializable { @Column(name = "reset_date") var resetDate: ZonedDateTime? = null + /** Authorities that a user has. */ + val authorities: Set? + get() { + return roles?.mapNotNull { obj: Role? -> obj?.authority?.name }?.toSet() + } + @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @ManyToMany(fetch = FetchType.EAGER) @JoinTable( name = "role_users", @@ -105,14 +111,10 @@ class User : AbstractEntity(), Serializable { var roles: MutableSet? = HashSet() //Lowercase the login before saving it in database - fun setLogin(login: String) { - this.login = login.lowercase() + fun setLogin(login: String?) { + this.login = login?.lowercase() } - val authorities: Set? - /** Authorities that a user has. */ - get() = roles?.map { obj: Role? -> obj?.authority }?.toSet() - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/src/main/java/org/radarbase/management/repository/UserRepository.kt b/src/main/java/org/radarbase/management/repository/UserRepository.kt index f1071863e..3543e5495 100644 --- a/src/main/java/org/radarbase/management/repository/UserRepository.kt +++ b/src/main/java/org/radarbase/management/repository/UserRepository.kt @@ -35,7 +35,7 @@ interface UserRepository : JpaRepository, RevisionRepository SimpleGrantedAuthority(authority?.name) } + user.authorities!!.map { authority -> SimpleGrantedAuthority(authority) } return User( lowercaseLogin, user.password, diff --git a/src/main/java/org/radarbase/management/service/MailService.kt b/src/main/java/org/radarbase/management/service/MailService.kt index 3f894424d..671ec5277 100644 --- a/src/main/java/org/radarbase/management/service/MailService.kt +++ b/src/main/java/org/radarbase/management/service/MailService.kt @@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.MessageSource import org.springframework.mail.javamail.JavaMailSender +import org.springframework.mail.javamail.JavaMailSenderImpl import org.springframework.mail.javamail.MimeMessageHelper import org.springframework.scheduling.annotation.Async import org.springframework.stereotype.Service @@ -21,18 +22,12 @@ import java.util.* * We use the @Async annotation to send emails asynchronously. */ @Service -class MailService { - @Autowired - private val managementPortalProperties: ManagementPortalProperties? = null - - @Autowired - private val javaMailSender: JavaMailSender? = null - - @Autowired - private val messageSource: MessageSource? = null - - @Autowired - private val templateEngine: SpringTemplateEngine? = null +class MailService( + @Autowired private val managementPortalProperties: ManagementPortalProperties, + @Autowired private val javaMailSender: JavaMailSender, + @Autowired private val messageSource: MessageSource, + @Autowired private val templateEngine: SpringTemplateEngine, +) { /** * Send an email. @@ -53,14 +48,14 @@ class MailService { ) // Prepare message using a Spring helper - val mimeMessage = javaMailSender!!.createMimeMessage() + val mimeMessage = javaMailSender.createMimeMessage() try { val message = MimeMessageHelper( mimeMessage, isMultipart, StandardCharsets.UTF_8.name() ) message.setTo(to) - message.setFrom(managementPortalProperties!!.mail.from) + message.setFrom(managementPortalProperties.mail.from) message.setSubject(subject) message.setText(content, isHtml) javaMailSender.send(mimeMessage) @@ -82,10 +77,10 @@ class MailService { context.setVariable(USER, user) context.setVariable( BASE_URL, - managementPortalProperties!!.common.managementPortalBaseUrl + managementPortalProperties.common.managementPortalBaseUrl ) - val content = templateEngine!!.process("activationEmail", context) - val subject = messageSource!!.getMessage("email.activation.title", null, locale) + val content = templateEngine.process("activationEmail", context) + val subject = messageSource.getMessage("email.activation.title", null, locale) sendEmail(user.email, subject, content, false, true) } @@ -101,11 +96,11 @@ class MailService { context.setVariable(USER, user) context.setVariable( BASE_URL, - managementPortalProperties!!.common.managementPortalBaseUrl + managementPortalProperties.common.managementPortalBaseUrl ) context.setVariable(EXPIRY, Duration.ofSeconds(duration).toHours()) - val content = templateEngine!!.process("creationEmail", context) - val subject = messageSource!!.getMessage("email.activation.title", null, locale) + val content = templateEngine.process("creationEmail", context) + val subject = messageSource.getMessage("email.activation.title", null, locale) sendEmail(user.email, subject, content, false, true) } @@ -122,10 +117,10 @@ class MailService { context.setVariable(USER, user) context.setVariable( BASE_URL, - managementPortalProperties!!.common.managementPortalBaseUrl + managementPortalProperties.common.managementPortalBaseUrl ) - val content = templateEngine!!.process("creationEmail", context) - val subject = messageSource!!.getMessage("email.activation.title", null, locale) + val content = templateEngine.process("creationEmail", context) + val subject = messageSource.getMessage("email.activation.title", null, locale) sendEmail(email, subject, content, false, true) } @@ -141,10 +136,10 @@ class MailService { context.setVariable(USER, user) context.setVariable( BASE_URL, - managementPortalProperties!!.common.managementPortalBaseUrl + managementPortalProperties.common.managementPortalBaseUrl ) - val content = templateEngine!!.process("passwordResetEmail", context) - val subject = messageSource!!.getMessage("email.reset.title", null, locale) + val content = templateEngine.process("passwordResetEmail", context) + val subject = messageSource.getMessage("email.reset.title", null, locale) sendEmail(user.email, subject, content, false, true) } diff --git a/src/main/java/org/radarbase/management/service/OAuthClientService.kt b/src/main/java/org/radarbase/management/service/OAuthClientService.kt index 9268d5d5e..7f09ce8f7 100644 --- a/src/main/java/org/radarbase/management/service/OAuthClientService.kt +++ b/src/main/java/org/radarbase/management/service/OAuthClientService.kt @@ -1,6 +1,5 @@ package org.radarbase.management.service -import org.radarbase.management.domain.Authority import org.radarbase.management.domain.User import org.radarbase.management.service.dto.ClientDetailsDTO import org.radarbase.management.service.mapper.ClientDetailsMapper @@ -131,7 +130,7 @@ class OAuthClientService( */ fun createAccessToken(user: User, clientId: String): OAuth2AccessToken { val authorities = user.authorities!! - .map { a: Authority? -> SimpleGrantedAuthority(a?.name) } + .map { a -> SimpleGrantedAuthority(a) } // lookup the OAuth client // getOAuthClient checks if the id exists val client = findOneByClientId(clientId) diff --git a/src/main/java/org/radarbase/management/service/RoleService.kt b/src/main/java/org/radarbase/management/service/RoleService.kt index 6f167e446..56a9c29e3 100644 --- a/src/main/java/org/radarbase/management/service/RoleService.kt +++ b/src/main/java/org/radarbase/management/service/RoleService.kt @@ -26,7 +26,7 @@ import java.util.function.Consumer */ @Service @Transactional -open class RoleService( +class RoleService( @Autowired private val roleRepository: RoleRepository, @Autowired private val authorityRepository: AuthorityRepository, @Autowired private val organizationRepository: OrganizationRepository, @@ -58,12 +58,12 @@ open class RoleService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(): List { + fun findAll(): List { val optUser = userService.userWithAuthorities ?: // return an empty list if we do not have a current user (e.g. with client credentials // oauth2 grant) return emptyList() - val currentUserAuthorities: List? = optUser.authorities?.map { auth -> auth?.name!! } + val currentUserAuthorities = optUser.authorities return if (currentUserAuthorities?.contains(RoleAuthority.SYS_ADMIN.authority) == true) { log.debug("Request to get all Roles") roleRepository.findAll().filterNotNull().map { role: Role -> roleMapper.roleToRoleDTO(role) }.toList() @@ -85,7 +85,7 @@ open class RoleService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findSuperAdminRoles(): List { + fun findSuperAdminRoles(): List { log.debug("Request to get admin Roles") return roleRepository.findRolesByAuthorityName(RoleAuthority.SYS_ADMIN.authority) .map { role: Role -> roleMapper.roleToRoleDTO(role) }.toList() @@ -98,7 +98,7 @@ open class RoleService( * @return the entity */ @Transactional(readOnly = true) - open fun findOne(id: Long): RoleDTO { + fun findOne(id: Long): RoleDTO { log.debug("Request to get Role : {}", id) val role = roleRepository.findById(id).get() return roleMapper.roleToRoleDTO(role) diff --git a/src/main/java/org/radarbase/management/service/SubjectService.kt b/src/main/java/org/radarbase/management/service/SubjectService.kt index 13ed472a8..f4b79a416 100644 --- a/src/main/java/org/radarbase/management/service/SubjectService.kt +++ b/src/main/java/org/radarbase/management/service/SubjectService.kt @@ -54,7 +54,7 @@ import javax.annotation.Nonnull */ @Service @Transactional -open class SubjectService( +class SubjectService( @Autowired private val subjectMapper: SubjectMapper, @Autowired private val projectMapper: ProjectMapper, @Autowired private val subjectRepository: SubjectRepository, @@ -76,7 +76,7 @@ open class SubjectService( * @return the newly created subject */ @Transactional - open fun createSubject(subjectDto: SubjectDTO): SubjectDTO? { + fun createSubject(subjectDto: SubjectDTO): SubjectDTO? { val subject = subjectMapper.subjectDTOToSubject(subjectDto) ?: throw NullPointerException() //assign roles val user = subject.user @@ -151,7 +151,7 @@ open class SubjectService( * @return the updated subject */ @Transactional - open fun updateSubject(newSubjectDto: SubjectDTO): SubjectDTO? { + fun updateSubject(newSubjectDto: SubjectDTO): SubjectDTO? { if (newSubjectDto.id == null) { return createSubject(newSubjectDto) } @@ -252,7 +252,7 @@ open class SubjectService( * updates meta-data. */ @Transactional - open fun assignOrUpdateSource( + fun assignOrUpdateSource( subject: Subject, sourceType: SourceType, project: Project?, sourceRegistrationDto: MinimalSourceDetailsDTO ): MinimalSourceDetailsDTO { val assignedSource: Source diff --git a/src/main/java/org/radarbase/management/service/dto/UserDTO.kt b/src/main/java/org/radarbase/management/service/dto/UserDTO.kt index 204bf4b4a..55f5bb1df 100644 --- a/src/main/java/org/radarbase/management/service/dto/UserDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/UserDTO.kt @@ -10,12 +10,12 @@ import javax.validation.constraints.Size */ open class UserDTO { var id: Long? = null - lateinit var login: @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") @Size(max = 50, min = 1) String - var firstName: @Size(max = 50) String? = null - var lastName: @Size(max = 50) String? = null - var email: @Email @Size(min = 5, max = 100) String? = null + @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") @Size(max = 50, min = 1) var login: String? = null + @Size(max = 50) var firstName: String? = null + @Size(max = 50) var lastName: String? = null + @Email @Size(min = 5, max = 100) var email: String? = null var isActivated = false - var langKey: @Size(min = 2, max = 5) String? = null + @Size(min = 2, max = 5) var langKey: String? = null var createdBy: String? = null var createdDate: ZonedDateTime? = null var lastModifiedBy: String? = null diff --git a/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt index 8296a076f..757c1ff1f 100644 --- a/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt +++ b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt @@ -4,13 +4,9 @@ import org.mapstruct.DecoratedWith import org.mapstruct.Mapper import org.mapstruct.Mapping import org.mapstruct.MappingConstants -import org.radarbase.management.domain.Authority import org.radarbase.management.domain.User import org.radarbase.management.service.dto.UserDTO import org.radarbase.management.service.mapper.decorator.UserMapperDecorator -import javax.validation.constraints.NotNull -import javax.validation.constraints.Pattern -import javax.validation.constraints.Size /** * Mapper for the entity User and its DTO UserDTO. @@ -40,20 +36,4 @@ interface UserMapper { @Mapping(target = "password", ignore = true) @Mapping(target = "authorities", ignore = true) fun userDTOToUser(userDto: UserDTO?): User? - - /** - * Map a set of [Authority]s to a set of strings that are the authority names. - * @param authorities the authorities to map - * @return the set of strings if authorities is not null, null otherwise - */ - fun map(authorities: Set): @NotNull @Size( - max = 50, - min = 0 - ) @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") Set { - return authorities.mapNotNull { it.name }.toSet() - } - - fun map(authority: Authority): String { - return authority.name!! - } } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt index 163eda4ee..a6cc665ed 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt @@ -8,16 +8,16 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Qualifier abstract class UserMapperDecorator( - @Autowired @Qualifier("delegate") private val delegate: UserMapper? = null, - @Autowired private val revisionService: RevisionService? = null ) : UserMapper { + @Autowired @Qualifier("delegate") private lateinit var delegate: UserMapper + @Autowired private lateinit var revisionService: RevisionService override fun userToUserDTO(user: User?): UserDTO? { if (user == null) { return null } - val dto = delegate!!.userToUserDTO(user) - val auditInfo = revisionService!!.getAuditInfo(user) + val dto = delegate.userToUserDTO(user) + val auditInfo = revisionService.getAuditInfo(user) dto?.createdDate = auditInfo.createdAt dto?.createdBy = auditInfo.createdBy dto?.lastModifiedDate = auditInfo.lastModifiedAt diff --git a/src/main/java/org/radarbase/management/web/rest/AccountResource.kt b/src/main/java/org/radarbase/management/web/rest/AccountResource.kt index d747595c6..399ee5c80 100644 --- a/src/main/java/org/radarbase/management/web/rest/AccountResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/AccountResource.kt @@ -6,8 +6,6 @@ import org.radarbase.auth.authorization.Permission import org.radarbase.auth.token.DataRadarToken import org.radarbase.auth.token.RadarToken import org.radarbase.management.config.ManagementPortalProperties -import org.radarbase.management.domain.User -import org.radarbase.management.security.JwtAuthenticationFilter import org.radarbase.management.security.JwtAuthenticationFilter.Companion.radarToken import org.radarbase.management.security.NotAuthorizedException import org.radarbase.management.service.AuthService @@ -33,7 +31,6 @@ import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController -import java.lang.Exception import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpSession import javax.validation.Valid @@ -53,7 +50,7 @@ class AccountResource( ) { @Autowired(required = false) - private val token: RadarToken? = null + var token: RadarToken? = null /** * GET /activate : activate the registered user. @@ -86,8 +83,8 @@ class AccountResource( if (token == null) { throw NotAuthorizedException("Cannot login without credentials") } - log.debug("Logging in user to session with principal {}", token.username) - session?.radarToken = DataRadarToken(token) + log.debug("Logging in user to session with principal {}", token!!.username) + session?.radarToken = DataRadarToken(token!!) return account } diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.kt b/src/main/java/org/radarbase/management/web/rest/UserResource.kt index 39fdbcc49..268d977a9 100644 --- a/src/main/java/org/radarbase/management/web/rest/UserResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/UserResource.kt @@ -106,7 +106,7 @@ class UserResource( ) ).body(null) // Lowercase the user login before comparing with database - } else if (managedUserVm.login.lowercase().let { userRepository.findOneByLogin(it) } != null) { + } else if (managedUserVm.login?.lowercase().let { userRepository.findOneByLogin(it) } != null) { ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( EntityName.USER, "userexists", "Login already in use" @@ -149,7 +149,7 @@ class UserResource( if (existingUser?.id != managedUserVm.id) { throw BadRequestException("Email already in use", EntityName.USER, "emailexists") } - existingUser = managedUserVm.login.lowercase()?.let { + existingUser = managedUserVm.login?.lowercase().let { userRepository.findOneByLogin( it ) diff --git a/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt b/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt index ca746c255..993433fb4 100644 --- a/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt +++ b/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt @@ -17,7 +17,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -34,22 +33,22 @@ import javax.servlet.ServletException @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser internal class JwtAuthenticationFilterIntTest( + @Autowired private val projectResource: ProjectResource, + @Autowired private val projectService: ProjectService, + @Autowired private val authService: AuthService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - private var rsaRestProjectMockMvc: MockMvc, - private var ecRestProjectMockMvc: MockMvc, - @Autowired private val authService: AuthService ) { + private lateinit var rsaRestProjectMockMvc: MockMvc + private lateinit var ecRestProjectMockMvc: MockMvc @BeforeEach @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val projectResource = ProjectResource - ReflectionTestUtils.setField(projectResource, "projectService", projectService) - ReflectionTestUtils.setField(projectResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) rsaRestProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) diff --git a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt index e414e8506..8ff6ad4f0 100644 --- a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt +++ b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt @@ -2,14 +2,22 @@ package org.radarbase.management.security import org.assertj.core.api.Assertions import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.management.ManagementPortalTestApp +import org.springframework.boot.test.context.SpringBootTest import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension /** * Test class for the SecurityUtils utility class. * * @see SecurityUtils */ +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) +@WithMockUser internal class SecurityUtilsUnitTest { @Test fun testGetCurrentUserLogin() { diff --git a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt index 5e167e471..5a79aae77 100644 --- a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt @@ -34,9 +34,9 @@ internal open class MetaTokenServiceTest( @Autowired private val subjectService: SubjectService, @Autowired private val subjectMapper: SubjectMapper, @Autowired private val oAuthClientService: OAuthClientService, - private var clientDetails: ClientDetails, - private var subjectDto: SubjectDTO ) { + private lateinit var clientDetails: ClientDetails + private lateinit var subjectDto: SubjectDTO @BeforeEach fun setUp() { diff --git a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt index d1200bb68..a3979786c 100644 --- a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt @@ -21,14 +21,14 @@ import java.util.* @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -open class SubjectServiceTest( +class SubjectServiceTest( @Autowired private val subjectService: SubjectService, @Autowired private val projectService: ProjectService ) { @Test @Transactional - open fun testGetPrivacyPolicyUrl() { + fun testGetPrivacyPolicyUrl() { projectService.save(createEntityDTO().project!!) val created = subjectService.createSubject(createEntityDTO()) Assertions.assertNotNull(created!!.id) diff --git a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt index eae6e9804..78fdea8f7 100644 --- a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt +++ b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt @@ -12,7 +12,6 @@ import org.radarbase.management.domain.Authority import org.radarbase.management.domain.Role import org.radarbase.management.domain.User import org.radarbase.management.domain.audit.CustomRevisionEntity -import org.radarbase.management.repository.CustomRevisionEntityRepository import org.radarbase.management.repository.UserRepository import org.radarbase.management.repository.filters.UserFilter import org.radarbase.management.security.Constants @@ -24,7 +23,6 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.data.domain.PageRequest import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.transaction.annotation.Transactional import java.time.Period import java.time.ZonedDateTime @@ -41,34 +39,26 @@ import javax.persistence.EntityManagerFactory @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -open class UserServiceIntTest( +class UserServiceIntTest( @Autowired private val userRepository: UserRepository, @Autowired private val userMapper: UserMapper, @Autowired private val userService: UserService, @Autowired private val revisionService: RevisionService, - @Autowired private val revisionEntityRepository: CustomRevisionEntityRepository, + @Autowired private val entityManagerFactory: EntityManagerFactory, @Autowired private val passwordService: PasswordService, - private var entityManager: EntityManager, - private var userDto: UserDTO? ) { + private lateinit var entityManager: EntityManager + private lateinit var userDto: UserDTO @BeforeEach fun setUp() { entityManager = entityManagerFactory.createEntityManager( entityManagerFactory.properties ) - userDto = userMapper.userToUserDTO(createEntity(passwordService)) - ReflectionTestUtils.setField( - revisionService, "revisionEntityRepository", - revisionEntityRepository - ) - ReflectionTestUtils.setField(revisionService, "entityManager", entityManager) - ReflectionTestUtils.setField(userService, "userMapper", userMapper) - ReflectionTestUtils.setField(userService, "userRepository", userRepository) - + userDto = userMapper.userToUserDTO(createEntity(passwordService))!! - userRepository.delete(userRepository.findOneByLogin(userDto!!.login)!!) + userRepository.delete(userRepository.findOneByLogin(userDto.login)!!) } @Test @@ -85,7 +75,7 @@ open class UserServiceIntTest( @Test @Throws(NotAuthorizedException::class) fun assertThatOnlyActivatedUserCanRequestPasswordReset() { - val user = userService.createUser(userDto!!) + val user = userService.createUser(userDto) val maybeUser = userService.requestPasswordReset( userDto?.email!! ) @@ -96,7 +86,7 @@ open class UserServiceIntTest( @Test @Throws(NotAuthorizedException::class) fun assertThatResetKeyMustNotBeOlderThan24Hours() { - val user = userService.createUser(userDto!!) + val user = userService.createUser(userDto) val daysAgo = ZonedDateTime.now().minusHours(25) val resetKey = passwordService.generateResetKey() user.activated = true @@ -114,7 +104,7 @@ open class UserServiceIntTest( @Test @Throws(NotAuthorizedException::class) fun assertThatResetKeyMustBeValid() { - val user = userService.createUser(userDto!!) + val user = userService.createUser(userDto) val daysAgo = ZonedDateTime.now().minusHours(25) user.activated = true user.resetDate = daysAgo @@ -131,7 +121,7 @@ open class UserServiceIntTest( @Test @Throws(NotAuthorizedException::class) fun assertThatUserCanResetPassword() { - val user = userService.createUser(userDto!!) + val user = userService.createUser(userDto) val oldPassword = user.password val daysAgo = ZonedDateTime.now().minusHours(2) val resetKey = passwordService.generateResetKey() diff --git a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt index 442093261..aaf65363b 100644 --- a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt @@ -5,10 +5,11 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.ArgumentMatchers -import org.mockito.Mock -import org.mockito.Mockito -import org.mockito.MockitoAnnotations +import org.mockito.kotlin.anyVararg +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import org.radarbase.auth.authorization.RoleAuthority import org.radarbase.auth.token.RadarToken import org.radarbase.management.ManagementPortalTestApp @@ -32,7 +33,6 @@ import org.springframework.http.MediaType import org.springframework.mock.web.MockHttpServletRequest import org.springframework.security.core.context.SecurityContextHolder import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -47,44 +47,46 @@ import java.util.* */ @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) -internal open class AccountResourceIntTest( +internal class AccountResourceIntTest( @Autowired private val userRepository: UserRepository, - @Autowired private val userService: UserService, - @Autowired private val userMapper: UserMapper, - @Autowired private val passwordService: PasswordService, - @Mock private val mockUserService: UserService, - @Mock private val mockMailService: MailService, @Autowired private val radarToken: RadarToken, + @Autowired private val userMapper: UserMapper, + @Autowired private val managementPortalProperties: ManagementPortalProperties, @Autowired private val authService: AuthService, - @Autowired private val managementPortalProperties: ManagementPortalProperties + @Autowired private val passwordService: PasswordService ) { + @Autowired private lateinit var mockUserService: UserService + @Autowired private lateinit var mockMailService: MailService private lateinit var restUserMockMvc: MockMvc + @BeforeEach fun setUp() { - MockitoAnnotations.openMocks(this) - Mockito.doNothing().`when`(mockMailService).sendActivationEmail( - ArgumentMatchers.any( - User::class.java - ) - ) + mockUserService = mock() + mockMailService = mock() + + whenever(mockMailService.sendActivationEmail(anyVararg())).doAnswer{ print("tried to send mail") } + SecurityContextHolder.getContext().authentication = RadarAuthentication(radarToken) val accountResource = AccountResource( - userService, + mockUserService, mockMailService, userMapper, managementPortalProperties, authService, - passwordService + passwordService, ) - ReflectionTestUtils.setField(accountResource, "token", radarToken) + accountResource.token = radarToken + val accountUserMockResource = AccountResource( - userService, + mockUserService, mockMailService, userMapper, managementPortalProperties, authService, - passwordService + passwordService, ) + accountUserMockResource.token = radarToken + restUserMockMvc = MockMvcBuilders.standaloneSetup(accountUserMockResource).build() } @@ -106,7 +108,7 @@ internal open class AccountResourceIntTest( @Test @Throws(Exception::class) fun testAuthenticatedUser() { - val token = Mockito.mock(RadarToken::class.java) + val token = mock() val roles: MutableSet = HashSet() val role = Role() val authority = Authority() @@ -120,7 +122,7 @@ internal open class AccountResourceIntTest( user.email = "john.doe@jhipster.com" user.langKey = "en" user.roles = roles - Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(user) + whenever(mockUserService.userWithAuthorities).doReturn(user) restUserMockMvc.perform(MockMvcRequestBuilders.post("/api/login") .with { request: MockHttpServletRequest -> request.radarToken = token @@ -158,7 +160,7 @@ internal open class AccountResourceIntTest( user.email = "john.doe@jhipster.com" user.langKey = "en" user.roles = roles - Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(user) + whenever(mockUserService.userWithAuthorities).doReturn(user) restUserMockMvc.perform( MockMvcRequestBuilders.get("/api/account") .accept(MediaType.APPLICATION_JSON) @@ -180,7 +182,7 @@ internal open class AccountResourceIntTest( @Test @Throws(Exception::class) fun testGetUnknownAccount() { - Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(null) + whenever(mockUserService.userWithAuthorities).doReturn(null) restUserMockMvc.perform( MockMvcRequestBuilders.get("/api/account") .accept(MediaType.APPLICATION_JSON) @@ -191,7 +193,7 @@ internal open class AccountResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun testSaveInvalidLogin() { + fun testSaveInvalidLogin() { val roles: MutableSet = HashSet() val role = RoleDTO() role.authorityName = RoleAuthority.PARTICIPANT.authority diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index 6a3815e9b..0d0a86a7a 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -178,7 +178,7 @@ internal open class OrganizationResourceIntTest( //TODO this is covered by not using a nullable type fun checkGroupNameIsRequired() { val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - orgDto.name = "" + orgDto.name = null restOrganizationMockMvc.perform( MockMvcRequestBuilders.post("/api/organizations") .contentType(TestUtil.APPLICATION_JSON_UTF8) diff --git a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt index ba9b4e2fa..5a66e84f9 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt @@ -7,11 +7,11 @@ import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations import org.radarbase.management.ManagementPortalTestApp +import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.core.env.Environment import org.springframework.http.MediaType import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -24,18 +24,19 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders */ @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) -internal class ProfileInfoResourceIntTest { - @Mock - private val environment: Environment? = null - private var restProfileMockMvc: MockMvc? = null +internal class ProfileInfoResourceIntTest( + @Autowired private val profileInfoResource: ProfileInfoResource +) { + + @Mock private lateinit var environment: Environment + private lateinit var restProfileMockMvc: MockMvc + @BeforeEach fun setUp() { MockitoAnnotations.openMocks(this) val activeProfiles = arrayOf("test") - Mockito.`when`(environment!!.defaultProfiles).thenReturn(activeProfiles) + Mockito.`when`(environment.defaultProfiles).thenReturn(activeProfiles) Mockito.`when`(environment.activeProfiles).thenReturn(activeProfiles) - val profileInfoResource = ProfileInfoResource() - ReflectionTestUtils.setField(profileInfoResource, "env", environment) restProfileMockMvc = MockMvcBuilders .standaloneSetup(profileInfoResource) .build() @@ -44,7 +45,7 @@ internal class ProfileInfoResourceIntTest { @Throws(Exception::class) @Test fun profileInfo() { - restProfileMockMvc!!.perform(MockMvcRequestBuilders.get("/api/profile-info")) + restProfileMockMvc.perform(MockMvcRequestBuilders.get("/api/profile-info")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) } @@ -53,9 +54,9 @@ internal class ProfileInfoResourceIntTest { @Test fun profileInfoWithoutActiveProfiles() { val emptyProfile = arrayOf() - Mockito.`when`(environment!!.defaultProfiles).thenReturn(emptyProfile) + Mockito.`when`(environment.defaultProfiles).thenReturn(emptyProfile) Mockito.`when`(environment.activeProfiles).thenReturn(emptyProfile) - restProfileMockMvc!!.perform(MockMvcRequestBuilders.get("/api/profile-info")) + restProfileMockMvc.perform(MockMvcRequestBuilders.get("/api/profile-info")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt index 6c4ed5696..e3b46d489 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt @@ -45,17 +45,17 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class SourceResourceIntTest( +internal class SourceResourceIntTest( + @Autowired private val sourceResource: SourceResource, + @Autowired private val sourceRepository: SourceRepository, @Autowired private val sourceMapper: SourceMapper, - @Autowired private val sourceService: SourceService, @Autowired private val sourceTypeService: SourceTypeService, @Autowired private val sourceTypeMapper: SourceTypeMapper, @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, @Autowired private val projectRepository: ProjectRepository, - @Autowired private val authService: AuthService ) { private lateinit var restDeviceMockMvc: MockMvc private lateinit var source: Source @@ -65,10 +65,6 @@ internal open class SourceResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val sourceResource = SourceResource - ReflectionTestUtils.setField(sourceResource, "authService", authService) - ReflectionTestUtils.setField(sourceResource, "sourceService", sourceService) - ReflectionTestUtils.setField(sourceResource, "sourceRepository", sourceRepository) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) restDeviceMockMvc = MockMvcBuilders.standaloneSetup(sourceResource) @@ -93,7 +89,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSource() { + fun createSource() { val databaseSizeBeforeCreate = sourceRepository.findAll().size // Create the Source @@ -117,7 +113,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSourceWithExistingId() { + fun createSourceWithExistingId() { val databaseSizeBeforeCreate = sourceRepository.findAll().size // Create the Source with an existing ID @@ -140,7 +136,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkSourcePhysicalIdIsGenerated() { + fun checkSourcePhysicalIdIsGenerated() { val databaseSizeBeforeTest = sourceRepository.findAll().size // set the field null source.sourceId = null @@ -170,7 +166,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkAssignedIsRequired() { + fun checkAssignedIsRequired() { val databaseSizeBeforeTest = sourceRepository.findAll().size // set the field null source.assigned = null @@ -190,7 +186,7 @@ internal open class SourceResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun allSources() { + fun allSources() { // Initialize the database sourceRepository.saveAndFlush(source) @@ -218,7 +214,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun getSource() { + fun getSource() { // Initialize the database sourceRepository.saveAndFlush(source) @@ -234,7 +230,7 @@ internal open class SourceResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun nonExistingSource() { + fun nonExistingSource() { // Get the source restDeviceMockMvc.perform(MockMvcRequestBuilders.get("/api/sources/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) @@ -243,7 +239,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateSource() { + fun updateSource() { // Initialize the database sourceRepository.saveAndFlush(source) val databaseSizeBeforeUpdate = sourceRepository.findAll().size @@ -272,7 +268,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateNonExistingSource() { + fun updateNonExistingSource() { val databaseSizeBeforeUpdate = sourceRepository.findAll().size // Create the Source @@ -294,7 +290,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun deleteSource() { + fun deleteSource() { // Initialize the database sourceRepository.saveAndFlush(source) val databaseSizeBeforeDelete = sourceRepository.findAll().size @@ -314,7 +310,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun equalsVerifier() { + fun equalsVerifier() { org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Source::class.java)) } diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt index 5949207d7..fbd97c356 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt @@ -10,7 +10,6 @@ import org.mockito.MockitoAnnotations import org.radarbase.auth.authentication.OAuthHelper import org.radarbase.auth.authorization.RoleAuthority import org.radarbase.management.ManagementPortalTestApp -import org.radarbase.management.config.ManagementPortalProperties import org.radarbase.management.domain.Authority import org.radarbase.management.domain.Project import org.radarbase.management.domain.Role @@ -35,7 +34,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -53,8 +51,9 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class UserResourceIntTest( - @Autowired private val managementPortalProperties: ManagementPortalProperties, +internal class UserResourceIntTest( + @Autowired private val userResource: UserResource, + @Autowired private val roleRepository: RoleRepository, @Autowired private val userRepository: UserRepository, @Autowired private val mailService: MailService, @@ -75,16 +74,7 @@ internal open class UserResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val userResource = UserResource - ReflectionTestUtils.setField(userResource, "userService", userService) - ReflectionTestUtils.setField(userResource, "mailService", mailService) - ReflectionTestUtils.setField(userResource, "userRepository", userRepository) - ReflectionTestUtils.setField(userResource, "subjectRepository", subjectRepository) - ReflectionTestUtils.setField(userResource, "authService", authService) - ReflectionTestUtils.setField( - userResource, - "managementPortalProperties", managementPortalProperties - ) + val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) restUserMockMvc = MockMvcBuilders.standaloneSetup(userResource) @@ -123,7 +113,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createUser() { + fun createUser() { val databaseSizeBeforeCreate = userRepository.findAll().size // Create the User @@ -153,7 +143,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createUserWithExistingId() { + fun createUserWithExistingId() { val databaseSizeBeforeCreate = userRepository.findAll().size val roles: MutableSet = HashSet() val role = RoleDTO() @@ -178,7 +168,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createUserWithExistingLogin() { + fun createUserWithExistingLogin() { // Initialize the database userRepository.saveAndFlush(user) val databaseSizeBeforeCreate = userRepository.findAll().size @@ -205,7 +195,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createUserWithExistingEmail() { + fun createUserWithExistingEmail() { // Initialize the database userRepository.saveAndFlush(user) val databaseSizeBeforeCreate = userRepository.findAll().size @@ -232,7 +222,7 @@ internal open class UserResourceIntTest( @get:Throws(Exception::class) @get:Transactional @get:Test - open val allUsers: Unit + val allUsers: Unit get() { // Initialize the database val adminRole = Role() @@ -282,7 +272,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun getUser() { + fun getUser() { // Initialize the database userRepository.saveAndFlush(user) @@ -304,7 +294,7 @@ internal open class UserResourceIntTest( @get:Throws(Exception::class) @get:Transactional @get:Test - open val nonExistingUser: Unit + val nonExistingUser: Unit get() { restUserMockMvc.perform(MockMvcRequestBuilders.get("/api/users/unknown")) .andExpect(MockMvcResultMatchers.status().isNotFound()) @@ -313,7 +303,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateUser() { + fun updateUser() { // Initialize the database userRepository.saveAndFlush(user) val databaseSizeBeforeUpdate = userRepository.findAll().size @@ -356,7 +346,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateUserLogin() { + fun updateUserLogin() { // Initialize the database userRepository.saveAndFlush(user) project = ProjectResourceIntTest.createEntity() @@ -400,7 +390,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateUserExistingEmail() { + fun updateUserExistingEmail() { // Initialize the database with 2 users userRepository.saveAndFlush(user) project = ProjectResourceIntTest.createEntity() @@ -442,7 +432,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateUserExistingLogin() { + fun updateUserExistingLogin() { // Initialize the database userRepository.saveAndFlush(user) project = ProjectResourceIntTest.createEntity() @@ -484,7 +474,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun deleteUser() { + fun deleteUser() { // Initialize the database userRepository.saveAndFlush(user) val databaseSizeBeforeDelete = userRepository.findAll().size @@ -503,7 +493,7 @@ internal open class UserResourceIntTest( @Test @Transactional - open fun equalsVerifier() { + fun equalsVerifier() { val userA = User() userA.setLogin("AAA") val userB = User() From 4839dc6986f8c915c9f3eefae27bb371f9371791 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 22:02:07 +0100 Subject: [PATCH 051/158] fix login generation --- .../java/org/radarbase/management/service/dto/SubjectDTO.kt | 4 +--- .../org/radarbase/management/service/SubjectServiceTest.kt | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt b/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt index 337ec975d..d9205e33e 100644 --- a/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt @@ -28,14 +28,12 @@ class SubjectDTO : Serializable { var id: Long? = null private var _login: String? = null var login: String? - get() = { - if (_login == null) { + get() = if (_login == null) { _login = UUID.randomUUID().toString() _login } else { _login } - }.toString() set(value) { _login = value } diff --git a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt index a3979786c..0414c0ecc 100644 --- a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt @@ -30,7 +30,8 @@ class SubjectServiceTest( @Transactional fun testGetPrivacyPolicyUrl() { projectService.save(createEntityDTO().project!!) - val created = subjectService.createSubject(createEntityDTO()) + val c = createEntityDTO() + val created = subjectService.createSubject(c) Assertions.assertNotNull(created!!.id) val subject = subjectService.findOneByLogin(created.login) Assertions.assertNotNull(subject) From 64205989f9e943b36920c5fff387acf4bb5a555c Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 22:46:17 +0100 Subject: [PATCH 052/158] user service tests passing --- .../radarbase/management/domain/Subject.kt | 2 +- .../management/service/UserService.kt | 32 +++++++++++-------- .../management/service/UserServiceIntTest.kt | 6 ++-- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Subject.kt b/src/main/java/org/radarbase/management/domain/Subject.kt index a86d547e7..e20b23dc0 100644 --- a/src/main/java/org/radarbase/management/domain/Subject.kt +++ b/src/main/java/org/radarbase/management/domain/Subject.kt @@ -145,7 +145,7 @@ class Subject( * @return [Project] currently active project of subject. */ get() = user?.roles - ?.first { r -> r.authority?.name == RoleAuthority.PARTICIPANT.authority } + ?.firstOrNull { r -> r.authority?.name == RoleAuthority.PARTICIPANT.authority } ?.project val associatedProject: Project? /** diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt index 7f332f726..b666cb90b 100644 --- a/src/main/java/org/radarbase/management/service/UserService.kt +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -46,7 +46,8 @@ open class UserService @Autowired constructor( private val managementPortalProperties: ManagementPortalProperties, private val authService: AuthService ) { - @Autowired lateinit var roleService: RoleService + @Autowired + lateinit var roleService: RoleService /** * Activate a user with the given activation key. @@ -83,12 +84,14 @@ open class UserService @Autowired constructor( val oneDayAgo = ZonedDateTime.now().minusSeconds( managementPortalProperties.common.activationKeyTimeoutInSeconds.toLong() ) - if (user?.resetDate?.isAfter(oneDayAgo) == true) user.password = passwordService.encode(newPassword) - user?.resetKey = null - user?.resetDate = null - user?.activated = true - - return user + return if (user?.resetDate?.isAfter(oneDayAgo) == true) { + user.password = passwordService.encode(newPassword) + user.resetKey = null + user.resetDate = null + user.activated = true + user + } else + null } /** @@ -118,9 +121,12 @@ open class UserService @Autowired constructor( */ fun requestPasswordReset(mail: String): User? { val user = userRepository.findOneByEmail(mail) - if (user?.activated == true) user.resetKey = passwordService.generateResetKey() - user?.resetDate = ZonedDateTime.now() - return user + return if (user?.activated == true) { + user.resetKey = passwordService.generateResetKey() + user.resetDate = ZonedDateTime.now() + user + } else + null } /** @@ -286,8 +292,7 @@ open class UserService @Autowired constructor( if (user != null) { userRepository.delete(user) log.debug("Deleted User: {}", user) - } - else { + } else { log.warn("could not delete User with login: {}", login) } } @@ -312,8 +317,7 @@ open class UserService @Autowired constructor( open fun changePassword(login: String, password: String) { val user = userRepository.findOneByLogin(login) - if (user != null) - { + if (user != null) { val encryptedPassword = passwordService.encode(password) user.password = encryptedPassword log.debug("Changed password for User: {}", user) diff --git a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt index 78fdea8f7..9353e68ac 100644 --- a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt +++ b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt @@ -40,9 +40,9 @@ import javax.persistence.EntityManagerFactory @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional class UserServiceIntTest( + @Autowired private val userService: UserService, @Autowired private val userRepository: UserRepository, @Autowired private val userMapper: UserMapper, - @Autowired private val userService: UserService, @Autowired private val revisionService: RevisionService, @Autowired private val entityManagerFactory: EntityManagerFactory, @@ -58,7 +58,7 @@ class UserServiceIntTest( ) userDto = userMapper.userToUserDTO(createEntity(passwordService))!! - userRepository.delete(userRepository.findOneByLogin(userDto.login)!!) + userRepository.findOneByLogin(userDto.login)?.let { userRepository.delete(it)} } @Test @@ -77,7 +77,7 @@ class UserServiceIntTest( fun assertThatOnlyActivatedUserCanRequestPasswordReset() { val user = userService.createUser(userDto) val maybeUser = userService.requestPasswordReset( - userDto?.email!! + userDto.email!! ) Assertions.assertThat(maybeUser).isNull() userRepository.delete(user) From 2ff9e894f2f9362e92bec095803cf887a15b0d05 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 23:01:55 +0100 Subject: [PATCH 053/158] autowire all decorator constructor parameters --- .../mapper/decorator/RoleMapperDecorator.kt | 2 +- .../mapper/decorator/SourceMapperDecorator.kt | 4 +-- .../decorator/SubjectMapperDecorator.kt | 8 ++--- .../web/rest/GroupResourceIntTest.kt | 33 +++++++++---------- .../web/rest/OAuthClientsResourceIntTest.kt | 12 +++---- 5 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt index 6ea4a059c..ad28dad59 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt @@ -14,7 +14,7 @@ abstract class RoleMapperDecorator() : RoleMapper { // constructor(roleMapper: RoleMapper, authorityRepository: AuthorityRepository?) : this(roleMapper) @Autowired @Qualifier("delegate") private val delegate: RoleMapper? = null - private var authorityRepository: AuthorityRepository? = null; + @Autowired private var authorityRepository: AuthorityRepository? = null; /** * Overrides standard RoleMapperImpl and loads authority from repository if not specified. diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt index 6a1136560..9ce30725e 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt @@ -19,8 +19,8 @@ import java.util.Map abstract class SourceMapperDecorator() : SourceMapper { @Autowired @Qualifier("delegate") private val delegate: SourceMapper? = null - private val sourceRepository: SourceRepository? = null - private val subjectRepository: SubjectRepository? = null + @Autowired private val sourceRepository: SourceRepository? = null + @Autowired private val subjectRepository: SubjectRepository? = null override fun minimalSourceDTOToSource(minimalSourceDetailsDto: MinimalSourceDetailsDTO): Source? { val source = sourceRepository diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt index 6396b670a..9c8d86acb 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt @@ -22,10 +22,10 @@ import org.springframework.beans.factory.annotation.Qualifier abstract class SubjectMapperDecorator() : SubjectMapper { @Autowired @Qualifier("delegate") private val delegate: SubjectMapper? = null - private var groupRepository: GroupRepository? = null - private var projectRepository: ProjectRepository? = null - private var revisionService: RevisionService? = null - private var projectMapper: ProjectMapper? = null + @Autowired private var groupRepository: GroupRepository? = null + @Autowired private var projectRepository: ProjectRepository? = null + @Autowired private var revisionService: RevisionService? = null + @Autowired private var projectMapper: ProjectMapper? = null override fun subjectToSubjectDTO(subject: Subject?): SubjectDTO? { if (subject == null) { return null diff --git a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt index 113b59f30..1c1a80d1a 100644 --- a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt @@ -18,8 +18,6 @@ import org.radarbase.management.repository.GroupRepository import org.radarbase.management.repository.ProjectRepository import org.radarbase.management.repository.RoleRepository import org.radarbase.management.repository.SubjectRepository -import org.radarbase.management.service.AuthService -import org.radarbase.management.service.GroupService import org.radarbase.management.service.SubjectService import org.radarbase.management.service.dto.SubjectDTO import org.radarbase.management.service.dto.SubjectDTO.SubjectStatus @@ -36,7 +34,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -54,18 +51,19 @@ import javax.servlet.ServletException @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser internal class GroupResourceIntTest( - @Autowired private val groupService: GroupService, + @Autowired private val groupResource: GroupResource, + + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val projectMapper: ProjectMapper, @Autowired private val projectRepository: ProjectRepository, @Autowired private val roleRepository: RoleRepository, @Autowired private val subjectRepository: SubjectRepository, @Autowired private val subjectService: SubjectService, @Autowired private val groupMapper: GroupMapper, - @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, - @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val groupRepository: GroupRepository, - @Autowired private val authService: AuthService + @Autowired private val groupRepository: GroupRepository ) { private lateinit var restGroupMockMvc: MockMvc private lateinit var group: Group @@ -77,18 +75,19 @@ internal class GroupResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val groupResource = GroupResource() - ReflectionTestUtils.setField(groupResource, "groupService", groupService) - ReflectionTestUtils.setField(groupResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) restGroupMockMvc = - MockMvcBuilders.standaloneSetup(groupResource).setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator).setMessageConverters(jacksonMessageConverter) - .addFilter(filter).defaultRequest( + MockMvcBuilders.standaloneSetup(groupResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest( MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken()) - ).build() - project = ProjectResourceIntTest.Companion.createEntity() + ) + .build() + project = ProjectResourceIntTest.createEntity() projectRepository.save(project) group = createEntity() } @@ -166,7 +165,7 @@ internal class GroupResourceIntTest( @Test @Throws(Exception::class) fun createGroupWithExistingNameInDifferentProject() { - val project2: Project = ProjectResourceIntTest.Companion.createEntity().projectName(project.projectName + "2") + val project2: Project = ProjectResourceIntTest.createEntity().projectName(project.projectName + "2") projectRepository.saveAndFlush(project2) val group2 = Group() group2.name = group.name diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt index 7d196a709..41af322f6 100644 --- a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt @@ -42,7 +42,7 @@ import java.util.function.Consumer */ @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalApp::class]) -internal open class OAuthClientsResourceIntTest @Autowired constructor ( +internal class OAuthClientsResourceIntTest @Autowired constructor ( private val clientDetailsService: JdbcClientDetailsService, private val clientDetailsMapper: ClientDetailsMapper, private val subjectService: SubjectService, @@ -111,7 +111,7 @@ internal open class OAuthClientsResourceIntTest @Autowired constructor ( @Test @Transactional @Throws(Exception::class) - open fun createAndFetchOAuthClient() { + fun createAndFetchOAuthClient() { // fetch the created oauth client and check the json result restOauthClientMvc.perform( MockMvcRequestBuilders.get("/api/oauth-clients/" + details.clientId) @@ -205,7 +205,7 @@ internal open class OAuthClientsResourceIntTest @Autowired constructor ( @Test @Transactional @Throws(Exception::class) - open fun dupliceOAuthClient() { + fun dupliceOAuthClient() { restOauthClientMvc.perform( MockMvcRequestBuilders.post("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -217,7 +217,7 @@ internal open class OAuthClientsResourceIntTest @Autowired constructor ( @Test @Transactional @Throws(Exception::class) - open fun updateOAuthClient() { + fun updateOAuthClient() { // update the client details.refreshTokenValiditySeconds = 20L restOauthClientMvc.perform( @@ -240,7 +240,7 @@ internal open class OAuthClientsResourceIntTest @Autowired constructor ( @Test @Transactional @Throws(Exception::class) - open fun deleteOAuthClient() { + fun deleteOAuthClient() { restOauthClientMvc.perform( MockMvcRequestBuilders.delete("/api/oauth-clients/" + details.clientId) .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -254,7 +254,7 @@ internal open class OAuthClientsResourceIntTest @Autowired constructor ( @Test @Transactional @Throws(Exception::class) - open fun cannotModifyProtected() { + fun cannotModifyProtected() { // first change our test client to be protected details.additionalInformation!!["protected"] = "true" restOauthClientMvc.perform( From cb860ec01968af5b0d00fcfea3422fc59650d24b Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 3 Nov 2023 13:22:16 +0100 Subject: [PATCH 054/158] fix failing tests in OAuthClientsResourceIntTest.kt, OrganizationResourceIntTest.kt and SourceDataResourceIntTest.kt --- .../management/domain/Organization.kt | 3 +- .../radarbase/management/domain/Project.kt | 7 +- .../management/service/SourceDataService.kt | 16 +- .../management/service/dto/OrganizationDTO.kt | 1 + .../management/service/dto/SourceDataDTO.kt | 4 +- .../web/rest/OAuthClientsResource.kt | 97 ++++----- .../web/rest/OrganizationResource.kt | 69 ++++--- .../management/web/rest/SourceDataResource.kt | 4 +- .../web/rest/OAuthClientsResourceIntTest.kt | 190 ++++++------------ .../web/rest/OrganizationResourceIntTest.kt | 3 +- .../web/rest/SourceDataResourceIntTest.kt | 32 ++- .../web/rest/SubjectResourceIntTest.kt | 59 ++---- 12 files changed, 191 insertions(+), 294 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Organization.kt b/src/main/java/org/radarbase/management/domain/Organization.kt index 283450a18..d0aa47a37 100644 --- a/src/main/java/org/radarbase/management/domain/Organization.kt +++ b/src/main/java/org/radarbase/management/domain/Organization.kt @@ -48,7 +48,8 @@ class Organization : AbstractEntity() { @JvmField @OneToMany(mappedBy = "organization") - var projects: List? = null + var projects: List = emptyList() + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index 3c142bc38..0713e5f72 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -87,14 +87,14 @@ class Project : AbstractEntity(), Serializable { @Column(name = "end_date") var endDate: ZonedDateTime? = null - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @JsonIgnore @OneToMany(mappedBy = "project", fetch = FetchType.LAZY) @Cascade(CascadeType.ALL) var roles: Set = HashSet() @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @ManyToMany(fetch = FetchType.LAZY) @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) @JoinTable( @@ -105,7 +105,7 @@ class Project : AbstractEntity(), Serializable { var sourceTypes: Set = HashSet() @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @ElementCollection(fetch = FetchType.EAGER) @MapKeyColumn(name = "attribute_key") @Column(name = "attribute_value") @@ -113,7 +113,6 @@ class Project : AbstractEntity(), Serializable { var attributes: MutableMap = HashMap() @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) @NotAudited @OneToMany( mappedBy = "project", diff --git a/src/main/java/org/radarbase/management/service/SourceDataService.kt b/src/main/java/org/radarbase/management/service/SourceDataService.kt index 03ab7afd0..0053f43f4 100644 --- a/src/main/java/org/radarbase/management/service/SourceDataService.kt +++ b/src/main/java/org/radarbase/management/service/SourceDataService.kt @@ -18,7 +18,7 @@ import org.springframework.transaction.annotation.Transactional */ @Service @Transactional -open class SourceDataService( +class SourceDataService( private val sourceDataRepository: SourceDataRepository, private val sourceDataMapper: SourceDataMapper ) { @@ -30,9 +30,9 @@ open class SourceDataService( */ fun save(sourceDataDto: SourceDataDTO?): SourceDataDTO? { log.debug("Request to save SourceData : {}", sourceDataDto) - if (sourceDataDto!!.sourceDataType == null) { + if (sourceDataDto?.sourceDataType == null) { throw BadRequestException( - ErrorConstants.ERR_VALIDATION, EntityName.Companion.SOURCE_DATA, + ErrorConstants.ERR_VALIDATION, EntityName.SOURCE_DATA, "Source Data must contain a type or a topic." ) } @@ -47,7 +47,7 @@ open class SourceDataService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(): List { + fun findAll(): List { log.debug("Request to get all SourceData") return sourceDataRepository.findAll().stream() .map { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } @@ -60,7 +60,7 @@ open class SourceDataService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(pageable: Pageable?): Page { + fun findAll(pageable: Pageable?): Page { log.debug("Request to get all SourceData") return sourceDataRepository.findAll(pageable) .map { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } @@ -73,7 +73,7 @@ open class SourceDataService( * @return the entity */ @Transactional(readOnly = true) - open fun findOne(id: Long): SourceDataDTO? { + fun findOne(id: Long): SourceDataDTO? { log.debug("Request to get SourceData : {}", id) val sourceData = sourceDataRepository.findById(id).get() return sourceDataMapper.sourceDataToSourceDataDTO(sourceData) @@ -86,7 +86,7 @@ open class SourceDataService( * @return the entity */ @Transactional(readOnly = true) - open fun findOneBySourceDataName(sourceDataName: String?): SourceDataDTO? { + fun findOneBySourceDataName(sourceDataName: String?): SourceDataDTO? { log.debug("Request to get SourceData : {}", sourceDataName) return sourceDataRepository.findOneBySourceDataName(sourceDataName) .let { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } @@ -98,7 +98,7 @@ open class SourceDataService( * @param id the id of the entity */ @Transactional - open fun delete(id: Long?) { + fun delete(id: Long?) { log.debug("Request to delete SourceData : {}", id) sourceDataRepository.deleteById(id) } diff --git a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt index 06d2ef19e..7fce03b43 100644 --- a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt @@ -16,6 +16,7 @@ class OrganizationDTO : Serializable { @NotNull var location: String? = null var projects: List = emptyList() + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt index 0bf175343..34a3e7dcf 100644 --- a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt @@ -10,8 +10,10 @@ import java.util.* class SourceDataDTO : Serializable { var id: Long? = null - //Source data type. + /** Source data type. Defaults to the topic of the source data. */ var sourceDataType: String? = null + get() = field ?: topic + var sourceDataName: String? = null //Default data frequency diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt index 600db7e5f..eec2b4409 100644 --- a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt @@ -43,45 +43,31 @@ import javax.validation.Valid */ @RestController @RequestMapping("/api") -class OAuthClientsResource { - @Autowired - private val oAuthClientService: OAuthClientService? = null +class OAuthClientsResource( + @Autowired private val oAuthClientService: OAuthClientService, + @Autowired private val metaTokenService: MetaTokenService, + @Autowired private val clientDetailsMapper: ClientDetailsMapper, + @Autowired private val subjectService: SubjectService, + @Autowired private val userService: UserService, + @Autowired private val eventRepository: AuditEventRepository, + @Autowired private val authService: AuthService +) { - @Autowired - private val metaTokenService: MetaTokenService? = null - - @Autowired - private val clientDetailsMapper: ClientDetailsMapper? = null - - @Autowired - private val subjectService: SubjectService? = null - - @Autowired - private val userService: UserService? = null - - @Autowired - private val eventRepository: AuditEventRepository? = null - - @Autowired - private val authService: AuthService? = null - - @get:Throws(NotAuthorizedException::class) - @get:Timed - @get:GetMapping("/oauth-clients") - val oAuthClients: ResponseEntity> - /** - * GET /api/oauth-clients. - * - * - * Retrieve a list of currently registered OAuth clients. - * - * @return the list of registered clients as a list of [ClientDetailsDTO] - */ - get() { - authService!!.checkPermission(Permission.OAUTHCLIENTS_READ) + @Throws(NotAuthorizedException::class) + @Timed + @GetMapping("/oauth-clients") + /** + * GET /api/oauth-clients. + * + * + * Retrieve a list of currently registered OAuth clients. + * + * @return the list of registered clients as a list of [ClientDetailsDTO] + */ + fun oAuthClients(): ResponseEntity> { + authService.checkPermission(Permission.OAUTHCLIENTS_READ) return ResponseEntity.ok().body( - clientDetailsMapper - ?.clientDetailsToClientDetailsDTO(oAuthClientService!!.findAllOAuthClients()) + clientDetailsMapper.clientDetailsToClientDetailsDTO(oAuthClientService.findAllOAuthClients()) ) } @@ -100,12 +86,13 @@ class OAuthClientsResource { NotAuthorizedException::class ) fun getOAuthClientById(@PathVariable("id") id: String?): ResponseEntity { - authService!!.checkPermission(Permission.OAUTHCLIENTS_READ) + authService.checkPermission(Permission.OAUTHCLIENTS_READ) + + val client = oAuthClientService.findOneByClientId(id) + val clientDTO = clientDetailsMapper.clientDetailsToClientDetailsDTO(client) + // getOAuthClient checks if the id exists - return ResponseEntity.ok().body( - clientDetailsMapper - ?.clientDetailsToClientDetailsDTO(oAuthClientService!!.findOneByClientId(id)) - ) + return ResponseEntity.ok().body(clientDTO) } /** @@ -121,9 +108,9 @@ class OAuthClientsResource { @Timed @Throws(NotAuthorizedException::class) fun updateOAuthClient(@RequestBody @Valid clientDetailsDto: ClientDetailsDTO?): ResponseEntity { - authService!!.checkPermission(Permission.OAUTHCLIENTS_UPDATE) + authService.checkPermission(Permission.OAUTHCLIENTS_UPDATE) // getOAuthClient checks if the id exists - OAuthClientService.checkProtected(oAuthClientService!!.findOneByClientId(clientDetailsDto!!.clientId)) + OAuthClientService.checkProtected(oAuthClientService.findOneByClientId(clientDetailsDto!!.clientId)) val updated = oAuthClientService.updateOauthClient(clientDetailsDto) return ResponseEntity.ok() .headers( @@ -132,7 +119,7 @@ class OAuthClientsResource { clientDetailsDto.clientId ) ) - .body(clientDetailsMapper!!.clientDetailsToClientDetailsDTO(updated)) + .body(clientDetailsMapper.clientDetailsToClientDetailsDTO(updated)) } /** @@ -150,9 +137,9 @@ class OAuthClientsResource { NotAuthorizedException::class ) fun deleteOAuthClient(@PathVariable id: String?): ResponseEntity { - authService!!.checkPermission(Permission.OAUTHCLIENTS_DELETE) + authService.checkPermission(Permission.OAUTHCLIENTS_DELETE) // getOAuthClient checks if the id exists - OAuthClientService.checkProtected(oAuthClientService!!.findOneByClientId(id)) + OAuthClientService.checkProtected(oAuthClientService.findOneByClientId(id)) oAuthClientService.deleteClientDetails(id) return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(EntityName.OAUTH_CLIENT, id)) .build() @@ -172,11 +159,11 @@ class OAuthClientsResource { @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) fun createOAuthClient(@RequestBody clientDetailsDto: @Valid ClientDetailsDTO): ResponseEntity { - authService!!.checkPermission(Permission.OAUTHCLIENTS_CREATE) - val created = oAuthClientService!!.createClientDetail(clientDetailsDto) + authService.checkPermission(Permission.OAUTHCLIENTS_CREATE) + val created = oAuthClientService.createClientDetail(clientDetailsDto) return ResponseEntity.created(ResourceUriService.getUri(clientDetailsDto)) .headers(HeaderUtil.createEntityCreationAlert(EntityName.OAUTH_CLIENT, created.clientId)) - .body(clientDetailsMapper!!.clientDetailsToClientDetailsDTO(created)) + .body(clientDetailsMapper.clientDetailsToClientDetailsDTO(created)) } /** @@ -199,15 +186,15 @@ class OAuthClientsResource { @RequestParam(value = "clientId") clientId: String, @RequestParam(value = "persistent", defaultValue = "false") persistent: Boolean? ): ResponseEntity { - authService!!.checkScope(Permission.SUBJECT_UPDATE) + authService.checkScope(Permission.SUBJECT_UPDATE) val currentUser = - userService!!.userWithAuthorities // We only allow this for actual logged in users for now, not for client_credentials + userService.userWithAuthorities // We only allow this for actual logged in users for now, not for client_credentials ?: throw AccessDeniedException( "You must be a logged in user to access this resource" ) // lookup the subject - val subject = subjectService!!.findOneByLogin(login) + val subject = subjectService.findOneByLogin(login) val projectName: String = subject.activeProject ?.projectName ?: throw NotFoundException( @@ -220,9 +207,9 @@ class OAuthClientsResource { authService.checkPermission( Permission.SUBJECT_UPDATE, { e: EntityDetails -> e.project(projectName).subject(login) }) - val cpi = metaTokenService!!.createMetaToken(subject, clientId, persistent!!) + val cpi = metaTokenService.createMetaToken(subject, clientId, persistent!!) // generate audit event - eventRepository!!.add( + eventRepository.add( AuditEvent( currentUser.login, "PAIR_CLIENT_REQUEST", "client_id=$clientId", "subject_login=$login" diff --git a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt index 7f87ab0cc..ea2acdbe1 100644 --- a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt @@ -36,8 +36,7 @@ import javax.validation.Valid @RestController @RequestMapping("/api") class OrganizationResource( - @Autowired private val organizationService: OrganizationService, - @Autowired private val authService: AuthService + @Autowired private val organizationService: OrganizationService, @Autowired private val authService: AuthService ) { /** @@ -57,39 +56,40 @@ class OrganizationResource( ): ResponseEntity { log.debug("REST request to save Organization : {}", organizationDto) authService.checkPermission(Permission.ORGANIZATION_CREATE) - if (organizationDto!!.id != null) { + if (organizationDto?.id != null) { val msg = "A new organization cannot already have an ID" val headers = createFailureAlert(ENTITY_NAME, "idexists", msg) return ResponseEntity.badRequest().headers(headers).body(null) } - val existingOrg = organizationDto.name?.let { organizationService.findByName(it) } + val existingOrg = organizationDto?.name?.let { organizationService.findByName(it) } if (existingOrg != null) { val msg = "An organization with this name already exists" val headers = createFailureAlert(ENTITY_NAME, "nameexists", msg) return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers).body(null) } - val result = organizationService.save(organizationDto) - return ResponseEntity.created(getUri(result)) - .headers(createEntityCreationAlert(ENTITY_NAME, result.name)) - .body(result) + val result = organizationDto?.let { organizationService.save(it) } + return result?.let { getUri(it) }?.let { + ResponseEntity.created(it).headers(createEntityCreationAlert(ENTITY_NAME, result.name)).body(result) + } + //TODO handle better + ?: ResponseEntity.badRequest().body(null) } - @get:Throws(NotAuthorizedException::class) - @get:Timed - @get:GetMapping("/organizations") - val allOrganizations: ResponseEntity<*> - /** - * GET /organizations : get all the organizations. - * - * @return the ResponseEntity with status 200 (OK) - * and the list of organizations in body - */ - get() { - log.debug("REST request to get Organizations") - authService.checkScope(Permission.ORGANIZATION_READ) - val orgs = organizationService.findAll() - return ResponseEntity(orgs, HttpStatus.OK) - } + /** + * GET /organizations : get all the organizations. + * + * @return the ResponseEntity with status 200 (OK) + * and the list of organizations in body + */ + @Throws(NotAuthorizedException::class) + @Timed + @GetMapping("/organizations") + fun allOrganizations(): ResponseEntity<*> { + log.debug("REST request to get Organizations") + authService.checkScope(Permission.ORGANIZATION_READ) + val orgs = organizationService.findAll() + return ResponseEntity(orgs, HttpStatus.OK) + } /** * PUT /organizations : Updates an existing organization. @@ -112,11 +112,9 @@ class OrganizationResource( return createOrganization(organizationDto) } val name = organizationDto.name - authService.checkPermission(Permission.ORGANIZATION_UPDATE, { (organization): EntityDetails -> organization }) + authService.checkPermission(Permission.ORGANIZATION_UPDATE, { e: EntityDetails -> e.organization(name) }) val result = organizationService.save(organizationDto) - return ResponseEntity.ok() - .headers(createEntityCreationAlert(ENTITY_NAME, result.name)) - .body(result) + return ResponseEntity.ok().headers(createEntityCreationAlert(ENTITY_NAME, result.name)).body(result) } /** @@ -136,13 +134,14 @@ class OrganizationResource( @PathVariable name: String ): ResponseEntity { log.debug("REST request to get Organization : {}", name) - authService.checkPermission(Permission.ORGANIZATION_READ, { (organization): EntityDetails -> organization }) + authService.checkPermission(Permission.ORGANIZATION_READ, { e: EntityDetails -> e.organization(name) }) val org = organizationService.findByName(name) val dto = org ?: throw NotFoundException( - "Organization not found with name $name", - EntityName.ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, - Collections.singletonMap("name", name) - ) + "Organization not found with name $name", + EntityName.ORGANIZATION, + ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, + Collections.singletonMap("name", name) + ) return ResponseEntity.ok(dto) } @@ -164,8 +163,8 @@ class OrganizationResource( @PathVariable name: String? ): ResponseEntity> { log.debug("REST request to get Projects of the Organization : {}", name) - authService.checkPermission(Permission.PROJECT_READ, { (organization): EntityDetails -> organization }) - val projects = organizationService.findAllProjectsByOrganizationName(name!!) + authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.organization(name) }) + val projects = name?.let { organizationService.findAllProjectsByOrganizationName(it) } return ResponseEntity.ok(projects) } diff --git a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt index cbbbc6090..352934caa 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt @@ -55,10 +55,10 @@ class SourceDataResource( @PostMapping("/source-data") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createSourceData(@RequestBody @Valid sourceDataDto: SourceDataDTO?): ResponseEntity { + fun createSourceData(@RequestBody @Valid sourceDataDto: SourceDataDTO): ResponseEntity { log.debug("REST request to save SourceData : {}", sourceDataDto) authService.checkPermission(Permission.SOURCEDATA_CREATE) - if (sourceDataDto!!.id != null) { + if (sourceDataDto.id != null) { return ResponseEntity.badRequest().headers( createFailureAlert( EntityName.SOURCE_DATA, diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt index 41af322f6..513307e69 100644 --- a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt @@ -2,19 +2,15 @@ package org.radarbase.management.web.rest import org.assertj.core.api.Assertions import org.hamcrest.Matchers +import org.hamcrest.Matchers.containsInAnyOrder import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.mockito.MockitoAnnotations import org.radarbase.auth.authentication.OAuthHelper import org.radarbase.management.ManagementPortalApp -import org.radarbase.management.service.AuthService -import org.radarbase.management.service.OAuthClientService import org.radarbase.management.service.OAuthClientServiceTestUtil -import org.radarbase.management.service.SubjectService -import org.radarbase.management.service.UserService import org.radarbase.management.service.dto.ClientDetailsDTO -import org.radarbase.management.service.mapper.ClientDetailsMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest @@ -26,7 +22,6 @@ import org.springframework.security.core.GrantedAuthority import org.springframework.security.oauth2.provider.ClientDetails import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -42,16 +37,12 @@ import java.util.function.Consumer */ @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalApp::class]) -internal class OAuthClientsResourceIntTest @Autowired constructor ( - private val clientDetailsService: JdbcClientDetailsService, - private val clientDetailsMapper: ClientDetailsMapper, - private val subjectService: SubjectService, - private val userService: UserService, - private val oAuthClientService: OAuthClientService, - private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, - private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, - private val exceptionTranslator: ExceptionTranslator, - private val authService: AuthService +internal class OAuthClientsResourceIntTest @Autowired constructor( + @Autowired private val oauthClientsResource: OAuthClientsResource, + @Autowired private val clientDetailsService: JdbcClientDetailsService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, ) { private lateinit var restOauthClientMvc: MockMvc private lateinit var details: ClientDetailsDTO @@ -62,46 +53,22 @@ internal class OAuthClientsResourceIntTest @Autowired constructor ( @Throws(Exception::class) fun setUp() { MockitoAnnotations.openMocks(this) - val oauthClientsResource = OAuthClientsResource() - ReflectionTestUtils.setField( - oauthClientsResource, "clientDetailsMapper", - clientDetailsMapper - ) - ReflectionTestUtils.setField( - oauthClientsResource, "subjectService", - subjectService - ) - ReflectionTestUtils.setField( - oauthClientsResource, "userService", - userService - ) - ReflectionTestUtils.setField( - oauthClientsResource, "authService", - authService - ) - ReflectionTestUtils.setField( - oauthClientsResource, "oAuthClientService", - oAuthClientService - ) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) - restOauthClientMvc = MockMvcBuilders.standaloneSetup(oauthClientsResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) - .build() + restOauthClientMvc = + MockMvcBuilders.standaloneSetup(oauthClientsResource).setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator).setMessageConverters(jacksonMessageConverter) + .addFilter(filter).defaultRequest( + MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken()) + ).build() databaseSizeBeforeCreate = clientDetailsService.listClientDetails().size // Create the OAuth Client details = OAuthClientServiceTestUtil.createClient() restOauthClientMvc.perform( - MockMvcRequestBuilders.post("/api/oauth-clients") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/oauth-clients").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Project in the database clientDetailsList = clientDetailsService.listClientDetails() @@ -113,65 +80,39 @@ internal class OAuthClientsResourceIntTest @Autowired constructor ( @Throws(Exception::class) fun createAndFetchOAuthClient() { // fetch the created oauth client and check the json result - restOauthClientMvc.perform( - MockMvcRequestBuilders.get("/api/oauth-clients/" + details.clientId) - .accept(MediaType.APPLICATION_JSON) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect( - MockMvcResultMatchers.jsonPath("$.clientId").value( - Matchers.equalTo( - details.clientId - ) - ) - ) - .andExpect(MockMvcResultMatchers.jsonPath("$.clientSecret").value(Matchers.nullValue())) - .andExpect( - MockMvcResultMatchers.jsonPath("$.accessTokenValiditySeconds").value( - Matchers.equalTo( - details - .accessTokenValiditySeconds?.toInt() - ) + var ans = restOauthClientMvc.perform( + MockMvcRequestBuilders.get("/api/oauth-clients/" + details.clientId).accept(MediaType.APPLICATION_JSON) + ).andExpect( + MockMvcResultMatchers.status().isOk() + ).andExpect( + MockMvcResultMatchers.jsonPath("$.clientId").value(Matchers.equalTo(details.clientId)) + ).andExpect(MockMvcResultMatchers.jsonPath("$.clientSecret").value(Matchers.nullValue())).andExpect( + MockMvcResultMatchers.jsonPath("$.accessTokenValiditySeconds").value( + Matchers.equalTo( + details.accessTokenValiditySeconds?.toInt() ) ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.refreshTokenValiditySeconds").value( - Matchers.equalTo( - details - .refreshTokenValiditySeconds?.toInt() - ) + ).andExpect( + MockMvcResultMatchers.jsonPath("$.refreshTokenValiditySeconds").value( + Matchers.equalTo( + details.refreshTokenValiditySeconds?.toInt() ) ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.scope").value( - Matchers.containsInAnyOrder( - details.scope?.toTypedArray() - ) - ) + ).andExpect( + MockMvcResultMatchers.jsonPath("$.scope") + .value(containsInAnyOrder(details.scope?.map { Matchers.equalTo(it) })) + ).andExpect(MockMvcResultMatchers.jsonPath("$.autoApproveScopes") + .value(containsInAnyOrder(details.autoApproveScopes?.map { Matchers.equalTo(it) }))) + .andExpect(MockMvcResultMatchers.jsonPath("$.authorizedGrantTypes") + .value(containsInAnyOrder(details.authorizedGrantTypes?.map { Matchers.equalTo(it) }))).andExpect( + MockMvcResultMatchers.jsonPath("$.authorities").value( + containsInAnyOrder(details.authorities?.map { Matchers.equalTo(it) }) ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.autoApproveScopes").value( - Matchers.containsInAnyOrder( - details.autoApproveScopes?.toTypedArray() - ) - ) - ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.authorizedGrantTypes").value( - Matchers.containsInAnyOrder( - details.authorizedGrantTypes?.toTypedArray() - ) - ) - ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.authorities").value( - Matchers.containsInAnyOrder(details.authorities?.toTypedArray()) - ) - ) - val testDetails = clientDetailsList.stream() - .filter { d: ClientDetails -> d.clientId == details.clientId } - .findFirst() - .orElseThrow() + ) + + val testDetails = + clientDetailsList.stream().filter { d: ClientDetails -> d.clientId == details.clientId }.findFirst() + .orElseThrow() Assertions.assertThat(testDetails.clientSecret).startsWith("$2a$10$") Assertions.assertThat(testDetails.scope).containsExactlyInAnyOrderElementsOf( details.scope @@ -205,13 +146,11 @@ internal class OAuthClientsResourceIntTest @Autowired constructor ( @Test @Transactional @Throws(Exception::class) - fun dupliceOAuthClient() { + fun duplicateOAuthClient() { restOauthClientMvc.perform( - MockMvcRequestBuilders.post("/api/oauth-clients") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/oauth-clients").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isConflict()) + ).andExpect(MockMvcResultMatchers.status().isConflict()) } @Test @@ -221,19 +160,16 @@ internal class OAuthClientsResourceIntTest @Autowired constructor ( // update the client details.refreshTokenValiditySeconds = 20L restOauthClientMvc.perform( - MockMvcRequestBuilders.put("/api/oauth-clients") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.put("/api/oauth-clients").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) // fetch the client clientDetailsList = clientDetailsService.listClientDetails() Assertions.assertThat(clientDetailsList).hasSize(databaseSizeBeforeCreate + 1) - val testDetails = clientDetailsList.stream() - .filter { d: ClientDetails -> d.clientId == details.clientId } - .findFirst() - .orElseThrow() + val testDetails = + clientDetailsList.stream().filter { d: ClientDetails -> d.clientId == details.clientId }.findFirst() + .orElseThrow() Assertions.assertThat(testDetails.refreshTokenValiditySeconds).isEqualTo(20) } @@ -243,10 +179,8 @@ internal class OAuthClientsResourceIntTest @Autowired constructor ( fun deleteOAuthClient() { restOauthClientMvc.perform( MockMvcRequestBuilders.delete("/api/oauth-clients/" + details.clientId) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + .contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(details)) + ).andExpect(MockMvcResultMatchers.status().isOk()) val clientDetailsList = clientDetailsService.listClientDetails() Assertions.assertThat(clientDetailsList.size).isEqualTo(databaseSizeBeforeCreate) } @@ -258,27 +192,21 @@ internal class OAuthClientsResourceIntTest @Autowired constructor ( // first change our test client to be protected details.additionalInformation!!["protected"] = "true" restOauthClientMvc.perform( - MockMvcRequestBuilders.put("/api/oauth-clients") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.put("/api/oauth-clients").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) // expect we can not delete it now restOauthClientMvc.perform( MockMvcRequestBuilders.delete("/api/oauth-clients/" + details.clientId) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isForbidden()) + .contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(details)) + ).andExpect(MockMvcResultMatchers.status().isForbidden()) // expect we can not update it now details.refreshTokenValiditySeconds = 20L restOauthClientMvc.perform( - MockMvcRequestBuilders.put("/api/oauth-clients") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.put("/api/oauth-clients").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isForbidden()) + ).andExpect(MockMvcResultMatchers.status().isForbidden()) } } diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index 0d0a86a7a..5abcf00e0 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -15,6 +15,7 @@ import org.radarbase.management.repository.OrganizationRepository import org.radarbase.management.repository.ProjectRepository import org.radarbase.management.service.AuthService import org.radarbase.management.service.OrganizationService +import org.radarbase.management.service.dto.OrganizationDTO import org.radarbase.management.service.mapper.OrganizationMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired @@ -177,7 +178,7 @@ internal open class OrganizationResourceIntTest( @Throws(Exception::class) //TODO this is covered by not using a nullable type fun checkGroupNameIsRequired() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + val orgDto: OrganizationDTO = organizationMapper.organizationToOrganizationDTO(organization) orgDto.name = null restOrganizationMockMvc.perform( MockMvcRequestBuilders.post("/api/organizations") diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt index 87bd2cff6..441ba818c 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt @@ -12,6 +12,7 @@ import org.radarbase.management.domain.SourceData import org.radarbase.management.repository.SourceDataRepository import org.radarbase.management.service.AuthService import org.radarbase.management.service.SourceDataService +import org.radarbase.management.service.dto.SourceDataDTO import org.radarbase.management.service.mapper.SourceDataMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired @@ -22,7 +23,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -39,7 +39,7 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class SourceDataResourceIntTest( +internal class SourceDataResourceIntTest( @Autowired private val sourceDataRepository: SourceDataRepository, @Autowired private val sourceDataMapper: SourceDataMapper, @Autowired private val sourceDataService: SourceDataService, @@ -59,8 +59,6 @@ internal open class SourceDataResourceIntTest( sourceDataService, authService ) - ReflectionTestUtils.setField(sourceDataResource, "sourceDataService", sourceDataService) - ReflectionTestUtils.setField(sourceDataResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) restSourceDataMockMvc = MockMvcBuilders.standaloneSetup(sourceDataResource) @@ -80,7 +78,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSourceData() { + fun createSourceData() { val databaseSizeBeforeCreate = sourceDataRepository.findAll().size // Create the SourceData @@ -109,7 +107,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSourceDataWithExistingId() { + fun createSourceDataWithExistingId() { val databaseSizeBeforeCreate = sourceDataRepository.findAll().size // Create the SourceData with an existing ID @@ -132,13 +130,13 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkSourceDataTypeIsNotRequired() { + fun checkSourceDataTypeIsNotRequired() { val databaseSizeBeforeTest = sourceDataRepository.findAll().size // set the field null sourceData.sourceDataType = null // Create the SourceData, which fails. - val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) + val sourceDataDto: SourceDataDTO? = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) restSourceDataMockMvc.perform( MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -152,7 +150,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkSourceDataTypeOrTopicIsRequired() { + fun checkSourceDataTypeOrTopicIsRequired() { val databaseSizeBeforeTest = sourceDataRepository.findAll().size // set the field null sourceData.sourceDataType = null @@ -173,7 +171,7 @@ internal open class SourceDataResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun allSourceData() { + fun allSourceData() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) @@ -243,7 +241,7 @@ internal open class SourceDataResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun allSourceDataWithPagination() { + fun allSourceDataWithPagination() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) @@ -313,7 +311,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun getSourceData() { + fun getSourceData() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) @@ -340,7 +338,7 @@ internal open class SourceDataResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun nonExistingSourceData() { + fun nonExistingSourceData() { // Get the sourceData restSourceDataMockMvc.perform( MockMvcRequestBuilders.get( @@ -354,7 +352,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateSourceData() { + fun updateSourceData() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) val databaseSizeBeforeUpdate = sourceDataRepository.findAll().size @@ -395,7 +393,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateNonExistingSourceData() { + fun updateNonExistingSourceData() { val databaseSizeBeforeUpdate = sourceDataRepository.findAll().size // Create the SourceData @@ -417,7 +415,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun deleteSourceData() { + fun deleteSourceData() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) val databaseSizeBeforeDelete = sourceDataRepository.findAll().size @@ -440,7 +438,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun equalsVerifier() { + fun equalsVerifier() { org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(SourceData::class.java)) } diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index be76669ca..5189d05f9 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -9,10 +9,7 @@ import org.mockito.MockitoAnnotations import org.radarbase.auth.authentication.OAuthHelper import org.radarbase.management.ManagementPortalTestApp import org.radarbase.management.domain.Subject -import org.radarbase.management.repository.ProjectRepository import org.radarbase.management.repository.SubjectRepository -import org.radarbase.management.service.AuthService -import org.radarbase.management.service.RevisionService import org.radarbase.management.service.SourceService import org.radarbase.management.service.SourceTypeService import org.radarbase.management.service.SubjectService @@ -25,7 +22,6 @@ import org.radarbase.management.service.dto.SubjectDTO import org.radarbase.management.service.mapper.SubjectMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.actuate.audit.AuditEventRepository import org.springframework.boot.test.context.SpringBootTest import org.springframework.data.web.PageableHandlerMethodArgumentResolver import org.springframework.http.MediaType @@ -51,7 +47,8 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class SubjectResourceIntTest( +internal class SubjectResourceIntTest( + @Autowired private val subjectResource: SubjectResource, @Autowired private val subjectRepository: SubjectRepository, @Autowired private val subjectMapper: SubjectMapper, @Autowired private val subjectService: SubjectService, @@ -60,10 +57,6 @@ internal open class SubjectResourceIntTest( @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val projectRepository: ProjectRepository, - @Autowired private val authService: AuthService, - @Autowired private val revisionService: RevisionService, - @Autowired private val eventRepository: AuditEventRepository ) { private lateinit var restSubjectMockMvc: MockMvc @@ -71,17 +64,6 @@ internal open class SubjectResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val subjectResource = SubjectResource( - subjectService, - subjectRepository, - subjectMapper, - projectRepository, - sourceTypeService, - eventRepository, - revisionService, - sourceService, - authService - ) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) @@ -97,7 +79,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSubject() { + fun createSubject() { val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject @@ -120,7 +102,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSubjectWithExistingId() { + fun createSubjectWithExistingId() { // Create a Subject val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeCreate = subjectRepository.findAll().size @@ -139,7 +121,7 @@ internal open class SubjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun allSubjects() { + fun allSubjects() { // Initialize the database val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) @@ -167,7 +149,7 @@ internal open class SubjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun subject() { + fun subject() { // Initialize the database val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) @@ -187,7 +169,7 @@ internal open class SubjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun nonExistingSubject() { + fun nonExistingSubject() { // Get the subject restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) @@ -196,7 +178,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateSubject() { + fun updateSubject() { // Initialize the database var subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeUpdate = subjectRepository.findAll().size @@ -223,7 +205,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateSubjectWithNewProject() { + fun updateSubjectWithNewProject() { // Initialize the database var subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeUpdate = subjectRepository.findAll().size @@ -256,7 +238,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateNonExistingSubject() { + fun updateNonExistingSubject() { val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Create the Subject @@ -276,7 +258,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun deleteSubject() { + fun deleteSubject() { // Initialize the database val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeDelete = subjectRepository.findAll().size @@ -295,14 +277,14 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun equalsVerifier() { + fun equalsVerifier() { org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Subject::class.java)) } @Test @Transactional @Throws(Exception::class) - open fun dynamicSourceRegistrationWithId() { + fun dynamicSourceRegistrationWithId() { val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject @@ -340,7 +322,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun dynamicSourceRegistrationWithoutId() { + fun dynamicSourceRegistrationWithoutId() { val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject @@ -388,7 +370,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun dynamicSourceRegistrationWithoutDynamicRegistrationFlag() { + fun dynamicSourceRegistrationWithoutDynamicRegistrationFlag() { val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject @@ -418,7 +400,7 @@ internal open class SubjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun subjectSources() { + fun subjectSources() { // Initialize the database val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) @@ -444,7 +426,7 @@ internal open class SubjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun subjectSourcesWithQueryParam() { + fun subjectSourcesWithQueryParam() { // Initialize the database val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) @@ -470,7 +452,7 @@ internal open class SubjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun inactiveSubjectSourcesWithQueryParam() { + fun inactiveSubjectSourcesWithQueryParam() { // Initialize the database val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) @@ -534,8 +516,7 @@ internal open class SubjectResourceIntTest( private fun createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration(): MinimalSourceDetailsDTO { val sourceTypes = - sourceTypeService.findAll().stream().filter { it: SourceTypeDTO -> !it.canRegisterDynamically } - .collect(Collectors.toList()) + sourceTypeService.findAll().filter { it: SourceTypeDTO -> !it.canRegisterDynamically } Assertions.assertThat(sourceTypes.size).isPositive() val sourceType = sourceTypes[0] return source.sourceTypeCatalogVersion(sourceType.catalogVersion).sourceTypeModel(sourceType.model) @@ -554,7 +535,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun testDynamicRegistrationAndUpdateSourceAttributes() { + fun testDynamicRegistrationAndUpdateSourceAttributes() { val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject From d3a753510f0911b9ac2c4f1d72bb4a0b83776c97 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 3 Nov 2023 15:56:40 +0100 Subject: [PATCH 055/158] all tests passing --- .../radarbase/management/domain/Subject.kt | 48 +++++----- .../repository/SubjectRepository.kt | 2 +- .../repository/filters/PredicateBuilder.kt | 2 +- .../filters/SubjectSpecification.kt | 26 ++--- .../service/dto/MinimalSourceDetailsDTO.kt | 2 +- .../management/web/rest/SubjectResource.kt | 4 +- .../management/web/rest/UserResource.kt | 4 +- .../web/rest/criteria/SubjectCriteria.kt | 95 ++++++++----------- .../web/rest/util/PaginationUtil.kt | 18 ++-- .../web/rest/SubjectResourceIntTest.kt | 27 +++--- .../web/rest/UserResourceIntTest.kt | 8 -- 11 files changed, 104 insertions(+), 132 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Subject.kt b/src/main/java/org/radarbase/management/domain/Subject.kt index e20b23dc0..1d84aa5c4 100644 --- a/src/main/java/org/radarbase/management/domain/Subject.kt +++ b/src/main/java/org/radarbase/management/domain/Subject.kt @@ -81,7 +81,7 @@ class Subject( var sources: MutableSet = HashSet() @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @ElementCollection(fetch = FetchType.EAGER) @MapKeyColumn(name = "attribute_key") @Column(name = "attribute_value") @@ -114,25 +114,6 @@ class Subject( @JvmField @Column(name = "person_name") var personName: String? = null - fun externalLink(externalLink: String?): Subject { - this.externalLink = externalLink - return this - } - - fun externalId(enternalId: String?): Subject { - externalId = enternalId - return this - } - - fun user(usr: User?): Subject { - user = usr - return this - } - - fun sources(sources: MutableSet): Subject { - this.sources = sources - return this - } val activeProject: Project? /** @@ -147,6 +128,7 @@ class Subject( get() = user?.roles ?.firstOrNull { r -> r.authority?.name == RoleAuthority.PARTICIPANT.authority } ?.project + val associatedProject: Project? /** * Get the active project of a subject, and otherwise the @@ -155,13 +137,33 @@ class Subject( */ get() { val user = user ?: return null - return user.roles?.asIterable() + return user.roles ?.filter { r -> PARTICIPANT_TYPES.contains(r.authority?.name) } - ?.sortedBy { it.authority?.name }?.first() + ?.sortedBy { it.authority?.name }?.firstOrNull() .let { obj: Role? -> obj?.project } } + fun externalLink(externalLink: String?): Subject { + this.externalLink = externalLink + return this + } + + fun externalId(enternalId: String?): Subject { + externalId = enternalId + return this + } + + fun user(usr: User?): Subject { + user = usr + return this + } + + fun sources(sources: MutableSet): Subject { + this.sources = sources + return this + } + override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -194,7 +196,7 @@ class Subject( companion object { private const val serialVersionUID = 1L - private val PARTICIPANT_TYPES = java.util.Set.of( + private val PARTICIPANT_TYPES = mutableSetOf( RoleAuthority.PARTICIPANT.authority, RoleAuthority.INACTIVE_PARTICIPANT.authority ) diff --git a/src/main/java/org/radarbase/management/repository/SubjectRepository.kt b/src/main/java/org/radarbase/management/repository/SubjectRepository.kt index ac0738a87..15c6ee95f 100644 --- a/src/main/java/org/radarbase/management/repository/SubjectRepository.kt +++ b/src/main/java/org/radarbase/management/repository/SubjectRepository.kt @@ -123,6 +123,6 @@ interface SubjectRepository : JpaRepository, RevisionRepository< ) fun findSubjectSourcesBySourceId( @Param("login") login: String?, - @Param("sourceId") sourceId: UUID + @Param("sourceId") sourceId: UUID? ): Source? } diff --git a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt index aa1b5bb75..a35e4d9e0 100644 --- a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt +++ b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt @@ -43,7 +43,7 @@ class PredicateBuilder(val criteriaBuilder: CriteriaBuilder) { fun toAndPredicate(): Predicate? { return if (predicates.size == 1) { predicates[0] - } else if (!predicates.isEmpty()) { + } else if (predicates.isNotEmpty()) { criteriaBuilder.and(*predicates.toTypedArray()) } else { null diff --git a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt index 162cd032d..95c6336dd 100644 --- a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt +++ b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt @@ -15,7 +15,6 @@ import org.radarbase.management.web.rest.errors.ErrorConstants import org.springframework.data.jpa.domain.Specification import java.time.LocalDate import java.time.ZonedDateTime -import java.util.stream.Collectors import javax.persistence.criteria.CriteriaBuilder import javax.persistence.criteria.CriteriaQuery import javax.persistence.criteria.Join @@ -25,6 +24,7 @@ import javax.persistence.criteria.Path import javax.persistence.criteria.Predicate import javax.persistence.criteria.Root + class SubjectSpecification(criteria: SubjectCriteria) : Specification { private val dateOfBirth: CriteriaRange? private val enrollmentDate: CriteriaRange? @@ -44,9 +44,9 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification * @param criteria criteria to use for the specification. */ init { - authority = criteria.authority.stream() - .map { obj: SubjectAuthority? -> obj!!.name } - .collect(Collectors.toSet()) + authority = criteria.authority + .map { obj: SubjectAuthority? -> obj?.name } + .toSet() dateOfBirth = criteria.dateOfBirth enrollmentDate = criteria.enrollmentDate groupId = criteria.groupId @@ -56,22 +56,22 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification projectName = criteria.projectName externalId = criteria.externalId subjectId = criteria.login - sort = criteria.getParsedSort() - if (last != null) { - sortLastValues = sort + sort = criteria.parsedSort + sortLastValues = if (last != null) { + sort ?.map { o: SubjectSortOrder -> getLastValue(o.sortBy) } ?.toList() } else { - sortLastValues = null + null } } override fun toPredicate( - root: Root?, query: CriteriaQuery<*>?, - builder: CriteriaBuilder? + root: Root, query: CriteriaQuery<*>, + builder: CriteriaBuilder ): Predicate? { if (root == null || query == null || builder == null) { - return null + return null; } query.distinct(true) root.alias("subject") @@ -136,7 +136,7 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification root: Root, queryResult: Class<*> ) { // Don't add content for count queries. - if (queryResult == Long::class.java || queryResult == Long::class.javaPrimitiveType) { + if (Long::class.javaObjectType == queryResult) { return } root.fetch("sources", JoinType.LEFT) @@ -173,7 +173,7 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification val rolesJoin = userJoin.join("roles") rolesJoin.alias("roles") predicates.equal({ rolesJoin.get("project").get("projectName") }, projectName) - if (!authority.isEmpty() && authority.size != SubjectAuthority.values().size) { + if (authority.isNotEmpty() && authority.size != SubjectAuthority.values().size) { predicates.add(rolesJoin.get("authority").get("name").`in`(authority)) } } diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt index 56eb19894..cab15b76d 100644 --- a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt @@ -13,7 +13,7 @@ class MinimalSourceDetailsDTO { var sourceTypeCatalogVersion: String? = null var expectedSourceName: String? = null private set - lateinit var sourceId: UUID + var sourceId: UUID? = null var sourceName: String? = null var isAssigned: Boolean? = null var attributes: MutableMap = HashMap() diff --git a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt index 13aede526..7d92ccc7f 100644 --- a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt @@ -37,7 +37,6 @@ import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.actuate.audit.AuditEvent import org.springframework.boot.actuate.audit.AuditEventRepository -import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity @@ -204,8 +203,7 @@ class SubjectResource( val externalId = subjectCriteria.externalId log.debug("ProjectName {} and external {}", projectName, externalId) // if not specified do not include inactive patients - val authoritiesToInclude = subjectCriteria.authority.stream() - .filter { obj: SubjectAuthority? -> Objects.nonNull(obj) } + val authoritiesToInclude = subjectCriteria.authority .map { obj: SubjectAuthority -> obj.name } .toList() return if (projectName != null && externalId != null) { diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.kt b/src/main/java/org/radarbase/management/web/rest/UserResource.kt index 268d977a9..615930039 100644 --- a/src/main/java/org/radarbase/management/web/rest/UserResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/UserResource.kt @@ -146,7 +146,7 @@ class UserResource( log.debug("REST request to update User : {}", managedUserVm) authService.checkPermission(Permission.USER_UPDATE, { e: EntityDetails -> e.user(managedUserVm.login) }) var existingUser = managedUserVm.email?.let { userRepository.findOneByEmail(it) } - if (existingUser?.id != managedUserVm.id) { + if (existingUser != null && existingUser.id != managedUserVm.id) { throw BadRequestException("Email already in use", EntityName.USER, "emailexists") } existingUser = managedUserVm.login?.lowercase().let { @@ -158,7 +158,7 @@ class UserResource( throw BadRequestException("Login already in use", EntityName.USER, "emailexists") } val subject = subjectRepository.findOneWithEagerBySubjectLogin(managedUserVm.login) - if (subject != null && managedUserVm.isActivated && subject.removed!!) { + if (subject != null && managedUserVm.isActivated && subject.removed) { // if the subject is also a user, check if the removed/activated states are valid throw InvalidRequestException( "Subject cannot be the user to request " + "this changes", EntityName.USER, "error.invalidsubjectstate" diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt index 312a35231..29b52dbfb 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt @@ -20,70 +20,51 @@ class SubjectCriteria { var last: SubjectCriteriaLast? = null var page: @Min(0) Int = 0 var size: @Min(1) Int = 20 - private var sort: List? = null + var sort: List? = null var personName: String? = null var projectName: String? = null var externalId: String? = null var login: String? = null @Transient - private var parsedSort: List? = null + var parsedSort: List? = null + get() = field ?: parseSort() + private set - @get:NotNull - val pageable: Pageable - /** Get the criteria paging settings, excluding sorting. */ - get() = PageRequest.of(page, size) - - fun getSort(): List? { - return sort - } - - /** Parse the sort criteria. */ - fun getParsedSort(): List? { - if (parsedSort == null) { - val flatSort = if (sort != null) sort!!.stream() - .flatMap { s: String -> - Arrays.stream(s.split(",".toRegex()).dropLastWhile { it.isEmpty() } - .toTypedArray()) + private fun parseSort(): List { + val flatSort = sort?.flatMap { s: String -> + s.split(",") + }?.toList() ?: listOf() + val parsedSort: MutableList = ArrayList(flatSort.size) + var hasDirection = true + var previous: SubjectSortOrder? = null + for (part in flatSort) { + if (!hasDirection) { + val direction = Sort.Direction.fromOptionalString(part) + if (direction.isPresent) { + previous?.direction = direction.get() + hasDirection = true + continue } - .toList() else listOf() - val parsedSort: MutableList = ArrayList(flatSort.size) - var hasDirection = true - var previous: SubjectSortOrder? = null - for (part in flatSort) { - if (!hasDirection) { - val direction = Sort.Direction.fromOptionalString(part) - if (direction.isPresent) { - previous?.direction = direction.get() - hasDirection = true - continue - } - } else { - hasDirection = false - } - previous = SubjectSortOrder(getSubjectSortBy(part)) - parsedSort.add(previous) + } else { + hasDirection = false } - optimizeSortList(parsedSort) - this.parsedSort = Collections.unmodifiableList(parsedSort).filterNotNull() + previous = SubjectSortOrder(getSubjectSortBy(part)) + parsedSort.add(previous) } + optimizeSortList(parsedSort) + this.parsedSort = Collections.unmodifiableList(parsedSort) return parsedSort } + + @get:NotNull + val pageable: Pageable + /** Get the criteria paging settings, excluding sorting. */ + get() = PageRequest.of(page, size) + override fun toString(): String { - return ("SubjectCriteria{" + "authority=" + authority - + ", dateOfBirth=" + dateOfBirth - + ", enrollmentDate=" + enrollmentDate - + ", groupId='" + groupId + '\'' - + ", humanReadableIdentifier='" + humanReadableIdentifier + '\'' - + ", last=" + last - + ", page=" + page - + ", sort=" + sort - + ", personName='" + personName + '\'' - + ", projectName='" + projectName + '\'' - + ", externalId='" + externalId + '\'' - + ", login='" + login + '\'' - + '}') + return ("SubjectCriteria{" + "authority=" + authority + ", dateOfBirth=" + dateOfBirth + ", enrollmentDate=" + enrollmentDate + ", groupId='" + groupId + '\'' + ", humanReadableIdentifier='" + humanReadableIdentifier + '\'' + ", last=" + last + ", page=" + page + ", sort=" + sort + ", personName='" + personName + '\'' + ", projectName='" + projectName + '\'' + ", externalId='" + externalId + '\'' + ", login='" + login + '\'' + '}') } companion object { @@ -91,7 +72,7 @@ class SubjectCriteria { * Remove duplication and redundancy from sort list and make the result order consistent. * @param sort modifiable ordered sort collection. */ - private fun optimizeSortList(sort: MutableCollection) { + private fun optimizeSortList(sort: MutableCollection) { val seenSortBy: EnumSet? = EnumSet.noneOf( SubjectSortBy::class.java ) @@ -99,10 +80,10 @@ class SubjectCriteria { val iterator = sort.iterator() while (iterator.hasNext()) { val order = iterator.next() - if (hasUnique || seenSortBy?.add(order?.sortBy) != true) { + if (hasUnique || seenSortBy?.add(order.sortBy) != true) { iterator.remove() } - if (order?.sortBy?.isUnique == true) { + if (order.sortBy?.isUnique == true) { hasUnique = true } } @@ -113,12 +94,12 @@ class SubjectCriteria { private fun getSubjectSortBy(param: String): SubjectSortBy { return Arrays.stream(SubjectSortBy.values()) - .filter { s: SubjectSortBy -> s.queryParam.equals(param, ignoreCase = true) } - .findAny() + .filter { s: SubjectSortBy -> s.queryParam.equals(param, ignoreCase = true) }.findAny() .orElseThrow { BadRequestException( - "Cannot convert sort parameter " + param - + " to subject property", EntityName.Companion.SUBJECT, ErrorConstants.ERR_VALIDATION + "Cannot convert sort parameter " + param + " to subject property", + EntityName.Companion.SUBJECT, + ErrorConstants.ERR_VALIDATION ) } } diff --git a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt index bc27cdb8d..667c65afd 100644 --- a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt +++ b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt @@ -100,18 +100,16 @@ object PaginationUtil { ) generateUriParam(builder, "projectName", criteria.projectName) generateUriParam(builder, "login", criteria.login) - if (criteria.authority != null) { - criteria.authority!!.forEach(Consumer { a: SubjectAuthority? -> - generateUriParam( - builder, - "authority", a - ) - }) - } + criteria.authority.forEach(Consumer { a: SubjectAuthority? -> + generateUriParam( + builder, + "authority", a + ) + }) generateUriParam(builder, "size", criteria.size) generateUriParam(builder, "page", criteria.page) - if (criteria.getSort() != null) { - criteria.getParsedSort()!!.forEach(Consumer { order: SubjectSortOrder? -> + if (criteria.sort != null) { + criteria.parsedSort!!.forEach(Consumer { order: SubjectSortOrder? -> generateUriParam( builder, "sort", order?.sortBy?.queryParam + ',' diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index 5189d05f9..0fd79e5af 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -2,6 +2,7 @@ package org.radarbase.management.web.rest import org.assertj.core.api.Assertions import org.hamcrest.Matchers +import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -96,7 +97,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.DEFAULT_ENTERNAL_ID) Assertions.assertThat(testSubject.removed).isEqualTo(SubjectServiceTest.DEFAULT_REMOVED) - org.junit.jupiter.api.Assertions.assertEquals(1, testSubject.user!!.roles!!.size) + Assertions.assertThat(testSubject.user!!.roles!!.size).isEqualTo(1) } @Test @@ -278,7 +279,7 @@ internal class SubjectResourceIntTest( @Transactional @Throws(Exception::class) fun equalsVerifier() { - org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Subject::class.java)) + assertTrue(TestUtil.equalsVerifier(Subject::class.java)) } @Test @@ -299,7 +300,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) val testSubject = subjectList[subjectList.size - 1] val subjectLogin = testSubject.user!!.login - org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) + assertNotNull(subjectLogin) // Create a source description val sourceRegistrationDto = createSourceWithSourceTypeId() @@ -337,7 +338,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) val testSubject = subjectList[subjectList.size - 1] val subjectLogin = testSubject.user!!.login - org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) + assertNotNull(subjectLogin) // Create a source description val sourceRegistrationDto = createSourceWithoutSourceTypeId() @@ -385,7 +386,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) val testSubject = subjectList[subjectList.size - 1] val subjectLogin = testSubject.user!!.login - org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) + assertNotNull(subjectLogin) // Create a source description val sourceRegistrationDto = createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration() @@ -407,9 +408,9 @@ internal class SubjectResourceIntTest( val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) .sourceTypeId(createdSource.sourceType?.id).sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) - org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) - org.junit.jupiter.api.Assertions.assertFalse(createdSubject!!.sources.isEmpty()) + assertFalse(createdSubject!!.sources.isEmpty()) // Get the subject restSubjectMockMvc.perform( @@ -433,10 +434,10 @@ internal class SubjectResourceIntTest( val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) .sourceTypeId(createdSource.sourceType?.id).sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) - org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) TestUtil.commitTransactionAndStartNew() - org.junit.jupiter.api.Assertions.assertNotNull(createdSubject!!.login) + assertNotNull(createdSubject!!.login) // Get the subject restSubjectMockMvc.perform( MockMvcRequestBuilders.get( @@ -459,13 +460,13 @@ internal class SubjectResourceIntTest( val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) .sourceTypeId(createdSource.sourceType?.id).sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) - org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) TestUtil.commitTransactionAndStartNew() createdSubject!!.sources = emptySet() val updatedSubject = subjectService.updateSubject(createdSubject) TestUtil.commitTransactionAndStartNew() - org.junit.jupiter.api.Assertions.assertNotNull(updatedSubject!!.login) + assertNotNull(updatedSubject!!.login) // Get the subject restSubjectMockMvc.perform( MockMvcRequestBuilders.get( @@ -550,7 +551,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) val testSubject = subjectList[subjectList.size - 1] val subjectLogin = testSubject.user!!.login - org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) + assertNotNull(subjectLogin) // Create a source description val sourceRegistrationDto = createSourceWithoutSourceTypeId() @@ -563,7 +564,7 @@ internal class SubjectResourceIntTest( val value = TestUtil.convertJsonStringToObject( result.response.contentAsString, MinimalSourceDetailsDTO::class.java ) as MinimalSourceDetailsDTO - org.junit.jupiter.api.Assertions.assertNotNull(value.sourceName) + assertNotNull(value.sourceName) val attributes: MutableMap = HashMap() attributes["TEST_KEY"] = "Value" attributes["ANDROID_VERSION"] = "something" diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt index fbd97c356..656219368 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt @@ -16,12 +16,8 @@ import org.radarbase.management.domain.Role import org.radarbase.management.domain.User import org.radarbase.management.repository.ProjectRepository import org.radarbase.management.repository.RoleRepository -import org.radarbase.management.repository.SubjectRepository import org.radarbase.management.repository.UserRepository -import org.radarbase.management.service.AuthService -import org.radarbase.management.service.MailService import org.radarbase.management.service.PasswordService -import org.radarbase.management.service.UserService import org.radarbase.management.service.UserServiceIntTest import org.radarbase.management.service.dto.RoleDTO import org.radarbase.management.web.rest.errors.ExceptionTranslator @@ -56,13 +52,9 @@ internal class UserResourceIntTest( @Autowired private val roleRepository: RoleRepository, @Autowired private val userRepository: UserRepository, - @Autowired private val mailService: MailService, - @Autowired private val userService: UserService, @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val subjectRepository: SubjectRepository, - @Autowired private val authService: AuthService, @Autowired private val passwordService: PasswordService, @Autowired private val projectRepository: ProjectRepository, ) { From b667116478a4cb16b5fa73c34637e96d7ef79703 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 3 Nov 2023 16:56:54 +0100 Subject: [PATCH 056/158] all but one e2e test passing --- .../management/security/JwtAuthenticationFilter.kt | 8 ++++---- .../jwt/ManagementPortalJwtAccessTokenConverter.kt | 7 ++++++- src/main/resources/logback-spring.xml | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt index c91c1dd38..abc8748fd 100644 --- a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt +++ b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt @@ -201,14 +201,14 @@ class JwtAuthenticationFilter @JvmOverloads constructor( @get:JvmStatic @set:JvmStatic - var HttpSession.radarToken: RadarToken - get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken + var HttpSession.radarToken: RadarToken? + get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken? set(value) = setAttribute(TOKEN_ATTRIBUTE, value) @get:JvmStatic @set:JvmStatic - var HttpServletRequest.radarToken: RadarToken - get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken + var HttpServletRequest.radarToken: RadarToken? + get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken? set(value) = setAttribute(TOKEN_ATTRIBUTE, value) val Authentication?.isAnonymous: Boolean diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt index c9d173c36..d4e7f2a96 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt @@ -83,7 +83,12 @@ open class ManagementPortalJwtAccessTokenConverter( } override fun extractAccessToken(value: String, map: Map?): OAuth2AccessToken { - return tokenConverter.extractAccessToken(value, map) + var mapCopy = map?.toMutableMap() + + if (mapCopy?.containsKey(AccessTokenConverter.EXP) == true) { + mapCopy[AccessTokenConverter.EXP] = (mapCopy[AccessTokenConverter.EXP] as Int).toLong() + } + return tokenConverter.extractAccessToken(value, mapCopy) } override fun extractAuthentication(map: Map?): OAuth2Authentication { diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index f5e23c7a0..ee0f2914f 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -24,7 +24,7 @@ - + @@ -57,7 +57,7 @@ true - + From c61c793e6a0fa253d901b18ef82dde6048897668 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 3 Nov 2023 17:23:43 +0100 Subject: [PATCH 057/158] stylefixes --- .../service/mapper/ClientDetailsMapper.java | 19 ++++---- .../ClientDetailsMapperDecorator.java | 11 +++-- .../management/web/rest/UserResource.kt | 43 ++++++++++--------- 3 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java index 10c1b1ad8..f8a1ddeaa 100644 --- a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java @@ -23,7 +23,7 @@ */ @Mapper(componentModel = "spring", uses = {BaseClientDetails.class}) @DecoratedWith(ClientDetailsMapperDecorator.class) - public interface ClientDetailsMapper { +public interface ClientDetailsMapper { @Mapping(target = "clientSecret", ignore = true) @Mapping(target = "autoApproveScopes", ignore = true) @@ -37,6 +37,7 @@ public interface ClientDetailsMapper { /** * Map a set of authorities represented as strings to a collection of {@link GrantedAuthority}s. + * * @param authorities the set of authorities to be mapped * @return a collection of {@link GrantedAuthority}s */ @@ -44,13 +45,12 @@ default Collection map(Set authorities) { if (Objects.isNull(authorities)) { return Collections.emptySet(); } - return authorities.stream() - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); + return authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()); } /** * Map a collection of authorities represented as {@link GrantedAuthority}s to a set of strings. + * * @param authorities the collection of {@link GrantedAuthority}s to be mapped * @return the set of strings */ @@ -58,23 +58,20 @@ default Set map(Collection authorities) { if (Objects.isNull(authorities)) { return Collections.emptySet(); } - return authorities.stream() - .map(GrantedAuthority::getAuthority) - .collect(Collectors.toSet()); + return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet()); } /** * Transforms the values in the input map to strings so the result is a * {@link Map}. * @param additionalInformation a {@link Map} to be transformed - * @return a new map with the same keys as the input map, but the values are transformed to - * strings using their {@link Object#toString()} method + * @return a new map with the same keys as the input map, but the values are strings */ default Map map(Map additionalInformation) { if (Objects.isNull(additionalInformation)) { return Collections.emptyMap(); } - return additionalInformation.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString())); + return additionalInformation.entrySet().stream().collect(Collectors.toMap( + Map.Entry::getKey, e -> e.getValue().toString())); } } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java index 119bdea64..a74d11dab 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java @@ -26,9 +26,10 @@ public abstract class ClientDetailsMapperDecorator implements ClientDetailsMappe public ClientDetailsDTO clientDetailsToClientDetailsDTO(ClientDetails details) { ClientDetailsDTO clientDetailsDto = delegate.clientDetailsToClientDetailsDTO(details); // collect the scopes that are auto-approve and set them in our DTO - clientDetailsDto.setAutoApproveScopes(details.getScope().stream() - .filter(details::isAutoApprove) - .collect(Collectors.toSet())); + clientDetailsDto.setAutoApproveScopes(details + .getScope() + .stream() + .filter(details::isAutoApprove).collect(Collectors.toSet())); return clientDetailsDto; } @@ -37,8 +38,6 @@ public List clientDetailsToClientDetailsDTO(List e.user(login) }) return ResponseUtil.wrapOrNotFound( Optional.ofNullable(userService.getUserWithAuthoritiesByLogin(login) - .let { obj: UserDTO? -> obj?.roles })) + .let { obj: UserDTO? -> obj?.roles }) + ) } /** From 7cdd0a4bdf69a1ed5d1bb9a672d82904b3352511 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 6 Nov 2023 12:14:08 +0100 Subject: [PATCH 058/158] name CriteriaRange.iss back to `is` to fix serialization --- cypress.json | 2 +- .../management/config/CacheConfiguration.kt | 6 +++--- .../management/config/DateTimeFormatConfiguration.kt | 2 +- .../management/config/OAuth2LoginUiWebConfig.kt | 5 +---- .../repository/CustomAuditEventRepository.kt | 8 ++++---- .../repository/filters/PredicateBuilder.kt | 4 ++-- .../repository/filters/SubjectSpecification.kt | 9 ++++----- .../management/security/PostgresApprovalStore.kt | 3 +-- .../management/web/rest/criteria/CriteriaRange.kt | 12 ++++++------ .../management/web/rest/criteria/SubjectCriteria.kt | 2 +- .../management/web/rest/util/PaginationUtil.kt | 2 +- 11 files changed, 25 insertions(+), 30 deletions(-) diff --git a/cypress.json b/cypress.json index 599ab3a69..b241d68f3 100644 --- a/cypress.json +++ b/cypress.json @@ -7,5 +7,5 @@ "screenshotsFolder": "src/test/javascript/e2e/cypress/screenshots", "pluginsFile": false, "fixturesFolder": false, - "baseUrl": "http://localhost:9000" + "baseUrl": "http://localhost:8081" } diff --git a/src/main/java/org/radarbase/management/config/CacheConfiguration.kt b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt index dcc1adbeb..e254d296c 100644 --- a/src/main/java/org/radarbase/management/config/CacheConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt @@ -27,7 +27,7 @@ import javax.annotation.PreDestroy @Configuration @EnableCaching @AutoConfigureBefore(value = [WebConfigurer::class, DatabaseConfiguration::class]) -open class CacheConfiguration { +class CacheConfiguration { @Autowired private val env: Environment? = null @PreDestroy @@ -37,7 +37,7 @@ open class CacheConfiguration { } @Bean - open fun HazelcastInstance.cacheManager(): CacheManager { + fun HazelcastInstance.cacheManager(): CacheManager { log.debug("Starting HazelcastCacheManager") return HazelcastCacheManager( this @@ -45,7 +45,7 @@ open class CacheConfiguration { } @Bean - open fun hazelcastConfig(jHipsterProperties: JHipsterProperties): Config { + fun hazelcastConfig(jHipsterProperties: JHipsterProperties): Config { val config = Config() config.setInstanceName("ManagementPortal") val networkConfig = config.networkConfig diff --git a/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt b/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt index 508f46ab1..16292ac6b 100644 --- a/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt @@ -12,7 +12,7 @@ import java.time.temporal.ChronoField import javax.annotation.Nonnull @Configuration -open class DateTimeFormatConfiguration : WebMvcConfigurer { +class DateTimeFormatConfiguration : WebMvcConfigurer { override fun addFormatters(@Nonnull registry: FormatterRegistry) { val registrar = DateTimeFormatterRegistrar() registrar.setUseIsoFormat(true) diff --git a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt index 741e9d882..a41ca544a 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt @@ -10,7 +10,6 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.SessionAttributes import org.springframework.web.servlet.ModelAndView import org.springframework.web.util.HtmlUtils -import java.lang.Boolean import java.text.SimpleDateFormat import java.util.* import java.util.function.Function @@ -18,8 +17,6 @@ import java.util.stream.Collectors import java.util.stream.Stream import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse -import kotlin.Any -import kotlin.String /** * Created by dverbeec on 6/07/2017. @@ -40,7 +37,7 @@ class OAuth2LoginUiWebConfig { fun getLogin(request: HttpServletRequest, response: HttpServletResponse?): ModelAndView { val model = TreeMap() if (request.parameterMap.containsKey("error")) { - model["loginError"] = Boolean.TRUE + model["loginError"] = true } return ModelAndView("login", model) } diff --git a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt index 018ae7ea4..e8b68ced7 100644 --- a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt +++ b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt @@ -25,8 +25,8 @@ open class CustomAuditEventRepository( ) : AuditEventRepository { override fun find(principal: String, after: Instant, type: String): List { - val persistentAuditEvents: Iterable? = persistenceAuditEventRepository - ?.findByPrincipalAndAuditEventDateAfterAndAuditEventType( + val persistentAuditEvents: Iterable = persistenceAuditEventRepository + .findByPrincipalAndAuditEventDateAfterAndAuditEventType( principal, LocalDateTime.from(after), type ) @@ -46,8 +46,8 @@ open class CustomAuditEventRepository( event.timestamp, ZoneId.systemDefault() ) - persistentAuditEvent.data = auditEventConverter!!.convertDataToStrings(event.data) - persistenceAuditEventRepository!!.save(persistentAuditEvent) + persistentAuditEvent.data = auditEventConverter.convertDataToStrings(event.data) + persistenceAuditEventRepository.save(persistentAuditEvent) } if (eventType != null && eventType.endsWith("_FAILURE")) { val typeObj = event.data["type"] diff --git a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt index a35e4d9e0..dcda7bba6 100644 --- a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt +++ b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt @@ -163,8 +163,8 @@ class PredicateBuilder(val criteriaBuilder: CriteriaBuilder) { return } range.validate() - if (range.iss != null) { - add(criteriaBuilder.equal(path, range.iss)) + if (range.`is` != null) { + add(criteriaBuilder.equal(path, range.`is`)) } else { val from = range.from val to = range.to diff --git a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt index 95c6336dd..312073fe2 100644 --- a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt +++ b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt @@ -3,18 +3,17 @@ package org.radarbase.management.repository.filters import org.radarbase.management.domain.Role import org.radarbase.management.domain.Subject import org.radarbase.management.domain.User -import org.radarbase.management.web.rest.criteria.CriteriaRange +import org.radarbase.management.web.rest.criteria.LocalDateCriteriaRange import org.radarbase.management.web.rest.criteria.SubjectAuthority import org.radarbase.management.web.rest.criteria.SubjectCriteria import org.radarbase.management.web.rest.criteria.SubjectCriteriaLast import org.radarbase.management.web.rest.criteria.SubjectSortBy import org.radarbase.management.web.rest.criteria.SubjectSortOrder +import org.radarbase.management.web.rest.criteria.ZonedDateTimeCriteriaRange import org.radarbase.management.web.rest.errors.BadRequestException import org.radarbase.management.web.rest.errors.EntityName import org.radarbase.management.web.rest.errors.ErrorConstants import org.springframework.data.jpa.domain.Specification -import java.time.LocalDate -import java.time.ZonedDateTime import javax.persistence.criteria.CriteriaBuilder import javax.persistence.criteria.CriteriaQuery import javax.persistence.criteria.Join @@ -26,8 +25,8 @@ import javax.persistence.criteria.Root class SubjectSpecification(criteria: SubjectCriteria) : Specification { - private val dateOfBirth: CriteriaRange? - private val enrollmentDate: CriteriaRange? + private val dateOfBirth: LocalDateCriteriaRange? + private val enrollmentDate: ZonedDateTimeCriteriaRange? private val groupId: Long? private val humanReadableIdentifier: String? private val last: SubjectCriteriaLast? diff --git a/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt b/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt index 1a5eadc0c..4ce4e6d1d 100644 --- a/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt +++ b/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt @@ -22,7 +22,6 @@ import org.springframework.jdbc.core.RowMapper import org.springframework.security.oauth2.provider.approval.Approval import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus import org.springframework.security.oauth2.provider.approval.ApprovalStore -import org.springframework.util.Assert import java.sql.PreparedStatement import java.sql.ResultSet import java.sql.SQLException @@ -48,7 +47,7 @@ class PostgresApprovalStore(dataSource: DataSource?) : ApprovalStore { private var handleRevocationsAsExpiry = false init { - Assert.notNull(dataSource) + dataSource ?: throw Exception("Data source not ready") jdbcTemplate = JdbcTemplate(dataSource) } diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt b/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt index 965f32fc0..29ee1b1fc 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt +++ b/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt @@ -9,33 +9,33 @@ package org.radarbase.management.web.rest.criteria open class CriteriaRange?>(var from: T? = null, var to: T? = null, - var iss: T? = null + var `is`: T? = null ) { fun from(): T? { - return if (this.iss == null) from else null + return if (this.`is` == null) from else null } fun to(): T? { - return if (this.iss == null) to else null + return if (this.`is` == null) to else null } val isEmpty: Boolean /** * Whether the criteria range contains any values at all. */ - get() = from == null && to == null && iss == null + get() = from == null && to == null && `is` == null /** * Validate this criteria range whether the from and to ranges are in order. */ fun validate() { - require(!(iss == null && from != null && to != null && from!!.compareTo(to!!) > 0)) { "CriteriaRange must have a from range that is smaller then the to range." } + require(!(`is` == null && from != null && to != null && from!!.compareTo(to!!) > 0)) { "CriteriaRange must have a from range that is smaller then the to range." } } override fun toString(): String { return ("CriteriaRange{" + "from=" + from() + ", to=" + to() - + ", is=" + this.iss + + ", is=" + this.`is` + '}') } } diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt index 29b52dbfb..76b0d6b08 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt @@ -83,7 +83,7 @@ class SubjectCriteria { if (hasUnique || seenSortBy?.add(order.sortBy) != true) { iterator.remove() } - if (order.sortBy?.isUnique == true) { + if (order.sortBy.isUnique) { hasUnique = true } } diff --git a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt index 667c65afd..ad8ca3eb5 100644 --- a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt +++ b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt @@ -133,7 +133,7 @@ object PaginationUtil { if (range == null) { return } - generateUriParam(builder, "$prefix.is", range.iss) + generateUriParam(builder, "$prefix.is", range.`is`) generateUriParam(builder, "$prefix.from", range.from) generateUriParam(builder, "$prefix.to", range.to) } From 74e6b3cfbcc46e2d7063abc26ed19de3296e7cd0 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 6 Nov 2023 13:13:06 +0100 Subject: [PATCH 059/158] fix warnings --- .../ManagementPortalSecurityConfigLoader.kt | 9 ++--- .../config/OAuth2LoginUiWebConfig.kt | 2 +- .../config/OAuth2ServerConfiguration.kt | 2 +- .../org/radarbase/management/domain/Source.kt | 2 +- .../radarbase/management/domain/SourceType.kt | 10 +++--- .../domain/audit/CustomRevisionEntity.kt | 11 +++--- .../domain/audit/CustomRevisionMetadata.kt | 14 +------- .../domain/audit/EntityAuditInfo.kt | 8 ++--- .../domain/support/AutowireHelper.kt | 2 +- .../repository/filters/UserFilter.kt | 10 +++--- ...ManagementPortalJwtAccessTokenConverter.kt | 4 +-- .../ManagementPortalOauthKeyStoreHandler.kt | 2 +- .../management/service/AuditEventService.kt | 2 +- .../management/service/GroupService.kt | 30 +++++++++------- .../management/service/MailService.kt | 10 +++--- .../management/service/RevisionService.kt | 36 +++++++++---------- .../management/service/SourceDataService.kt | 2 +- .../management/service/SubjectService.kt | 8 +++-- .../service/dto/ClientPairInfoDTO.kt | 8 ++--- .../management/service/dto/RoleDTO.kt | 8 ++--- .../management/service/dto/TokenDTO.kt | 8 ++--- .../mapper/decorator/SourceMapperDecorator.kt | 5 ++- .../management/web/rest/AuditResource.kt | 6 ++-- .../management/web/rest/GroupResource.kt | 35 +++++++++--------- .../management/web/rest/SourceDataResource.kt | 2 +- .../web/rest/errors/ExceptionTranslator.kt | 6 +--- .../web/rest/OAuthClientsResourceIntTest.kt | 2 +- .../web/rest/ProjectResourceIntTest.kt | 1 - 28 files changed, 111 insertions(+), 134 deletions(-) diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt b/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt index b12b7ce13..97b96ce68 100644 --- a/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt +++ b/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt @@ -16,15 +16,10 @@ import org.springframework.security.oauth2.provider.NoSuchClientException import org.springframework.security.oauth2.provider.client.BaseClientDetails import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService import org.springframework.stereotype.Component -import java.lang.Boolean import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths import java.util.* -import kotlin.Any -import kotlin.Array -import kotlin.Exception -import kotlin.String /** * Loads security configs such as oauth-clients, and overriding admin password if specified. @@ -80,8 +75,8 @@ class ManagementPortalSecurityConfigLoader { "authorization_code" ) ) - details.setAdditionalInformation(Collections.singletonMap("protected", Boolean.TRUE)) - val allScopes = Arrays.asList(*scopes()) + details.setAdditionalInformation(Collections.singletonMap("protected", true)) + val allScopes = listOf(*scopes()) details.setScope(allScopes) details.setAutoApproveScopes(allScopes) loadOAuthClient(details) diff --git a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt index a41ca544a..625540bbd 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt @@ -88,7 +88,7 @@ class OAuth2LoginUiWebConfig { val oauthError = error errorParams["status"] = String.format("%d", oauthError.httpErrorCode) errorParams["code"] = oauthError.oAuth2ErrorCode - errorParams["message"] = HtmlUtils.htmlEscape(oauthError.message) + errorParams["message"] = oauthError.message?.let { HtmlUtils.htmlEscape(it) } ?: "No error message found" // transform the additionalInfo map to a comma seperated list of key: value pairs if (oauthError.additionalInformation != null) { errorParams["additionalInfo"] = HtmlUtils.htmlEscape( diff --git a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt index ce5b0ecc8..ca7cc87a8 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt @@ -215,7 +215,7 @@ open class OAuth2ServerConfiguration { @Bean open fun approvalStore(): ApprovalStore { - return if (jpaProperties!!.database == Database.POSTGRESQL) { + return if (jpaProperties.database == Database.POSTGRESQL) { PostgresApprovalStore(dataSource) } else { // to have compatibility for other databases including H2 diff --git a/src/main/java/org/radarbase/management/domain/Source.kt b/src/main/java/org/radarbase/management/domain/Source.kt index 15ea02d99..770d5233a 100644 --- a/src/main/java/org/radarbase/management/domain/Source.kt +++ b/src/main/java/org/radarbase/management/domain/Source.kt @@ -79,7 +79,7 @@ class Source : AbstractEntity, Serializable { var project: Project? = null @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @ElementCollection(fetch = FetchType.EAGER) @MapKeyColumn(name = "attribute_key") @Column(name = "attribute_value") diff --git a/src/main/java/org/radarbase/management/domain/SourceType.kt b/src/main/java/org/radarbase/management/domain/SourceType.kt index 5e64cbfd4..baf41d505 100644 --- a/src/main/java/org/radarbase/management/domain/SourceType.kt +++ b/src/main/java/org/radarbase/management/domain/SourceType.kt @@ -79,7 +79,7 @@ class SourceType : AbstractEntity(), Serializable { @NotNull var canRegisterDynamically: Boolean? = false @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @OneToMany(mappedBy = "sourceType", orphanRemoval = true, fetch = FetchType.LAZY) @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) @Cascade( @@ -122,14 +122,14 @@ class SourceType : AbstractEntity(), Serializable { return this } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val sourceType = o as SourceType + val sourceType = other as SourceType return if (sourceType.id == null || id == null) { false } else id == sourceType.id && producer == sourceType.producer && model == sourceType.model && catalogVersion == sourceType.catalogVersion && canRegisterDynamically == sourceType.canRegisterDynamically && sourceTypeScope == sourceType.sourceTypeScope && name == sourceType.name && description == sourceType.description && appProvider == sourceType.appProvider && assessmentType == sourceType.assessmentType diff --git a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt index 0cf7486dc..573d2ea7e 100644 --- a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt +++ b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt @@ -40,7 +40,7 @@ class CustomRevisionEntity : Serializable { var id = 0 @JvmField - @get:Temporal(TemporalType.TIMESTAMP) + @Temporal(TemporalType.TIMESTAMP) @RevisionTimestamp var timestamp: Date? = null @JvmField @@ -55,15 +55,14 @@ class CustomRevisionEntity : Serializable { ) @ModifiedEntityNames var modifiedEntityNames: Set? = null - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o !is CustomRevisionEntity) { + if (other !is CustomRevisionEntity) { return false } - val that = o - return id == that.id && timestamp == that.timestamp && auditor == that.auditor && modifiedEntityNames == that.modifiedEntityNames + return id == other.id && timestamp == other.timestamp && auditor == other.auditor && modifiedEntityNames == other.modifiedEntityNames } override fun hashCode(): Int { diff --git a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt index d23f92927..42853ec24 100644 --- a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt +++ b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt @@ -26,27 +26,15 @@ class CustomRevisionMetadata(entity: CustomRevisionEntity) : RevisionMetadata { return Optional.ofNullable(entity.timestamp).map { ts: Date -> ts.toInstant() } } - override fun getRequiredRevisionInstant(): Instant { - return super.getRequiredRevisionInstant() - } - /* * (non-Javadoc) * @see org.springframework.data.history.RevisionMetadata#getDelegate() */ - override fun getDelegate(): T { + override fun getDelegate(): T { return entity as T } - - override fun getRevisionType(): RevisionMetadata.RevisionType { - return super.getRevisionType() - } } diff --git a/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt b/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt index cd1d2b73d..520ce9675 100644 --- a/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt +++ b/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt @@ -36,14 +36,14 @@ class EntityAuditInfo { return this } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val that = o as EntityAuditInfo + val that = other as EntityAuditInfo return createdAt == that.createdAt && createdBy == that.createdBy && lastModifiedAt == that.lastModifiedAt && lastModifiedBy == that.lastModifiedBy } diff --git a/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt b/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt index defda715f..22efc363c 100644 --- a/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt +++ b/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt @@ -31,7 +31,7 @@ class AutowireHelper private constructor() : ApplicationContextAware { * @param beansToAutowireInClass the beans which have the @Autowire annotation in the specified * {#classToAutowire} */ - fun autowire(classToAutowire: Any?, vararg beansToAutowireInClass: Any?) { + fun autowire(classToAutowire: Any, vararg beansToAutowireInClass: Any?) { for (bean in beansToAutowireInClass) { if (bean == null) { applicationContext!!.autowireCapableBeanFactory.autowireBean(classToAutowire) diff --git a/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt b/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt index 9dc2110b3..4c6979ef4 100644 --- a/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt +++ b/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt @@ -56,7 +56,7 @@ class UserFilter : Specification { if (authoritiesAllowed.isEmpty()) { val builder = predicates.criteriaBuilder // never match - predicates.add(builder!!.isTrue(builder.literal(false))) + predicates.add(builder.isTrue(builder.literal(false))) return } determineScope(predicates, roleJoin, query, authoritiesAllowed, allowNoRole) @@ -109,9 +109,9 @@ class UserFilter : Specification { ) } if (allowNoRoleInScope) { - authorityPredicates!!.isNull(roleJoin.get("id")) + authorityPredicates.isNull(roleJoin.get("id")) } - predicates.add(authorityPredicates!!.toOrPredicate()) + predicates.add(authorityPredicates.toOrPredicate()) } private fun addAllowedAuthorities( @@ -160,8 +160,8 @@ class UserFilter : Specification { subQuery.select(orgRoot.get("id")) val subqueryPredicates = predicates.newBuilder() queryMatch.accept(subqueryPredicates, orgRoot) - subQuery.where(subqueryPredicates!!.toAndPredicate()) - authorityPredicates!!.`in`( + subQuery.where(subqueryPredicates.toAndPredicate()) + authorityPredicates.`in`( roleJoin.get( when (scope) { RoleAuthority.Scope.ORGANIZATION -> "organization" diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt index d4e7f2a96..a57826d0a 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt @@ -168,7 +168,7 @@ open class ManagementPortalJwtAccessTokenConverter( } override fun isRefreshToken(token: OAuth2AccessToken): Boolean { - return token?.additionalInformation?.containsKey(JwtAccessTokenConverter.ACCESS_TOKEN_ID) == true + return token.additionalInformation?.containsKey(JwtAccessTokenConverter.ACCESS_TOKEN_ID) == true } override fun encode(accessToken: OAuth2AccessToken, authentication: OAuth2Authentication): String { @@ -184,7 +184,7 @@ open class ManagementPortalJwtAccessTokenConverter( .forEach { claim: String -> builder.withArrayClaim( claim, - (claims[claim] as Collection?)!!.toTypedArray() + (claims[claim] as Collection).toTypedArray() ) } diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt index 57625c3f4..169ecb656 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt @@ -93,7 +93,7 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( val localStore = KeyStore.getInstance(type) localStore.load(resource.inputStream, password) logger.debug("Loaded JWT key store {}", resource) - if (resource != null && localStore != null) + if (localStore != null) return SimpleImmutableEntry(resource, localStore) } catch (ex: CertificateException) { logger.error("Cannot load JWT key store", ex) diff --git a/src/main/java/org/radarbase/management/service/AuditEventService.kt b/src/main/java/org/radarbase/management/service/AuditEventService.kt index 9881c7195..cc2b4c961 100644 --- a/src/main/java/org/radarbase/management/service/AuditEventService.kt +++ b/src/main/java/org/radarbase/management/service/AuditEventService.kt @@ -23,7 +23,7 @@ class AuditEventService( private val persistenceAuditEventRepository: PersistenceAuditEventRepository, private val auditEventConverter: AuditEventConverter ) { - fun findAll(pageable: Pageable?): Page { + fun findAll(pageable: Pageable): Page { return persistenceAuditEventRepository.findAll(pageable) .map { persistentAuditEvent: PersistentAuditEvent? -> auditEventConverter.convertToAuditEvent( diff --git a/src/main/java/org/radarbase/management/service/GroupService.kt b/src/main/java/org/radarbase/management/service/GroupService.kt index 3cda93ef0..400eb5e10 100644 --- a/src/main/java/org/radarbase/management/service/GroupService.kt +++ b/src/main/java/org/radarbase/management/service/GroupService.kt @@ -29,7 +29,7 @@ import javax.transaction.Transactional * Service to manage project groups. */ @Service -open class GroupService( +class GroupService( @Autowired private val groupRepository: GroupRepository, @Autowired private val projectRepository: ProjectRepository, @Autowired private val subjectRepository: SubjectRepository, @@ -45,7 +45,7 @@ open class GroupService( */ @Throws(NotFoundException::class) @Transactional - open fun getGroup(projectName: String, groupName: String): GroupDTO { + fun getGroup(projectName: String, groupName: String): GroupDTO { return groupMapper.groupToGroupDTOFull( groupRepository.findByProjectNameAndName( projectName, groupName @@ -54,7 +54,7 @@ open class GroupService( EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND ) - )!! + ) } /** @@ -65,7 +65,7 @@ open class GroupService( * @throws NotFoundException if the project or group is not found. */ @Transactional - open fun deleteGroup(projectName: String, groupName: String, unlinkSubjects: Boolean) { + fun deleteGroup(projectName: String, groupName: String, unlinkSubjects: Boolean) { val group = groupRepository.findByProjectNameAndName(projectName, groupName) ?: throw NotFoundException( "Group $groupName not found in project $projectName", EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND ) @@ -88,7 +88,7 @@ open class GroupService( * @throws ConflictException if the group name already exists. */ @Transactional - open fun createGroup(projectName: String, groupDto: GroupDTO): GroupDTO? { + fun createGroup(projectName: String, groupDto: GroupDTO): GroupDTO { val project = projectRepository.findOneWithGroupsByName(projectName) ?: throw NotFoundException( "Project with name $projectName not found", EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND ) @@ -99,19 +99,23 @@ open class GroupService( ErrorConstants.ERR_GROUP_EXISTS ) } - val group = groupMapper.groupDTOToGroup(groupDto) - if (group != null) { + return try { + val group = groupMapper.groupDTOToGroup(groupDto) + group.project = project val groupDtoResult = groupMapper.groupToGroupDTOFull(groupRepository.save(group)) project.groups.add(group) projectRepository.save(project) - return groupDtoResult - } - else { + groupDtoResult + } catch(e: Throwable) { throw NotFoundException( - "Group ${groupDto.name} not found in project $projectName", EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + "Group ${groupDto.name} not found in project $projectName", + EntityName.GROUP, + ErrorConstants.ERR_GROUP_NOT_FOUND ) } + + } /** @@ -135,14 +139,14 @@ open class GroupService( * @throws NotFoundException if the project or group is not found. */ @Transactional - open fun updateGroupSubjects( + fun updateGroupSubjects( projectName: String, groupName: String, subjectsToAdd: List, subjectsToRemove: List ) { - groupRepository ?: throw NullPointerException() + groupRepository val group = groupRepository.findByProjectNameAndName(projectName, groupName) ?: throw NotFoundException( "Group $groupName not found in project $projectName", EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND diff --git a/src/main/java/org/radarbase/management/service/MailService.kt b/src/main/java/org/radarbase/management/service/MailService.kt index 671ec5277..05496e60f 100644 --- a/src/main/java/org/radarbase/management/service/MailService.kt +++ b/src/main/java/org/radarbase/management/service/MailService.kt @@ -54,10 +54,10 @@ class MailService( mimeMessage, isMultipart, StandardCharsets.UTF_8.name() ) - message.setTo(to) + message.setTo(to!!) message.setFrom(managementPortalProperties.mail.from) - message.setSubject(subject) - message.setText(content, isHtml) + message.setSubject(subject!!) + message.setText(content!!, isHtml) javaMailSender.send(mimeMessage) log.debug("Sent email to User '{}'", to) } catch (e: Exception) { @@ -81,7 +81,7 @@ class MailService( ) val content = templateEngine.process("activationEmail", context) val subject = messageSource.getMessage("email.activation.title", null, locale) - sendEmail(user.email, subject, content, false, true) + sendEmail(user.email, subject, content, isMultipart = false, isHtml = true) } /** @@ -101,7 +101,7 @@ class MailService( context.setVariable(EXPIRY, Duration.ofSeconds(duration).toHours()) val content = templateEngine.process("creationEmail", context) val subject = messageSource.getMessage("email.activation.title", null, locale) - sendEmail(user.email, subject, content, false, true) + sendEmail(user.email, subject, content, isMultipart = false, isHtml = true) } /** diff --git a/src/main/java/org/radarbase/management/service/RevisionService.kt b/src/main/java/org/radarbase/management/service/RevisionService.kt index 6676d7827..44940b681 100644 --- a/src/main/java/org/radarbase/management/service/RevisionService.kt +++ b/src/main/java/org/radarbase/management/service/RevisionService.kt @@ -43,7 +43,6 @@ import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentMap import java.util.function.Consumer import java.util.function.Function -import java.util.stream.Collectors import java.util.stream.Stream import javax.persistence.EntityManager import javax.persistence.NoResultException @@ -78,7 +77,7 @@ open class RevisionService(@param:Autowired private val revisionEntityRepository AuditEntity.revisionNumber().minimize() .computeAggregationInInstanceContext() ) - .singleResult as Array + .singleResult as Array<*> val first = firstRevision[1] as CustomRevisionEntity // find last revision of the entity @@ -89,7 +88,7 @@ open class RevisionService(@param:Autowired private val revisionEntityRepository AuditEntity.revisionNumber().maximize() .computeAggregationInInstanceContext() ) - .singleResult as Array + .singleResult as Array<*> val last = lastRevision[1] as CustomRevisionEntity // now populate the result object and return it @@ -177,34 +176,31 @@ open class RevisionService(@param:Autowired private val revisionEntityRepository .add(AuditEntity.id().eq(entity.id)) // add the page sorting information to the query - if (pageable.sort != null) { - pageable.sort - .forEach(Consumer { order: Sort.Order -> - query.addOrder( - if (order.direction.isAscending) AuditEntity.property( - order.property - ).asc() else AuditEntity.property(order.property).desc() - ) - }) - } + pageable.sort + .forEach(Consumer { order: Sort.Order -> + query.addOrder( + if (order.direction.isAscending) AuditEntity.property( + order.property + ).asc() else AuditEntity.property(order.property).desc() + ) + }) // add the page constraints (offset and amount of results) query.setFirstResult(Math.toIntExact(pageable.offset)) .setMaxResults(Math.toIntExact(pageable.pageSize.toLong())) val dtoMapper = getDtoMapper(entity.javaClass) - val resultList = query.resultList as List?> - val revisionDtos = resultList.stream() - .map { objArray: Array? -> + val resultList = query.resultList as List?> + val revisionDtos = resultList + .map { objArray: Array<*>? -> RevisionDTO( Revision.of( CustomRevisionMetadata((objArray!![1] as CustomRevisionEntity)), objArray[0] ), objArray[2] as RevisionType, - dtoMapper.apply(objArray[0]) + objArray[0]?.let { dtoMapper.apply(it) } ) } - .collect(Collectors.toList()) return PageImpl(revisionDtos, pageable, count.toLong()) } @@ -363,7 +359,7 @@ open class RevisionService(@param:Autowired private val revisionEntityRepository }) }) .findAny() - .orElse(Function { obj: Any? -> null }) + .orElse(Function { null }) } private fun beanFromDefinition(beanDefinition: BeanDefinition): Any { @@ -390,7 +386,7 @@ open class RevisionService(@param:Autowired private val revisionEntityRepository } private val auditReader: AuditReader - private get() = AuditReaderFactory.get(entityManager) + get() = AuditReaderFactory.get(entityManager) companion object { private val log = LoggerFactory.getLogger(RevisionService::class.java) diff --git a/src/main/java/org/radarbase/management/service/SourceDataService.kt b/src/main/java/org/radarbase/management/service/SourceDataService.kt index 0053f43f4..ec175844a 100644 --- a/src/main/java/org/radarbase/management/service/SourceDataService.kt +++ b/src/main/java/org/radarbase/management/service/SourceDataService.kt @@ -60,7 +60,7 @@ class SourceDataService( * @return the list of entities */ @Transactional(readOnly = true) - fun findAll(pageable: Pageable?): Page { + fun findAll(pageable: Pageable): Page { log.debug("Request to get all SourceData") return sourceDataRepository.findAll(pageable) .map { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } diff --git a/src/main/java/org/radarbase/management/service/SubjectService.kt b/src/main/java/org/radarbase/management/service/SubjectService.kt index f4b79a416..6c70e8bac 100644 --- a/src/main/java/org/radarbase/management/service/SubjectService.kt +++ b/src/main/java/org/radarbase/management/service/SubjectService.kt @@ -220,8 +220,12 @@ class SubjectService( } private fun ensureSubject(subjectDto: SubjectDTO): Subject { - return subjectRepository.findById(subjectDto.id).orElseThrow { - NotFoundException( + return try { + subjectDto.id?.let { subjectRepository.findById(it).get() } + ?: throw Exception("invalid subject ${subjectDto.login}: No ID") + } + catch(e: Throwable) { + throw NotFoundException( "Subject with ID " + subjectDto.id + " not found.", EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND diff --git a/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt b/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt index 9955c4d22..6db908179 100644 --- a/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt @@ -30,14 +30,14 @@ class ClientPairInfoDTO(baseUrl: URL, tokenName: String, tokenUrl: URL?, timeout timesOutAt = Instant.now().plus(timeout) } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val that = o as ClientPairInfoDTO + val that = other as ClientPairInfoDTO return tokenName == that.tokenName && tokenUrl == that.tokenUrl && baseUrl == that.baseUrl && timeout == that.timeout && timesOutAt == that.timesOutAt } diff --git a/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt b/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt index 73f60a599..25b487219 100644 --- a/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt @@ -21,14 +21,14 @@ class RoleDTO { + '}') } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val roleDto = o as RoleDTO + val roleDto = other as RoleDTO return id == roleDto.id && organizationId == roleDto.organizationId && organizationName == roleDto.organizationName && projectId == roleDto.projectId && projectName == roleDto.projectName && authorityName == roleDto.authorityName } diff --git a/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt b/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt index df681db36..71f4b2a0f 100644 --- a/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt @@ -12,14 +12,14 @@ class TokenDTO * @param privacyPolicyUrl privacyPolicyUrl for this token. */(val refreshToken: String, val baseUrl: URL, val privacyPolicyUrl: URL) { - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val that = o as TokenDTO + val that = other as TokenDTO return refreshToken == that.refreshToken && baseUrl == that.baseUrl && privacyPolicyUrl == that.privacyPolicyUrl } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt index 9ce30725e..c19a17760 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt @@ -11,7 +11,6 @@ import org.radarbase.management.web.rest.errors.ErrorConstants import org.radarbase.management.web.rest.errors.NotFoundException import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Qualifier -import java.util.Map /** * Created by nivethika on 13-6-17. @@ -29,7 +28,7 @@ abstract class SourceMapperDecorator() : SourceMapper { NotFoundException( "Source ID " + minimalSourceDetailsDto.sourceId + " not found", EntityName.Companion.SOURCE, ErrorConstants.ERR_SOURCE_NOT_FOUND, - Map.of("sourceId", minimalSourceDetailsDto.sourceId.toString()) + mapOf(Pair("sourceId", minimalSourceDetailsDto.sourceId.toString())) ) source.assigned = minimalSourceDetailsDto.isAssigned return source @@ -44,7 +43,7 @@ abstract class SourceMapperDecorator() : SourceMapper { NotFoundException( "Source ID " + sourceDto.id + " not found", EntityName.Companion.SOURCE, ErrorConstants.ERR_SOURCE_NOT_FOUND, - Map.of("sourceId", sourceDto.id.toString()) + mapOf(Pair("sourceId", sourceDto.id.toString())) ) } }!! diff --git a/src/main/java/org/radarbase/management/web/rest/AuditResource.kt b/src/main/java/org/radarbase/management/web/rest/AuditResource.kt index 04b80b4c4..cd7ca7502 100644 --- a/src/main/java/org/radarbase/management/web/rest/AuditResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/AuditResource.kt @@ -32,11 +32,11 @@ class AuditResource(private val auditEventService: AuditEventService, private va */ @GetMapping @Throws(NotAuthorizedException::class) - fun getAll(@Parameter pageable: Pageable?): ResponseEntity> { + fun getAll(@Parameter pageable: Pageable): ResponseEntity> { authService.checkPermission(Permission.AUDIT_READ) val page = auditEventService.findAll(pageable) val headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits") - return ResponseEntity(page!!.content, headers, HttpStatus.OK) + return ResponseEntity(page.content, headers, HttpStatus.OK) } /** @@ -58,7 +58,7 @@ class AuditResource(private val auditEventService: AuditEventService, private va val page = auditEventService .findByDates(fromDate.atTime(0, 0), toDate.atTime(23, 59), pageable) val headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits") - return ResponseEntity(page!!.content, headers, HttpStatus.OK) + return ResponseEntity(page.content, headers, HttpStatus.OK) } /** diff --git a/src/main/java/org/radarbase/management/web/rest/GroupResource.kt b/src/main/java/org/radarbase/management/web/rest/GroupResource.kt index dbd0ef7df..709eb1476 100644 --- a/src/main/java/org/radarbase/management/web/rest/GroupResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/GroupResource.kt @@ -36,12 +36,10 @@ import javax.validation.Valid @RestController @RequestMapping("/api/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/groups") -class GroupResource { - @Autowired - private val groupService: GroupService? = null - - @Autowired - private val authService: AuthService? = null +class GroupResource( + @Autowired private val groupService: GroupService, + @Autowired private val authService: AuthService +) { /** * Create group. @@ -56,11 +54,11 @@ class GroupResource { @PathVariable projectName: String?, @RequestBody @Valid groupDto: GroupDTO? ): ResponseEntity { - authService!!.checkPermission(Permission.PROJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) - val groupDtoResult = groupService!!.createGroup(projectName!!, groupDto!!) + authService.checkPermission(Permission.PROJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) + val groupDtoResult = groupService.createGroup(projectName!!, groupDto!!) val location = MvcUriComponentsBuilder.fromController(javaClass) .path("/{groupName}") - .buildAndExpand(projectName, groupDtoResult?.name) + .buildAndExpand(projectName, groupDtoResult.name) .toUri() return ResponseEntity.created(location) .body(groupDtoResult) @@ -77,8 +75,8 @@ class GroupResource { fun listGroups( @PathVariable projectName: String? ): List { - authService!!.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.project(projectName) }) - return groupService!!.listGroups(projectName!!) + authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.project(projectName) }) + return groupService.listGroups(projectName!!) } /** @@ -96,8 +94,8 @@ class GroupResource { @PathVariable projectName: String?, @PathVariable groupName: String? ): GroupDTO { - authService!!.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.project(projectName) }) - return groupService!!.getGroup(projectName!!, groupName!!) + authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.project(projectName) }) + return groupService.getGroup(projectName!!, groupName!!) } /** @@ -115,8 +113,8 @@ class GroupResource { @PathVariable projectName: String?, @PathVariable groupName: String? ): ResponseEntity<*> { - authService!!.checkPermission(Permission.PROJECT_UPDATE, { (_, project): EntityDetails -> project }) - groupService!!.deleteGroup(projectName!!, groupName!!, unlinkSubjects!!) + authService.checkPermission(Permission.PROJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) + groupService.deleteGroup(projectName!!, groupName!!, unlinkSubjects!!) return ResponseEntity.noContent().build() } @@ -140,12 +138,11 @@ class GroupResource { // so it would make sense to check permissions per subject, // but I assume that only those who are authorized to perform project-wide actions // should be allowed to use this endpoint - authService!!.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) + authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) val addedItems = ArrayList() val removedItems = ArrayList() for (operation in patchOperations) { - val opCode = operation.op - when (opCode) { + when (val opCode = operation.op) { "add" -> operation.value?.let { addedItems.addAll(it) } "remove" -> operation.value?.let { removedItems.addAll(it) } else -> throw BadRequestException( @@ -154,7 +151,7 @@ class GroupResource { ) } } - groupService!!.updateGroupSubjects(projectName!!, groupName!!, addedItems.filterNotNull(), removedItems.filterNotNull()) + groupService.updateGroupSubjects(projectName!!, groupName!!, addedItems.filterNotNull(), removedItems.filterNotNull()) return ResponseEntity.noContent().build() } } diff --git a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt index 352934caa..f982fec0e 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt @@ -114,7 +114,7 @@ class SourceDataResource( @Timed @Throws(NotAuthorizedException::class) fun getAllSourceData( - @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable? + @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable ): ResponseEntity> { log.debug("REST request to get all SourceData") authService.checkScope(Permission.SOURCEDATA_READ) diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt b/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt index c405793cf..76b2b392c 100644 --- a/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt +++ b/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt @@ -1,9 +1,6 @@ package org.radarbase.management.web.rest.errors import org.radarbase.management.security.NotAuthorizedException -import org.radarbase.management.web.rest.errors.InvalidStateException -import org.radarbase.management.web.rest.errors.RadarWebApplicationException -import org.radarbase.management.web.rest.errors.RequestGoneException import org.radarbase.management.web.rest.util.HeaderUtil import org.slf4j.LoggerFactory import org.springframework.core.annotation.AnnotationUtils @@ -48,7 +45,6 @@ class ExceptionTranslator { @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody fun processValidationError(ex: TransactionSystemException): ErrorVM { - // TODO: this is the top level exception that is thrown when e.g. a // ConstraintValidationException occurs. Need to investigate what other exceptions result // in this one and probably add a check for it. return ErrorVM(ErrorConstants.ERR_VALIDATION, ex.message) @@ -69,7 +65,7 @@ class ExceptionTranslator { for (fieldError in fieldErrors) { dto.add( fieldError.objectName, fieldError.field, - fieldError.code + ": " + fieldError.defaultMessage + (fieldError.code?.plus(": ") ?: "undefined.error.code") + fieldError.defaultMessage ) } return dto diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt index 513307e69..cb12ebb4c 100644 --- a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt @@ -80,7 +80,7 @@ internal class OAuthClientsResourceIntTest @Autowired constructor( @Throws(Exception::class) fun createAndFetchOAuthClient() { // fetch the created oauth client and check the json result - var ans = restOauthClientMvc.perform( + restOauthClientMvc.perform( MockMvcRequestBuilders.get("/api/oauth-clients/" + details.clientId).accept(MediaType.APPLICATION_JSON) ).andExpect( MockMvcResultMatchers.status().isOk() diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt index 230042584..e5e230044 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt @@ -146,7 +146,6 @@ internal open class ProjectResourceIntTest( // Create the Project, which fails. val projectDto: ProjectDTO? = projectMapper.projectToProjectDTO(project) - val projectt: Project? = projectMapper.projectDTOToProject(projectDto) restProjectMockMvc.perform( MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) From 86f4c4537c3956b3834fb178086abc0e84d0d02b Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 6 Nov 2023 15:20:12 +0100 Subject: [PATCH 060/158] fix gatling tests project: organization was not provided as valid json Sourcetype: catalogversion was incorrectly set during save subject: incomplete projectDTO was provided (no name). this could be resolved by looking up the name if an id is provided. --- src/gatling/scala/ProjectGatlingTest.scala | 2 +- src/gatling/scala/SubjectGatlingTest.scala | 3 +- .../management/service/ProjectService.kt | 12 +++---- .../management/service/ResourceUriService.kt | 2 +- .../management/service/SourceTypeService.kt | 32 ++++++++++++------- .../management/web/rest/ProjectResource.kt | 6 ++-- .../management/web/rest/SourceTypeResource.kt | 2 +- .../management/web/rest/SubjectResource.kt | 5 ++- 8 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/gatling/scala/ProjectGatlingTest.scala b/src/gatling/scala/ProjectGatlingTest.scala index fde7b673d..0f8211fe9 100644 --- a/src/gatling/scala/ProjectGatlingTest.scala +++ b/src/gatling/scala/ProjectGatlingTest.scala @@ -44,7 +44,7 @@ class ProjectGatlingTest extends ManagementPortalSimulation { .exec(http("Create new project") .post("/api/projects") .headers(headers_http_authenticated) - .body(StringBody("""{"id":null, "projectName":"PROJECT-${randstring}", "description":"SAMPLE_TEXT", "organization":"SAMPLE_TEXT", "location":"SAMPLE_TEXT", "startDate":"2020-01-01T00:00:00.000Z", "projectStatus":null, "endDate":"2020-01-01T00:00:00.000Z", "projectAdmin":null}""")).asJson + .body(StringBody("""{"id":null, "projectName":"PROJECT-${randstring}", "description":"SAMPLE_TEXT", "organizationName":"SAMPLE_TEXT", "location":"SAMPLE_TEXT", "startDate":"2020-01-01T00:00:00.000Z", "projectStatus":null, "endDate":"2020-01-01T00:00:00.000Z", "projectAdmin":null}""")).asJson .check(status.is(201)) .check(headerRegex("Location", "(.*)").saveAs("new_project_url"))).exitHereIfFailed .pause(5) diff --git a/src/gatling/scala/SubjectGatlingTest.scala b/src/gatling/scala/SubjectGatlingTest.scala index baea1fdf3..bba54636e 100644 --- a/src/gatling/scala/SubjectGatlingTest.scala +++ b/src/gatling/scala/SubjectGatlingTest.scala @@ -38,6 +38,7 @@ class SubjectGatlingTest extends ManagementPortalSimulation { .get("/api/projects") .headers(headers_http_authenticated) .check(status.is(200)) + .check(jsonPath("$[0].projectName").saveAs("project_name")) .check(jsonPath("$[0].id").saveAs("project_id"))).exitHereIfFailed .repeat(2) { exec(http("Get all subjects") @@ -49,7 +50,7 @@ class SubjectGatlingTest extends ManagementPortalSimulation { .exec(http("Create new subject") .post("/api/subjects") .headers(headers_http_authenticated) - .body(StringBody("""{"id":null, "externalLink":"SAMPLE_TEXT", "enternalId":"${randstring}", "project": {"id": "${project_id}"}}""")).asJson + .body(StringBody("""{"id":null, "externalLink":"SAMPLE_TEXT", "externalId":"${randstring}", "project": {"id": "${project_id}", "projectName": "${project_name}"}}""")).asJson .check(status.is(201)) .check(headerRegex("Location", "(.*)").saveAs("new_subject_url"))).exitHereIfFailed .pause(5) diff --git a/src/main/java/org/radarbase/management/service/ProjectService.kt b/src/main/java/org/radarbase/management/service/ProjectService.kt index adaaaa547..0975c75bc 100644 --- a/src/main/java/org/radarbase/management/service/ProjectService.kt +++ b/src/main/java/org/radarbase/management/service/ProjectService.kt @@ -24,7 +24,7 @@ import java.util.* */ @Service @Transactional -open class ProjectService( +class ProjectService( @Autowired private val projectRepository: ProjectRepository, @Autowired private val projectMapper: ProjectMapper, @Autowired private val sourceTypeMapper: SourceTypeMapper, @@ -50,7 +50,7 @@ open class ProjectService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(fetchMinimal: Boolean, pageable: Pageable): Page<*> { + fun findAll(fetchMinimal: Boolean, pageable: Pageable): Page<*> { val projects: Page val referents = authService.referentsByScope(Permission.PROJECT_READ) projects = if (referents.isEmpty()) { @@ -76,7 +76,7 @@ open class ProjectService( * @return the entity */ @Transactional(readOnly = true) - open fun findOne(id: Long): ProjectDTO? { + fun findOne(id: Long): ProjectDTO? { log.debug("Request to get Project : {}", id) val project = projectRepository.findOneWithEagerRelationships(id) ?: throw NotFoundException( @@ -96,7 +96,7 @@ open class ProjectService( * @return the entity */ @Transactional(readOnly = true) - open fun findOneByName(name: String): ProjectDTO { + fun findOneByName(name: String): ProjectDTO { log.debug("Request to get Project by name: {}", name) val project = projectRepository.findOneWithEagerRelationshipsByName(name) ?: throw NotFoundException( @@ -115,10 +115,10 @@ open class ProjectService( * @return the list of source-types assigned. */ @Transactional(readOnly = true) - open fun findSourceTypesByProjectId(id: Long): List { + fun findSourceTypesByProjectId(id: Long): List { log.debug("Request to get Project.sourceTypes of project: {}", id) val sourceTypes = projectRepository.findSourceTypesByProjectId(id) - return sourceTypeMapper.sourceTypesToSourceTypeDTOs(sourceTypes).filterNotNull() + return sourceTypeMapper.sourceTypesToSourceTypeDTOs(sourceTypes) } /** diff --git a/src/main/java/org/radarbase/management/service/ResourceUriService.kt b/src/main/java/org/radarbase/management/service/ResourceUriService.kt index c02792779..ecb5ad361 100644 --- a/src/main/java/org/radarbase/management/service/ResourceUriService.kt +++ b/src/main/java/org/radarbase/management/service/ResourceUriService.kt @@ -91,7 +91,7 @@ object ResourceUriService { return URI( HeaderUtil.buildPath( "api", "source-types", resource.producer, - resource.model, resource.model + resource.model, resource.catalogVersion ) ) } diff --git a/src/main/java/org/radarbase/management/service/SourceTypeService.kt b/src/main/java/org/radarbase/management/service/SourceTypeService.kt index bc2c42ed6..da67436af 100644 --- a/src/main/java/org/radarbase/management/service/SourceTypeService.kt +++ b/src/main/java/org/radarbase/management/service/SourceTypeService.kt @@ -28,7 +28,7 @@ import javax.validation.constraints.NotNull */ @Service @Transactional -open class SourceTypeService( +class SourceTypeService( @Autowired private val sourceTypeRepository: SourceTypeRepository, @Autowired private val sourceTypeMapper: SourceTypeMapper, @Autowired private val sourceDataRepository: SourceDataRepository, @@ -61,7 +61,7 @@ open class SourceTypeService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(): List { + fun findAll(): List { log.debug("Request to get all SourceTypes") val result = sourceTypeRepository.findAllWithEagerRelationships() return result @@ -95,23 +95,33 @@ open class SourceTypeService( * Fetch SourceType by producer and model. */ fun findByProducerAndModelAndVersion( - @NotNull producer: String, - @NotNull model: String, @NotNull version: String + @NotNull producer: String?, + @NotNull model: String?, @NotNull version: String? ): SourceTypeDTO { log.debug( "Request to get SourceType by producer and model and version: {}, {}, {}", producer, model, version ) - return sourceTypeRepository - .findOneWithEagerRelationshipsByProducerAndModelAndVersion(producer, model, version) - .let { sourceType: SourceType? -> sourceType?.let { sourceTypeMapper.sourceTypeToSourceTypeDTO(it) } } - ?: throw NotFoundException( - "SourceType not found with producer, model, " + "version ", EntityName.Companion.SOURCE_TYPE, - ErrorConstants.ERR_SOURCE_TYPE_NOT_FOUND, Collections.singletonMap( + if (producer == null || model == null || version == null) { + throw NotFoundException( + "SourceType not found with producer, model, " + "version ", EntityName.SOURCE_TYPE, + ErrorConstants.ERR_SOURCE_TYPE_NOT_FOUND, Collections.singletonMap( + "producer-model-version", + "$producer-$model-$version" + ) + ) + } + val result = + sourceTypeRepository.findOneWithEagerRelationshipsByProducerAndModelAndVersion(producer, model, version) + ?: throw NotFoundException( + "SourceType not found with producer, model, " + "version ", EntityName.SOURCE_TYPE, + ErrorConstants.ERR_SOURCE_TYPE_NOT_FOUND, Collections.singletonMap( "producer-model-version", "$producer-$model-$version" ) ) + + return sourceTypeMapper.sourceTypeToSourceTypeDTO(result) } /** @@ -159,7 +169,7 @@ open class SourceTypeService( * @param catalogSourceTypes list of source-type from catalogue-server. */ @Transactional - open fun saveSourceTypesFromCatalogServer(catalogSourceTypes: List) { + fun saveSourceTypesFromCatalogServer(catalogSourceTypes: List) { for (catalogSourceType in catalogSourceTypes) { var sourceType = catalogSourceTypeMapper .catalogSourceTypeToSourceType(catalogSourceType) diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index 725e15a88..ce44a1b5a 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -76,8 +76,8 @@ class ProjectResource( @Throws(URISyntaxException::class, NotAuthorizedException::class) fun createProject(@RequestBody @Valid projectDto: ProjectDTO?): ResponseEntity { log.debug("REST request to save Project : {}", projectDto) - val org = projectDto?.organization - if (org?.name == null) { + val org = projectDto?.organizationName + if (org == null) { throw BadRequestException( "Organization must be provided", ENTITY_NAME, ErrorConstants.ERR_VALIDATION @@ -85,7 +85,7 @@ class ProjectResource( } authService.checkPermission( Permission.PROJECT_CREATE, - { e: EntityDetails -> e.organization(org.name) }) + { e: EntityDetails -> e.organization(org) }) if (projectDto.id != null) { return ResponseEntity.badRequest() .headers( diff --git a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt index b94d22046..1cb524223 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt @@ -242,7 +242,7 @@ class SourceTypeResource( producer, model, version ) - if (!projects.isEmpty()) { + if (projects.isNotEmpty()) { throw InvalidRequestException( // we know the list is not empty so calling get() is safe here "Cannot delete a source-type that " + "is being used by project(s)", EntityName.SOURCE_TYPE, ErrorConstants.ERR_SOURCE_TYPE_IN_USE, Collections.singletonMap( diff --git a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt index 7d92ccc7f..3bba61551 100644 --- a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt @@ -110,7 +110,10 @@ class SubjectResource( .body(result) } + private fun getProjectName(subjectDto: SubjectDTO): String { + // not ideal, because only name is needed. however, id is checked to verify the project is in the database + // this does prevent calls to the database? if (subjectDto.project == null || subjectDto.project!!.id == null || subjectDto.project!!.projectName == null) { throw BadRequestException( "A subject should be assigned to a project", EntityName.SUBJECT, @@ -215,7 +218,7 @@ class SubjectResource( listOf( subjectMapper.subjectToSubjectReducedProjectDTO(s) ) - }); + }) ResponseUtil.wrapOrNotFound(subject) } else if (projectName == null && externalId != null) { val page = subjectService.findAll(subjectCriteria) From 65e839dc422792ba6fda376c287a194946c64e8f Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 6 Nov 2023 17:46:54 +0100 Subject: [PATCH 061/158] project.organizationName now defaults to the project.organization.name, and overwrites the field on get() to prevent inconsistencies. Only if there is no organization.name, the original field can be used. --- src/gatling/scala/ProjectGatlingTest.scala | 2 +- .../config/AuthorizationConfiguration.kt | 6 ++-- .../radarbase/management/domain/Project.kt | 12 ++++++- .../repository/ProjectRepository.kt | 6 ++-- .../management/service/UserService.kt | 16 ++++----- .../management/service/dto/ProjectDTO.kt | 9 +++++ .../decorator/ProjectMapperDecorator.kt | 10 +++--- .../management/web/rest/ProjectResource.kt | 18 +++++----- .../web/rest/ProjectResourceIntTest.kt | 35 +++++++++---------- 9 files changed, 65 insertions(+), 49 deletions(-) diff --git a/src/gatling/scala/ProjectGatlingTest.scala b/src/gatling/scala/ProjectGatlingTest.scala index 0f8211fe9..c1eba2ccb 100644 --- a/src/gatling/scala/ProjectGatlingTest.scala +++ b/src/gatling/scala/ProjectGatlingTest.scala @@ -44,7 +44,7 @@ class ProjectGatlingTest extends ManagementPortalSimulation { .exec(http("Create new project") .post("/api/projects") .headers(headers_http_authenticated) - .body(StringBody("""{"id":null, "projectName":"PROJECT-${randstring}", "description":"SAMPLE_TEXT", "organizationName":"SAMPLE_TEXT", "location":"SAMPLE_TEXT", "startDate":"2020-01-01T00:00:00.000Z", "projectStatus":null, "endDate":"2020-01-01T00:00:00.000Z", "projectAdmin":null}""")).asJson + .body(StringBody("""{"id":null, "projectName":"PROJECT-${randstring}", "description":"SAMPLE_TEXT", "organization": {"id": 1, "name": "main" }, "location":"SAMPLE_TEXT", "startDate":"2020-01-01T00:00:00.000Z", "projectStatus":null, "endDate":"2020-01-01T00:00:00.000Z", "projectAdmin":null}""")).asJson .check(status.is(201)) .check(headerRegex("Location", "(.*)").saveAs("new_project_url"))).exitHereIfFailed .pause(5) diff --git a/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt b/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt index 6b479d296..c175df23c 100644 --- a/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt @@ -10,15 +10,15 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration -open class AuthorizationConfiguration( +class AuthorizationConfiguration( private val projectRepository: ProjectRepository, ) { @Bean - open fun authorizationOracle(): AuthorizationOracle = MPAuthorizationOracle( + fun authorizationOracle(): AuthorizationOracle = MPAuthorizationOracle( object : EntityRelationService { override suspend fun findOrganizationOfProject(project: String): String? = withContext(Dispatchers.IO) { projectRepository.findOneWithEagerRelationshipsByName(project) - ?.organization?.name + ?.organizationName } } ) diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index 0713e5f72..7beb687fa 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -61,9 +61,19 @@ class Project : AbstractEntity(), Serializable { @Column(name = "description", nullable = false) @NotNull var description: String? = null - @JvmField + // Defaults to organization name, but if that is not set then we can use the organizationName @Column(name = "jhi_organization") var organizationName: String? = null + get() { + if (organization?.name != null) + field = organization?.name + return field + } + // needed because the @JVMField annotation cannot be added when a custom getter/setter is set + set(value) { + field = value + } + @JvmField @ManyToOne(fetch = FetchType.EAGER) diff --git a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt index 2eb10938f..fdcf4f1d4 100644 --- a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt +++ b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt @@ -27,10 +27,10 @@ interface ProjectRepository : JpaRepository, RevisionRepository< value = "select distinct project from Project project " + "left join fetch project.sourceTypes " + "WHERE project.projectName in (:projectNames) " - + "OR project.organization.name in (:organizationNames)", + + "OR project.organizationName in (:organizationNames)", countQuery = "select distinct count(project) from Project project " + "WHERE project.projectName in (:projectNames) " - + "OR project.organization.name in (:organizationNames)" + + "OR project.organizationName in (:organizationNames)" ) fun findAllWithEagerRelationshipsInOrganizationsOrProjects( pageable: Pageable?, @@ -40,7 +40,7 @@ interface ProjectRepository : JpaRepository, RevisionRepository< @Query( "select project from Project project " - + "WHERE project.organization.name = :organization_name" + + "WHERE project.organizationName = :organization_name" ) fun findAllByOrganizationName( @Param("organization_name") organizationName: String diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt index b666cb90b..c35f24538 100644 --- a/src/main/java/org/radarbase/management/service/UserService.kt +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -38,7 +38,7 @@ import java.util.function.Function */ @Service @Transactional -open class UserService @Autowired constructor( +class UserService @Autowired constructor( private val userRepository: UserRepository, private val passwordService: PasswordService, private val userMapper: UserMapper, @@ -205,7 +205,7 @@ open class UserService @Autowired constructor( RoleAuthority.Scope.ORGANIZATION -> e.organization(role.organization?.name) RoleAuthority.Scope.PROJECT -> { if (role.project?.organization != null) { - e.organization(role.project?.organization?.name) + e.organization(role.project?.organizationName) } e.project(role.project?.projectName) } @@ -262,7 +262,7 @@ open class UserService @Autowired constructor( */ @Transactional @Throws(NotAuthorizedException::class) - open fun updateUser(userDto: UserDTO): UserDTO? { + fun updateUser(userDto: UserDTO): UserDTO? { val userOpt = userDto.id?.let { userRepository.findById(it) } return if (userOpt?.isPresent == true) { var user = userOpt.get() @@ -314,7 +314,7 @@ open class UserService @Autowired constructor( * @param password the new password * @param login of the user to change password */ - open fun changePassword(login: String, password: String) { + fun changePassword(login: String, password: String) { val user = userRepository.findOneByLogin(login) if (user != null) { @@ -331,7 +331,7 @@ open class UserService @Autowired constructor( * @return the requested page of users */ @Transactional(readOnly = true) - open fun getAllManagedUsers(pageable: Pageable): Page { + fun getAllManagedUsers(pageable: Pageable): Page { log.debug("Request to get all Users") return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER) .map { user: User? -> userMapper.userToUserDTO(user) } @@ -344,12 +344,12 @@ open class UserService @Autowired constructor( * and is empty otherwise */ @Transactional(readOnly = true) - open fun getUserWithAuthoritiesByLogin(login: String): UserDTO? { + fun getUserWithAuthoritiesByLogin(login: String): UserDTO? { return userMapper.userToUserDTO(userRepository.findOneWithRolesByLogin(login)) } @get:Transactional(readOnly = true) - open val userWithAuthorities: User? + val userWithAuthorities: User? /** * Get the current user. * @return the currently authenticated user, or null if no user is currently authenticated @@ -412,7 +412,7 @@ open class UserService @Autowired constructor( */ @Transactional @Throws(NotAuthorizedException::class) - open fun updateRoles(login: String, roleDtos: Set?) { + fun updateRoles(login: String, roleDtos: Set?) { val user = userRepository.findOneByLogin(login) ?: throw NotFoundException( "User with login $login not found", diff --git a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt index 0955cec77..f7376bab0 100644 --- a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt @@ -17,7 +17,16 @@ class ProjectDTO : Serializable { var humanReadableProjectName: String? = null @NotNull var description: String? = null var organization: OrganizationDTO? = null + + // Defaults to organization name, but if that is not set then we can use the organizationName var organizationName: String? = null + get() { + if (organization?.name != null) + field = organization?.name + return field + } + + @NotNull var location: String? = null var startDate: ZonedDateTime? = null var projectStatus: ProjectStatus? = null diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt index 9f7811647..3fae78093 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt @@ -53,17 +53,17 @@ abstract class ProjectMapperDecorator : ProjectMapper { val project = delegate.projectDTOToProject(projectDto) val projectName = projectDto.humanReadableProjectName if (!projectName.isNullOrEmpty()) { - project!!.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] = projectName + project!!.attributes[ProjectDTO.HUMAN_READABLE_PROJECT_NAME] = projectName } - val name = projectDto.organization?.name - if (name != null) { + val name = projectDto.organizationName + if (name != null && projectDto.organization != null) { val org = organizationRepository.findOneByName(name) ?: throw NotFoundException( "Organization not found with name", - EntityName.Companion.ORGANIZATION, + EntityName.ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, - Collections.singletonMap("name", name) + Collections.singletonMap("name", name) ) project!!.organization = org } diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index ce44a1b5a..9b052727d 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -77,12 +77,10 @@ class ProjectResource( fun createProject(@RequestBody @Valid projectDto: ProjectDTO?): ResponseEntity { log.debug("REST request to save Project : {}", projectDto) val org = projectDto?.organizationName - if (org == null) { - throw BadRequestException( + ?: throw BadRequestException( "Organization must be provided", ENTITY_NAME, ErrorConstants.ERR_VALIDATION ) - } authService.checkPermission( Permission.PROJECT_CREATE, { e: EntityDetails -> e.organization(org) }) @@ -156,7 +154,7 @@ class ProjectResource( e.organization(newOrgName) e.project(existingProject?.projectName) }) - val oldOrgName = existingProject?.organization?.name + val oldOrgName = existingProject?.organizationName if (newOrgName != oldOrgName) { authService.checkPermission( Permission.PROJECT_UPDATE, @@ -210,7 +208,7 @@ class ProjectResource( log.debug("REST request to get Project : {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> - e.organization(projectDto.organization?.name) + e.organization(projectDto.organizationName) e.project(projectDto.projectName) }) return ResponseEntity.ok(projectDto) @@ -233,7 +231,7 @@ class ProjectResource( log.debug("REST request to get Project : {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> - e.organization(projectDto.organization?.name) + e.organization(projectDto.organizationName) e.project(projectDto.projectName) }) return projectService.findSourceTypesByProjectId(projectDto.id!!) @@ -255,7 +253,7 @@ class ProjectResource( log.debug("REST request to delete Project : {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.PROJECT_DELETE, { e: EntityDetails -> - e.organization(projectDto.organization?.name) + e.organization(projectDto.organizationName) e.project(projectDto.projectName) }) return try { @@ -284,7 +282,7 @@ class ProjectResource( log.debug("REST request to get all Roles for project {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.ROLE_READ, { e: EntityDetails -> - e.organization(projectDto.organization?.name) + e.organization(projectDto.organizationName) e.project(projectDto.projectName) }) return ResponseEntity.ok(roleService.getRolesByProject(projectName)) @@ -311,7 +309,7 @@ class ProjectResource( val projectDto = projectService.findOneByName(projectName) //?: throw NoSuchElementException() authService.checkPermission(Permission.SOURCE_READ, { e: EntityDetails -> - e.organization(projectDto.organization?.name) + e.organization(projectDto.organizationName) e.project(projectDto.projectName) }) return if (assigned != null) { @@ -375,7 +373,7 @@ class ProjectResource( // this checks if the project exists val projectDto = projectName.let { projectService.findOneByName(it) } authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> - e.organization(projectDto.organization?.name) + e.organization(projectDto.organizationName) e.project(projectDto.projectName) }) diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt index e5e230044..25f97edd6 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt @@ -44,7 +44,7 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class ProjectResourceIntTest( +internal class ProjectResourceIntTest( @Autowired private val projectResource: ProjectResource, // @Autowired private val subjectMapper: SubjectMapper, @@ -88,7 +88,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createProject() { + fun createProject() { val databaseSizeBeforeCreate = projectRepository.findAll().size // Create the Project @@ -116,7 +116,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createProjectWithExistingId() { + fun createProjectWithExistingId() { val databaseSizeBeforeCreate = projectRepository.findAll().size // Create the Project with an existing ID @@ -139,7 +139,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkProjectNameIsRequired() { + fun checkProjectNameIsRequired() { val databaseSizeBeforeTest = projectRepository.findAll().size // set the field null project.projectName = null @@ -159,7 +159,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkDescriptionIsRequired() { + fun checkDescriptionIsRequired() { val databaseSizeBeforeTest = projectRepository.findAll().size // set the field null project.description = null @@ -179,7 +179,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkLocationIsRequired() { + fun checkLocationIsRequired() { val databaseSizeBeforeTest = projectRepository.findAll().size // set the field null project.location = null @@ -199,7 +199,7 @@ internal open class ProjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun allProjects() { + fun allProjects() { // Initialize the database projectRepository.saveAndFlush(project) @@ -266,7 +266,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun getProject() { + fun getProject() { // Initialize the database projectRepository.saveAndFlush(project) @@ -287,7 +287,7 @@ internal open class ProjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun nonExistingProject() { + fun nonExistingProject() { // Get the project restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) @@ -296,11 +296,11 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateProject() { + fun updateProject() { // Initialize the database projectRepository.saveAndFlush(project) val org = Organization() - org.name = "org1" + org.name = UPDATED_ORGANIZATION org.description = "Test Organization 1" org.location = "Somewhere" organizationRepository.saveAndFlush(org) @@ -312,7 +312,6 @@ internal open class ProjectResourceIntTest( updatedProject .projectName(UPDATED_PROJECT_NAME) .description(UPDATED_DESCRIPTION) - .organizationName(UPDATED_ORGANIZATION) .organization(org) .location(UPDATED_LOCATION) .startDate(UPDATED_START_DATE) @@ -345,7 +344,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateNonExistingProject() { + fun updateNonExistingProject() { val databaseSizeBeforeUpdate = projectRepository.findAll().size // Create the Project @@ -367,7 +366,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun deleteProject() { + fun deleteProject() { // Initialize the database projectRepository.saveAndFlush(project) val databaseSizeBeforeDelete = projectRepository.findAll().size @@ -387,7 +386,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun equalsVerifier() { + fun equalsVerifier() { org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Project::class.java)) } @@ -396,8 +395,8 @@ internal open class ProjectResourceIntTest( private const val UPDATED_PROJECT_NAME = "BBBBBBBBBB" private const val DEFAULT_DESCRIPTION = "AAAAAAAAAA" private const val UPDATED_DESCRIPTION = "BBBBBBBBBB" - private const val DEFAULT_ORGANIZATION = "AAAAAAAAAA" - private const val UPDATED_ORGANIZATION = "BBBBBBBBBB" + private const val DEFAULT_ORGANIZATION = "main" + private const val UPDATED_ORGANIZATION = "org1" private const val DEFAULT_LOCATION = "AAAAAAAAAA" private const val UPDATED_LOCATION = "BBBBBBBBBB" private val DEFAULT_START_DATE = ZonedDateTime.ofInstant( @@ -425,7 +424,7 @@ internal open class ProjectResourceIntTest( fun createEntity(): Project { val organization = Organization() organization.id = 1L - organization.name = "main" + organization.name = DEFAULT_ORGANIZATION organization.description = "test" return Project() .projectName(DEFAULT_PROJECT_NAME) From 47e101da362d2769b1e9d502c961223cda0c68f9 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 6 Nov 2023 18:05:43 +0100 Subject: [PATCH 062/158] resolve Joris' comments --- .../java/org/radarbase/auth/token/DataRadarToken.kt | 4 ++-- .../main/java/org/radarbase/auth/token/RadarToken.kt | 4 ++-- .../auth/authentication/TokenValidatorTest.kt | 10 +++++----- .../radarbase/management/config/AsyncConfiguration.kt | 2 +- .../management/config/DatabaseConfiguration.kt | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt b/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt index 27bba10c1..7a2392ee7 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt @@ -12,7 +12,7 @@ data class DataRadarToken( * Get all roles defined in this token. * @return non-null set describing the roles defined in this token. */ - override val roles: Set?, + override val roles: Set, /** * Get a list of scopes assigned to this token. @@ -101,7 +101,7 @@ data class DataRadarToken( clientId = radarToken.clientId, ) - override fun copyWithRoles(roles: Set?): DataRadarToken = copy(roles = roles) + override fun copyWithRoles(roles: Set): DataRadarToken = copy(roles = roles) companion object { fun RadarToken.toDataRadarToken(): DataRadarToken = DataRadarToken(this) diff --git a/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt b/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt index 39341d0c9..52acb36d9 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt @@ -11,7 +11,7 @@ interface RadarToken { * Get all roles defined in this token. * @return non-null set describing the roles defined in this token. */ - val roles: Set? + val roles: Set /** * Get a list of scopes assigned to this token. @@ -92,7 +92,7 @@ interface RadarToken { val isClientCredentials: Boolean get() = grantType == CLIENT_CREDENTIALS - fun copyWithRoles(roles: Set?): RadarToken + fun copyWithRoles(roles: Set): RadarToken companion object { const val CLIENT_CREDENTIALS = "client_credentials" diff --git a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt index 9c35dc29e..2dca2a112 100644 --- a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt +++ b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt @@ -28,7 +28,7 @@ internal class TokenValidatorTest { */ @BeforeEach fun setUp() { - wireMockServer!!.stubFor( + wireMockServer.stubFor( WireMock.get(WireMock.urlEqualTo(TokenTestUtils.PUBLIC_KEY_PATH)) .willReturn( WireMock.aResponse() @@ -48,7 +48,7 @@ internal class TokenValidatorTest { @AfterEach fun reset() { - wireMockServer!!.resetAll() + wireMockServer.resetAll() } @Test @@ -78,7 +78,7 @@ internal class TokenValidatorTest { } companion object { - private var wireMockServer: WireMockServer? = null + private lateinit var wireMockServer: WireMockServer @JvmStatic @BeforeAll @@ -87,13 +87,13 @@ internal class TokenValidatorTest { WireMockConfiguration() .port(WIREMOCK_PORT) ) - wireMockServer!!.start() + wireMockServer.start() } @JvmStatic @AfterAll fun tearDown() { - wireMockServer!!.stop() + wireMockServer.stop() } } } diff --git a/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt index bca9e4d4f..2f89550b0 100644 --- a/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt @@ -16,7 +16,7 @@ import tech.jhipster.config.JHipsterProperties @Configuration @EnableAsync @EnableScheduling -open class AsyncConfiguration( +class AsyncConfiguration( @Autowired private val jHipsterProperties: JHipsterProperties) : AsyncConfigurer { @Bean(name = ["taskExecutor"]) override fun getAsyncExecutor(): ExceptionHandlingAsyncTaskExecutor { diff --git a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt index 896feab14..8c301a5a2 100644 --- a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt @@ -23,11 +23,11 @@ import javax.sql.DataSource ) @EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware") @EnableTransactionManagement -open class DatabaseConfiguration { +class DatabaseConfiguration { @Autowired private val env: Environment? = null @Bean - open fun liquibase( + fun liquibase( dataSource: DataSource, liquibaseProperties: LiquibaseProperties ): SpringLiquibase { @@ -50,7 +50,7 @@ open class DatabaseConfiguration { } @Bean - open fun hibernate5Module(): Hibernate5Module { + fun hibernate5Module(): Hibernate5Module { return Hibernate5Module() } From 01c1292783bfd314d7c8a264ba967f986a1d3e3b Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 7 Nov 2023 15:53:35 +0100 Subject: [PATCH 063/158] Revert "let it run on the ci for now" This reverts commit 68fc25aa6b9f4e1af1e9dc5e1ae78758d80395e4. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6c927da01..94bcbb137 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,7 +4,7 @@ name: Main # Run in master and dev branches and in all pull requests to those branches on: push: - branches: [ master, dev, 732-append-managementportal-to-baseurl ] + branches: [ master, dev ] pull_request: {} env: From 2eab27b1ddce508ed3eeab9d7dd7a940a68819bb Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 7 Nov 2023 16:52:55 +0100 Subject: [PATCH 064/158] minor fix --- .../auth/authorization/MPAuthorizationOracle.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt b/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt index ef7f0ad5d..35601eeeb 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt @@ -24,9 +24,9 @@ class MPAuthorizationOracle( if (identity.isClientCredentials) return true - return identity.roles?.forkAny { + return identity.roles.forkAny { it.hasPermission(identity, permission, entity, entityScope) - } ?: false + } } /** @@ -39,8 +39,7 @@ class MPAuthorizationOracle( if (identity.isClientCredentials) return true - return identity.roles?.any { it.role.mayBeGranted(permission) } - ?: false + return identity.roles.any { it.role.mayBeGranted(permission) } } /** @@ -62,7 +61,7 @@ class MPAuthorizationOracle( val projects = mutableSetOf() val personalProjects = mutableSetOf() - identity.roles?.forEach { + identity.roles.forEach { if (it.role.mayBeGranted(permission)) { when (it.role.scope) { RoleAuthority.Scope.GLOBAL -> global = true From dc2f453263bb0bd848d87e3914759c7aab6f91d0 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 8 Nov 2023 09:40:51 +0100 Subject: [PATCH 065/158] update yml indentation --- .../config/application-e2e-prod-test.yml | 14 +- .../resources/config/application-prod.yml | 160 ++++++------- src/main/resources/config/application.yml | 214 +++++++++--------- 3 files changed, 194 insertions(+), 194 deletions(-) diff --git a/src/main/resources/config/application-e2e-prod-test.yml b/src/main/resources/config/application-e2e-prod-test.yml index b9a461307..f42d6a74a 100644 --- a/src/main/resources/config/application-e2e-prod-test.yml +++ b/src/main/resources/config/application-e2e-prod-test.yml @@ -14,10 +14,10 @@ # =================================================================== spring: - profiles: - active: prod,api-docs,e2e-prod-test - datasource: - username: radarbase - password: radarbase - liquibase: - contexts: dev + profiles: + active: prod,api-docs,e2e-prod-test + datasource: + username: radarbase + password: radarbase + liquibase: + contexts: dev diff --git a/src/main/resources/config/application-prod.yml b/src/main/resources/config/application-prod.yml index 152a3f3b2..1f369e317 100644 --- a/src/main/resources/config/application-prod.yml +++ b/src/main/resources/config/application-prod.yml @@ -13,46 +13,46 @@ # http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html # =================================================================== spring: - devtools: - restart: - enabled: false - livereload: - enabled: false - datasource: - type: com.zaxxer.hikari.HikariDataSource - driverClassName: org.postgresql.Driver - url: jdbc:postgresql://localhost:5432/managementportal - # name: managementportal - # username: radarbase - # password: radarbase -# hikari: -# data-source-properties: -# cachePrepStmts: true -# prepStmtCacheSize: 250 -# prepStmtCacheSqlLimit: 2048 -# useServerPrepStmts: true - jpa: - database-platform: org.hibernate.dialect.PostgreSQLDialect - database: POSTGRESQL - show-sql: false - properties: - hibernate.id.new_generator_mappings: true - hibernate.cache.use_second_level_cache: true - hibernate.cache.use_query_cache: false - hibernate.generate_statistics: false - hibernate.cache.region.factory_class: com.hazelcast.hibernate.HazelcastCacheRegionFactory - hibernate.cache.hazelcast.instance_name: ManagementPortal - hibernate.cache.use_minimal_puts: true - hibernate.cache.hazelcast.use_lite_member: true - mail: - host: smtp - port: 25 - protocol: smtp - properties.mail.smtp: - auth: false - starttls.enable: false - thymeleaf: - cache: true + devtools: + restart: + enabled: false + livereload: + enabled: false + datasource: + type: com.zaxxer.hikari.HikariDataSource + driverClassName: org.postgresql.Driver + url: jdbc:postgresql://localhost:5432/managementportal +# name: managementportal +# username: radarbase +# password: radarbase +# hikari: +# data-source-properties: +# cachePrepStmts: true +# prepStmtCacheSize: 250 +# prepStmtCacheSqlLimit: 2048 +# useServerPrepStmts: true + jpa: + database-platform: org.hibernate.dialect.PostgreSQLDialect + database: POSTGRESQL + show-sql: false + properties: + hibernate.id.new_generator_mappings: true + hibernate.cache.use_second_level_cache: true + hibernate.cache.use_query_cache: false + hibernate.generate_statistics: false + hibernate.cache.region.factory_class: com.hazelcast.hibernate.HazelcastCacheRegionFactory + hibernate.cache.hazelcast.instance_name: ManagementPortal + hibernate.cache.use_minimal_puts: true + hibernate.cache.hazelcast.use_lite_member: true + mail: + host: smtp + port: 25 + protocol: smtp + properties.mail.smtp: + auth: false + starttls.enable: false + thymeleaf: + cache: true # =================================================================== # To enable SSL, generate a certificate using: @@ -72,12 +72,12 @@ spring: # keyAlias: ManagementPortal # =================================================================== server: - port: 8080 - servlet: - context-path: /managementportal - session: - cookie: - path: / + port: 8080 + servlet: + context-path: /managementportal + session: + cookie: + path: / # =================================================================== @@ -85,27 +85,27 @@ server: # # =================================================================== managementportal: - common: - baseUrl: http://my-server-url-to-change-here # Modify according to your server's URL - managementPortalBaseUrl: http://localhost:8080/managementportal - privacyPolicyUrl: http://info.thehyve.nl/radar-cns-privacy-policy - adminPassword: - activationKeyTimeoutInSeconds: 86400 - mail: # specific JHipster mail property, for standard properties see MailProperties - from: ManagementPortal@localhost - frontend: - clientId: ManagementPortalapp - clientSecret: - accessTokenValiditySeconds: 14400 - refreshTokenValiditySeconds: 259200 - sessionTimeout : 86400 - oauth: - clientsFile: /mp-includes/config/oauth_client_details.csv - metaTokenTimeout: PT1H #timeout should be specified as the ISO-8601 duration format {@code PnDTnHnMn.nS}. - persistentMetaTokenTimeout: P31D #timeout should be specified as the ISO-8601 duration format {@code PnDTnHnMn.nS}. - catalogueServer: - enableAutoImport: false - serverUrl: + common: + baseUrl: http://my-server-url-to-change-here # Modify according to your server's URL + managementPortalBaseUrl: http://localhost:8080/managementportal + privacyPolicyUrl: http://info.thehyve.nl/radar-cns-privacy-policy + adminPassword: + activationKeyTimeoutInSeconds: 86400 + mail: # specific JHipster mail property, for standard properties see MailProperties + from: ManagementPortal@localhost + frontend: + clientId: ManagementPortalapp + clientSecret: + accessTokenValiditySeconds: 14400 + refreshTokenValiditySeconds: 259200 + sessionTimeout: 86400 + oauth: + clientsFile: /mp-includes/config/oauth_client_details.csv + metaTokenTimeout: PT1H #timeout should be specified as the ISO-8601 duration format {@code PnDTnHnMn.nS}. + persistentMetaTokenTimeout: P31D #timeout should be specified as the ISO-8601 duration format {@code PnDTnHnMn.nS}. + catalogueServer: + enableAutoImport: false + serverUrl: # =================================================================== # JHipster specific properties @@ -114,19 +114,19 @@ managementportal: # =================================================================== jhipster: - http: - cache: # Used by the CachingHttpHeadersFilter - timeToLiveInDays: 1461 - cache: # Cache configuration - hazelcast: # Hazelcast distributed cache - time-to-live-seconds: 3600 - backup-count: 1 - logging: - logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration - enabled: false - host: localhost - port: 5000 - queue-size: 512 + http: + cache: # Used by the CachingHttpHeadersFilter + timeToLiveInDays: 1461 + cache: # Cache configuration + hazelcast: # Hazelcast distributed cache + time-to-live-seconds: 3600 + backup-count: 1 + logging: + logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration + enabled: false + host: localhost + port: 5000 + queue-size: 512 # =================================================================== # Application specific properties diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml index 58904f340..32e7f9d19 100644 --- a/src/main/resources/config/application.yml +++ b/src/main/resources/config/application.yml @@ -1,124 +1,124 @@ management: - endpoints: - web: - base-path: /management - exposure: - include: [ "configprops", "env", "health", "info", "jhimetrics", "logfile", "loggers", "prometheus", "threaddump", "caches", "liquibase"] - endpoint: - health: - show-details: ALWAYS - probes: - enabled: true - jhimetrics: - enabled: true + endpoints: + web: + base-path: /management + exposure: + include: [ "configprops", "env", "health", "info", "jhimetrics", "logfile", "loggers", "prometheus", "threaddump", "caches", "liquibase" ] + endpoint: health: - diskspace: - # disabling diskspace as the standard config, since we have removed - # security check for health endpoint - enabled: false - mail: - enabled: false # When using the MailService, configure an SMTP server and set this to true - db: + show-details: ALWAYS + probes: + enabled: true + jhimetrics: + enabled: true + health: + diskspace: + # disabling diskspace as the standard config, since we have removed + # security check for health endpoint + enabled: false + mail: + enabled: false # When using the MailService, configure an SMTP server and set this to true + db: + enabled: true + metrics: + export: + defaults: + enabled: true + prometheus: + enabled: true + step: 60 + enable: + http: true + jvm: true + logback: true + process: true + system: true + distribution: + percentiles-histogram: + all: true + percentiles: + all: 0, 0.5, 0.75, 0.95, 0.99, 1.0 + tags: + application: ${spring.application.name} + web: + server: + request: + autotime: enabled: true - metrics: - export: - defaults: - enabled: true - prometheus: - enabled: true - step: 60 - enable: - http: true - jvm: true - logback: true - process: true - system: true - distribution: - percentiles-histogram: - all: true - percentiles: - all: 0, 0.5, 0.75, 0.95, 0.99, 1.0 - tags: - application: ${spring.application.name} - web: - server: - request: - autotime: - enabled: true spring: - application: - name: ManagementPortal - profiles: - # The commented value for `active` can be replaced with valid Spring profiles to load. - # Otherwise, it will be filled in by gradle when building the WAR file - # Either way, it can be overridden by `--spring.profiles.active` value passed in the commandline or `-Dspring.profiles.active` set in `JAVA_OPTS` - active: #spring.profiles.active# - jackson: - serialization.write_dates_as_timestamps: false - jpa: - open-in-view: false - hibernate: - ddl-auto: none - naming: - physical-strategy: org.radarbase.management.hibernate.CaseSensitivePhysicalNamingStrategy - implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy - properties: - org.hibernate.envers: - store_data_at_delete: true - audit_strategy: org.hibernate.envers.strategy.ValidityAuditStrategy - audit_strategy_validity_store_revend_timestamp: true - global_with_modified_flag: true - track_entities_changed_in_revision: true - hibernate: - jdbc: - lob: - non_contextual_creation: true - main: - allow-circular-references: true - messages: - basename: i18n/messages - thymeleaf: - mode: HTML - liquibase: - contexts: prod + application: + name: ManagementPortal + profiles: + # The commented value for `active` can be replaced with valid Spring profiles to load. + # Otherwise, it will be filled in by gradle when building the WAR file + # Either way, it can be overridden by `--spring.profiles.active` value passed in the commandline or `-Dspring.profiles.active` set in `JAVA_OPTS` + active: #spring.profiles.active# + jackson: + serialization.write_dates_as_timestamps: false + jpa: + open-in-view: false + hibernate: + ddl-auto: none + naming: + physical-strategy: org.radarbase.management.hibernate.CaseSensitivePhysicalNamingStrategy + implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + properties: + org.hibernate.envers: + store_data_at_delete: true + audit_strategy: org.hibernate.envers.strategy.ValidityAuditStrategy + audit_strategy_validity_store_revend_timestamp: true + global_with_modified_flag: true + track_entities_changed_in_revision: true + hibernate: + jdbc: + lob: + non_contextual_creation: true + main: + allow-circular-references: true + messages: + basename: i18n/messages + thymeleaf: + mode: HTML + liquibase: + contexts: prod springdoc: - api-docs: - path: /api-docs - enabled: false - swagger-ui: - enabled: false + api-docs: + path: /api-docs + enabled: false + swagger-ui: + enabled: false server: - servlet: - session: - cookie: - http-only: true - secure: true - max-age: 30m - timeout: 15m + servlet: + session: + cookie: + http-only: true + secure: true + max-age: 30m + timeout: 15m info: - project: - version: #project.version# + project: + version: #project.version# # =================================================================== # ManagementPortal specific properties # # =================================================================== managementportal: - account: - enableExposeToken: false - mail: # specific JHipster mail property, for standard properties see MailProperties - from: ManagementPortal@localhost - oauth: - keyStorePassword: radarbase - signingKeyAlias: radarbase-managementportal-ec - enablePublicKeyVerifiers: false - siteSettings: - hiddenSubjectFields: [] + account: + enableExposeToken: false + mail: # specific JHipster mail property, for standard properties see MailProperties + from: ManagementPortal@localhost + oauth: + keyStorePassword: radarbase + signingKeyAlias: radarbase-managementportal-ec + enablePublicKeyVerifiers: false + siteSettings: + hiddenSubjectFields: [ ] # =================================================================== # JHipster specific properties @@ -127,10 +127,10 @@ managementportal: # =================================================================== jhipster: - async: - core-pool-size: 2 - max-pool-size: 50 - queue-capacity: 10000 + async: + core-pool-size: 2 + max-pool-size: 50 + queue-capacity: 10000 # =================================================================== # Application specific properties From 14b5ce21cc783eacce7d779a76ac36684072db07 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Thu, 9 Nov 2023 10:15:53 +0100 Subject: [PATCH 066/158] faulty test config --- src/main/resources/config/application-dev.yml | 2 +- .../config/application-e2e-prod-test.yml | 2 -- src/main/resources/logback-spring.xml | 34 +++++++++---------- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/main/resources/config/application-dev.yml b/src/main/resources/config/application-dev.yml index 5b3c68fe9..dd1f079fc 100644 --- a/src/main/resources/config/application-dev.yml +++ b/src/main/resources/config/application-dev.yml @@ -92,7 +92,7 @@ server: # =================================================================== managementportal: common: - baseUrl: http://localhost:8081 # Modify according to your server's URL + baseUrl: http://localhost:8080 # Modify according to your server's URL managementPortalBaseUrl: http://localhost:8080/managementportal privacyPolicyUrl: http://info.thehyve.nl/radar-cns-privacy-policy adminPassword: admin diff --git a/src/main/resources/config/application-e2e-prod-test.yml b/src/main/resources/config/application-e2e-prod-test.yml index f42d6a74a..5f2601dfa 100644 --- a/src/main/resources/config/application-e2e-prod-test.yml +++ b/src/main/resources/config/application-e2e-prod-test.yml @@ -14,8 +14,6 @@ # =================================================================== spring: - profiles: - active: prod,api-docs,e2e-prod-test datasource: username: radarbase password: radarbase diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index f5e23c7a0..6e7c1871b 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -3,24 +3,24 @@ - - + + + 512 + + + --> From a750e62f748906ed3fe40f0082460d8e7d315742 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 13:56:50 +0100 Subject: [PATCH 067/158] revert ClaimsTokenEnhancer to java and reintegrate it in the oAuth2ServerConfig --- .../config/OAuth2ServerConfiguration.kt | 34 ++-- .../security/ClaimsTokenEnhancer.java | 154 ++++++++++++++++++ .../security/ClaimsTokenEnhancer.kt | 132 --------------- 3 files changed, 174 insertions(+), 146 deletions(-) create mode 100644 src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java delete mode 100644 src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt diff --git a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt index ca7cc87a8..f0e582027 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt @@ -2,6 +2,7 @@ package org.radarbase.management.config import org.radarbase.auth.authorization.RoleAuthority import org.radarbase.management.repository.UserRepository +import org.radarbase.management.security.ClaimsTokenEnhancer import org.radarbase.management.security.Http401UnauthorizedEntryPoint import org.radarbase.management.security.JwtAuthenticationFilter import org.radarbase.management.security.PostgresApprovalStore @@ -41,6 +42,7 @@ import org.springframework.security.oauth2.provider.client.JdbcClientDetailsServ import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices import org.springframework.security.oauth2.provider.token.DefaultTokenServices +import org.springframework.security.oauth2.provider.token.TokenEnhancer import org.springframework.security.oauth2.provider.token.TokenEnhancerChain import org.springframework.security.oauth2.provider.token.TokenStore import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter @@ -49,7 +51,7 @@ import java.util.* import javax.sql.DataSource @Configuration -open class OAuth2ServerConfiguration { +class OAuth2ServerConfiguration { @Autowired private val dataSource: DataSource? = null @@ -58,7 +60,7 @@ open class OAuth2ServerConfiguration { @Configuration @Order(-20) - protected open class LoginConfig : WebSecurityConfigurerAdapter() { + protected class LoginConfig : WebSecurityConfigurerAdapter() { @Autowired private val authenticationManager: AuthenticationManager? = null @@ -87,7 +89,7 @@ open class OAuth2ServerConfiguration { } @Configuration - open class JwtAuthenticationFilterConfiguration { + class JwtAuthenticationFilterConfiguration { @Autowired private val authenticationManager: AuthenticationManager? = null @@ -98,7 +100,7 @@ open class OAuth2ServerConfiguration { private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null @Bean - open fun jwtAuthenticationFilter(): JwtAuthenticationFilter { + fun jwtAuthenticationFilter(): JwtAuthenticationFilter { return JwtAuthenticationFilter( keyStoreHandler!!.tokenValidator, authenticationManager!!, @@ -109,7 +111,7 @@ open class OAuth2ServerConfiguration { } @Bean - open fun jdbcClientDetailsService(): JdbcClientDetailsService { + fun jdbcClientDetailsService(): JdbcClientDetailsService { val clientDetailsService = JdbcClientDetailsService(dataSource) clientDetailsService.setPasswordEncoder(passwordEncoder) return clientDetailsService @@ -117,7 +119,7 @@ open class OAuth2ServerConfiguration { @Configuration @EnableResourceServer - protected open class ResourceServerConfiguration( + protected class ResourceServerConfiguration( @Autowired private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler, @Autowired private val tokenStore: TokenStore, @Autowired private val http401UnauthorizedEntryPoint: Http401UnauthorizedEntryPoint, @@ -200,7 +202,7 @@ open class OAuth2ServerConfiguration { @Configuration @EnableAuthorizationServer - protected open class AuthorizationServerConfiguration( + protected class AuthorizationServerConfiguration( @Autowired private val jpaProperties: JpaProperties, @Autowired @Qualifier("authenticationManagerBean") private val authenticationManager: AuthenticationManager, @Autowired private val dataSource: DataSource, @@ -209,12 +211,12 @@ open class OAuth2ServerConfiguration { ) : AuthorizationServerConfigurerAdapter() { @Bean - protected open fun authorizationCodeServices(): AuthorizationCodeServices { + protected fun authorizationCodeServices(): AuthorizationCodeServices { return JdbcAuthorizationCodeServices(dataSource) } @Bean - open fun approvalStore(): ApprovalStore { + fun approvalStore(): ApprovalStore { return if (jpaProperties.database == Database.POSTGRESQL) { PostgresApprovalStore(dataSource) } else { @@ -224,12 +226,17 @@ open class OAuth2ServerConfiguration { } @Bean - open fun tokenStore(): TokenStore { + fun tokenEnhancer(): TokenEnhancer { + return ClaimsTokenEnhancer() + } + + @Bean + fun tokenStore(): TokenStore { return ManagementPortalJwtTokenStore(accessTokenConverter()) } @Bean - open fun accessTokenConverter(): ManagementPortalJwtAccessTokenConverter { + fun accessTokenConverter(): ManagementPortalJwtAccessTokenConverter { logger.debug("loading token converter from keystore configurations") return ManagementPortalJwtAccessTokenConverter( keyStoreHandler.algorithmForSigning, @@ -240,7 +247,7 @@ open class OAuth2ServerConfiguration { @Bean @Primary - open fun tokenServices(tokenStore: TokenStore?): DefaultTokenServices { + fun tokenServices(tokenStore: TokenStore?): DefaultTokenServices { val defaultTokenServices = DefaultTokenServices() defaultTokenServices.setTokenStore(tokenStore) defaultTokenServices.setSupportRefreshToken(true) @@ -251,8 +258,7 @@ open class OAuth2ServerConfiguration { override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) { val tokenEnhancerChain = TokenEnhancerChain() tokenEnhancerChain.setTokenEnhancers( - //TODO listOf(tokenEnhancer(), accessTokenConverter()) - listOf(accessTokenConverter()) + listOf(tokenEnhancer(), accessTokenConverter()) ) endpoints .authorizationCodeServices(authorizationCodeServices()) diff --git a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java new file mode 100644 index 000000000..8fdf15b7c --- /dev/null +++ b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java @@ -0,0 +1,154 @@ +package org.radarbase.management.security; + +import org.radarbase.auth.authorization.AuthorizationOracle; +import org.radarbase.auth.authorization.Permission; +import org.radarbase.auth.authorization.RoleAuthority; +import org.radarbase.management.domain.Role; +import org.radarbase.management.domain.Source; +import org.radarbase.management.repository.SubjectRepository; +import org.radarbase.management.repository.UserRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.boot.actuate.audit.AuditEventRepository; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.OAuth2Request; +import org.springframework.security.oauth2.provider.token.TokenEnhancer; +import org.springframework.stereotype.Component; + +import java.security.Principal; +import java.time.Instant; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import static org.radarbase.auth.jwt.JwtTokenVerifier.GRANT_TYPE_CLAIM; +import static org.radarbase.auth.jwt.JwtTokenVerifier.ROLES_CLAIM; +import static org.radarbase.auth.jwt.JwtTokenVerifier.SOURCES_CLAIM; + +@Component +public class ClaimsTokenEnhancer implements TokenEnhancer, InitializingBean { + private static final Logger logger = LoggerFactory.getLogger(ClaimsTokenEnhancer.class); + + @Autowired + private SubjectRepository subjectRepository; + + @Autowired + private UserRepository userRepository; + + @Autowired + private AuditEventRepository auditEventRepository; + + @Autowired + private AuthorizationOracle authorizationOracle; + + @Value("${spring.application.name}") + private String appName; + + private static final String GRANT_TOKEN_EVENT = "GRANT_ACCESS_TOKEN"; + + @Override + public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, + OAuth2Authentication authentication) { + logger.debug("Enhancing token of authentication {}" , authentication); + + Map additionalInfo = new HashMap<>(); + + String userName = authentication.getName(); + + if (authentication.getPrincipal() instanceof Principal + || authentication.getPrincipal() instanceof UserDetails) { + // add the 'sub' claim in accordance with JWT spec + additionalInfo.put("sub", userName); + + Optional.ofNullable(userRepository.findOneByLogin(userName)) + .ifPresent(user -> { + var roles = user.roles.stream() + .map(role -> { + var auth = role.authority.name; + return switch (role.getRole().getScope()) { + case GLOBAL -> auth; + case ORGANIZATION -> role.organization.name + + ":" + auth; + case PROJECT -> role.project.getProjectName() + + ":" + auth; + }; + }) + .toList(); + additionalInfo.put(ROLES_CLAIM, roles); + + // Do not grant scopes that cannot be given to a user. + Set currentScopes = accessToken.getScope(); + Set newScopes = currentScopes.stream() + .filter(scope -> { + Permission permission = Permission.ofScope(scope); + var roleAuthorities = user.roles.stream() + .map(Role::getRole) + .collect(Collectors.toCollection(() -> + EnumSet.noneOf(RoleAuthority.class))); + return authorizationOracle.mayBeGranted(roleAuthorities, + permission); + }) + .collect(Collectors.toCollection(TreeSet::new)); + + if (!newScopes.equals(currentScopes)) { + ((DefaultOAuth2AccessToken) accessToken).setScope(newScopes); + } + }); + + List assignedSources = subjectRepository.findSourcesBySubjectLogin(userName); + + List sourceIds = assignedSources.stream() + .map(s -> s.sourceId.toString()) + .toList(); + additionalInfo.put(SOURCES_CLAIM, sourceIds); + } + // add iat and iss optional JWT claims + additionalInfo.put("iat", Instant.now().getEpochSecond()); + additionalInfo.put("iss", appName); + additionalInfo.put(GRANT_TYPE_CLAIM, + authentication.getOAuth2Request().getGrantType()); + ((DefaultOAuth2AccessToken) accessToken) + .setAdditionalInformation(additionalInfo); + + // HACK: since all granted tokens need to pass here, we can use this point to create an + // audit event for a granted token, there is an open issue about oauth2 audit events in + // spring security but it has been inactive for a long time: + // https://github.com/spring-projects/spring-security-oauth/issues/223 + Map auditData = auditData(accessToken, authentication); + auditEventRepository.add(new AuditEvent(userName, GRANT_TOKEN_EVENT, + auditData)); + logger.info("[{}] for {}: {}", GRANT_TOKEN_EVENT, userName, auditData); + + return accessToken; + } + + @Override + public void afterPropertiesSet() throws Exception { + // nothing to do for now + } + + private Map auditData(OAuth2AccessToken accessToken, + OAuth2Authentication authentication) { + Map result = new HashMap<>(); + result.put("tokenType", accessToken.getTokenType()); + result.put("scope", String.join(", ", accessToken.getScope())); + result.put("expiresIn", Integer.toString(accessToken.getExpiresIn())); + result.putAll(accessToken.getAdditionalInformation()); + OAuth2Request request = authentication.getOAuth2Request(); + result.put("clientId", request.getClientId()); + result.put("grantType", request.getGrantType()); + return result; + } +} diff --git a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt deleted file mode 100644 index 6000870db..000000000 --- a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt +++ /dev/null @@ -1,132 +0,0 @@ -package org.radarbase.management.security - -import org.radarbase.auth.authorization.AuthorizationOracle -import org.radarbase.auth.authorization.Permission -import org.radarbase.auth.authorization.RoleAuthority -import org.radarbase.auth.jwt.JwtTokenVerifier -import org.radarbase.management.domain.Role -import org.radarbase.management.domain.Source -import org.radarbase.management.domain.User -import org.radarbase.management.repository.SubjectRepository -import org.radarbase.management.repository.UserRepository -import org.slf4j.LoggerFactory -import org.springframework.beans.factory.InitializingBean -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Value -import org.springframework.boot.actuate.audit.AuditEvent -import org.springframework.boot.actuate.audit.AuditEventRepository -import org.springframework.security.core.userdetails.UserDetails -import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken -import org.springframework.security.oauth2.common.OAuth2AccessToken -import org.springframework.security.oauth2.provider.OAuth2Authentication -import org.springframework.security.oauth2.provider.token.TokenEnhancer -import java.security.Principal -import java.time.Instant -import java.util.* - -class ClaimsTokenEnhancer( - @Autowired private val subjectRepository: SubjectRepository, - @Autowired private val userRepository: UserRepository, - @Autowired private val auditEventRepository: AuditEventRepository, - @Autowired private val authorizationOracle: AuthorizationOracle -) : TokenEnhancer, InitializingBean { - - @Value("\${spring.application.name}") - private val appName: String? = null - override fun enhance( - accessToken: OAuth2AccessToken, authentication: OAuth2Authentication - ): OAuth2AccessToken { - logger.debug("Enhancing token of authentication {}", authentication) - val additionalInfo: MutableMap = HashMap() - val userName = authentication.getName() - if (authentication.principal is Principal || authentication.principal is UserDetails) { - // add the 'sub' claim in accordance with JWT spec - additionalInfo["sub"] = userName - userRepository.findOneByLogin(userName)?.let { user: User? -> - val roles = user!!.roles!!.stream().map { role: Role -> - val auth = role.authority!!.name - when (role.role!!.scope) { - RoleAuthority.Scope.GLOBAL -> auth - RoleAuthority.Scope.ORGANIZATION -> (role.organization!!.name + ":" + auth) - - RoleAuthority.Scope.PROJECT -> (role.project!!.projectName + ":" + auth) - } - }.toList() - additionalInfo[JwtTokenVerifier.ROLES_CLAIM] = roles - - // Do not grant scopes that cannot be given to a user. - val currentScopes: MutableSet = accessToken.scope - val newScopes: Set = currentScopes - .filter { scope: String -> - val permission: Permission = Permission.ofScope(scope) - - val roleAuthorities = user - .roles!!.mapNotNull { it.role } - .let{ _ -> EnumSet.noneOf(RoleAuthority::class.java)} - .filterNotNull() - - roleAuthorities.mayBeGranted(permission) - } - .toSet() - - if (newScopes != currentScopes) { - (accessToken as DefaultOAuth2AccessToken).scope = newScopes - } - } - val assignedSources = subjectRepository.findSourcesBySubjectLogin(userName) - val sourceIds = assignedSources.stream().map { s: Source? -> s!!.sourceId.toString() }.toList() - additionalInfo[JwtTokenVerifier.SOURCES_CLAIM] = sourceIds - } - // add iat and iss optional JWT claims - additionalInfo["iat"] = Instant.now().epochSecond - additionalInfo["iss"] = appName - additionalInfo[JwtTokenVerifier.GRANT_TYPE_CLAIM] = authentication.oAuth2Request.getGrantType() - (accessToken as DefaultOAuth2AccessToken).additionalInformation = additionalInfo - - // HACK: since all granted tokens need to pass here, we can use this point to create an - // audit event for a granted token, there is an open issue about oauth2 audit events in - // spring security but it has been inactive for a long time: - // https://github.com/spring-projects/spring-security-oauth/issues/223 - val auditData = auditData(accessToken, authentication) - auditEventRepository.add( - AuditEvent( - userName, GRANT_TOKEN_EVENT, auditData - ) - ) - logger.info("[{}] for {}: {}", GRANT_TOKEN_EVENT, userName, auditData) - return accessToken - } - - @Throws(Exception::class) - override fun afterPropertiesSet() { - // nothing to do for now - } - - private fun auditData( - accessToken: OAuth2AccessToken, authentication: OAuth2Authentication - ): Map { - val result: MutableMap = HashMap() - result["tokenType"] = accessToken.tokenType - result["scope"] = java.lang.String.join(", ", accessToken.scope) - result["expiresIn"] = accessToken.expiresIn.toString() - result.putAll(accessToken.additionalInformation) - val request = authentication.oAuth2Request - result["clientId"] = request.clientId - result["grantType"] = request.getGrantType() - return result - } - - open fun mayBeGranted(role: RoleAuthority, permission: Permission): Boolean = with(authorizationOracle) { - role.mayBeGranted(permission) - } - - fun Collection.mayBeGranted(permission: Permission): Boolean = with(authorizationOracle) { - return any { it.mayBeGranted(permission) } - } - - companion object { - private val logger = LoggerFactory.getLogger(ClaimsTokenEnhancer::class.java) - private const val GRANT_TOKEN_EVENT = "GRANT_ACCESS_TOKEN" - } -} - From 4896095520ae6896a13308c586fb5add34bf9a7a Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:08:44 +0100 Subject: [PATCH 068/158] get rid of some TODOs --- .../filters/SubjectSpecification.kt | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt index 312073fe2..e53c7b0c8 100644 --- a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt +++ b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt @@ -35,8 +35,8 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification private val externalId: String? private val subjectId: String? private val sort: List? - private val authority: Set - private var sortLastValues: List? = null + private val authority: Set + private var sortLastValues: List? = null /** * Subject specification based on criteria. @@ -44,7 +44,7 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification */ init { authority = criteria.authority - .map { obj: SubjectAuthority? -> obj?.name } + .map { obj: SubjectAuthority -> obj.name } .toSet() dateOfBirth = criteria.dateOfBirth enrollmentDate = criteria.enrollmentDate @@ -58,7 +58,7 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification sort = criteria.parsedSort sortLastValues = if (last != null) { sort - ?.map { o: SubjectSortOrder -> getLastValue(o.sortBy) } + ?.mapNotNull { o: SubjectSortOrder -> getLastValue(o.sortBy) } ?.toList() } else { null @@ -93,7 +93,6 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification return predicates.toAndPredicate()!! } - //TODO I don't think return type needs to be nullable private fun filterLastValues(root: Root, builder: CriteriaBuilder): Predicate? { val lastPredicates = arrayOfNulls( sort!!.size @@ -111,10 +110,15 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification lastAndPredicates!![j] = builder.equal(paths[j], sortLastValues!![j]) } val order = sort[i] + val saveVal = sortLastValues + ?: throw BadRequestException( + "No last value given", + EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION + ) val currentSort: Predicate? = if (order.direction.isAscending) { - builder.greaterThan(paths[i], sortLastValues!![i]!!)//TODO + builder.greaterThan(paths[i], saveVal[i]) } else { - builder.lessThan(paths[i], sortLastValues!![i]!!)//TODO + builder.lessThan(paths[i], saveVal[i]) } if (lastAndPredicates != null) { lastAndPredicates[i] = currentSort @@ -154,7 +158,7 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification if (property.isUnique && result == null) { throw BadRequestException( "No last value given for sort property $property", - EntityName.Companion.SUBJECT, ErrorConstants.ERR_VALIDATION + EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION ) } return result From 8e6cddbe35c97affc1e0904b5c2933556ac40a8d Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:10:48 +0100 Subject: [PATCH 069/158] get rid of some TODOs --- .../org/radarbase/management/domain/User.kt | 3 +-- .../ManagementPortalOauthKeyStoreHandler.kt | 24 ++++++++++++------- .../management/service/SourceService.kt | 3 +-- .../web/rest/OrganizationResourceIntTest.kt | 1 - 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/User.kt b/src/main/java/org/radarbase/management/domain/User.kt index a780da221..240f74880 100644 --- a/src/main/java/org/radarbase/management/domain/User.kt +++ b/src/main/java/org/radarbase/management/domain/User.kt @@ -107,8 +107,7 @@ class User : AbstractEntity(), Serializable { @Cascade( CascadeType.SAVE_UPDATE ) - //TODO remove ? - var roles: MutableSet? = HashSet() + var roles: MutableSet = HashSet() //Lowercase the login before saving it in database fun setLogin(login: String?) { diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt index 169ecb656..a31cd5f36 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt @@ -268,15 +268,21 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( return null } val privateKey = keyPair.private - return if (privateKey is ECPrivateKey) { - EcdsaJwtAlgorithm(keyPair) - } else if (privateKey is RSAPrivateKey) { - RsaJwtAlgorithm(keyPair) - } else { - logger.warn( - "No JWT algorithm found for key type {}", privateKey.javaClass - ) - null + return when (privateKey) { + is ECPrivateKey -> { + EcdsaJwtAlgorithm(keyPair) + } + + is RSAPrivateKey -> { + RsaJwtAlgorithm(keyPair) + } + + else -> { + logger.warn( + "No JWT algorithm found for key type {}", privateKey.javaClass + ) + null + } } } } diff --git a/src/main/java/org/radarbase/management/service/SourceService.kt b/src/main/java/org/radarbase/management/service/SourceService.kt index eb21d13e9..1f1e11778 100644 --- a/src/main/java/org/radarbase/management/service/SourceService.kt +++ b/src/main/java/org/radarbase/management/service/SourceService.kt @@ -247,9 +247,8 @@ open class SourceService( + "source-type", IdentifierGenerator.ENTITY_NAME, "error.invalidTransfer" ) - //TODO all the nullchecks are the result of jvmfiel;d annotations not allowing lateinits // set old source-type, ensures compatibility - sourceDto.sourceType = existingSource.sourceType?.let { sourceTypeMapper.sourceTypeToSourceTypeDTO(it) }!! + sourceDto.sourceType = existingSource.sourceType?.let { sourceTypeMapper.sourceTypeToSourceTypeDTO(it) } } return save(sourceDto) } diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index 5abcf00e0..f15d6fcd2 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -176,7 +176,6 @@ internal open class OrganizationResourceIntTest( @Test @Throws(Exception::class) - //TODO this is covered by not using a nullable type fun checkGroupNameIsRequired() { val orgDto: OrganizationDTO = organizationMapper.organizationToOrganizationDTO(organization) orgDto.name = null From daff9d990bb788fe3a9eb3d092c36ff448767ddd Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:20:30 +0100 Subject: [PATCH 070/158] fix compilation error --- .../org/radarbase/management/service/SubjectService.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/SubjectService.kt b/src/main/java/org/radarbase/management/service/SubjectService.kt index 6c70e8bac..ad281e4c4 100644 --- a/src/main/java/org/radarbase/management/service/SubjectService.kt +++ b/src/main/java/org/radarbase/management/service/SubjectService.kt @@ -174,11 +174,11 @@ class SubjectService( ) } - private fun updateParticipantRoles(subject: Subject, subjectDto: SubjectDTO): MutableSet? { + private fun updateParticipantRoles(subject: Subject, subjectDto: SubjectDTO): MutableSet { if (subjectDto.project == null || subjectDto.project!!.projectName == null) { return subject.user!!.roles } - val existingRoles = subject.user!!.roles?.map { + val existingRoles = subject.user!!.roles.map { // make participant inactive in projects that do not match the new project if (it.authority!!.name == RoleAuthority.PARTICIPANT.authority && it.project!!.projectName != subjectDto.project!!.projectName) { return@map getProjectParticipantRole(it.project, RoleAuthority.INACTIVE_PARTICIPANT) @@ -186,12 +186,12 @@ class SubjectService( // do not modify other roles. return@map it } - }?.toMutableSet() + }.toMutableSet() // Ensure that given project is present val newProjectRole = getProjectParticipantRole(projectMapper.projectDTOToProject(subjectDto.project), RoleAuthority.PARTICIPANT) - existingRoles?.add(newProjectRole) + existingRoles.add(newProjectRole) return existingRoles From 307fc891e4f760c6ed114373aa3cd54e5551c974 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:27:43 +0100 Subject: [PATCH 071/158] more native kotlin --- .../ManagementPortalOauthKeyStoreHandler.kt | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt index a31cd5f36..2c783ca6c 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt @@ -31,7 +31,6 @@ import java.security.interfaces.ECPrivateKey import java.security.interfaces.RSAPrivateKey import java.util.* import java.util.AbstractMap.SimpleImmutableEntry -import java.util.stream.Stream import javax.annotation.Nonnull import javax.servlet.ServletContext import kotlin.collections.Map.Entry @@ -72,12 +71,12 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( ("http://localhost:" + environment.getProperty("server.port") + servletContext.contextPath) logger.info("Using Management Portal base-url {}", managementPortalBaseUrl) val algorithms = loadAlgorithmsFromAlias().filter { obj: Algorithm? -> Objects.nonNull(obj) }.toList() - verifiers = algorithms.stream().map { algo: Algorithm? -> - JWT.require(algo).withAudience(ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL).build() - }.toList() + verifiers = algorithms.map { algo: Algorithm? -> + JWT.require(algo).withAudience(ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL).build() + }.toMutableList() // No need to check audience with a refresh token: it can be used // to refresh tokens intended for other resources. - refreshTokenVerifiers = algorithms.stream().map { algo: Algorithm? -> JWT.require(algo).build() }.toList() + refreshTokenVerifiers = algorithms.map { algo: Algorithm -> JWT.require(algo).build() }.toMutableList() } @Nonnull @@ -124,17 +123,18 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( * @return List of public keys for token verification. */ fun loadJwks(): JsonWebKeySet { - return JsonWebKeySet(verifierPublicKeyAliasList.map { alias: String? -> this.getKeyPair(alias) } + return JsonWebKeySet(verifierPublicKeyAliasList.map { alias: String -> this.getKeyPair(alias) } .map { keyPair: KeyPair? -> getJwtAlgorithm(keyPair) }.mapNotNull { obj: JwtAlgorithm? -> obj?.jwk }) } /** * Load default verifiers from configured keystore and aliases. */ - private fun loadAlgorithmsFromAlias(): Stream { - return verifierPublicKeyAliasList.stream().map { alias: String? -> this.getKeyPair(alias) } - .map { keyPair: KeyPair? -> getJwtAlgorithm(keyPair) }.filter { obj: JwtAlgorithm? -> Objects.nonNull(obj) } - .map { obj: JwtAlgorithm? -> obj?.algorithm } + private fun loadAlgorithmsFromAlias(): Collection { + return verifierPublicKeyAliasList + .map { alias: String -> this.getKeyPair(alias) } + .mapNotNull { keyPair -> getJwtAlgorithm(keyPair) } + .map { obj: JwtAlgorithm -> obj.algorithm } } val algorithmForSigning: Algorithm @@ -159,7 +159,7 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( * @throws IllegalArgumentException if the key alias password is wrong or the key cannot * loaded. */ - private fun getKeyPair(alias: String?): KeyPair? { + private fun getKeyPair(alias: String): KeyPair? { return getKeyPair(alias, password) } @@ -172,7 +172,7 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( * @throws IllegalArgumentException if the key alias password is wrong or the key cannot * load. */ - private fun getKeyPair(alias: String?, password: CharArray): KeyPair? { + private fun getKeyPair(alias: String, password: CharArray): KeyPair? { return try { val key = store.getKey(alias, password) as PrivateKey? if (key == null) { From 0daf310962776d120017f0afb095a0751c80414b Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:40:46 +0100 Subject: [PATCH 072/158] fixing compilation errors --- .../management/service/UserService.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt index c35f24538..cf46ccbb9 100644 --- a/src/main/java/org/radarbase/management/service/UserService.kt +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -155,16 +155,16 @@ class UserService @Autowired constructor( user.resetKey = passwordService.generateResetKey() user.resetDate = ZonedDateTime.now() user.activated = false - user.roles = userDto.roles?.let { getUserRoles(it, mutableSetOf()) } + user.roles = getUserRoles(userDto.roles, mutableSetOf()) user = userRepository.save(user) log.debug("Created Information for User: {}", user) return user } @Throws(NotAuthorizedException::class) - private fun getUserRoles(roleDtos: Set?, oldRoles: MutableSet): MutableSet? { + private fun getUserRoles(roleDtos: Set?, oldRoles: MutableSet): MutableSet { if (roleDtos == null) { - return null + return mutableSetOf() } val roles = roleDtos.map { roleDto: RoleDTO -> val authority = getRoleAuthority(roleDto) @@ -273,8 +273,8 @@ class UserService @Autowired constructor( user.langKey = userDto.langKey val managedRoles = user.roles val oldRoles = java.util.Set.copyOf(managedRoles) - managedRoles?.clear() - managedRoles?.addAll(getUserRoles(userDto.roles, oldRoles)!!) + managedRoles.clear() + managedRoles.addAll(getUserRoles(userDto.roles, oldRoles)) user = userRepository.save(user) log.debug("Changed Information for User: {}", user) userMapper.userToUserDTO(user) @@ -422,11 +422,11 @@ class UserService @Autowired constructor( ) val managedRoles = user.roles - val oldRoles = managedRoles?.toMutableSet() + val oldRoles = managedRoles.toMutableSet() - managedRoles?.clear() - managedRoles?.addAll(roleDtos?.let { oldRoles?.let { oldroles -> getUserRoles(it, oldroles) } }!!) - ?: throw Exception("could not add rolser for user: $user") + managedRoles.clear() + roleDtos?.let { getUserRoles(it, oldRoles) }?.let { managedRoles.addAll(it) } + ?: throw Exception("could not add roles for user: $user") userRepository.save(user) } From 616e8440b7e66d8434ffbed902563fa502c061dd Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:41:02 +0100 Subject: [PATCH 073/158] nullcheck sessionId to prevent throwing errors --- .../radarbase/management/config/audit/AuditEventConverter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt index 09b6872b6..d2f742049 100644 --- a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt +++ b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt @@ -73,7 +73,7 @@ class AuditEventConverter { for ((key, value) in data) { // Extract the data that will be saved. - if (value is WebAuthenticationDetails) { + if (value is WebAuthenticationDetails && value.sessionId != null) { results["sessionId"] = value.sessionId } else if (value != null) { results[key] = value.toString() From 293fc4ab36cc2330f9b45a15fab535a13435bfa3 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:56:13 +0100 Subject: [PATCH 074/158] enable appserver downstream testing --- src/main/docker/etc/config/oauth_client_details.csv | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/docker/etc/config/oauth_client_details.csv b/src/main/docker/etc/config/oauth_client_details.csv index b55f42881..d869cab87 100644 --- a/src/main/docker/etc/config/oauth_client_details.csv +++ b/src/main/docker/etc/config/oauth_client_details.csv @@ -1,8 +1,9 @@ client_id;resource_ids;client_secret;scope;authorized_grant_types;redirect_uri;authorities;access_token_validity;refresh_token_validity;additional_information;autoapprove -pRMT;res_ManagementPortal,res_gateway;;MEASUREMENT.CREATE,SUBJECT.UPDATE,SUBJECT.READ,PROJECT.READ,SOURCETYPE.READ,SOURCE.READ,SOURCETYPE.READ,SOURCEDATA.READ,USER.READ,ROLE.READ;refresh_token,authorization_code;;;43200;7948800;{"dynamic_registration": true}; -aRMT;res_ManagementPortal,res_gateway;;MEASUREMENT.CREATE,SUBJECT.UPDATE,SUBJECT.READ,PROJECT.READ,SOURCETYPE.READ,SOURCE.READ,SOURCETYPE.READ,SOURCEDATA.READ,USER.READ,ROLE.READ;refresh_token,authorization_code;;;43200;7948800;{"dynamic_registration": true}; -THINC-IT;res_ManagementPortal,res_gateway;;MEASUREMENT.CREATE,SUBJECT.UPDATE,SUBJECT.READ,PROJECT.READ,SOURCETYPE.READ,SOURCE.READ,SOURCETYPE.READ,SOURCEDATA.READ,USER.READ,ROLE.READ;refresh_token,authorization_code;;;43200;7948800;{"dynamic_registration": true}; -radar_restapi;res_ManagementPortal;secret;SUBJECT.READ,PROJECT.READ,SOURCE.READ,SOURCETYPE.READ;client_credentials;;;43200;259200;{}; +pRMT;res_ManagementPortal,res_gateway,res_AppServer;;MEASUREMENT.CREATE,SUBJECT.UPDATE,SUBJECT.READ,PROJECT.READ,SOURCETYPE.READ,SOURCE.READ,SOURCETYPE.READ,SOURCEDATA.READ,USER.READ,ROLE.READ;refresh_token,authorization_code;;;43200;7948800;{"dynamic_registration": true}; +aRMT;res_ManagementPortal,res_gateway,res_AppServer;;MEASUREMENT.CREATE,SUBJECT.UPDATE,SUBJECT.READ,PROJECT.READ,SOURCETYPE.READ,SOURCE.READ,SOURCETYPE.READ,SOURCEDATA.READ,USER.READ,ROLE.READ;refresh_token,authorization_code;;;43200;7948800;{"dynamic_registration": true}; +THINC-IT;res_ManagementPortal,res_gateway;secret;MEASUREMENT.CREATE,SUBJECT.UPDATE,SUBJECT.READ,PROJECT.READ,SOURCETYPE.READ,SOURCE.READ,SOURCETYPE.READ,SOURCEDATA.READ,USER.READ,ROLE.READ;refresh_token,authorization_code;;;43200;7948800;{"dynamic_registration": true}; +radar_restapi;res_ManagementPortal;secret;SUBJECT.READ,PROJECT.READ,SOURCE.READ,SOURCETYPE.READ;password,client_credentials;;;43200;259200;{}; radar_redcap_integrator;res_ManagementPortal;secret;PROJECT.READ,SUBJECT.CREATE,SUBJECT.READ,SUBJECT.UPDATE;client_credentials;;;43200;259200;{}; radar_dashboard;res_ManagementPortal,res_RestApi;;SUBJECT.READ,PROJECT.READ,SOURCE.READ,SOURCETYPE.READ;refresh_token,authorization_code;;;43200;259200;{}; radar_upload_backend;res_ManagementPortal,res_upload;secret;SUBJECT.READ,PROJECT.READ,SOURCETYPE.READ,SOURCE.READ,SOURCETYPE.READ,SOURCEDATA.READ;refresh_token,authorization_code,password,client_credentials;http://localhost:8080/callback;;43200;7948800;{"dynamic_registration": true}; +radar_appserver_client;res_ManagementPortal,res_AppServer;;MEASUREMENT.CREATE,UBJECT.UPDATE,SUBJECT.READ,PROJECT.READ,SOURCETYPE.READ,SOURCE.READ,SOURCETYPE.READ,SOURCEDATA.READ,USER.READ,ROLE.READ;client_credentials;;;43200;259200;{}; From e651508d62c7c0c04f72a71f4184aaaadf583cf4 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 15:08:16 +0100 Subject: [PATCH 075/158] stylefixes --- .../security/ClaimsTokenEnhancer.java | 63 ++++++++----------- .../web/rest/SubjectResourceIntTest.kt | 4 +- 2 files changed, 27 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java index 8fdf15b7c..d645f0cba 100644 --- a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java +++ b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java @@ -60,47 +60,38 @@ public class ClaimsTokenEnhancer implements TokenEnhancer, InitializingBean { @Override public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, - OAuth2Authentication authentication) { - logger.debug("Enhancing token of authentication {}" , authentication); + OAuth2Authentication authentication) { + logger.debug("Enhancing token of authentication {}", authentication); Map additionalInfo = new HashMap<>(); String userName = authentication.getName(); if (authentication.getPrincipal() instanceof Principal - || authentication.getPrincipal() instanceof UserDetails) { + || authentication.getPrincipal() instanceof UserDetails) { // add the 'sub' claim in accordance with JWT spec additionalInfo.put("sub", userName); - Optional.ofNullable(userRepository.findOneByLogin(userName)) - .ifPresent(user -> { - var roles = user.roles.stream() - .map(role -> { - var auth = role.authority.name; - return switch (role.getRole().getScope()) { - case GLOBAL -> auth; - case ORGANIZATION -> role.organization.name - + ":" + auth; - case PROJECT -> role.project.getProjectName() - + ":" + auth; - }; - }) - .toList(); + Optional.ofNullable(userRepository.findOneByLogin(userName)).ifPresent(user -> { + var roles = user.roles.stream().map(role -> { + var auth = role.authority.name; + return switch (role.getRole().getScope()) { + case GLOBAL -> auth; + case ORGANIZATION -> role.organization.name + ":" + auth; + case PROJECT -> role.project.getProjectName() + ":" + auth; + }; + }).toList(); additionalInfo.put(ROLES_CLAIM, roles); // Do not grant scopes that cannot be given to a user. Set currentScopes = accessToken.getScope(); - Set newScopes = currentScopes.stream() - .filter(scope -> { - Permission permission = Permission.ofScope(scope); - var roleAuthorities = user.roles.stream() - .map(Role::getRole) - .collect(Collectors.toCollection(() -> - EnumSet.noneOf(RoleAuthority.class))); - return authorizationOracle.mayBeGranted(roleAuthorities, - permission); - }) - .collect(Collectors.toCollection(TreeSet::new)); + Set newScopes = currentScopes.stream().filter(scope -> { + Permission permission = Permission.ofScope(scope); + var roleAuthorities = user.roles.stream().map(Role::getRole) + .collect(Collectors.toCollection(() -> + EnumSet.noneOf(RoleAuthority.class))); + return authorizationOracle.mayBeGranted(roleAuthorities, permission); + }).collect(Collectors.toCollection(TreeSet::new)); if (!newScopes.equals(currentScopes)) { ((DefaultOAuth2AccessToken) accessToken).setScope(newScopes); @@ -109,26 +100,22 @@ public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, List assignedSources = subjectRepository.findSourcesBySubjectLogin(userName); - List sourceIds = assignedSources.stream() - .map(s -> s.sourceId.toString()) - .toList(); + List sourceIds = assignedSources.stream().map(s -> + s.sourceId.toString()).toList(); additionalInfo.put(SOURCES_CLAIM, sourceIds); } // add iat and iss optional JWT claims additionalInfo.put("iat", Instant.now().getEpochSecond()); additionalInfo.put("iss", appName); - additionalInfo.put(GRANT_TYPE_CLAIM, - authentication.getOAuth2Request().getGrantType()); - ((DefaultOAuth2AccessToken) accessToken) - .setAdditionalInformation(additionalInfo); + additionalInfo.put(GRANT_TYPE_CLAIM, authentication.getOAuth2Request().getGrantType()); + ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); // HACK: since all granted tokens need to pass here, we can use this point to create an // audit event for a granted token, there is an open issue about oauth2 audit events in // spring security but it has been inactive for a long time: // https://github.com/spring-projects/spring-security-oauth/issues/223 Map auditData = auditData(accessToken, authentication); - auditEventRepository.add(new AuditEvent(userName, GRANT_TOKEN_EVENT, - auditData)); + auditEventRepository.add(new AuditEvent(userName, GRANT_TOKEN_EVENT, auditData)); logger.info("[{}] for {}: {}", GRANT_TOKEN_EVENT, userName, auditData); return accessToken; @@ -140,7 +127,7 @@ public void afterPropertiesSet() throws Exception { } private Map auditData(OAuth2AccessToken accessToken, - OAuth2Authentication authentication) { + OAuth2Authentication authentication) { Map result = new HashMap<>(); result.put("tokenType", accessToken.getTokenType()); result.put("scope", String.join(", ", accessToken.getScope())); diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index 0fd79e5af..de0fc3a96 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -97,7 +97,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.DEFAULT_ENTERNAL_ID) Assertions.assertThat(testSubject.removed).isEqualTo(SubjectServiceTest.DEFAULT_REMOVED) - Assertions.assertThat(testSubject.user!!.roles!!.size).isEqualTo(1) + Assertions.assertThat(testSubject.user!!.roles.size).isEqualTo(1) } @Test @@ -233,7 +233,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.UPDATED_EXTERNAL_LINK) Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.UPDATED_ENTERNAL_ID) Assertions.assertThat(testSubject.removed).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) - Assertions.assertThat(testSubject.user!!.roles!!.size).isEqualTo(2) + Assertions.assertThat(testSubject.user!!.roles.size).isEqualTo(2) } @Test From cb1a53ec37de53122098e401a2807619aca9d347 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Thu, 16 Nov 2023 11:07:31 +0100 Subject: [PATCH 076/158] update codeowners --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 8ebeaf5d9..5fa12df6c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @nivemaham @blootsvoets +* @nivemaham @blootsvoets @bdegraaf1234 @peyman-mohtashami From 63624195e72c53a7324795cf54b5b7ae236165f8 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 14:15:02 +0200 Subject: [PATCH 077/158] Rename .java to .kt --- .../{TokenValidatorTest.java => TokenValidatorTest.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename radar-auth/src/test/java/org/radarbase/auth/authentication/{TokenValidatorTest.java => TokenValidatorTest.kt} (100%) diff --git a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.java b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt similarity index 100% rename from radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.java rename to radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt From d509771082f1caab4d93fa3ebdf2ea5fd9a36847 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 14:15:02 +0200 Subject: [PATCH 078/158] last file in radar auth to kotlin --- .../auth/authentication/TokenValidatorTest.kt | 128 +++++++++--------- 1 file changed, 66 insertions(+), 62 deletions(-) diff --git a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt index 3c6314932..222a2c21c 100644 --- a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt +++ b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt @@ -1,93 +1,97 @@ -package org.radarbase.auth.authentication; +package org.radarbase.auth.authentication -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.radarbase.auth.exception.TokenValidationException; -import org.radarbase.auth.jwks.JwkAlgorithmParser; -import org.radarbase.auth.jwks.JwksTokenVerifierLoader; -import org.radarbase.auth.jwks.RSAPEMCertificateParser; -import org.radarbase.auth.util.TokenTestUtils; - -import java.util.List; - -import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.get; -import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.radarbase.auth.util.TokenTestUtils.WIREMOCK_PORT; +import com.github.tomakehurst.wiremock.WireMockServer +import com.github.tomakehurst.wiremock.client.WireMock +import com.github.tomakehurst.wiremock.core.WireMockConfiguration +import org.junit.jupiter.api.AfterAll +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.radarbase.auth.exception.TokenValidationException +import org.radarbase.auth.jwks.JwkAlgorithmParser +import org.radarbase.auth.jwks.JwksTokenVerifierLoader +import org.radarbase.auth.jwks.RSAPEMCertificateParser +import org.radarbase.auth.util.TokenTestUtils +import org.radarbase.auth.util.TokenTestUtils.WIREMOCK_PORT +import java.util.List /** * Created by dverbeec on 24/04/2017. */ - -class TokenValidatorTest { - - private static WireMockServer wireMockServer; - private TokenValidator validator; - - @BeforeAll - public static void loadToken() { - wireMockServer = new WireMockServer(new WireMockConfiguration() - .port(WIREMOCK_PORT)); - wireMockServer.start(); - } +internal class TokenValidatorTest { + private var validator: TokenValidator? = null /** * Set up a stub public key endpoint and initialize a TokenValidator object. * */ @BeforeEach - public void setUp() { - wireMockServer.stubFor(get(urlEqualTo(TokenTestUtils.PUBLIC_KEY_PATH)) - .willReturn(aResponse() + fun setUp() { + wireMockServer!!.stubFor( + WireMock.get(WireMock.urlEqualTo(TokenTestUtils.PUBLIC_KEY_PATH)) + .willReturn( + WireMock.aResponse() .withStatus(200) .withHeader("Content-type", TokenTestUtils.APPLICATION_JSON) - .withBody(TokenTestUtils.PUBLIC_KEY_BODY))); - - var algorithmParser = new JwkAlgorithmParser(List.of(new RSAPEMCertificateParser())); - var verifierLoader = new JwksTokenVerifierLoader( - "http://localhost:" + WIREMOCK_PORT + TokenTestUtils.PUBLIC_KEY_PATH, - "unit_test", - algorithmParser - ); - validator = new TokenValidator(List.of(verifierLoader)); + .withBody(TokenTestUtils.PUBLIC_KEY_BODY) + ) + ) + val algorithmParser = JwkAlgorithmParser(List.of(RSAPEMCertificateParser())) + val verifierLoader = JwksTokenVerifierLoader( + "http://localhost:" + WIREMOCK_PORT + TokenTestUtils.PUBLIC_KEY_PATH, + "unit_test", + algorithmParser + ) + validator = TokenValidator(List.of(verifierLoader)) } @AfterEach - public void reset() { - wireMockServer.resetAll(); + fun reset() { + wireMockServer!!.resetAll() } - @AfterAll - public static void tearDown() { - wireMockServer.stop(); + @Test + fun testValidToken() { + validator!!.validateBlocking(TokenTestUtils.VALID_RSA_TOKEN) } @Test - void testValidToken() { - validator.validateBlocking(TokenTestUtils.VALID_RSA_TOKEN); + fun testIncorrectAudienceToken() { + Assertions.assertThrows( + TokenValidationException::class.java + ) { validator!!.validateBlocking(TokenTestUtils.INCORRECT_AUDIENCE_TOKEN) } } @Test - void testIncorrectAudienceToken() { - assertThrows(TokenValidationException.class, - () -> validator.validateBlocking(TokenTestUtils.INCORRECT_AUDIENCE_TOKEN)); + fun testExpiredToken() { + Assertions.assertThrows( + TokenValidationException::class.java + ) { validator!!.validateBlocking(TokenTestUtils.EXPIRED_TOKEN) } } @Test - void testExpiredToken() { - assertThrows(TokenValidationException.class, - () -> validator.validateBlocking(TokenTestUtils.EXPIRED_TOKEN)); + fun testIncorrectAlgorithmToken() { + Assertions.assertThrows( + TokenValidationException::class.java + ) { validator!!.validateBlocking(TokenTestUtils.INCORRECT_ALGORITHM_TOKEN) } } - @Test - void testIncorrectAlgorithmToken() { - assertThrows(TokenValidationException.class, - () -> validator.validateBlocking(TokenTestUtils.INCORRECT_ALGORITHM_TOKEN)); + companion object { + private var wireMockServer: WireMockServer? = null + @BeforeAll + fun loadToken() { + wireMockServer = WireMockServer( + WireMockConfiguration() + .port(WIREMOCK_PORT) + ) + wireMockServer!!.start() + } + + @AfterAll + fun tearDown() { + wireMockServer!!.stop() + } } } From 2edec1f0b973717e930ebfdfb889e0be40bb641e Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 14:57:06 +0200 Subject: [PATCH 079/158] Rename .java to .kt --- .../{ApplicationProperties.java => ApplicationProperties.kt} | 0 .../config/{AsyncConfiguration.java => AsyncConfiguration.kt} | 0 .../config/{CacheConfiguration.java => CacheConfiguration.kt} | 0 .../{DatabaseConfiguration.java => DatabaseConfiguration.kt} | 0 ...imeFormatConfiguration.java => DateTimeFormatConfiguration.kt} | 0 .../config/{LocaleConfiguration.java => LocaleConfiguration.kt} | 0 ...gingAspectConfiguration.java => LoggingAspectConfiguration.kt} | 0 .../config/{LoggingConfiguration.java => LoggingConfiguration.kt} | 0 ...Auth2ServerConfiguration.java => OAuth2ServerConfiguration.kt} | 0 .../management/config/{package-info.java => package-info.kt} | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/config/{ApplicationProperties.java => ApplicationProperties.kt} (100%) rename src/main/java/org/radarbase/management/config/{AsyncConfiguration.java => AsyncConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{CacheConfiguration.java => CacheConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{DatabaseConfiguration.java => DatabaseConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{DateTimeFormatConfiguration.java => DateTimeFormatConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{LocaleConfiguration.java => LocaleConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{LoggingAspectConfiguration.java => LoggingAspectConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{LoggingConfiguration.java => LoggingConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{OAuth2ServerConfiguration.java => OAuth2ServerConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{package-info.java => package-info.kt} (100%) diff --git a/src/main/java/org/radarbase/management/config/ApplicationProperties.java b/src/main/java/org/radarbase/management/config/ApplicationProperties.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/ApplicationProperties.java rename to src/main/java/org/radarbase/management/config/ApplicationProperties.kt diff --git a/src/main/java/org/radarbase/management/config/AsyncConfiguration.java b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/AsyncConfiguration.java rename to src/main/java/org/radarbase/management/config/AsyncConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/CacheConfiguration.java b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/CacheConfiguration.java rename to src/main/java/org/radarbase/management/config/CacheConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.java b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/DatabaseConfiguration.java rename to src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.java b/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.java rename to src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/LocaleConfiguration.java b/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/LocaleConfiguration.java rename to src/main/java/org/radarbase/management/config/LocaleConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.java b/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.java rename to src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/LoggingConfiguration.java b/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/LoggingConfiguration.java rename to src/main/java/org/radarbase/management/config/LoggingConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.java b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.java rename to src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/package-info.java b/src/main/java/org/radarbase/management/config/package-info.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/package-info.java rename to src/main/java/org/radarbase/management/config/package-info.kt From b8dd7736723e73777e61361f9fd2bbb6fcf2ad93 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 14:57:06 +0200 Subject: [PATCH 080/158] first conversions, tests passing --- .../auth/authentication/TokenValidatorTest.kt | 8 +- .../config/ApplicationProperties.kt | 11 +- .../management/config/AsyncConfiguration.kt | 61 ++- .../management/config/CacheConfiguration.kt | 164 ++++--- .../config/DatabaseConfiguration.kt | 86 ++-- .../config/DateTimeFormatConfiguration.kt | 53 ++- .../management/config/LocaleConfiguration.kt | 45 +- .../config/LoggingAspectConfiguration.kt | 23 +- .../management/config/LoggingConfiguration.kt | 67 ++- .../config/OAuth2ServerConfiguration.kt | 408 +++++++++--------- .../management/config/package-info.kt | 2 +- 11 files changed, 448 insertions(+), 480 deletions(-) diff --git a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt index 222a2c21c..9b62292c8 100644 --- a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt +++ b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt @@ -15,7 +15,6 @@ import org.radarbase.auth.jwks.JwksTokenVerifierLoader import org.radarbase.auth.jwks.RSAPEMCertificateParser import org.radarbase.auth.util.TokenTestUtils import org.radarbase.auth.util.TokenTestUtils.WIREMOCK_PORT -import java.util.List /** * Created by dverbeec on 24/04/2017. @@ -38,13 +37,13 @@ internal class TokenValidatorTest { .withBody(TokenTestUtils.PUBLIC_KEY_BODY) ) ) - val algorithmParser = JwkAlgorithmParser(List.of(RSAPEMCertificateParser())) + val algorithmParser = JwkAlgorithmParser(listOf(RSAPEMCertificateParser())) val verifierLoader = JwksTokenVerifierLoader( "http://localhost:" + WIREMOCK_PORT + TokenTestUtils.PUBLIC_KEY_PATH, "unit_test", algorithmParser ) - validator = TokenValidator(List.of(verifierLoader)) + validator = TokenValidator(listOf(verifierLoader)) } @AfterEach @@ -80,6 +79,8 @@ internal class TokenValidatorTest { companion object { private var wireMockServer: WireMockServer? = null + + @JvmStatic @BeforeAll fun loadToken() { wireMockServer = WireMockServer( @@ -89,6 +90,7 @@ internal class TokenValidatorTest { wireMockServer!!.start() } + @JvmStatic @AfterAll fun tearDown() { wireMockServer!!.stop() diff --git a/src/main/java/org/radarbase/management/config/ApplicationProperties.kt b/src/main/java/org/radarbase/management/config/ApplicationProperties.kt index 4b42ad774..524c0b24f 100644 --- a/src/main/java/org/radarbase/management/config/ApplicationProperties.kt +++ b/src/main/java/org/radarbase/management/config/ApplicationProperties.kt @@ -1,13 +1,12 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.ConfigurationProperties /** * Properties specific to JHipster. * - *

Properties are configured in the application.yml file.

+ * + * Properties are configured in the application.yml file. */ @ConfigurationProperties(prefix = "application", ignoreUnknownFields = false) -public class ApplicationProperties { - -} +class ApplicationProperties diff --git a/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt index 485a9dbf9..51e7aaf21 100644 --- a/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt @@ -1,43 +1,40 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import tech.jhipster.async.ExceptionHandlingAsyncTaskExecutor; -import tech.jhipster.config.JHipsterProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; -import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.AsyncConfigurer; -import org.springframework.scheduling.annotation.EnableAsync; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.slf4j.LoggerFactory +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler +import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.scheduling.annotation.AsyncConfigurer +import org.springframework.scheduling.annotation.EnableAsync +import org.springframework.scheduling.annotation.EnableScheduling +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor +import tech.jhipster.async.ExceptionHandlingAsyncTaskExecutor +import tech.jhipster.config.JHipsterProperties @Configuration @EnableAsync @EnableScheduling -public class AsyncConfiguration implements AsyncConfigurer { - - private static final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class); - +open class AsyncConfiguration : AsyncConfigurer { @Autowired - private JHipsterProperties jHipsterProperties; + private val jHipsterProperties: JHipsterProperties? = null + @Bean(name = ["taskExecutor"]) + override fun getAsyncExecutor(): ExceptionHandlingAsyncTaskExecutor { + log.debug("Creating Async Task Executor") + val executor = ThreadPoolTaskExecutor() + executor.corePoolSize = jHipsterProperties!!.async.corePoolSize + executor.maxPoolSize = jHipsterProperties.async.maxPoolSize + executor.queueCapacity = jHipsterProperties.async.queueCapacity + executor.setThreadNamePrefix("management-portal-Executor-") + return ExceptionHandlingAsyncTaskExecutor(executor) + } - @Override - @Bean(name = "taskExecutor") - public ExceptionHandlingAsyncTaskExecutor getAsyncExecutor() { - log.debug("Creating Async Task Executor"); - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - executor.setCorePoolSize(jHipsterProperties.getAsync().getCorePoolSize()); - executor.setMaxPoolSize(jHipsterProperties.getAsync().getMaxPoolSize()); - executor.setQueueCapacity(jHipsterProperties.getAsync().getQueueCapacity()); - executor.setThreadNamePrefix("management-portal-Executor-"); - return new ExceptionHandlingAsyncTaskExecutor(executor); + override fun getAsyncUncaughtExceptionHandler(): AsyncUncaughtExceptionHandler { + return SimpleAsyncUncaughtExceptionHandler() } - @Override - public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { - return new SimpleAsyncUncaughtExceptionHandler(); + companion object { + private val log = LoggerFactory.getLogger(AsyncConfiguration::class.java) } } diff --git a/src/main/java/org/radarbase/management/config/CacheConfiguration.kt b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt index 41b56bf88..57b0cd25e 100644 --- a/src/main/java/org/radarbase/management/config/CacheConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt @@ -1,119 +1,113 @@ -package org.radarbase.management.config; - -import com.hazelcast.config.AttributeConfig; -import com.hazelcast.config.Config; -import com.hazelcast.config.EvictionPolicy; -import com.hazelcast.config.IndexConfig; -import com.hazelcast.config.IndexType; -import com.hazelcast.config.MapConfig; -import com.hazelcast.config.NetworkConfig; -import com.hazelcast.core.Hazelcast; -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.spring.cache.HazelcastCacheManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -import org.springframework.cache.CacheManager; -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.session.hazelcast.Hazelcast4IndexedSessionRepository; -import org.springframework.session.hazelcast.Hazelcast4PrincipalNameExtractor; -import tech.jhipster.config.JHipsterConstants; -import tech.jhipster.config.JHipsterProperties; - -import javax.annotation.PreDestroy; -import java.util.List; - -import static com.hazelcast.config.MaxSizePolicy.USED_HEAP_SIZE; +package org.radarbase.management.config + +import com.hazelcast.config.AttributeConfig +import com.hazelcast.config.Config +import com.hazelcast.config.EvictionPolicy +import com.hazelcast.config.IndexConfig +import com.hazelcast.config.IndexType +import com.hazelcast.config.MapConfig +import com.hazelcast.config.MaxSizePolicy +import com.hazelcast.core.Hazelcast +import com.hazelcast.core.HazelcastInstance +import com.hazelcast.spring.cache.HazelcastCacheManager +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.AutoConfigureBefore +import org.springframework.cache.CacheManager +import org.springframework.cache.annotation.EnableCaching +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.core.env.Environment +import org.springframework.session.hazelcast.Hazelcast4IndexedSessionRepository +import org.springframework.session.hazelcast.Hazelcast4PrincipalNameExtractor +import tech.jhipster.config.JHipsterConstants +import tech.jhipster.config.JHipsterProperties +import javax.annotation.PreDestroy @Configuration @EnableCaching -@AutoConfigureBefore(value = {WebConfigurer.class, DatabaseConfiguration.class}) -public class CacheConfiguration { - - private static final Logger log = LoggerFactory.getLogger(CacheConfiguration.class); - +@AutoConfigureBefore(value = [WebConfigurer::class, DatabaseConfiguration::class]) +open class CacheConfiguration { @Autowired - private Environment env; - + private val env: Environment? = null @PreDestroy - public void destroy() { - log.info("Closing Cache Manager"); - Hazelcast.shutdownAll(); + fun destroy() { + log.info("Closing Cache Manager") + Hazelcast.shutdownAll() } @Bean - public CacheManager cacheManager(HazelcastInstance hazelcastInstance) { - log.debug("Starting HazelcastCacheManager"); - return new HazelcastCacheManager( - hazelcastInstance); + open fun HazelcastInstance?.cacheManager(): CacheManager { + log.debug("Starting HazelcastCacheManager") + return HazelcastCacheManager( + this + ) } @Bean - public Config hazelcastConfig(JHipsterProperties jHipsterProperties) { - Config config = new Config(); - config.setInstanceName("ManagementPortal"); - NetworkConfig networkConfig = config.getNetworkConfig(); - networkConfig.setPort(5701); - networkConfig.setPortAutoIncrement(true); + open fun hazelcastConfig(jHipsterProperties: JHipsterProperties): Config { + val config = Config() + config.setInstanceName("ManagementPortal") + val networkConfig = config.networkConfig + networkConfig.setPort(5701) + networkConfig.setPortAutoIncrement(true) // In development, remove multicast auto-configuration - if (env.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) { - networkConfig.getInterfaces().setEnabled(true); - networkConfig.getInterfaces().setInterfaces(List.of("127.0.0.1")); - - networkConfig.getJoin().getAwsConfig().setEnabled(false); - networkConfig.getJoin().getMulticastConfig().setEnabled(false); - networkConfig.getJoin().getTcpIpConfig().setEnabled(false); - networkConfig.getJoin().getAzureConfig().setEnabled(false); - networkConfig.getJoin().getGcpConfig().setEnabled(false); - networkConfig.getJoin().getEurekaConfig().setEnabled(false); - networkConfig.getJoin().getKubernetesConfig().setEnabled(false); + if (env!!.acceptsProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) { + networkConfig.interfaces.setEnabled(true) + networkConfig.interfaces.setInterfaces(listOf("127.0.0.1")) + networkConfig.join.awsConfig.setEnabled(false) + networkConfig.join.multicastConfig.setEnabled(false) + networkConfig.join.tcpIpConfig.setEnabled(false) + networkConfig.join.azureConfig.setEnabled(false) + networkConfig.join.gcpConfig.setEnabled(false) + networkConfig.join.eurekaConfig.setEnabled(false) + networkConfig.join.kubernetesConfig.setEnabled(false) } - AttributeConfig attributeConfig = new AttributeConfig() - .setName(Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE) - .setExtractorClassName(Hazelcast4PrincipalNameExtractor.class.getName()); + val attributeConfig = AttributeConfig() + .setName(Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE) + .setExtractorClassName(Hazelcast4PrincipalNameExtractor::class.java.getName()) config.getMapConfig(Hazelcast4IndexedSessionRepository.DEFAULT_SESSION_MAP_NAME) - .addAttributeConfig(attributeConfig).addIndexConfig( - new IndexConfig(IndexType.HASH, - Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE)); - config.getMapConfigs().put("default", initializeDefaultMapConfig()); - config.getMapConfigs().put("org.radarbase.management.domain.*", - initializeDomainMapConfig(jHipsterProperties)); - return config; + .addAttributeConfig(attributeConfig).addIndexConfig( + IndexConfig( + IndexType.HASH, + Hazelcast4IndexedSessionRepository.PRINCIPAL_NAME_ATTRIBUTE + ) + ) + config.mapConfigs["default"] = initializeDefaultMapConfig() + config.mapConfigs["org.radarbase.management.domain.*"] = initializeDomainMapConfig(jHipsterProperties) + return config } - private MapConfig initializeDefaultMapConfig() { - MapConfig mapConfig = new MapConfig(); + private fun initializeDefaultMapConfig(): MapConfig { + val mapConfig = MapConfig() /* Number of backups. If 1 is set as the backup-count for example, then all entries of the map will be copied to another JVM for - fail-safety. Valid numbers are 0 (no backup), 1, 2, 3. */ - mapConfig.setBackupCount(0); + fail-safety. Valid numbers are 0 (no backup), 1, 2, 3. */mapConfig.setBackupCount(0) /* Valid values are: NONE (no eviction), LRU (Least Recently Used), LFU (Least Frequently Used). - NONE is the default. */ - mapConfig.getEvictionConfig().setEvictionPolicy(EvictionPolicy.LRU); + NONE is the default. */mapConfig.evictionConfig.setEvictionPolicy(EvictionPolicy.LRU) /* Maximum size of the map. When max size is reached, map is evicted based on the policy defined. Any integer between 0 and Integer.MAX_VALUE. 0 means - Integer.MAX_VALUE. Default is 0. */ - mapConfig.getEvictionConfig().setMaxSizePolicy(USED_HEAP_SIZE); - - return mapConfig; + Integer.MAX_VALUE. Default is 0. */mapConfig.evictionConfig.setMaxSizePolicy(MaxSizePolicy.USED_HEAP_SIZE) + return mapConfig } - private MapConfig initializeDomainMapConfig(JHipsterProperties jHipsterProperties) { - MapConfig mapConfig = new MapConfig(); + private fun initializeDomainMapConfig(jHipsterProperties: JHipsterProperties): MapConfig { + val mapConfig = MapConfig() mapConfig.setTimeToLiveSeconds( - jHipsterProperties.getCache().getHazelcast().getTimeToLiveSeconds()); - return mapConfig; + jHipsterProperties.cache.hazelcast.timeToLiveSeconds + ) + return mapConfig + } + + companion object { + private val log = LoggerFactory.getLogger(CacheConfiguration::class.java) } } diff --git a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt index 971954b6f..752f96662 100644 --- a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt @@ -1,58 +1,60 @@ -package org.radarbase.management.config; - -import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module; -import liquibase.integration.spring.SpringLiquibase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.core.env.Profiles; -import org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean; -import org.springframework.data.jpa.repository.config.EnableJpaAuditing; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import org.springframework.transaction.annotation.EnableTransactionManagement; -import tech.jhipster.config.JHipsterConstants; - -import javax.sql.DataSource; +package org.radarbase.management.config + +import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module +import liquibase.integration.spring.SpringLiquibase +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.core.env.Environment +import org.springframework.core.env.Profiles +import org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean +import org.springframework.data.jpa.repository.config.EnableJpaAuditing +import org.springframework.data.jpa.repository.config.EnableJpaRepositories +import org.springframework.transaction.annotation.EnableTransactionManagement +import tech.jhipster.config.JHipsterConstants +import javax.sql.DataSource @Configuration -@EnableJpaRepositories(basePackages = "org.radarbase.management.repository", - repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class) +@EnableJpaRepositories( + basePackages = ["org.radarbase.management.repository"], + repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean::class +) @EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware") @EnableTransactionManagement -public class DatabaseConfiguration { - - private static final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class); - +open class DatabaseConfiguration { @Autowired - private Environment env; - + private val env: Environment? = null @Bean - public SpringLiquibase liquibase(DataSource dataSource, - LiquibaseProperties liquibaseProperties) { + open fun liquibase( + dataSource: DataSource?, + liquibaseProperties: LiquibaseProperties + ): SpringLiquibase { // Use liquibase.integration.spring.SpringLiquibase if you don't want Liquibase to start // asynchronously - SpringLiquibase liquibase = new SpringLiquibase(); - liquibase.setDataSource(dataSource); - liquibase.setChangeLog("classpath:config/liquibase/master.xml"); - liquibase.setContexts(liquibaseProperties.getContexts()); - liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema()); - liquibase.setDropFirst(liquibaseProperties.isDropFirst()); - if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE))) { - liquibase.setShouldRun(false); + val liquibase = SpringLiquibase() + liquibase.dataSource = dataSource + liquibase.changeLog = "classpath:config/liquibase/master.xml" + liquibase.contexts = liquibaseProperties.contexts + liquibase.defaultSchema = liquibaseProperties.defaultSchema + liquibase.isDropFirst = liquibaseProperties.isDropFirst + if (env!!.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE))) { + liquibase.setShouldRun(false) } else { - liquibase.setShouldRun(liquibaseProperties.isEnabled()); - log.debug("Configuring Liquibase"); + liquibase.setShouldRun(liquibaseProperties.isEnabled) + log.debug("Configuring Liquibase") } - return liquibase; + return liquibase } @Bean - public Hibernate5Module hibernate5Module() { - return new Hibernate5Module(); + open fun hibernate5Module(): Hibernate5Module { + return Hibernate5Module() + } + + companion object { + private val log = LoggerFactory.getLogger(DatabaseConfiguration::class.java) } } diff --git a/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt b/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt index 0dbf2d722..508f46ab1 100644 --- a/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt @@ -1,29 +1,23 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.springframework.context.annotation.Configuration; -import org.springframework.format.FormatterRegistry; -import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -import javax.annotation.Nonnull; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.ResolverStyle; - -import static java.time.temporal.ChronoField.HOUR_OF_DAY; -import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; -import static java.time.temporal.ChronoField.NANO_OF_SECOND; -import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; +import org.springframework.context.annotation.Configuration +import org.springframework.format.FormatterRegistry +import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import java.time.format.DateTimeFormatterBuilder +import java.time.format.ResolverStyle +import java.time.temporal.ChronoField +import javax.annotation.Nonnull @Configuration -public class DateTimeFormatConfiguration implements WebMvcConfigurer { - - @Override - public void addFormatters(@Nonnull FormatterRegistry registry) { - DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar(); - registrar.setUseIsoFormat(true); - registrar.setDateTimeFormatter(new DateTimeFormatterBuilder() +open class DateTimeFormatConfiguration : WebMvcConfigurer { + override fun addFormatters(@Nonnull registry: FormatterRegistry) { + val registrar = DateTimeFormatterRegistrar() + registrar.setUseIsoFormat(true) + registrar.setDateTimeFormatter( + DateTimeFormatterBuilder() .parseCaseInsensitive() .append(DateTimeFormatter.ISO_LOCAL_DATE) .optionalStart() @@ -41,13 +35,14 @@ public class DateTimeFormatConfiguration implements WebMvcConfigurer { .appendLiteral(']') .optionalEnd() .optionalEnd() - .parseDefaulting(HOUR_OF_DAY, HOUR_OF_DAY.range().getMinimum()) - .parseDefaulting(MINUTE_OF_HOUR, MINUTE_OF_HOUR.range().getMinimum()) - .parseDefaulting(SECOND_OF_MINUTE, SECOND_OF_MINUTE.range().getMinimum()) - .parseDefaulting(NANO_OF_SECOND, NANO_OF_SECOND.range().getMinimum()) + .parseDefaulting(ChronoField.HOUR_OF_DAY, ChronoField.HOUR_OF_DAY.range().minimum) + .parseDefaulting(ChronoField.MINUTE_OF_HOUR, ChronoField.MINUTE_OF_HOUR.range().minimum) + .parseDefaulting(ChronoField.SECOND_OF_MINUTE, ChronoField.SECOND_OF_MINUTE.range().minimum) + .parseDefaulting(ChronoField.NANO_OF_SECOND, ChronoField.NANO_OF_SECOND.range().minimum) .toFormatter() .withZone(ZoneId.of("UTC")) - .withResolverStyle(ResolverStyle.LENIENT)); - registrar.registerFormatters(registry); + .withResolverStyle(ResolverStyle.LENIENT) + ) + registrar.registerFormatters(registry) } } diff --git a/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt b/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt index 3d30a9765..856175555 100644 --- a/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt @@ -1,34 +1,31 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import tech.jhipster.config.locale.AngularCookieLocaleResolver; -import org.springframework.context.EnvironmentAware; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.web.servlet.LocaleResolver; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; +import org.springframework.context.EnvironmentAware +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.core.env.Environment +import org.springframework.web.servlet.LocaleResolver +import org.springframework.web.servlet.config.annotation.InterceptorRegistry +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer +import org.springframework.web.servlet.i18n.LocaleChangeInterceptor +import tech.jhipster.config.locale.AngularCookieLocaleResolver @Configuration -public class LocaleConfiguration implements WebMvcConfigurer, EnvironmentAware { - - @Override - public void setEnvironment(Environment environment) { +open class LocaleConfiguration : WebMvcConfigurer, EnvironmentAware { + override fun setEnvironment(environment: Environment) { // unused } - @Bean(name = "localeResolver") - public LocaleResolver localeResolver() { - AngularCookieLocaleResolver cookieLocaleResolver = new AngularCookieLocaleResolver(); - cookieLocaleResolver.setCookieName("NG_TRANSLATE_LANG_KEY"); - return cookieLocaleResolver; + @Bean(name = ["localeResolver"]) + open fun localeResolver(): LocaleResolver { + val cookieLocaleResolver = AngularCookieLocaleResolver() + cookieLocaleResolver.cookieName = "NG_TRANSLATE_LANG_KEY" + return cookieLocaleResolver } - @Override - public void addInterceptors(InterceptorRegistry registry) { - LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor(); - localeChangeInterceptor.setParamName("language"); - registry.addInterceptor(localeChangeInterceptor); + override fun addInterceptors(registry: InterceptorRegistry) { + val localeChangeInterceptor = LocaleChangeInterceptor() + localeChangeInterceptor.paramName = "language" + registry.addInterceptor(localeChangeInterceptor) } } diff --git a/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt b/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt index e2f0e71f4..33bdb8a5c 100644 --- a/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt @@ -1,20 +1,19 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import tech.jhipster.config.JHipsterConstants; -import org.radarbase.management.aop.logging.LoggingAspect; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.EnableAspectJAutoProxy; -import org.springframework.context.annotation.Profile; -import org.springframework.core.env.Environment; +import org.radarbase.management.aop.logging.LoggingAspect +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.EnableAspectJAutoProxy +import org.springframework.context.annotation.Profile +import org.springframework.core.env.Environment +import tech.jhipster.config.JHipsterConstants @Configuration @EnableAspectJAutoProxy -public class LoggingAspectConfiguration { - +open class LoggingAspectConfiguration { @Bean @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) - public LoggingAspect loggingAspect(Environment env) { - return new LoggingAspect(env); + open fun loggingAspect(env: Environment?): LoggingAspect { + return LoggingAspect(env!!) } } diff --git a/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt b/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt index 1899a111e..6e6651e07 100644 --- a/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt @@ -1,46 +1,37 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import ch.qos.logback.classic.LoggerContext; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; -import tech.jhipster.config.JHipsterProperties; - -import java.util.HashMap; -import java.util.Map; - -import static tech.jhipster.config.logging.LoggingUtils.addContextListener; -import static tech.jhipster.config.logging.LoggingUtils.addJsonConsoleAppender; -import static tech.jhipster.config.logging.LoggingUtils.addLogstashTcpSocketAppender; +import ch.qos.logback.classic.LoggerContext +import com.fasterxml.jackson.databind.ObjectMapper +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Configuration +import tech.jhipster.config.JHipsterProperties +import tech.jhipster.config.logging.LoggingUtils @Configuration -public class LoggingConfiguration { - /** Logging configuration for JHipster. */ - public LoggingConfiguration(@Value("${spring.application.name}") String appName, - @Value("${server.port}") String serverPort, - JHipsterProperties jHipsterProperties, - ObjectMapper mapper) throws JsonProcessingException { - LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); - - Map map = new HashMap<>(); - map.put("app_name", appName); - map.put("app_port", serverPort); - - String customFields = mapper.writeValueAsString(map); - - JHipsterProperties.Logging loggingProperties = jHipsterProperties.getLogging(); - JHipsterProperties.Logging.Logstash logstashProperties = loggingProperties.getLogstash(); - - if (loggingProperties.isUseJsonFormat()) { - addJsonConsoleAppender(context, customFields); +open class LoggingConfiguration( + @Value("\${spring.application.name}") appName: String, + @Value("\${server.port}") serverPort: String, + jHipsterProperties: JHipsterProperties, + mapper: ObjectMapper +) { + /** Logging configuration for JHipster. */ + init { + val context = LoggerFactory.getILoggerFactory() as LoggerContext + val map: MutableMap = HashMap() + map["app_name"] = appName + map["app_port"] = serverPort + val customFields = mapper.writeValueAsString(map) + val loggingProperties = jHipsterProperties.logging + val logstashProperties = loggingProperties.logstash + if (loggingProperties.isUseJsonFormat) { + LoggingUtils.addJsonConsoleAppender(context, customFields) } - if (logstashProperties.isEnabled()) { - addLogstashTcpSocketAppender(context, customFields, logstashProperties); + if (logstashProperties.isEnabled) { + LoggingUtils.addLogstashTcpSocketAppender(context, customFields, logstashProperties) } - if (loggingProperties.isUseJsonFormat() || logstashProperties.isEnabled()) { - addContextListener(context, customFields, loggingProperties); + if (loggingProperties.isUseJsonFormat || logstashProperties.isEnabled) { + LoggingUtils.addContextListener(context, customFields, loggingProperties) } } } diff --git a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt index 7f9755c6f..ee0d02c04 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt @@ -1,311 +1,303 @@ -package org.radarbase.management.config; - -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.security.ClaimsTokenEnhancer; -import org.radarbase.management.security.Http401UnauthorizedEntryPoint; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.security.PostgresApprovalStore; -import org.radarbase.management.security.jwt.ManagementPortalJwtAccessTokenConverter; -import org.radarbase.management.security.jwt.ManagementPortalJwtTokenStore; -import org.radarbase.management.security.jwt.ManagementPortalOauthKeyStoreHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.core.annotation.Order; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.Authentication; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; -import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; -import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; -import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; -import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; -import org.springframework.security.oauth2.provider.approval.ApprovalStore; -import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore; -import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; -import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; -import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices; -import org.springframework.security.oauth2.provider.token.DefaultTokenServices; -import org.springframework.security.oauth2.provider.token.TokenEnhancer; -import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; -import org.springframework.security.oauth2.provider.token.TokenStore; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; - -import javax.sql.DataSource; -import java.util.Arrays; - -import static org.springframework.orm.jpa.vendor.Database.POSTGRESQL; +package org.radarbase.management.config + +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.security.ClaimsTokenEnhancer +import org.radarbase.management.security.Http401UnauthorizedEntryPoint +import org.radarbase.management.security.JwtAuthenticationFilter +import org.radarbase.management.security.PostgresApprovalStore +import org.radarbase.management.security.jwt.ManagementPortalJwtAccessTokenConverter +import org.radarbase.management.security.jwt.ManagementPortalJwtTokenStore +import org.radarbase.management.security.jwt.ManagementPortalOauthKeyStoreHandler +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Primary +import org.springframework.core.annotation.Order +import org.springframework.http.HttpMethod +import org.springframework.orm.jpa.vendor.Database +import org.springframework.security.authentication.AuthenticationManager +import org.springframework.security.authentication.DefaultAuthenticationEventPublisher +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter +import org.springframework.security.config.http.SessionCreationPolicy +import org.springframework.security.core.Authentication +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer +import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer +import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer +import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer +import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer +import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer +import org.springframework.security.oauth2.provider.approval.ApprovalStore +import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService +import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices +import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices +import org.springframework.security.oauth2.provider.token.DefaultTokenServices +import org.springframework.security.oauth2.provider.token.TokenEnhancer +import org.springframework.security.oauth2.provider.token.TokenEnhancerChain +import org.springframework.security.oauth2.provider.token.TokenStore +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler +import java.util.* +import javax.sql.DataSource @Configuration -public class OAuth2ServerConfiguration { - private static final Logger logger = LoggerFactory.getLogger(OAuth2ServerConfiguration.class); - +open class OAuth2ServerConfiguration { @Autowired - private DataSource dataSource; + private val dataSource: DataSource? = null @Autowired - private PasswordEncoder passwordEncoder; + private val passwordEncoder: PasswordEncoder? = null @Configuration @Order(-20) - protected static class LoginConfig extends WebSecurityConfigurerAdapter { + protected open class LoginConfig : WebSecurityConfigurerAdapter() { @Autowired - private AuthenticationManager authenticationManager; + private val authenticationManager: AuthenticationManager? = null @Autowired - private JwtAuthenticationFilter jwtAuthenticationFilter; - - @Override - protected void configure(HttpSecurity http) throws Exception { + private val jwtAuthenticationFilter: JwtAuthenticationFilter? = null + @Throws(Exception::class) + override fun configure(http: HttpSecurity) { http - .formLogin().loginPage("/login").permitAll() - .and() - .addFilterAfter(jwtAuthenticationFilter, - UsernamePasswordAuthenticationFilter.class) - .requestMatchers() - .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access") - - .and() - .authorizeRequests().anyRequest().authenticated(); + .formLogin().loginPage("/login").permitAll() + .and() + .addFilterAfter( + jwtAuthenticationFilter, + UsernamePasswordAuthenticationFilter::class.java + ) + .requestMatchers() + .antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access") + .and() + .authorizeRequests().anyRequest().authenticated() } - @Override - protected void configure(AuthenticationManagerBuilder auth) throws Exception { - auth.parentAuthenticationManager(authenticationManager); + @Throws(Exception::class) + override fun configure(auth: AuthenticationManagerBuilder) { + auth.parentAuthenticationManager(authenticationManager) } - } @Configuration - public static class JwtAuthenticationFilterConfiguration { + open class JwtAuthenticationFilterConfiguration { @Autowired - private AuthenticationManager authenticationManager; + private val authenticationManager: AuthenticationManager? = null @Autowired - private UserRepository userRepository; + private val userRepository: UserRepository? = null @Autowired - private ManagementPortalOauthKeyStoreHandler keyStoreHandler; - + private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null @Bean - public JwtAuthenticationFilter jwtAuthenticationFilter() { - return new JwtAuthenticationFilter( - keyStoreHandler.getTokenValidator(), - authenticationManager, - userRepository, - true); + open fun jwtAuthenticationFilter(): JwtAuthenticationFilter { + return JwtAuthenticationFilter( + keyStoreHandler!!.getTokenValidator(), + authenticationManager!!, + userRepository!!, + true + ) } } @Bean - public JdbcClientDetailsService jdbcClientDetailsService() { - JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource); - clientDetailsService.setPasswordEncoder(passwordEncoder); - return clientDetailsService; + open fun jdbcClientDetailsService(): JdbcClientDetailsService { + val clientDetailsService = JdbcClientDetailsService(dataSource) + clientDetailsService.setPasswordEncoder(passwordEncoder) + return clientDetailsService } @Configuration @EnableResourceServer - protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { + protected open class ResourceServerConfiguration : ResourceServerConfigurerAdapter() { @Autowired - private ManagementPortalOauthKeyStoreHandler keyStoreHandler; + private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null @Autowired - private TokenStore tokenStore; + private val tokenStore: TokenStore? = null @Autowired - private Http401UnauthorizedEntryPoint http401UnauthorizedEntryPoint; + private val http401UnauthorizedEntryPoint: Http401UnauthorizedEntryPoint? = null @Autowired - private LogoutSuccessHandler logoutSuccessHandler; + private val logoutSuccessHandler: LogoutSuccessHandler? = null @Autowired - private AuthenticationManager authenticationManager; + private val authenticationManager: AuthenticationManager? = null @Autowired - private UserRepository userRepository; - - public JwtAuthenticationFilter jwtAuthenticationFilter() { - return new JwtAuthenticationFilter( - keyStoreHandler.getTokenValidator(), authenticationManager, userRepository + private val userRepository: UserRepository? = null + fun jwtAuthenticationFilter(): JwtAuthenticationFilter { + return JwtAuthenticationFilter( + keyStoreHandler!!.getTokenValidator(), authenticationManager!!, userRepository!! ) - .skipUrlPattern(HttpMethod.GET, "/management/health") - .skipUrlPattern(HttpMethod.GET, "/api/meta-token/*") - .skipUrlPattern(HttpMethod.GET, "/api/sitesettings") - .skipUrlPattern(HttpMethod.GET, "/images/**") - .skipUrlPattern(HttpMethod.GET, "/css/**") - .skipUrlPattern(HttpMethod.GET, "/js/**") - .skipUrlPattern(HttpMethod.GET, "/radar-baseRR.png"); + .skipUrlPattern(HttpMethod.GET, "/management/health") + .skipUrlPattern(HttpMethod.GET, "/api/meta-token/*") + .skipUrlPattern(HttpMethod.GET, "/api/sitesettings") + .skipUrlPattern(HttpMethod.GET, "/images/**") + .skipUrlPattern(HttpMethod.GET, "/css/**") + .skipUrlPattern(HttpMethod.GET, "/js/**") + .skipUrlPattern(HttpMethod.GET, "/radar-baseRR.png") } - @Override - public void configure(HttpSecurity http) throws Exception { + @Throws(Exception::class) + override fun configure(http: HttpSecurity) { http - .exceptionHandling() - .authenticationEntryPoint(http401UnauthorizedEntryPoint) - .and() - .logout() - .invalidateHttpSession(true) - .logoutUrl("/api/logout") - .logoutSuccessHandler(logoutSuccessHandler) - .and() - .csrf() - .disable() - .addFilterBefore(jwtAuthenticationFilter(), - UsernamePasswordAuthenticationFilter.class) - .headers() - .frameOptions() - .disable() - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) - .and() - .authorizeRequests() - .antMatchers("/oauth/**").permitAll() - .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() - .antMatchers("/api/register") - .hasAnyAuthority(RoleAuthority.SYS_ADMIN_AUTHORITY) - .antMatchers("/api/profile-info").permitAll() - .antMatchers("/api/sitesettings").permitAll() - .antMatchers("/api/**").authenticated() - // Allow management/health endpoint to all to allow kubernetes to be able to - // detect the health of the service - .antMatchers("/management/health").permitAll() - .antMatchers("/management/**") - .hasAnyAuthority(RoleAuthority.SYS_ADMIN_AUTHORITY) - .antMatchers("/v2/api-docs/**").permitAll() - .antMatchers("/swagger-resources/configuration/ui").permitAll() - .antMatchers("/swagger-ui/index.html") - .hasAnyAuthority(RoleAuthority.SYS_ADMIN_AUTHORITY); + .exceptionHandling() + .authenticationEntryPoint(http401UnauthorizedEntryPoint) + .and() + .logout() + .invalidateHttpSession(true) + .logoutUrl("/api/logout") + .logoutSuccessHandler(logoutSuccessHandler) + .and() + .csrf() + .disable() + .addFilterBefore( + jwtAuthenticationFilter(), + UsernamePasswordAuthenticationFilter::class.java + ) + .headers() + .frameOptions() + .disable() + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.ALWAYS) + .and() + .authorizeRequests() + .antMatchers("/oauth/**").permitAll() + .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() + .antMatchers("/api/register") + .hasAnyAuthority(RoleAuthority.SYS_ADMIN_AUTHORITY) + .antMatchers("/api/profile-info").permitAll() + .antMatchers("/api/sitesettings").permitAll() + .antMatchers("/api/**") + .authenticated() // Allow management/health endpoint to all to allow kubernetes to be able to + // detect the health of the service + .antMatchers("/management/health").permitAll() + .antMatchers("/management/**") + .hasAnyAuthority(RoleAuthority.SYS_ADMIN_AUTHORITY) + .antMatchers("/v2/api-docs/**").permitAll() + .antMatchers("/swagger-resources/configuration/ui").permitAll() + .antMatchers("/swagger-ui/index.html") + .hasAnyAuthority(RoleAuthority.SYS_ADMIN_AUTHORITY) } - @Override - public void configure(ResourceServerSecurityConfigurer resources) throws Exception { + @Throws(Exception::class) + override fun configure(resources: ResourceServerSecurityConfigurer) { resources.resourceId("res_ManagementPortal") - .tokenStore(tokenStore) - .eventPublisher(new CustomEventPublisher()); + .tokenStore(tokenStore) + .eventPublisher(CustomEventPublisher()) } - protected static class CustomEventPublisher extends DefaultAuthenticationEventPublisher { - - @Override - public void publishAuthenticationSuccess(Authentication authentication) { + protected class CustomEventPublisher : DefaultAuthenticationEventPublisher() { + override fun publishAuthenticationSuccess(authentication: Authentication) { // OAuth2AuthenticationProcessingFilter publishes an authentication success audit // event for EVERY successful OAuth request to our API resources, this is way too // much so we override the event publisher to not publish these events. } } - } @Configuration @EnableAuthorizationServer - protected static class AuthorizationServerConfiguration extends - AuthorizationServerConfigurerAdapter { - + protected open class AuthorizationServerConfiguration : AuthorizationServerConfigurerAdapter() { @Autowired - private JpaProperties jpaProperties; + private val jpaProperties: JpaProperties? = null @Autowired @Qualifier("authenticationManagerBean") - private AuthenticationManager authenticationManager; + private val authenticationManager: AuthenticationManager? = null @Autowired - private DataSource dataSource; + private val dataSource: DataSource? = null @Autowired - private JdbcClientDetailsService jdbcClientDetailsService; + private val jdbcClientDetailsService: JdbcClientDetailsService? = null @Autowired - private ManagementPortalOauthKeyStoreHandler keyStoreHandler; - + private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null @Bean - protected AuthorizationCodeServices authorizationCodeServices() { - return new JdbcAuthorizationCodeServices(dataSource); + protected open fun authorizationCodeServices(): AuthorizationCodeServices { + return JdbcAuthorizationCodeServices(dataSource) } @Bean - public ApprovalStore approvalStore() { - if (jpaProperties.getDatabase().equals(POSTGRESQL)) { - return new PostgresApprovalStore(dataSource); + open fun approvalStore(): ApprovalStore { + return if (jpaProperties!!.database == Database.POSTGRESQL) { + PostgresApprovalStore(dataSource) } else { // to have compatibility for other databases including H2 - return new JdbcApprovalStore(dataSource); + JdbcApprovalStore(dataSource) } } @Bean - public TokenEnhancer tokenEnhancer() { - return new ClaimsTokenEnhancer(); + open fun tokenEnhancer(): TokenEnhancer { + return ClaimsTokenEnhancer() } @Bean - public TokenStore tokenStore() { - return new ManagementPortalJwtTokenStore(accessTokenConverter()); + open fun tokenStore(): TokenStore { + return ManagementPortalJwtTokenStore(accessTokenConverter()) } @Bean - public ManagementPortalJwtAccessTokenConverter accessTokenConverter() { - logger.debug("loading token converter from keystore configurations"); - return new ManagementPortalJwtAccessTokenConverter( - keyStoreHandler.getAlgorithmForSigning(), - keyStoreHandler.getVerifiers(), - keyStoreHandler.getRefreshTokenVerifiers()); + open fun accessTokenConverter(): ManagementPortalJwtAccessTokenConverter { + logger.debug("loading token converter from keystore configurations") + return ManagementPortalJwtAccessTokenConverter( + keyStoreHandler!!.getAlgorithmForSigning(), + keyStoreHandler.verifiers, + keyStoreHandler.refreshTokenVerifiers + ) } @Bean @Primary - public DefaultTokenServices tokenServices(TokenStore tokenStore) { - DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); - defaultTokenServices.setTokenStore(tokenStore); - defaultTokenServices.setSupportRefreshToken(true); - defaultTokenServices.setReuseRefreshToken(false); - return defaultTokenServices; + open fun tokenServices(tokenStore: TokenStore?): DefaultTokenServices { + val defaultTokenServices = DefaultTokenServices() + defaultTokenServices.setTokenStore(tokenStore) + defaultTokenServices.setSupportRefreshToken(true) + defaultTokenServices.setReuseRefreshToken(false) + return defaultTokenServices } - @Override - public void configure(AuthorizationServerEndpointsConfigurer endpoints) { - TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); + override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) { + val tokenEnhancerChain = TokenEnhancerChain() tokenEnhancerChain.setTokenEnhancers( - Arrays.asList(tokenEnhancer(), accessTokenConverter())); - + Arrays.asList(tokenEnhancer(), accessTokenConverter()) + ) endpoints - .authorizationCodeServices(authorizationCodeServices()) - .approvalStore(approvalStore()) - .tokenStore(tokenStore()) - .tokenEnhancer(tokenEnhancerChain) - .reuseRefreshTokens(false) - .authenticationManager(authenticationManager); + .authorizationCodeServices(authorizationCodeServices()) + .approvalStore(approvalStore()) + .tokenStore(tokenStore()) + .tokenEnhancer(tokenEnhancerChain) + .reuseRefreshTokens(false) + .authenticationManager(authenticationManager) } - @Override - public void configure(AuthorizationServerSecurityConfigurer oauthServer) { + override fun configure(oauthServer: AuthorizationServerSecurityConfigurer) { oauthServer.allowFormAuthenticationForClients() - .checkTokenAccess("isAuthenticated()") - .tokenKeyAccess("permitAll()") - .passwordEncoder(new BCryptPasswordEncoder()); + .checkTokenAccess("isAuthenticated()") + .tokenKeyAccess("permitAll()") + .passwordEncoder(BCryptPasswordEncoder()) } - @Override - public void configure(ClientDetailsServiceConfigurer clients) throws Exception { - clients.withClientDetails(jdbcClientDetailsService); + @Throws(Exception::class) + override fun configure(clients: ClientDetailsServiceConfigurer) { + clients.withClientDetails(jdbcClientDetailsService) } } + + companion object { + private val logger = LoggerFactory.getLogger(OAuth2ServerConfiguration::class.java) + } } diff --git a/src/main/java/org/radarbase/management/config/package-info.kt b/src/main/java/org/radarbase/management/config/package-info.kt index e1b91b4d3..dd8ac5d6b 100644 --- a/src/main/java/org/radarbase/management/config/package-info.kt +++ b/src/main/java/org/radarbase/management/config/package-info.kt @@ -1,4 +1,4 @@ /** * Spring Framework configuration files. */ -package org.radarbase.management.config; +package org.radarbase.management.config From 38b3e646d590ed711f89ed0d04e1056df5046b78 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 14:58:38 +0200 Subject: [PATCH 081/158] Rename .java to .kt --- .../config/{OpenApiConfiguration.java => OpenApiConfiguration.kt} | 0 .../{RadarTokenConfiguration.java => RadarTokenConfiguration.kt} | 0 .../{SecurityConfiguration.java => SecurityConfiguration.kt} | 0 .../config/{SourceTypeLoader.java => SourceTypeLoader.kt} | 0 .../{ThymeleafConfiguration.java => ThymeleafConfiguration.kt} | 0 .../management/config/{WebConfigurer.java => WebConfigurer.kt} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/config/{OpenApiConfiguration.java => OpenApiConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{RadarTokenConfiguration.java => RadarTokenConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{SecurityConfiguration.java => SecurityConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{SourceTypeLoader.java => SourceTypeLoader.kt} (100%) rename src/main/java/org/radarbase/management/config/{ThymeleafConfiguration.java => ThymeleafConfiguration.kt} (100%) rename src/main/java/org/radarbase/management/config/{WebConfigurer.java => WebConfigurer.kt} (100%) diff --git a/src/main/java/org/radarbase/management/config/OpenApiConfiguration.java b/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/OpenApiConfiguration.java rename to src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.java b/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/RadarTokenConfiguration.java rename to src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/SecurityConfiguration.java b/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/SecurityConfiguration.java rename to src/main/java/org/radarbase/management/config/SecurityConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/SourceTypeLoader.java b/src/main/java/org/radarbase/management/config/SourceTypeLoader.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/SourceTypeLoader.java rename to src/main/java/org/radarbase/management/config/SourceTypeLoader.kt diff --git a/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.java b/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/ThymeleafConfiguration.java rename to src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt diff --git a/src/main/java/org/radarbase/management/config/WebConfigurer.java b/src/main/java/org/radarbase/management/config/WebConfigurer.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/WebConfigurer.java rename to src/main/java/org/radarbase/management/config/WebConfigurer.kt From 5bff0760415e877d20d12024e02aebbbe8579e07 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 14:58:39 +0200 Subject: [PATCH 082/158] finished config folder --- .../management/config/OpenApiConfiguration.kt | 75 ++++---- .../config/RadarTokenConfiguration.kt | 37 ++-- .../config/SecurityConfiguration.kt | 167 ++++++++---------- .../management/config/SourceTypeLoader.kt | 100 +++++------ .../config/ThymeleafConfiguration.kt | 31 ++-- .../management/config/WebConfigurer.kt | 147 ++++++++------- 6 files changed, 266 insertions(+), 291 deletions(-) diff --git a/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt b/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt index b161b51e9..7e3d96126 100644 --- a/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt @@ -6,41 +6,54 @@ * * See the file LICENSE in the root of this repository. */ +package org.radarbase.management.config -package org.radarbase.management.config; - -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.info.License; -import io.swagger.v3.oas.models.security.OAuthFlow; -import io.swagger.v3.oas.models.security.OAuthFlows; -import io.swagger.v3.oas.models.security.SecurityScheme; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Profile; -import tech.jhipster.config.JHipsterConstants; +import io.swagger.v3.oas.models.Components +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.info.Info +import io.swagger.v3.oas.models.info.License +import io.swagger.v3.oas.models.security.OAuthFlow +import io.swagger.v3.oas.models.security.OAuthFlows +import io.swagger.v3.oas.models.security.SecurityScheme +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Profile +import tech.jhipster.config.JHipsterConstants @Configuration @Profile(JHipsterConstants.SPRING_PROFILE_API_DOCS) -public class OpenApiConfiguration { +open class OpenApiConfiguration { @Bean - public OpenAPI customOpenAPI() { - return new OpenAPI() - .components(new Components() - .addSecuritySchemes("oauth2Login", new SecurityScheme() - .type(SecurityScheme.Type.OAUTH2) - .flows(new OAuthFlows() - .authorizationCode(new OAuthFlow() - .authorizationUrl("/oauth/authorize") - .tokenUrl("/oauth/token")) - .clientCredentials(new OAuthFlow() - .tokenUrl("/oauth/token"))))) - .info(new Info() - .title("ManagementPortal API") - .description("ManagementPortal for RADAR-base") - .license(new License() - .name("Apache 2.0") - .url("https://radar-base.org"))); + open fun customOpenAPI(): OpenAPI { + return OpenAPI() + .components( + Components() + .addSecuritySchemes( + "oauth2Login", SecurityScheme() + .type(SecurityScheme.Type.OAUTH2) + .flows( + OAuthFlows() + .authorizationCode( + OAuthFlow() + .authorizationUrl("/oauth/authorize") + .tokenUrl("/oauth/token") + ) + .clientCredentials( + OAuthFlow() + .tokenUrl("/oauth/token") + ) + ) + ) + ) + .info( + Info() + .title("ManagementPortal API") + .description("ManagementPortal for RADAR-base") + .license( + License() + .name("Apache 2.0") + .url("https://radar-base.org") + ) + ) } } diff --git a/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt b/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt index 6f5633bf4..deb2e5484 100644 --- a/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt @@ -1,30 +1,19 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.radarbase.auth.token.RadarToken; -import org.radarbase.management.security.jwt.RadarTokenLoader; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; - -import javax.annotation.Nullable; -import javax.servlet.http.HttpServletRequest; - -import static org.springframework.context.annotation.ScopedProxyMode.TARGET_CLASS; +import org.radarbase.auth.token.RadarToken +import org.radarbase.management.security.jwt.RadarTokenLoader +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Scope +import org.springframework.context.annotation.ScopedProxyMode +import javax.servlet.http.HttpServletRequest @Configuration -public class RadarTokenConfiguration { - private final RadarTokenLoader radarTokenLoader; - - @Autowired - public RadarTokenConfiguration(RadarTokenLoader radarTokenLoader) { - this.radarTokenLoader = radarTokenLoader; - } - - @Scope(value = "request", proxyMode = TARGET_CLASS) +class RadarTokenConfiguration @Autowired constructor(private val radarTokenLoader: RadarTokenLoader) { + @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) @Bean - @Nullable - public RadarToken radarToken(HttpServletRequest request) { - return radarTokenLoader.loadToken(request); + fun radarToken(request: HttpServletRequest?): RadarToken? { + return radarTokenLoader.loadToken(request!!) } } diff --git a/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt b/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt index 1f85f5b0c..8089515f7 100644 --- a/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt @@ -1,120 +1,105 @@ -package org.radarbase.management.config; +package org.radarbase.management.config - -import org.radarbase.management.security.Http401UnauthorizedEntryPoint; -import org.radarbase.management.security.RadarAuthenticationProvider; -import org.springframework.beans.factory.BeanInitializationException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.builders.WebSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; -import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; -import tech.jhipster.security.AjaxLogoutSuccessHandler; - -import javax.annotation.PostConstruct; +import org.radarbase.management.security.Http401UnauthorizedEntryPoint +import org.radarbase.management.security.RadarAuthenticationProvider +import org.springframework.beans.factory.BeanInitializationException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.ApplicationEventPublisher +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.http.HttpMethod +import org.springframework.security.authentication.AuthenticationManager +import org.springframework.security.authentication.DefaultAuthenticationEventPublisher +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.builders.WebSecurity +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter +import org.springframework.security.config.http.SessionCreationPolicy +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler +import tech.jhipster.security.AjaxLogoutSuccessHandler +import javax.annotation.PostConstruct @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) -public class SecurityConfiguration extends WebSecurityConfigurerAdapter { - private final AuthenticationManagerBuilder authenticationManagerBuilder; - - private final UserDetailsService userDetailsService; - - private final ApplicationEventPublisher applicationEventPublisher; - private final PasswordEncoder passwordEncoder; - - /** Security configuration constructor. */ - @Autowired - public SecurityConfiguration(AuthenticationManagerBuilder authenticationManagerBuilder, - UserDetailsService userDetailsService, - ApplicationEventPublisher applicationEventPublisher, - PasswordEncoder passwordEncoder) { - this.authenticationManagerBuilder = authenticationManagerBuilder; - this.userDetailsService = userDetailsService; - this.applicationEventPublisher = applicationEventPublisher; - this.passwordEncoder = passwordEncoder; - } - +open class SecurityConfiguration +/** Security configuration constructor. */ @Autowired constructor( + private val authenticationManagerBuilder: AuthenticationManagerBuilder, + private val userDetailsService: UserDetailsService, + private val applicationEventPublisher: ApplicationEventPublisher, + private val passwordEncoder: PasswordEncoder +) : WebSecurityConfigurerAdapter() { @PostConstruct - public void init() { + fun init() { try { authenticationManagerBuilder - .userDetailsService(userDetailsService) - .passwordEncoder(passwordEncoder) - .and() - .authenticationProvider(new RadarAuthenticationProvider()) - .authenticationEventPublisher( - new DefaultAuthenticationEventPublisher(applicationEventPublisher)); - } catch (Exception e) { - throw new BeanInitializationException("Security configuration failed", e); + .userDetailsService(userDetailsService) + .passwordEncoder(passwordEncoder) + .and() + .authenticationProvider(RadarAuthenticationProvider()) + .authenticationEventPublisher( + DefaultAuthenticationEventPublisher(applicationEventPublisher) + ) + } catch (e: Exception) { + throw BeanInitializationException("Security configuration failed", e) } } @Bean - public LogoutSuccessHandler logoutSuccessHandler() { - return new AjaxLogoutSuccessHandler(); + open fun logoutSuccessHandler(): LogoutSuccessHandler { + return AjaxLogoutSuccessHandler() } @Bean - public Http401UnauthorizedEntryPoint http401UnauthorizedEntryPoint() { - return new Http401UnauthorizedEntryPoint(); + open fun http401UnauthorizedEntryPoint(): Http401UnauthorizedEntryPoint { + return Http401UnauthorizedEntryPoint() } - @Override - public void configure(WebSecurity web) { + override fun configure(web: WebSecurity) { web.ignoring() - .antMatchers("/") - .antMatchers("/*.{js,ico,css,html}") - .antMatchers(HttpMethod.OPTIONS, "/**") - .antMatchers("/app/**/*.{js,html}") - .antMatchers("/bower_components/**") - .antMatchers("/i18n/**") - .antMatchers("/content/**") - .antMatchers("/swagger-ui/**") - .antMatchers("/api-docs/**") - .antMatchers("/swagger-ui.html") - .antMatchers("/api-docs{,.json,.yml}") - .antMatchers("/api/register") - .antMatchers("/api/profile-info") - .antMatchers("/api/activate") - .antMatchers("/api/account/reset_password/init") - .antMatchers("/api/account/reset_password/finish") - .antMatchers("/test/**") - .antMatchers("/management/health") - .antMatchers(HttpMethod.GET, "/api/meta-token/**"); + .antMatchers("/") + .antMatchers("/*.{js,ico,css,html}") + .antMatchers(HttpMethod.OPTIONS, "/**") + .antMatchers("/app/**/*.{js,html}") + .antMatchers("/bower_components/**") + .antMatchers("/i18n/**") + .antMatchers("/content/**") + .antMatchers("/swagger-ui/**") + .antMatchers("/api-docs/**") + .antMatchers("/swagger-ui.html") + .antMatchers("/api-docs{,.json,.yml}") + .antMatchers("/api/register") + .antMatchers("/api/profile-info") + .antMatchers("/api/activate") + .antMatchers("/api/account/reset_password/init") + .antMatchers("/api/account/reset_password/finish") + .antMatchers("/test/**") + .antMatchers("/management/health") + .antMatchers(HttpMethod.GET, "/api/meta-token/**") } - @Override - public void configure(HttpSecurity http) throws Exception { + @Throws(Exception::class) + public override fun configure(http: HttpSecurity) { http - .httpBasic().realmName("ManagementPortal") - .and() - .sessionManagement() - .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); + .httpBasic().realmName("ManagementPortal") + .and() + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) } - @Override @Bean - public AuthenticationManager authenticationManagerBean() throws Exception { - return super.authenticationManagerBean(); + @Throws(Exception::class) + override fun authenticationManagerBean(): AuthenticationManager { + return super.authenticationManagerBean() } @Bean - public SecurityEvaluationContextExtension securityEvaluationContextExtension() { - return new SecurityEvaluationContextExtension(); + open fun securityEvaluationContextExtension(): SecurityEvaluationContextExtension { + return SecurityEvaluationContextExtension() } } diff --git a/src/main/java/org/radarbase/management/config/SourceTypeLoader.kt b/src/main/java/org/radarbase/management/config/SourceTypeLoader.kt index dbe666d7d..e456f9e95 100644 --- a/src/main/java/org/radarbase/management/config/SourceTypeLoader.kt +++ b/src/main/java/org/radarbase/management/config/SourceTypeLoader.kt @@ -1,20 +1,14 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.radarbase.management.service.SourceTypeService; -import org.radarbase.management.service.catalog.CatalogSourceType; -import org.radarbase.management.service.catalog.SourceTypeResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.CommandLineRunner; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestClientException; -import org.springframework.web.client.RestTemplate; +import org.radarbase.management.service.SourceTypeService +import org.radarbase.management.service.catalog.CatalogSourceType +import org.radarbase.management.service.catalog.SourceTypeResponse +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.CommandLineRunner +import org.springframework.stereotype.Component +import org.springframework.web.client.RestClientException +import org.springframework.web.client.RestTemplate /** * Upon start of Spring application, this class automatically import the source-types provided by @@ -22,53 +16,53 @@ import org.springframework.web.client.RestTemplate; * provided and enableAutoImport is set to true. */ @Component -public class SourceTypeLoader implements CommandLineRunner { - - private static final Logger log = LoggerFactory.getLogger(SourceTypeLoader.class); - +class SourceTypeLoader : CommandLineRunner { @Autowired - private SourceTypeService sourceTypeService; + private val sourceTypeService: SourceTypeService? = null @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Override - public void run(String... args) { - if (!managementPortalProperties.getCatalogueServer().isEnableAutoImport()) { - log.info("Auto source-type import is disabled"); - return; + private val managementPortalProperties: ManagementPortalProperties? = null + override fun run(vararg args: String) { + if (!managementPortalProperties!!.catalogueServer.isEnableAutoImport) { + log.info("Auto source-type import is disabled") + return } - - String catalogServerUrl = managementPortalProperties.getCatalogueServer().getServerUrl(); - + val catalogServerUrl = managementPortalProperties.catalogueServer.serverUrl try { - RestTemplate restTemplate = new RestTemplate(); - log.debug("Requesting source-types from catalog server..."); - ResponseEntity catalogues = restTemplate - .getForEntity(catalogServerUrl, SourceTypeResponse.class); - SourceTypeResponse catalogueDto = catalogues.getBody(); + val restTemplate = RestTemplate() + log.debug("Requesting source-types from catalog server...") + val catalogues = restTemplate + .getForEntity(catalogServerUrl, SourceTypeResponse::class.java) + val catalogueDto = catalogues.body if (catalogueDto == null) { - log.warn("Catalog Service {} returned empty response", catalogServerUrl); - return; + log.warn("Catalog Service {} returned empty response", catalogServerUrl) + return } - List catalogSourceTypes = new ArrayList<>(); - addNonNull(catalogSourceTypes, catalogueDto.getPassiveSources()); - addNonNull(catalogSourceTypes, catalogueDto.getActiveSources()); - addNonNull(catalogSourceTypes, catalogueDto.getMonitorSources()); - addNonNull(catalogSourceTypes, catalogueDto.getConnectorSources()); - sourceTypeService.saveSourceTypesFromCatalogServer(catalogSourceTypes); - } catch (RestClientException e) { - log.warn("Cannot fetch source types from Catalog Service at {}: {}", catalogServerUrl, - e.toString()); - } catch (RuntimeException exe) { - log.warn("An error has occurred during auto import of source-types: {}", exe - .getMessage()); + val catalogSourceTypes: MutableList = ArrayList() + addNonNull(catalogSourceTypes, catalogueDto.passiveSources) + addNonNull(catalogSourceTypes, catalogueDto.activeSources) + addNonNull(catalogSourceTypes, catalogueDto.monitorSources) + addNonNull(catalogSourceTypes, catalogueDto.connectorSources) + sourceTypeService!!.saveSourceTypesFromCatalogServer(catalogSourceTypes) + } catch (e: RestClientException) { + log.warn( + "Cannot fetch source types from Catalog Service at {}: {}", catalogServerUrl, + e.toString() + ) + } catch (exe: RuntimeException) { + log.warn( + "An error has occurred during auto import of source-types: {}", exe + .message + ) } } - private static void addNonNull(Collection collection, Collection toAdd) { - if (toAdd != null && !toAdd.isEmpty()) { - collection.addAll(toAdd); + companion object { + private val log = LoggerFactory.getLogger(SourceTypeLoader::class.java) + private fun addNonNull(collection: MutableCollection, toAdd: Collection?) { + if (toAdd != null && !toAdd.isEmpty()) { + collection.addAll(toAdd) + } } } } diff --git a/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt b/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt index a7f77132d..16dc8fd58 100644 --- a/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt @@ -1,23 +1,22 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Description; -import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver; - -import java.nio.charset.StandardCharsets; +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Description +import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver +import java.nio.charset.StandardCharsets @Configuration -public class ThymeleafConfiguration { +class ThymeleafConfiguration { @Bean @Description("Thymeleaf template resolver serving HTML 5 emails") - public ClassLoaderTemplateResolver emailTemplateResolver() { - ClassLoaderTemplateResolver emailTemplateResolver = new ClassLoaderTemplateResolver(); - emailTemplateResolver.setPrefix("templates/"); - emailTemplateResolver.setSuffix(".html"); - emailTemplateResolver.setTemplateMode("HTML"); - emailTemplateResolver.setCharacterEncoding(StandardCharsets.UTF_8.name()); - emailTemplateResolver.setOrder(1); - return emailTemplateResolver; + fun emailTemplateResolver(): ClassLoaderTemplateResolver { + val emailTemplateResolver = ClassLoaderTemplateResolver() + emailTemplateResolver.prefix = "templates/" + emailTemplateResolver.suffix = ".html" + emailTemplateResolver.setTemplateMode("HTML") + emailTemplateResolver.characterEncoding = StandardCharsets.UTF_8.name() + emailTemplateResolver.order = 1 + return emailTemplateResolver } } diff --git a/src/main/java/org/radarbase/management/config/WebConfigurer.kt b/src/main/java/org/radarbase/management/config/WebConfigurer.kt index 83d5bf0a5..1ff446223 100644 --- a/src/main/java/org/radarbase/management/config/WebConfigurer.kt +++ b/src/main/java/org/radarbase/management/config/WebConfigurer.kt @@ -1,115 +1,110 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.web.server.MimeMappings; -import org.springframework.boot.web.server.WebServerFactoryCustomizer; -import org.springframework.boot.web.servlet.ServletContextInitializer; -import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; -import org.springframework.core.env.Profiles; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import tech.jhipster.config.JHipsterConstants; -import tech.jhipster.config.JHipsterProperties; -import tech.jhipster.web.filter.CachingHttpHeadersFilter; - -import javax.servlet.DispatcherType; -import javax.servlet.FilterRegistration; -import javax.servlet.ServletContext; -import java.io.File; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.EnumSet; +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.web.server.MimeMappings +import org.springframework.boot.web.server.WebServerFactoryCustomizer +import org.springframework.boot.web.servlet.ServletContextInitializer +import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.core.env.Environment +import org.springframework.core.env.Profiles +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder +import org.springframework.security.crypto.password.PasswordEncoder +import tech.jhipster.config.JHipsterConstants +import tech.jhipster.config.JHipsterProperties +import tech.jhipster.web.filter.CachingHttpHeadersFilter +import java.io.File +import java.nio.file.Paths +import java.util.* +import javax.servlet.DispatcherType +import javax.servlet.ServletContext /** * Configuration of web application with Servlet 3.0 APIs. */ @Configuration -public class WebConfigurer implements ServletContextInitializer, - WebServerFactoryCustomizer { - - private static final Logger log = LoggerFactory.getLogger(WebConfigurer.class); - +class WebConfigurer : ServletContextInitializer, WebServerFactoryCustomizer { @Autowired - private Environment env; + private val env: Environment? = null @Autowired - private JHipsterProperties jHipsterProperties; - - @Override - public void onStartup(ServletContext servletContext) { - if (env.getActiveProfiles().length != 0) { - log.info("Web application configuration, using profiles: {}", - Arrays.asList(env.getActiveProfiles())); + private val jHipsterProperties: JHipsterProperties? = null + override fun onStartup(servletContext: ServletContext) { + if (env!!.activeProfiles.size != 0) { + log.info( + "Web application configuration, using profiles: {}", + Arrays.asList(*env.activeProfiles) + ) } if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_PRODUCTION))) { - EnumSet disps = EnumSet - .of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC); - initCachingHttpHeadersFilter(servletContext, disps); + val disps = EnumSet + .of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC) + initCachingHttpHeadersFilter(servletContext, disps) } - log.info("Web application fully configured"); + log.info("Web application fully configured") } /** * Customize the Servlet engine: Mime types, the document root, the cache. */ - - @Override - public void customize(ConfigurableServletWebServerFactory factory) { - MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT); + override fun customize(factory: ConfigurableServletWebServerFactory) { + val mappings = MimeMappings(MimeMappings.DEFAULT) // IE issue, see https://github.com/jhipster/generator-jhipster/pull/711 - mappings.add("html", "text/html;charset=utf-8"); + mappings.add("html", "text/html;charset=utf-8") // CloudFoundry issue, see https://github.com/cloudfoundry/gorouter/issues/64 - mappings.add("json", "text/html;charset=utf-8"); - factory.setMimeMappings(mappings); + mappings.add("json", "text/html;charset=utf-8") + factory.setMimeMappings(mappings) // When running in an IDE or with ./gradlew bootRun, set location of the static web assets. - setLocationForStaticAssets(factory); + setLocationForStaticAssets(factory) } - private void setLocationForStaticAssets(ConfigurableServletWebServerFactory factory) { - File root; - String prefixPath = resolvePathPrefix(); - root = new File(prefixPath + "build/www/"); + private fun setLocationForStaticAssets(factory: ConfigurableServletWebServerFactory) { + val root: File + val prefixPath = resolvePathPrefix() + root = File(prefixPath + "build/www/") if (root.exists() && root.isDirectory()) { - factory.setDocumentRoot(root); + factory.setDocumentRoot(root) } } /** * Resolve path prefix to static resources. */ - private String resolvePathPrefix() { - String fullExecutablePath = this.getClass().getResource("").getPath(); - String rootPath = Paths.get(".").toUri().normalize().getPath(); - String extractedPath = fullExecutablePath.replace(rootPath, ""); - int extractionEndIndex = extractedPath.indexOf("build/"); - if (extractionEndIndex <= 0) { - return ""; - } - return extractedPath.substring(0, extractionEndIndex); + private fun resolvePathPrefix(): String { + val fullExecutablePath = this.javaClass.getResource("").path + val rootPath = Paths.get(".").toUri().normalize().getPath() + val extractedPath = fullExecutablePath.replace(rootPath, "") + val extractionEndIndex = extractedPath.indexOf("build/") + return if (extractionEndIndex <= 0) { + "" + } else extractedPath.substring(0, extractionEndIndex) } /** * Initializes the caching HTTP Headers Filter. */ - private void initCachingHttpHeadersFilter(ServletContext servletContext, - EnumSet disps) { - log.debug("Registering Caching HTTP Headers Filter"); - FilterRegistration.Dynamic cachingHttpHeadersFilter = - servletContext.addFilter("cachingHttpHeadersFilter", - new CachingHttpHeadersFilter(jHipsterProperties)); - - cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/content/*"); - cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/app/*"); - cachingHttpHeadersFilter.setAsyncSupported(true); + private fun initCachingHttpHeadersFilter( + servletContext: ServletContext, + disps: EnumSet + ) { + log.debug("Registering Caching HTTP Headers Filter") + val cachingHttpHeadersFilter = servletContext.addFilter( + "cachingHttpHeadersFilter", + CachingHttpHeadersFilter(jHipsterProperties) + ) + cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/content/*") + cachingHttpHeadersFilter.addMappingForUrlPatterns(disps, true, "/app/*") + cachingHttpHeadersFilter.setAsyncSupported(true) } @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); + fun passwordEncoder(): PasswordEncoder { + return BCryptPasswordEncoder() + } + + companion object { + private val log = LoggerFactory.getLogger(WebConfigurer::class.java) } } From 2d9f7d5a0b06af579854efb9bfb9d8ea4787faf1 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 15:03:01 +0200 Subject: [PATCH 083/158] Rename .java to .kt --- .../audit/{AuditEventConverter.java => AuditEventConverter.kt} | 0 .../{CustomRevisionListener.java => CustomRevisionListener.kt} | 0 ...ingSecurityAuditorAware.java => SpringSecurityAuditorAware.kt} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/config/audit/{AuditEventConverter.java => AuditEventConverter.kt} (100%) rename src/main/java/org/radarbase/management/config/audit/{CustomRevisionListener.java => CustomRevisionListener.kt} (100%) rename src/main/java/org/radarbase/management/security/{SpringSecurityAuditorAware.java => SpringSecurityAuditorAware.kt} (100%) diff --git a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.java b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/audit/AuditEventConverter.java rename to src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt diff --git a/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.java b/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.java rename to src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt diff --git a/src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.java b/src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.kt similarity index 100% rename from src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.java rename to src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.kt From 18a9af848cb26fb3480d3b39bb10a1ff37960dfc Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 15:03:02 +0200 Subject: [PATCH 084/158] finished config folder --- .../config/audit/AuditEventConverter.kt | 83 +++++++++---------- .../config/audit/CustomRevisionListener.kt | 30 ++++--- .../security/SpringSecurityAuditorAware.kt | 27 +++--- 3 files changed, 63 insertions(+), 77 deletions(-) diff --git a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt index a1e7a9a13..dcfb7f086 100644 --- a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt +++ b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt @@ -1,36 +1,30 @@ -package org.radarbase.management.config.audit; +package org.radarbase.management.config.audit -import java.time.Instant; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.radarbase.management.domain.PersistentAuditEvent; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.security.web.authentication.WebAuthenticationDetails; -import org.springframework.stereotype.Component; +import org.radarbase.management.domain.PersistentAuditEvent +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.security.web.authentication.WebAuthenticationDetails +import org.springframework.stereotype.Component +import java.time.ZoneId @Component -public class AuditEventConverter { - +class AuditEventConverter { /** * Convert a list of PersistentAuditEvent to a list of AuditEvent. * * @param persistentAuditEvents the list to convert * @return the converted list. */ - public List convertToAuditEvent( - Iterable persistentAuditEvents) { + fun convertToAuditEvent( + persistentAuditEvents: Iterable? + ): List { if (persistentAuditEvents == null) { - return Collections.emptyList(); + return emptyList() } - List auditEvents = new ArrayList<>(); - for (PersistentAuditEvent persistentAuditEvent : persistentAuditEvents) { - auditEvents.add(convertToAuditEvent(persistentAuditEvent)); + val auditEvents: MutableList = ArrayList() + for (persistentAuditEvent in persistentAuditEvents) { + auditEvents.add(convertToAuditEvent(persistentAuditEvent)) } - return auditEvents; + return auditEvents } /** @@ -39,12 +33,14 @@ public class AuditEventConverter { * @param persistentAuditEvent the event to convert * @return the converted list. */ - public AuditEvent convertToAuditEvent(PersistentAuditEvent persistentAuditEvent) { - Instant instant = persistentAuditEvent.getAuditEventDate().atZone(ZoneId.systemDefault()) - .toInstant(); - return new AuditEvent(instant, persistentAuditEvent.getPrincipal(), - persistentAuditEvent.getAuditEventType(), - convertDataToObjects(persistentAuditEvent.getData())); + fun convertToAuditEvent(persistentAuditEvent: PersistentAuditEvent): AuditEvent { + val instant = persistentAuditEvent.auditEventDate.atZone(ZoneId.systemDefault()) + .toInstant() + return AuditEvent( + instant, persistentAuditEvent.principal, + persistentAuditEvent.auditEventType, + convertDataToObjects(persistentAuditEvent.data) + ) } /** @@ -54,15 +50,14 @@ public class AuditEventConverter { * @param data the data to convert * @return a map of String, Object */ - public Map convertDataToObjects(Map data) { - Map results = new HashMap<>(); - + fun convertDataToObjects(data: Map?): Map { + val results: MutableMap = HashMap() if (data != null) { - for (Map.Entry entry : data.entrySet()) { - results.put(entry.getKey(), entry.getValue()); + for ((key, value) in data) { + results[key] = value } } - return results; + return results } /** @@ -72,25 +67,21 @@ public class AuditEventConverter { * @param data the data to convert * @return a map of String, String */ - public Map convertDataToStrings(Map data) { - Map results = new HashMap<>(); - + fun convertDataToStrings(data: Map?): Map { + val results: MutableMap = HashMap() if (data != null) { - for (Map.Entry entry : data.entrySet()) { - Object val = entry.getValue(); + for ((key, value) in data) { // Extract the data that will be saved. - if (val instanceof WebAuthenticationDetails) { - WebAuthenticationDetails authenticationDetails = (WebAuthenticationDetails) val; - results.put("sessionId", authenticationDetails.getSessionId()); - } else if (val != null) { - results.put(entry.getKey(), val.toString()); + if (value is WebAuthenticationDetails) { + results["sessionId"] = value.sessionId + } else if (value != null) { + results[key] = value.toString() } else { - results.put(entry.getKey(), "null"); + results[key] = "null" } } } - - return results; + return results } } diff --git a/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt b/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt index c0ede037a..eb7f4589f 100644 --- a/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt +++ b/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt @@ -1,22 +1,20 @@ -package org.radarbase.management.config.audit; +package org.radarbase.management.config.audit -import org.hibernate.envers.RevisionListener; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.audit.CustomRevisionEntity; -import org.radarbase.management.domain.support.AutowireHelper; -import org.radarbase.management.security.SpringSecurityAuditorAware; -import org.springframework.beans.factory.annotation.Autowired; +import org.hibernate.envers.RevisionListener +import org.radarbase.management.domain.audit.CustomRevisionEntity +import org.radarbase.management.domain.support.AutowireHelper +import org.radarbase.management.security.Constants +import org.radarbase.management.security.SpringSecurityAuditorAware +import org.springframework.beans.factory.annotation.Autowired -public class CustomRevisionListener implements RevisionListener { +class CustomRevisionListener : RevisionListener { @Autowired - private SpringSecurityAuditorAware springSecurityAuditorAware; - - @Override - public void newRevision(Object revisionEntity) { - AutowireHelper.autowire(this, springSecurityAuditorAware); - CustomRevisionEntity entity = (CustomRevisionEntity) revisionEntity; - entity.setAuditor(springSecurityAuditorAware.getCurrentAuditor() - .orElse(Constants.SYSTEM_ACCOUNT)); + private val springSecurityAuditorAware: SpringSecurityAuditorAware? = null + override fun newRevision(revisionEntity: Any) { + AutowireHelper.autowire(this, springSecurityAuditorAware) + val entity = revisionEntity as CustomRevisionEntity + entity.auditor = springSecurityAuditorAware!!.currentAuditor + .orElse(Constants.SYSTEM_ACCOUNT) } } diff --git a/src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.kt b/src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.kt index 4a9a7fead..e6989ddf0 100644 --- a/src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.kt +++ b/src/main/java/org/radarbase/management/security/SpringSecurityAuditorAware.kt @@ -1,25 +1,22 @@ -package org.radarbase.management.security; +package org.radarbase.management.security -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.AuditorAware; -import org.springframework.security.core.Authentication; -import org.springframework.stereotype.Component; - -import javax.annotation.Nonnull; -import java.util.Optional; +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.AuditorAware +import org.springframework.security.core.Authentication +import org.springframework.stereotype.Component +import java.util.* +import javax.annotation.Nonnull /** * Implementation of AuditorAware based on Spring Security. */ @Component -public class SpringSecurityAuditorAware implements AuditorAware { +class SpringSecurityAuditorAware : AuditorAware { @Autowired - private Optional authentication; - - @Override + private val authentication: Optional? = null @Nonnull - public Optional getCurrentAuditor() { - return authentication.map(Authentication::getName) - .filter(n -> !n.isEmpty()); + override fun getCurrentAuditor(): Optional { + return authentication!!.map { obj: Authentication -> obj.name } + .filter { n: String -> n.isNotEmpty() } } } From 9cc55b1592d99e389fe5d5ffc02ccb723e2ee3ec Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 15:03:33 +0200 Subject: [PATCH 085/158] CustomRevisionListener needs to be a @component --- .../management/config/audit/CustomRevisionListener.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt b/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt index eb7f4589f..c2279fc22 100644 --- a/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt +++ b/src/main/java/org/radarbase/management/config/audit/CustomRevisionListener.kt @@ -6,8 +6,9 @@ import org.radarbase.management.domain.support.AutowireHelper import org.radarbase.management.security.Constants import org.radarbase.management.security.SpringSecurityAuditorAware import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component - +@Component class CustomRevisionListener : RevisionListener { @Autowired private val springSecurityAuditorAware: SpringSecurityAuditorAware? = null From a60d3e6472383d70b1273a44f48d2ba5f6627b54 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 25 Oct 2023 15:12:32 +0200 Subject: [PATCH 086/158] tests passing --- .../radarbase/management/config/RadarTokenConfiguration.kt | 4 ++-- .../org/radarbase/management/config/ThymeleafConfiguration.kt | 4 ++-- .../java/org/radarbase/management/config/WebConfigurer.kt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt b/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt index deb2e5484..b7b032cc1 100644 --- a/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt @@ -10,10 +10,10 @@ import org.springframework.context.annotation.ScopedProxyMode import javax.servlet.http.HttpServletRequest @Configuration -class RadarTokenConfiguration @Autowired constructor(private val radarTokenLoader: RadarTokenLoader) { +open class RadarTokenConfiguration @Autowired constructor(private val radarTokenLoader: RadarTokenLoader) { @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) @Bean - fun radarToken(request: HttpServletRequest?): RadarToken? { + open fun radarToken(request: HttpServletRequest?): RadarToken? { return radarTokenLoader.loadToken(request!!) } } diff --git a/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt b/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt index 16dc8fd58..2ef1685e6 100644 --- a/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt @@ -7,10 +7,10 @@ import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver import java.nio.charset.StandardCharsets @Configuration -class ThymeleafConfiguration { +open class ThymeleafConfiguration { @Bean @Description("Thymeleaf template resolver serving HTML 5 emails") - fun emailTemplateResolver(): ClassLoaderTemplateResolver { + open fun emailTemplateResolver(): ClassLoaderTemplateResolver { val emailTemplateResolver = ClassLoaderTemplateResolver() emailTemplateResolver.prefix = "templates/" emailTemplateResolver.suffix = ".html" diff --git a/src/main/java/org/radarbase/management/config/WebConfigurer.kt b/src/main/java/org/radarbase/management/config/WebConfigurer.kt index 1ff446223..205656634 100644 --- a/src/main/java/org/radarbase/management/config/WebConfigurer.kt +++ b/src/main/java/org/radarbase/management/config/WebConfigurer.kt @@ -25,7 +25,7 @@ import javax.servlet.ServletContext * Configuration of web application with Servlet 3.0 APIs. */ @Configuration -class WebConfigurer : ServletContextInitializer, WebServerFactoryCustomizer { +open class WebConfigurer : ServletContextInitializer, WebServerFactoryCustomizer { @Autowired private val env: Environment? = null @@ -100,7 +100,7 @@ class WebConfigurer : ServletContextInitializer, WebServerFactoryCustomizer Date: Thu, 26 Oct 2023 17:14:08 +0200 Subject: [PATCH 087/158] Rename .java to .kt --- .../audit/{CustomRevisionEntity.java => CustomRevisionEntity.kt} | 0 .../{CustomRevisionMetadata.java => CustomRevisionMetadata.kt} | 0 .../domain/audit/{EntityAuditInfo.java => EntityAuditInfo.kt} | 0 .../domain/enumeration/{ProjectStatus.java => ProjectStatus.kt} | 0 .../management/domain/enumeration/{Role.java => Role.kt} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/domain/audit/{CustomRevisionEntity.java => CustomRevisionEntity.kt} (100%) rename src/main/java/org/radarbase/management/domain/audit/{CustomRevisionMetadata.java => CustomRevisionMetadata.kt} (100%) rename src/main/java/org/radarbase/management/domain/audit/{EntityAuditInfo.java => EntityAuditInfo.kt} (100%) rename src/main/java/org/radarbase/management/domain/enumeration/{ProjectStatus.java => ProjectStatus.kt} (100%) rename src/main/java/org/radarbase/management/domain/enumeration/{Role.java => Role.kt} (100%) diff --git a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.java b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt similarity index 100% rename from src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.java rename to src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt diff --git a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.java b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt similarity index 100% rename from src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.java rename to src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt diff --git a/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.java b/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt similarity index 100% rename from src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.java rename to src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt diff --git a/src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.java b/src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.kt similarity index 100% rename from src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.java rename to src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.kt diff --git a/src/main/java/org/radarbase/management/domain/enumeration/Role.java b/src/main/java/org/radarbase/management/domain/enumeration/Role.kt similarity index 100% rename from src/main/java/org/radarbase/management/domain/enumeration/Role.java rename to src/main/java/org/radarbase/management/domain/enumeration/Role.kt From 42fb2bbbc232dd4ef81735c41beb2bcfb75b702d Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Thu, 26 Oct 2023 17:14:08 +0200 Subject: [PATCH 088/158] gradle build works, only test fails --- build.gradle | 1 + .../authorization/MPAuthorizationOracle.kt | 8 +- .../radarbase/auth/token/DataRadarToken.kt | 4 +- .../org/radarbase/auth/token/RadarToken.kt | 4 +- .../config/AuthorizationConfiguration.kt | 3 +- .../config/audit/AuditEventConverter.kt | 4 +- .../management/domain/AbstractEntity.java | 18 - .../management/domain/AbstractEntity.kt | 17 + .../management/domain/Authority.java | 85 --- .../radarbase/management/domain/Authority.kt | 65 ++ .../radarbase/management/domain/Group.java | 115 ---- .../org/radarbase/management/domain/Group.kt | 79 +++ .../management/domain/MetaToken.java | 194 ------ .../radarbase/management/domain/MetaToken.kt | 164 +++++ .../management/domain/Organization.java | 127 ---- .../management/domain/Organization.kt | 81 +++ .../domain/PersistentAuditEvent.java | 98 --- .../management/domain/PersistentAuditEvent.kt | 57 ++ .../radarbase/management/domain/Project.java | 311 ---------- .../radarbase/management/domain/Project.kt | 207 +++++++ .../org/radarbase/management/domain/Role.java | 180 ------ .../org/radarbase/management/domain/Role.kt | 130 ++++ .../radarbase/management/domain/Source.java | 275 --------- .../org/radarbase/management/domain/Source.kt | 189 ++++++ .../management/domain/SourceData.java | 274 -------- .../radarbase/management/domain/SourceData.kt | 171 +++++ .../management/domain/SourceType.java | 270 -------- .../radarbase/management/domain/SourceType.kt | 163 +++++ .../radarbase/management/domain/Subject.java | 292 --------- .../radarbase/management/domain/Subject.kt | 207 +++++++ .../org/radarbase/management/domain/User.java | 248 -------- .../org/radarbase/management/domain/User.kt | 146 +++++ .../domain/audit/CustomRevisionEntity.kt | 148 ++--- .../domain/audit/CustomRevisionMetadata.kt | 57 +- .../domain/audit/EntityAuditInfo.kt | 91 ++- .../domain/enumeration/ProjectStatus.kt | 8 +- .../management/domain/enumeration/Role.kt | 4 +- .../management/domain/package-info.java | 4 - .../management/domain/package-info.kt | 5 + .../support/AbstractEntityListener.java | 85 --- .../domain/support/AbstractEntityListener.kt | 87 +++ .../domain/support/AutowireHelper.java | 51 -- .../domain/support/AutowireHelper.kt | 43 ++ .../CustomAuditEventRepository.java | 8 +- .../repository/GroupRepository.java | 38 -- .../management/repository/GroupRepository.kt | 40 ++ .../repository/ProjectRepository.java | 83 --- .../repository/ProjectRepository.kt | 101 +++ .../security/ClaimsTokenEnhancer.java | 12 +- .../security/DomainUserDetailsService.java | 6 +- .../security/JwtAuthenticationFilter.kt | 20 +- .../management/service/GroupService.java | 244 -------- .../management/service/GroupService.kt | 233 +++++++ .../management/service/MailService.java | 20 +- .../management/service/MetaTokenService.java | 236 ------- .../management/service/MetaTokenService.kt | 253 ++++++++ .../service/OAuthClientService.java | 2 +- .../service/OrganizationService.java | 2 +- .../management/service/ProjectService.java | 143 ----- .../management/service/ProjectService.kt | 134 ++++ .../service/ResourceUriService.java | 2 +- .../management/service/RevisionService.java | 391 ------------ .../management/service/RevisionService.kt | 401 ++++++++++++ .../management/service/RoleService.java | 271 -------- .../management/service/RoleService.kt | 270 ++++++++ .../management/service/SourceService.java | 261 -------- .../management/service/SourceService.kt | 267 ++++++++ .../management/service/SourceTypeService.java | 36 +- .../management/service/SubjectService.java | 546 ---------------- .../management/service/SubjectService.kt | 516 ++++++++++++++++ .../management/service/UserService.java | 434 ------------- .../management/service/UserService.kt | 428 +++++++++++++ .../management/service/dto/RevisionDTO.java | 2 +- .../service/dto/RevisionInfoDTO.java | 6 +- .../{SubjectMapper.java => SubjectMapper.kt} | 63 +- .../mapper/{UserMapper.java => UserMapper.kt} | 53 +- .../decorator/ProjectMapperDecorator.java | 8 +- .../mapper/decorator/RoleMapperDecorator.java | 4 +- .../decorator/SourceMapperDecorator.java | 6 +- .../decorator/SubjectMapperDecorator.java | 173 ------ .../decorator/SubjectMapperDecorator.kt | 146 +++++ .../web/rest/MetaTokenResource.java | 84 --- .../management/web/rest/MetaTokenResource.kt | 91 +++ .../web/rest/OAuthClientsResource.java | 224 ------- .../web/rest/OAuthClientsResource.kt | 243 ++++++++ .../management/web/rest/ProjectResource.java | 367 ----------- .../management/web/rest/ProjectResource.kt | 396 ++++++++++++ .../management/web/rest/SubjectResource.java | 572 ----------------- .../management/web/rest/SubjectResource.kt | 584 ++++++++++++++++++ .../management/web/rest/UserResource.java | 282 --------- .../management/web/rest/UserResource.kt | 280 +++++++++ .../auth/authentication/OAuthHelper.java | 2 +- .../service/UserServiceIntTest.java | 72 +-- .../web/rest/AccountResourceIntTest.java | 24 +- .../web/rest/AuditResourceIntTest.java | 8 +- .../web/rest/GroupResourceIntTest.java | 70 +-- .../web/rest/OrganizationResourceIntTest.java | 16 +- .../web/rest/ProjectResourceIntTest.java | 48 +- .../web/rest/SourceDataResourceIntTest.java | 42 +- .../web/rest/SourceResourceIntTest.java | 18 +- .../web/rest/SourceTypeResourceIntTest.java | 38 +- .../web/rest/SubjectResourceIntTest.java | 24 +- .../web/rest/UserResourceIntTest.java | 92 +-- 103 files changed, 6682 insertions(+), 7524 deletions(-) delete mode 100644 src/main/java/org/radarbase/management/domain/AbstractEntity.java create mode 100644 src/main/java/org/radarbase/management/domain/AbstractEntity.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Authority.java create mode 100644 src/main/java/org/radarbase/management/domain/Authority.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Group.java create mode 100644 src/main/java/org/radarbase/management/domain/Group.kt delete mode 100644 src/main/java/org/radarbase/management/domain/MetaToken.java create mode 100644 src/main/java/org/radarbase/management/domain/MetaToken.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Organization.java create mode 100644 src/main/java/org/radarbase/management/domain/Organization.kt delete mode 100644 src/main/java/org/radarbase/management/domain/PersistentAuditEvent.java create mode 100644 src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Project.java create mode 100644 src/main/java/org/radarbase/management/domain/Project.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Role.java create mode 100644 src/main/java/org/radarbase/management/domain/Role.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Source.java create mode 100644 src/main/java/org/radarbase/management/domain/Source.kt delete mode 100644 src/main/java/org/radarbase/management/domain/SourceData.java create mode 100644 src/main/java/org/radarbase/management/domain/SourceData.kt delete mode 100644 src/main/java/org/radarbase/management/domain/SourceType.java create mode 100644 src/main/java/org/radarbase/management/domain/SourceType.kt delete mode 100644 src/main/java/org/radarbase/management/domain/Subject.java create mode 100644 src/main/java/org/radarbase/management/domain/Subject.kt delete mode 100644 src/main/java/org/radarbase/management/domain/User.java create mode 100644 src/main/java/org/radarbase/management/domain/User.kt delete mode 100644 src/main/java/org/radarbase/management/domain/package-info.java create mode 100644 src/main/java/org/radarbase/management/domain/package-info.kt delete mode 100644 src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.java create mode 100644 src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.kt delete mode 100644 src/main/java/org/radarbase/management/domain/support/AutowireHelper.java create mode 100644 src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt delete mode 100644 src/main/java/org/radarbase/management/repository/GroupRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/GroupRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/ProjectRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/ProjectRepository.kt delete mode 100644 src/main/java/org/radarbase/management/service/GroupService.java create mode 100644 src/main/java/org/radarbase/management/service/GroupService.kt delete mode 100644 src/main/java/org/radarbase/management/service/MetaTokenService.java create mode 100644 src/main/java/org/radarbase/management/service/MetaTokenService.kt delete mode 100644 src/main/java/org/radarbase/management/service/ProjectService.java create mode 100644 src/main/java/org/radarbase/management/service/ProjectService.kt delete mode 100644 src/main/java/org/radarbase/management/service/RevisionService.java create mode 100644 src/main/java/org/radarbase/management/service/RevisionService.kt delete mode 100644 src/main/java/org/radarbase/management/service/RoleService.java create mode 100644 src/main/java/org/radarbase/management/service/RoleService.kt delete mode 100644 src/main/java/org/radarbase/management/service/SourceService.java create mode 100644 src/main/java/org/radarbase/management/service/SourceService.kt delete mode 100644 src/main/java/org/radarbase/management/service/SubjectService.java create mode 100644 src/main/java/org/radarbase/management/service/SubjectService.kt delete mode 100644 src/main/java/org/radarbase/management/service/UserService.java create mode 100644 src/main/java/org/radarbase/management/service/UserService.kt rename src/main/java/org/radarbase/management/service/mapper/{SubjectMapper.java => SubjectMapper.kt} (65%) rename src/main/java/org/radarbase/management/service/mapper/{UserMapper.java => UserMapper.kt} (51%) delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/MetaTokenResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/MetaTokenResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/ProjectResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/ProjectResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/SubjectResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/SubjectResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/UserResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/UserResource.kt diff --git a/build.gradle b/build.gradle index 3041a9979..24c364e83 100644 --- a/build.gradle +++ b/build.gradle @@ -147,6 +147,7 @@ if (project.hasProperty('prod')) { ext.findbugAnnotationVersion = '3.0.2' dependencies { + implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.10") implementation("tech.jhipster:jhipster-framework:${jhipster_server_version}") implementation("tech.jhipster:jhipster-dependencies:${jhipster_server_version}") implementation("io.micrometer:micrometer-core") diff --git a/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt b/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt index 35601eeeb..804470a50 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt @@ -24,9 +24,10 @@ class MPAuthorizationOracle( if (identity.isClientCredentials) return true - return identity.roles.forkAny { + return identity.roles?.forkAny { it.hasPermission(identity, permission, entity, entityScope) } + ?: false } /** @@ -39,7 +40,8 @@ class MPAuthorizationOracle( if (identity.isClientCredentials) return true - return identity.roles.any { it.role.mayBeGranted(permission) } + return identity.roles?.any { it.role.mayBeGranted(permission) } + ?: false } /** @@ -61,7 +63,7 @@ class MPAuthorizationOracle( val projects = mutableSetOf() val personalProjects = mutableSetOf() - identity.roles.forEach { + identity.roles?.forEach { if (it.role.mayBeGranted(permission)) { when (it.role.scope) { RoleAuthority.Scope.GLOBAL -> global = true diff --git a/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt b/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt index 7a2392ee7..27bba10c1 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt @@ -12,7 +12,7 @@ data class DataRadarToken( * Get all roles defined in this token. * @return non-null set describing the roles defined in this token. */ - override val roles: Set, + override val roles: Set?, /** * Get a list of scopes assigned to this token. @@ -101,7 +101,7 @@ data class DataRadarToken( clientId = radarToken.clientId, ) - override fun copyWithRoles(roles: Set): DataRadarToken = copy(roles = roles) + override fun copyWithRoles(roles: Set?): DataRadarToken = copy(roles = roles) companion object { fun RadarToken.toDataRadarToken(): DataRadarToken = DataRadarToken(this) diff --git a/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt b/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt index 52acb36d9..39341d0c9 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt @@ -11,7 +11,7 @@ interface RadarToken { * Get all roles defined in this token. * @return non-null set describing the roles defined in this token. */ - val roles: Set + val roles: Set? /** * Get a list of scopes assigned to this token. @@ -92,7 +92,7 @@ interface RadarToken { val isClientCredentials: Boolean get() = grantType == CLIENT_CREDENTIALS - fun copyWithRoles(roles: Set): RadarToken + fun copyWithRoles(roles: Set?): RadarToken companion object { const val CLIENT_CREDENTIALS = "client_credentials" diff --git a/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt b/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt index 96900e083..6b479d296 100644 --- a/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt @@ -18,8 +18,7 @@ open class AuthorizationConfiguration( object : EntityRelationService { override suspend fun findOrganizationOfProject(project: String): String? = withContext(Dispatchers.IO) { projectRepository.findOneWithEagerRelationshipsByName(project) - .map { it.organization.name } - .orElse(null) + ?.organization?.name } } ) diff --git a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt index dcfb7f086..09b6872b6 100644 --- a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt +++ b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt @@ -34,8 +34,8 @@ class AuditEventConverter { * @return the converted list. */ fun convertToAuditEvent(persistentAuditEvent: PersistentAuditEvent): AuditEvent { - val instant = persistentAuditEvent.auditEventDate.atZone(ZoneId.systemDefault()) - .toInstant() + val instant = persistentAuditEvent.auditEventDate?.atZone(ZoneId.systemDefault()) + ?.toInstant() return AuditEvent( instant, persistentAuditEvent.principal, persistentAuditEvent.auditEventType, diff --git a/src/main/java/org/radarbase/management/domain/AbstractEntity.java b/src/main/java/org/radarbase/management/domain/AbstractEntity.java deleted file mode 100644 index b582ee903..000000000 --- a/src/main/java/org/radarbase/management/domain/AbstractEntity.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.radarbase.management.domain; - -import org.radarbase.management.domain.support.AbstractEntityListener; - -import java.io.Serializable; - -/** - * Base abstract class for entities which will hold definitions for created, last modified by and - * created, last modified by date. These will be populated by {@link AbstractEntityListener} on - * the {@code PostLoad} trigger. Since this class is not an Entity or a MappedSuperClass, we need - * to define the entitylistener on each of the subclasses. - */ -public abstract class AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - public abstract Long getId(); -} diff --git a/src/main/java/org/radarbase/management/domain/AbstractEntity.kt b/src/main/java/org/radarbase/management/domain/AbstractEntity.kt new file mode 100644 index 000000000..33247e352 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/AbstractEntity.kt @@ -0,0 +1,17 @@ +package org.radarbase.management.domain + +import java.io.Serializable + +/** + * Base abstract class for entities which will hold definitions for created, last modified by and + * created, last modified by date. These will be populated by [AbstractEntityListener] on + * the `PostLoad` trigger. Since this class is not an Entity or a MappedSuperClass, we need + * to define the entitylistener on each of the subclasses. + */ +abstract class AbstractEntity : Serializable { + abstract val id: Long? + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/Authority.java b/src/main/java/org/radarbase/management/domain/Authority.java deleted file mode 100644 index b45cae9d4..000000000 --- a/src/main/java/org/radarbase/management/domain/Authority.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.radarbase.management.domain; - -import java.io.Serializable; -import java.util.Objects; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.envers.Audited; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.security.Constants; - -/** - * An authority (a security role) used by Spring Security. - */ -@Entity -@Audited -@Table(name = "radar_authority") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -public class Authority implements Serializable { - - private static final long serialVersionUID = 1L; - - @NotNull - @Size(min = 0, max = 50) - @Id - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(length = 50) - private String name; - - public Authority() { - // builder constructor - } - - public Authority(String authorityName) { - this.name = authorityName; - } - - public Authority(RoleAuthority role) { - this(role.getAuthority()); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - Authority authority = (Authority) o; - - if (name == null || authority.name == null) { - return false; - } - - return Objects.equals(name, authority.name); - } - - @Override - public int hashCode() { - return name != null ? name.hashCode() : 0; - } - - @Override - public String toString() { - return "Authority{" - + "name='" + name + '\'' - + "}"; - } -} diff --git a/src/main/java/org/radarbase/management/domain/Authority.kt b/src/main/java/org/radarbase/management/domain/Authority.kt new file mode 100644 index 000000000..773957f64 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Authority.kt @@ -0,0 +1,65 @@ +package org.radarbase.management.domain + +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.envers.Audited +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.security.Constants +import java.io.Serializable +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.Id +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern +import javax.validation.constraints.Size + +/** + * An authority (a security role) used by Spring Security. + */ +@Entity +@Audited +@Table(name = "radar_authority") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +class Authority : Serializable { + @JvmField + @Id + @Column(length = 50) + var name: @NotNull @Size(min = 0, max = 50) @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + constructor() + + constructor(authorityName: String?) { + name = authorityName + this.name = authorityName + } + + constructor(role: RoleAuthority) : this(role.authority) + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val authority = o as Authority + return if (name == null || authority.name == null) { + false + } else name == authority.name + } + + override fun hashCode(): Int { + return if (name != null) name.hashCode() else 0 + } + + override fun toString(): String { + return ("Authority{" + + "name='" + name + '\'' + + "}") + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/Group.java b/src/main/java/org/radarbase/management/domain/Group.java deleted file mode 100644 index ccbe4e851..000000000 --- a/src/main/java/org/radarbase/management/domain/Group.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2021 The Hyve and respective contributors. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.radarbase.management.security.Constants; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; - -import java.io.Serializable; -import java.util.Objects; - -/** - * A Group. - */ -@Entity -@Table(name = "radar_group") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -public class Group extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Size(min = 1, max = 50) - @Column(name = "name", length = 50, nullable = false) - private String name; - - @JsonIgnore - @ManyToOne(fetch = FetchType.EAGER, optional = false) - @JoinColumn(name = "project_id", nullable = false) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Project project; - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Group group = (Group) o; - if (group.id == null || id == null) { - return false; - } - return Objects.equals(id, group.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "Group{" - + "id=" + id + ", " - + "name=" + name + ", " - + "project='" + project.getProjectName() + "', " - + "}"; - } - -} diff --git a/src/main/java/org/radarbase/management/domain/Group.kt b/src/main/java/org/radarbase/management/domain/Group.kt new file mode 100644 index 000000000..539378939 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Group.kt @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021 The Hyve and respective contributors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.radarbase.management.security.Constants +import java.io.Serializable +import java.util.* +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern +import javax.validation.constraints.Size + +/** + * A Group. + */ +@Entity +@Table(name = "radar_group") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +class Group : AbstractEntity(), Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @JvmField + @Column(name = "name", length = 50, nullable = false) + var name: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) String? = null + + @JvmField + @JsonIgnore + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "project_id", nullable = false) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var project: Project? = null + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val group = o as Group + return if (group.id == null || id == null) { + false + } else id == group.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("Group{" + + "id=" + id + ", " + + "name=" + name + ", " + + "project='" + project?.projectName + "', " + + "}") + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/MetaToken.java b/src/main/java/org/radarbase/management/domain/MetaToken.java deleted file mode 100644 index 1353037bc..000000000 --- a/src/main/java/org/radarbase/management/domain/MetaToken.java +++ /dev/null @@ -1,194 +0,0 @@ -package org.radarbase.management.domain; - -import java.time.Instant; -import java.util.Objects; -import java.util.concurrent.ThreadLocalRandom; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.envers.Audited; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.support.AbstractEntityListener; - -@Entity -@Audited -@Table(name = "radar_meta_token") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class MetaToken extends AbstractEntity { - private static final char[] ID_CHARS = { - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', - 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', - 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '-', '.' - }; - - //https://math.stackexchange.com/questions/889538/ - // probability-of-collision-with-randomly-generated-id - // Current length of tokenName is 8 for short-lived tokens, and double that - // for persistent tokens. - public static final int SHORT_ID_LENGTH = 8; - public static final int LONG_ID_LENGTH = 16; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Pattern(regexp = Constants.TOKEN_NAME_REGEX) - @Column(name = "token_name", nullable = false, unique = true) - private String tokenName; - - @Column(name = "fetched", nullable = false) - private Boolean fetched; - - @Column(name = "expiry_date") - private Instant expiryDate = null; - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "subject_id") - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Subject subject; - - @Column(name = "client_id", nullable = false) - private String clientId; - - @Column(name = "persistent", nullable = false) - private Boolean persistent; - - /** - * Generates a alphanumeric with '.' and '-' token name. Suggested token name lengths are - * {@link #SHORT_ID_LENGTH} for short-living tokens and {@link #LONG_ID_LENGTH} for long-living - * meta tokens. - * - * @param length token length - * @return this - */ - public MetaToken generateName(int length) { - ThreadLocalRandom random = ThreadLocalRandom.current(); - char[] tokenChars = new char[length]; - for (int i = 0; i < length; i++) { - tokenChars[i] = ID_CHARS[random.nextInt(ID_CHARS.length)]; - } - tokenName = String.valueOf(tokenChars); - return this; - } - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getTokenName() { - return tokenName; - } - - public MetaToken tokenName(String tokenName) { - this.tokenName = tokenName; - return this; - } - - public boolean isFetched() { - return fetched; - } - - public MetaToken fetched(boolean fetched) { - this.fetched = fetched; - return this; - } - - public Instant getExpiryDate() { - return expiryDate; - } - - public MetaToken expiryDate(Instant expiryDate) { - this.expiryDate = expiryDate; - return this; - } - - public Subject getSubject() { - return subject; - } - - public MetaToken subject(Subject subject) { - this.subject = subject; - return this; - } - - public String getClientId() { - return clientId; - } - - public MetaToken clientId(String clientId) { - this.clientId = clientId; - return this; - } - - public boolean isValid() { - return (persistent || !fetched) && Instant.now().isBefore(expiryDate); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - MetaToken metaToken = (MetaToken) o; - return Objects.equals(id, metaToken.id) - && Objects.equals(tokenName, metaToken.tokenName) - && Objects.equals(fetched, metaToken.fetched) - && Objects.equals(expiryDate, metaToken.expiryDate) - && Objects.equals(clientId, metaToken.clientId) - && Objects.equals(subject, metaToken.subject) - && Objects.equals(persistent, metaToken.persistent); - } - - @Override - public int hashCode() { - return Objects.hash(id, tokenName, fetched, expiryDate, subject, clientId, persistent); - } - - @Override - public String toString() { - return "MetaToken{" + "id=" + id - + ", tokenName='" + tokenName - + ", fetched=" + fetched - + ", expiryDate=" + expiryDate - + ", subject=" + subject - + ", clientId=" + clientId - + ", persistent=" + persistent - + '}'; - } - - public boolean isPersistent() { - return persistent; - } - - public MetaToken persistent(boolean persistent) { - this.persistent = persistent; - return this; - } -} diff --git a/src/main/java/org/radarbase/management/domain/MetaToken.kt b/src/main/java/org/radarbase/management/domain/MetaToken.kt new file mode 100644 index 000000000..5980d8329 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/MetaToken.kt @@ -0,0 +1,164 @@ +package org.radarbase.management.domain + +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.envers.Audited +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.time.Instant +import java.util.* +import java.util.concurrent.ThreadLocalRandom +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern + +@Entity +@Audited +@Table(name = "radar_meta_token") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class MetaToken : AbstractEntity() { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @Column(name = "token_name", nullable = false, unique = true) + var tokenName: @NotNull @Pattern(regexp = Constants.TOKEN_NAME_REGEX) String? = null + private set + + @Column(name = "fetched", nullable = false) + private var fetched: Boolean? = null + + @Column(name = "expiry_date") + var expiryDate: Instant? = null + private set + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "subject_id") + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var subject: Subject? = null + private set + + @Column(name = "client_id", nullable = false) + var clientId: String? = null + private set + + @Column(name = "persistent", nullable = false) + private var persistent: Boolean? = null + + /** + * Generates a alphanumeric with '.' and '-' token name. Suggested token name lengths are + * [.SHORT_ID_LENGTH] for short-living tokens and [.LONG_ID_LENGTH] for long-living + * meta tokens. + * + * @param length token length + * @return this + */ + fun generateName(length: Int): MetaToken { + val random = ThreadLocalRandom.current() + val tokenChars = CharArray(length) + for (i in 0 until length) { + tokenChars[i] = ID_CHARS[random.nextInt(ID_CHARS.size)] + } + tokenName = String(tokenChars) + return this + } + + fun tokenName(tokenName: String?): MetaToken { + this.tokenName = tokenName + return this + } + + fun isFetched(): Boolean { + return fetched!! + } + + fun fetched(fetched: Boolean): MetaToken { + this.fetched = fetched + return this + } + + fun expiryDate(expiryDate: Instant?): MetaToken { + this.expiryDate = expiryDate + return this + } + + fun subject(subject: Subject?): MetaToken { + this.subject = subject + return this + } + + fun clientId(clientId: String?): MetaToken { + this.clientId = clientId + return this + } + + val isValid: Boolean + get() = (persistent!! || !fetched!!) && Instant.now().isBefore(expiryDate) + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val metaToken = o as MetaToken + return id == metaToken.id && tokenName == metaToken.tokenName && fetched == metaToken.fetched && expiryDate == metaToken.expiryDate && clientId == metaToken.clientId && subject == metaToken.subject && persistent == metaToken.persistent + } + + override fun hashCode(): Int { + return Objects.hash(id, tokenName, fetched, expiryDate, subject, clientId, persistent) + } + + override fun toString(): String { + return ("MetaToken{" + "id=" + id + + ", tokenName='" + tokenName + + ", fetched=" + fetched + + ", expiryDate=" + expiryDate + + ", subject=" + subject + + ", clientId=" + clientId + + ", persistent=" + persistent + + '}') + } + + fun isPersistent(): Boolean { + return persistent!! + } + + fun persistent(persistent: Boolean): MetaToken { + this.persistent = persistent + return this + } + + companion object { + private val ID_CHARS = charArrayOf( + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', + 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', + 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '-', '.' + ) + + //https://math.stackexchange.com/questions/889538/ + // probability-of-collision-with-randomly-generated-id + // Current length of tokenName is 8 for short-lived tokens, and double that + // for persistent tokens. + const val SHORT_ID_LENGTH = 8 + const val LONG_ID_LENGTH = 16 + } +} diff --git a/src/main/java/org/radarbase/management/domain/Organization.java b/src/main/java/org/radarbase/management/domain/Organization.java deleted file mode 100644 index 108587d6e..000000000 --- a/src/main/java/org/radarbase/management/domain/Organization.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.radarbase.management.domain; - -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.envers.Audited; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.OneToMany; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.util.List; -import java.util.Objects; - -/** - * An Organization. - */ -@Entity -@Audited -@Table(name = "radar_organization") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class Organization extends AbstractEntity { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "name", nullable = false, unique = true) - private String name; - - @NotNull - @Column(name = "description", nullable = false) - private String description; - - @NotNull - @Column(name = "location", nullable = false) - private String location; - - @OneToMany(mappedBy = "organization") - private List projects; - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - - public List getProjects() { - return projects; - } - - public void setProjects(List projects) { - this.projects = projects; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - var org = (Organization) o; - if (org.id == null || id == null) { - return false; - } - return Objects.equals(id, org.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "Organization{" - + "id=" + id - + ", name='" + name + "'" - + ", description='" + description + "'" - + ", location='" + location + "'" - + "}"; - } -} diff --git a/src/main/java/org/radarbase/management/domain/Organization.kt b/src/main/java/org/radarbase/management/domain/Organization.kt new file mode 100644 index 000000000..479a0f708 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Organization.kt @@ -0,0 +1,81 @@ +package org.radarbase.management.domain + +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.envers.Audited +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.util.* +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.OneToMany +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern + +/** + * An Organization. + */ +@Entity +@Audited +@Table(name = "radar_organization") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class Organization : AbstractEntity() { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @JvmField + @Column(name = "name", nullable = false, unique = true) + var name: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + @JvmField + @Column(name = "description", nullable = false) + var description: @NotNull String? = null + + @JvmField + @Column(name = "location", nullable = false) + var location: @NotNull String? = null + + @JvmField + @OneToMany(mappedBy = "organization") + var projects: List? = null + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val org = o as Organization + return if (org.id == null || id == null) { + false + } else id == org.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("Organization{" + + "id=" + id + + ", name='" + name + "'" + + ", description='" + description + "'" + + ", location='" + location + "'" + + "}") + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.java b/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.java deleted file mode 100644 index 09e21d02b..000000000 --- a/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.radarbase.management.domain; - - -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; - -import java.io.Serializable; -import java.time.LocalDateTime; -import java.util.HashMap; -import java.util.Map; -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.MapKeyColumn; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; - -/** - * Persist AuditEvent managed by the Spring Boot actuator. - * - * @see org.springframework.boot.actuate.audit.AuditEvent - */ -@Entity -@Table(name = "jhi_persistent_audit_event") -public class PersistentAuditEvent implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - @Column(name = "event_id") - private Long id; - - @NotNull - @Column(nullable = false) - private String principal; - - @Column(name = "event_date") - private LocalDateTime auditEventDate; - @Column(name = "event_type") - private String auditEventType; - - @ElementCollection - @MapKeyColumn(name = "name") - @Column(name = "value") - @CollectionTable(name = "jhi_persistent_audit_evt_data", - joinColumns = @JoinColumn(name = "event_id")) - private Map data = new HashMap<>(); - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getPrincipal() { - return principal; - } - - public void setPrincipal(String principal) { - this.principal = principal; - } - - public LocalDateTime getAuditEventDate() { - return auditEventDate; - } - - public void setAuditEventDate(LocalDateTime auditEventDate) { - this.auditEventDate = auditEventDate; - } - - public String getAuditEventType() { - return auditEventType; - } - - public void setAuditEventType(String auditEventType) { - this.auditEventType = auditEventType; - } - - public Map getData() { - return data; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setData(Map data) { - this.data = data; - } -} diff --git a/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt b/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt new file mode 100644 index 000000000..9f04a713f --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt @@ -0,0 +1,57 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import java.io.Serializable +import java.time.LocalDateTime +import javax.persistence.CollectionTable +import javax.persistence.Column +import javax.persistence.ElementCollection +import javax.persistence.Entity +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.MapKeyColumn +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull + +/** + * Persist AuditEvent managed by the Spring Boot actuator. + * + * @see org.springframework.boot.actuate.audit.AuditEvent + */ +@Entity +@Table(name = "jhi_persistent_audit_event") +class PersistentAuditEvent : Serializable { + @JvmField + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + @Column(name = "event_id") + var id: Long? = null + + @JvmField + @Column(nullable = false) + var principal: @NotNull String? = null + + @JvmField + @Column(name = "event_date") + var auditEventDate: LocalDateTime? = null + + @JvmField + @Column(name = "event_type") + var auditEventType: String? = null + + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ElementCollection + @MapKeyColumn(name = "name") + @Column(name = "value") + @CollectionTable(name = "jhi_persistent_audit_evt_data", joinColumns = [JoinColumn(name = "event_id")]) + var data: Map = HashMap() + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/Project.java b/src/main/java/org/radarbase/management/domain/Project.java deleted file mode 100644 index 04f6c9c27..000000000 --- a/src/main/java/org/radarbase/management/domain/Project.java +++ /dev/null @@ -1,311 +0,0 @@ -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.CascadeType; -import org.hibernate.annotations.DynamicInsert; -import org.hibernate.envers.Audited; -import org.hibernate.envers.NotAudited; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.enumeration.ProjectStatus; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.MapKeyColumn; -import javax.persistence.OneToMany; -import javax.persistence.OrderBy; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.io.Serializable; -import java.time.ZonedDateTime; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; - -import static javax.persistence.CascadeType.DETACH; -import static javax.persistence.CascadeType.REFRESH; -import static javax.persistence.CascadeType.REMOVE; - -/** - * A Project. - */ -@Entity -@Audited -@Table(name = "project") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -@DynamicInsert -public class Project extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "project_name", nullable = false, unique = true) - private String projectName; - - @NotNull - @Column(name = "description", nullable = false) - private String description; - - @Column(name = "jhi_organization") - private String organizationName; - - @ManyToOne(fetch = FetchType.EAGER) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Organization organization; - - @NotNull - @Column(name = "location", nullable = false) - private String location; - - @Column(name = "start_date") - private ZonedDateTime startDate; - - @Enumerated(EnumType.STRING) - @Column(name = "project_status") - private ProjectStatus projectStatus; - - @Column(name = "end_date") - private ZonedDateTime endDate; - - @JsonIgnore - @OneToMany(mappedBy = "project", fetch = FetchType.LAZY) - @Cascade(CascadeType.ALL) - private Set roles = new HashSet<>(); - - @ManyToMany(fetch = FetchType.LAZY) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @JoinTable(name = "project_source_type", - joinColumns = @JoinColumn(name = "projects_id", referencedColumnName = "id"), - inverseJoinColumns = @JoinColumn(name = "source_types_id", referencedColumnName = "id")) - private Set sourceTypes = new HashSet<>(); - - @ElementCollection(fetch = FetchType.EAGER) - @MapKeyColumn(name = "attribute_key") - @Column(name = "attribute_value") - @CollectionTable(name = "project_metadata", joinColumns = @JoinColumn(name = "id")) - private Map attributes = new HashMap<>(); - - @NotAudited - @OneToMany(mappedBy = "project", fetch = FetchType.LAZY, orphanRemoval = true, - cascade = {REMOVE, REFRESH, DETACH}) - @OrderBy("name ASC") - private Set groups = new HashSet<>(); - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getProjectName() { - return projectName; - } - - public Project projectName(String projectName) { - this.projectName = projectName; - return this; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - public String getDescription() { - return description; - } - - public Project description(String description) { - this.description = description; - return this; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getOrganizationName() { - return organizationName; - } - - public Project organizationName(String organizationName) { - this.organizationName = organizationName; - return this; - } - - public Set getRoles() { - return roles; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setRoles(Set roles) { - this.roles = roles; - } - - public void setOrganizationName(String organizationName) { - this.organizationName = organizationName; - } - - public Organization getOrganization() { - return organization; - } - - public Project organization(Organization organization) { - this.organization = organization; - return this; - } - - public void setOrganization(Organization organization) { - this.organization = organization; - } - - public String getLocation() { - return location; - } - - public Project location(String location) { - this.location = location; - return this; - } - - public void setLocation(String location) { - this.location = location; - } - - public ZonedDateTime getStartDate() { - return startDate; - } - - public Project startDate(ZonedDateTime startDate) { - this.startDate = startDate; - return this; - } - - public void setStartDate(ZonedDateTime startDate) { - this.startDate = startDate; - } - - public ProjectStatus getProjectStatus() { - return projectStatus; - } - - public Project projectStatus(ProjectStatus projectStatus) { - this.projectStatus = projectStatus; - return this; - } - - public void setProjectStatus(ProjectStatus projectStatus) { - this.projectStatus = projectStatus; - } - - public ZonedDateTime getEndDate() { - return endDate; - } - - public Project endDate(ZonedDateTime endDate) { - this.endDate = endDate; - return this; - } - - public void setEndDate(ZonedDateTime endDate) { - this.endDate = endDate; - } - - public Set getSourceTypes() { - return sourceTypes; - } - - public Project sourceTypes(Set sourceTypes) { - this.sourceTypes = sourceTypes; - return this; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setSourceTypes(Set sourceTypes) { - this.sourceTypes = sourceTypes; - } - - public Map getAttributes() { - return attributes; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - public Set getGroups() { - return groups; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setGroups(Set groups) { - this.groups = groups; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Project project = (Project) o; - if (project.id == null || id == null) { - return false; - } - return Objects.equals(id, project.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "Project{" - + "id=" + id - + ", projectName='" + projectName + "'" - + ", description='" + description + "'" - + ", organization='" + organizationName + "'" - + ", location='" + location + "'" - + ", startDate='" + startDate + "'" - + ", projectStatus='" + projectStatus + "'" - + ", endDate='" + endDate + "'" - + "}"; - } -} diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt new file mode 100644 index 000000000..a6da31807 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -0,0 +1,207 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.annotations.Cascade +import org.hibernate.annotations.CascadeType +import org.hibernate.annotations.DynamicInsert +import org.hibernate.envers.Audited +import org.hibernate.envers.NotAudited +import org.radarbase.management.domain.enumeration.ProjectStatus +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.io.Serializable +import java.time.ZonedDateTime +import java.util.* +import javax.persistence.CollectionTable +import javax.persistence.Column +import javax.persistence.ElementCollection +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.EnumType +import javax.persistence.Enumerated +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.JoinTable +import javax.persistence.ManyToMany +import javax.persistence.ManyToOne +import javax.persistence.MapKeyColumn +import javax.persistence.OneToMany +import javax.persistence.OrderBy +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern + +/** + * A Project. + */ +@Entity +@Audited +@Table(name = "project") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +@DynamicInsert +class Project : AbstractEntity(), Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @JvmField + @Column(name = "project_name", nullable = false, unique = true) + var projectName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + @JvmField + @Column(name = "description", nullable = false) + var description: @NotNull String? = null + + @JvmField + @Column(name = "jhi_organization") + var organizationName: String? = null + + @JvmField + @ManyToOne(fetch = FetchType.EAGER) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var organization: Organization? = null + + @JvmField + @Column(name = "location", nullable = false) + var location: @NotNull String? = null + + @JvmField + @Column(name = "start_date") + var startDate: ZonedDateTime? = null + + @JvmField + @Enumerated(EnumType.STRING) + @Column(name = "project_status") + var projectStatus: ProjectStatus? = null + + @JvmField + @Column(name = "end_date") + var endDate: ZonedDateTime? = null + + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonIgnore + @OneToMany(mappedBy = "project", fetch = FetchType.LAZY) + @Cascade(CascadeType.ALL) + var roles: Set = HashSet() + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ManyToMany(fetch = FetchType.LAZY) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @JoinTable( + name = "project_source_type", + joinColumns = [JoinColumn(name = "projects_id", referencedColumnName = "id")], + inverseJoinColumns = [JoinColumn(name = "source_types_id", referencedColumnName = "id")] + ) + var sourceTypes: Set = HashSet() + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ElementCollection(fetch = FetchType.EAGER) + @MapKeyColumn(name = "attribute_key") + @Column(name = "attribute_value") + @CollectionTable(name = "project_metadata", joinColumns = [JoinColumn(name = "id")]) + var attributes: Map = HashMap() + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @NotAudited + @OneToMany( + mappedBy = "project", + fetch = FetchType.LAZY, + orphanRemoval = true, + cascade = [javax.persistence.CascadeType.REMOVE, javax.persistence.CascadeType.REFRESH, javax.persistence.CascadeType.DETACH] + ) + @OrderBy("name ASC") + var groups: MutableSet = HashSet() + fun projectName(projectName: String?): Project { + this.projectName = projectName + return this + } + + fun description(description: String?): Project { + this.description = description + return this + } + + fun organizationName(organizationName: String?): Project { + this.organizationName = organizationName + return this + } + + fun organization(organization: Organization?): Project { + this.organization = organization + return this + } + + fun location(location: String?): Project { + this.location = location + return this + } + + fun startDate(startDate: ZonedDateTime?): Project { + this.startDate = startDate + return this + } + + fun projectStatus(projectStatus: ProjectStatus?): Project { + this.projectStatus = projectStatus + return this + } + + fun endDate(endDate: ZonedDateTime?): Project { + this.endDate = endDate + return this + } + + fun sourceTypes(sourceTypes: Set): Project { + this.sourceTypes = sourceTypes + return this + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val project = o as Project + return if (project.id == null || id == null) { + false + } else id == project.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("Project{" + + "id=" + id + + ", projectName='" + projectName + "'" + + ", description='" + description + "'" + + ", organization='" + organizationName + "'" + + ", location='" + location + "'" + + ", startDate='" + startDate + "'" + + ", projectStatus='" + projectStatus + "'" + + ", endDate='" + endDate + "'" + + "}") + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/Role.java b/src/main/java/org/radarbase/management/domain/Role.java deleted file mode 100644 index 501078f17..000000000 --- a/src/main/java/org/radarbase/management/domain/Role.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2017 The Hyve and respective contributors. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import javax.persistence.FetchType; - -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.envers.Audited; -import org.hibernate.envers.RelationTargetAuditMode; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import java.io.Serializable; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -/** - * A Role. - */ -@Entity -@Audited -@Table(name = "radar_role") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class Role extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY) - @JsonIgnore - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) - private Set users = new HashSet<>(); - - @ManyToOne(fetch = FetchType.EAGER) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Project project; - - @ManyToOne(fetch = FetchType.EAGER) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Organization organization; - - @JsonProperty() - @ManyToOne(fetch = FetchType.EAGER) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @JoinColumn(name = "authority_name", referencedColumnName = "name") - private Authority authority; - - public Role() { - // constructor for reflection - } - - public Role(Authority authority, Project project) { - this.authority = authority; - this.project = project; - } - - public Role(Authority authority) { - this.authority = authority; - } - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Set getUsers() { - return users; - } - - public Role users(Set users) { - this.users = users; - return this; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setUsers(Set users) { - this.users = users; - } - - public Organization getOrganization() { - return organization; - } - - public void setOrganization(Organization organization) { - this.organization = organization; - } - - public Project getProject() { - return project; - } - - public Role project(Project project) { - this.project = project; - return this; - } - - public void setProject(Project project) { - this.project = project; - } - - public Authority getAuthority() { - return authority; - } - - public RoleAuthority getRole() { - return RoleAuthority.valueOfAuthorityOrNull(authority.getName()); - } - - public Role authority(Authority authority) { - this.authority = authority; - return this; - } - - public void setAuthority(Authority authority) { - this.authority = authority; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Role role = (Role) o; - return Objects.equals(authority, role.authority) - && Objects.equals(project, role.project) - && Objects.equals(organization, role.organization); - } - - @Override - public int hashCode() { - return Objects.hash(authority, project, organization); - } - - @Override - public String toString() { - return "Role{" - + "id=" + id + ", " - + "organization='" + (organization == null ? "null" : organization.getName()) - + "', " - + "project='" + (project == null ? "null" : project.getProjectName()) + "', " - + "authority='" + getAuthority().getName() + "', " - + "}"; - } - -} diff --git a/src/main/java/org/radarbase/management/domain/Role.kt b/src/main/java/org/radarbase/management/domain/Role.kt new file mode 100644 index 000000000..b71751401 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Role.kt @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2017 The Hyve and respective contributors. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.envers.Audited +import org.hibernate.envers.RelationTargetAuditMode +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.auth.authorization.RoleAuthority.Companion.valueOfAuthorityOrNull +import org.radarbase.management.domain.support.AbstractEntityListener +import java.io.Serializable +import java.util.* +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToMany +import javax.persistence.ManyToOne +import javax.persistence.SequenceGenerator +import javax.persistence.Table + +/** + * A Role. + */ +@Entity +@Audited +@Table(name = "radar_role") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class Role : AbstractEntity, Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY) + @JsonIgnore + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) + var users: Set = HashSet() + + @JvmField + @ManyToOne(fetch = FetchType.EAGER) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var project: Project? = null + + @JvmField + @ManyToOne(fetch = FetchType.EAGER) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var organization: Organization? = null + + @JvmField + @JsonProperty + @ManyToOne(fetch = FetchType.EAGER) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @JoinColumn(name = "authority_name", referencedColumnName = "name") + var authority: Authority? = null + + constructor() + constructor(authority: Authority?, project: Project?) { + this.authority = authority + this.project = project + } + + constructor(authority: Authority?) { + this.authority = authority + } + + fun users(users: Set): Role { + this.users = users + return this + } + + fun project(project: Project?): Role { + this.project = project + return this + } + + val role: RoleAuthority? + get() = valueOfAuthorityOrNull(authority?.name!!) + + fun authority(authority: Authority?): Role { + this.authority = authority + return this + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val role = o as Role + return authority == role.authority && project == role.project && organization == role.organization + } + + override fun hashCode(): Int { + return Objects.hash(authority, project, organization) + } + + override fun toString(): String { + return ("Role{" + + "id=" + id + ", " + + "organization='" + (if (organization == null) "null" else organization?.name) + + "', " + + "project='" + (if (project == null) "null" else project?.projectName) + "', " + + "authority='" + authority?.name + "', " + + "}") + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/Source.java b/src/main/java/org/radarbase/management/domain/Source.java deleted file mode 100644 index bffb3828d..000000000 --- a/src/main/java/org/radarbase/management/domain/Source.java +++ /dev/null @@ -1,275 +0,0 @@ -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.envers.Audited; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.MapKeyColumn; -import javax.persistence.PrePersist; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; - -/** - * A Source. - */ -@Entity -@Audited -@Table(name = "radar_source") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class Source extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Column(name = "source_id", nullable = false, unique = true) - private UUID sourceId; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "source_name", nullable = false, unique = true) - private String sourceName; - - @Column(name = "expected_source_name") - private String expectedSourceName; - - @NotNull - @Column(name = "assigned", nullable = false) - private Boolean assigned; - - @NotNull - @Column(name = "deleted", nullable = false) - private Boolean deleted = false; - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "subject_id") - @JsonIgnore - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Subject subject; - - @ManyToOne(fetch = FetchType.EAGER) - private SourceType sourceType; - - @ManyToOne(fetch = FetchType.LAZY) - private Project project; - - @ElementCollection(fetch = FetchType.EAGER) - @MapKeyColumn(name = "attribute_key") - @Column(name = "attribute_value") - @CollectionTable(name = "source_metadata", joinColumns = @JoinColumn(name = "id")) - private Map attributes = new HashMap<>(); - - /** - * Default constructor. Needed for other JPA operations. - */ - public Source() { - // default constructor - } - - /** - * Constructor with SourceType. This will assign sourceType and assign default values for - * sourceId and sourceName. - * @param sourceType sourceType of the source. - */ - public Source(SourceType sourceType) { - this.sourceType = sourceType; - this.generateUuid(); - } - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public UUID getSourceId() { - return sourceId; - } - - public Source sourceId(UUID devicePhysicalId) { - this.sourceId = devicePhysicalId; - return this; - } - - public void setSourceId(UUID sourceId) { - // pass - this.sourceId = sourceId; - } - - /** - * Add default values for sourceId and sourceName if they are not provided before persisting - * this object. The default for sourceId is to generate a new UUID. The default for - * sourceName is to take to model name, and append a dash followed by the first 8 characters - * of the string representation of the UUID. - */ - @PrePersist - public final void generateUuid() { - if (this.sourceId == null) { - this.sourceId = UUID.randomUUID(); - } - if (this.sourceName == null) { - this.sourceName = String.join("-", this.getSourceType().getModel(), - this.sourceId.toString().substring(0, 8)); - } - } - - public Boolean isAssigned() { - return assigned; - } - - public Source assigned(Boolean assigned) { - this.assigned = assigned; - return this; - } - - public void setAssigned(Boolean assigned) { - this.assigned = assigned; - } - - public Boolean isDeleted() { - return deleted; - } - - public Source deleted(Boolean deleted) { - this.deleted = deleted; - return this; - } - - public void setDeleted(Boolean deleted) { - this.deleted = deleted; - } - - public void setSourceType(SourceType sourceType) { - this.sourceType = sourceType; - } - - public SourceType getSourceType() { - return sourceType; - } - - public Source sourceType(SourceType sourceType) { - this.sourceType = sourceType; - return this; - } - - public void setProject(Project project) { - this.project = project; - } - - public Project getProject() { - return project; - } - - public Source project(Project project) { - this.project = project; - return this; - } - - public Subject getSubject() { - return subject; - } - - public Source subject(Subject subject) { - this.subject = subject; - return this; - } - - public String getSourceName() { - return sourceName; - } - - public void setSourceName(String sourceName) { - this.sourceName = sourceName; - } - - public Source sourceName(String sourceName) { - this.sourceName = sourceName; - return this; - } - - public String getExpectedSourceName() { - return expectedSourceName; - } - - public void setExpectedSourceName(String expectedSourceName) { - this.expectedSourceName = expectedSourceName; - } - - public Map getAttributes() { - return attributes; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - public void setSubject(Subject subject) { - this.subject = subject; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Source source = (Source) o; - if (source.id == null || id == null) { - return false; - } - return Objects.equals(id, source.id) - && Objects.equals(sourceId, source.sourceId); - } - - @Override - public int hashCode() { - return Objects.hash(id , sourceId); - } - - @Override - public String toString() { - return "Source{" - + "id=" + id - + ", sourceId='" + sourceId + '\'' - + ", sourceName='" + sourceName + '\'' - + ", assigned=" + assigned - + ", sourceType=" + sourceType - + ", project=" + project - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/domain/Source.kt b/src/main/java/org/radarbase/management/domain/Source.kt new file mode 100644 index 000000000..7e308f5f9 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Source.kt @@ -0,0 +1,189 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.envers.Audited +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.io.Serializable +import java.util.* +import javax.persistence.CollectionTable +import javax.persistence.Column +import javax.persistence.ElementCollection +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne +import javax.persistence.MapKeyColumn +import javax.persistence.PrePersist +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern + +/** + * A Source. + */ +@Entity +@Audited +@Table(name = "radar_source") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class Source : AbstractEntity, Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + // pass + @JvmField + @Column(name = "source_id", nullable = false, unique = true) + var sourceId: @NotNull UUID? = null + + @JvmField + @Column(name = "source_name", nullable = false, unique = true) + var sourceName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + @JvmField + @Column(name = "expected_source_name") + var expectedSourceName: String? = null + + @Column(name = "assigned", nullable = false) + var isAssigned: @NotNull Boolean? = null + + @Column(name = "deleted", nullable = false) + var isDeleted: @NotNull Boolean? = false + + @JvmField + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "subject_id") + @JsonIgnore + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var subject: Subject? = null + + @JvmField + @ManyToOne(fetch = FetchType.EAGER) + var sourceType: SourceType? = null + + @JvmField + @ManyToOne(fetch = FetchType.LAZY) + var project: Project? = null + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ElementCollection(fetch = FetchType.EAGER) + @MapKeyColumn(name = "attribute_key") + @Column(name = "attribute_value") + @CollectionTable(name = "source_metadata", joinColumns = [JoinColumn(name = "id")]) + var attributes: Map = HashMap() + + /** + * Default constructor. Needed for other JPA operations. + */ + constructor() + + /** + * Constructor with SourceType. This will assign sourceType and assign default values for + * sourceId and sourceName. + * @param sourceType sourceType of the source. + */ + constructor(sourceType: SourceType?) { + this.sourceType = sourceType + generateUuid() + } + + fun sourceId(devicePhysicalId: UUID?): Source { + sourceId = devicePhysicalId + return this + } + + /** + * Add default values for sourceId and sourceName if they are not provided before persisting + * this object. The default for sourceId is to generate a new UUID. The default for + * sourceName is to take to model name, and append a dash followed by the first 8 characters + * of the string representation of the UUID. + */ + @PrePersist + fun generateUuid() { + if (sourceId == null) { + sourceId = UUID.randomUUID() + } + if (sourceName == null) { + sourceName = java.lang.String.join( + "-", sourceType?.model, + sourceId.toString().substring(0, 8) + ) + } + } + + fun assigned(assigned: Boolean?): Source { + isAssigned = assigned + return this + } + + fun deleted(deleted: Boolean?): Source { + isDeleted = deleted + return this + } + + fun sourceType(sourceType: SourceType?): Source { + this.sourceType = sourceType + return this + } + + fun project(project: Project?): Source { + this.project = project + return this + } + + fun subject(subject: Subject?): Source { + this.subject = subject + return this + } + + fun sourceName(sourceName: String?): Source { + this.sourceName = sourceName + return this + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val source = o as Source + return if (source.id == null || id == null) { + false + } else id == source.id && sourceId == source.sourceId + } + + override fun hashCode(): Int { + return Objects.hash(id, sourceId) + } + + override fun toString(): String { + return ("Source{" + + "id=" + id + + ", sourceId='" + sourceId + '\'' + + ", sourceName='" + sourceName + '\'' + + ", assigned=" + isAssigned + + ", sourceType=" + sourceType + + ", project=" + project + + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/SourceData.java b/src/main/java/org/radarbase/management/domain/SourceData.java deleted file mode 100644 index 0e222c656..000000000 --- a/src/main/java/org/radarbase/management/domain/SourceData.java +++ /dev/null @@ -1,274 +0,0 @@ -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.envers.Audited; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToOne; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.io.Serializable; -import java.util.Objects; - -/** - * A SourceData. - */ -@Entity -@Audited -@Table(name = "source_data") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class SourceData extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - //SourceData type e.g. ACCELEROMETER, TEMPERATURE. - @NotNull - @Column(name = "source_data_type", nullable = false) - private String sourceDataType; - - // this will be the unique human readable identifier of - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "source_data_name", nullable = false, unique = true) - private String sourceDataName; - - //Default data frequency - @Column(name = "frequency") - private String frequency; - - //Measurement unit. - @Column(name = "unit") - private String unit; - - // Define if the samples are RAW data or instead they the result of some computation - @Column(name = "processing_state") - private String processingState; - - // the storage - @Column(name = "data_class") - private String dataClass; - - @Column(name = "key_schema") - private String keySchema; - - - @Column(name = "value_schema") - private String valueSchema; - - // source data topic - @Column(name = "topic") - private String topic; - - // app provider - @Column(name = "provider") - private String provider; - - @Column(name = "enabled") - private boolean enabled = true; - - @ManyToOne(fetch = FetchType.LAZY) - @JsonIgnoreProperties({"sourceData"}) // avoids infinite recursion in JSON serialization - private SourceType sourceType; - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getSourceDataType() { - return sourceDataType; - } - - public SourceData sourceDataType(String sourceDataType) { - this.sourceDataType = sourceDataType; - return this; - } - - public SourceData sourceDataName(String sourceDataName) { - this.sourceDataName = sourceDataName; - return this; - } - - public void setSourceDataType(String sourceDataType) { - this.sourceDataType = sourceDataType; - } - - public String getProcessingState() { - return processingState; - } - - public SourceData processingState(String processingState) { - this.processingState = processingState; - return this; - } - - public void setProcessingState(String processingState) { - this.processingState = processingState; - } - - public String getKeySchema() { - return keySchema; - } - - public SourceData keySchema(String keySchema) { - this.keySchema = keySchema; - return this; - } - - public void setKeySchema(String keySchema) { - this.keySchema = keySchema; - } - - public String getFrequency() { - return frequency; - } - - public SourceData frequency(String frequency) { - this.frequency = frequency; - return this; - } - - public void setFrequency(String frequency) { - this.frequency = frequency; - } - - public SourceType getSourceType() { - return sourceType; - } - - public void setSourceType(SourceType sourceType) { - this.sourceType = sourceType; - } - - public SourceData sourceType(SourceType sourceType) { - this.sourceType = sourceType; - return this; - } - - public String getUnit() { - return unit; - } - - public void setUnit(String unit) { - this.unit = unit; - } - - public SourceData unit(String unit) { - this.unit = unit; - return this; - } - - - public String getDataClass() { - return dataClass; - } - - public void setDataClass(String dataClass) { - this.dataClass = dataClass; - } - - public String getValueSchema() { - return valueSchema; - } - - public void setValueSchema(String valueSchema) { - this.valueSchema = valueSchema; - } - - public SourceData valueSchema(String valueSchema) { - this.valueSchema = valueSchema; - return this; - } - - public String getTopic() { - return topic; - } - - public void setTopic(String topic) { - this.topic = topic; - } - - public SourceData topic(String topic) { - this.topic = topic; - return this; - } - - public String getProvider() { - return provider; - } - - public void setProvider(String provider) { - this.provider = provider; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getSourceDataName() { - return sourceDataName; - } - - public void setSourceDataName(String sourceDataName) { - this.sourceDataName = sourceDataName; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - SourceData sourceData = (SourceData) o; - if (sourceData.id == null || id == null) { - return false; - } - return Objects.equals(id, sourceData.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "SourceData{" + "id=" + id + ", sourceDataType='" + sourceDataType + '\'' - + ", frequency='" - + frequency + '\'' + ", unit='" + unit + '\'' + ", processingState=" - + processingState - + ", dataClass='" + dataClass + '\'' + ", keySchema='" + keySchema + '\'' - + ", valueSchema='" + valueSchema + '\'' + ", topic='" + topic + '\'' - + ", provider='" - + provider + '\'' + ", enabled=" + enabled + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/domain/SourceData.kt b/src/main/java/org/radarbase/management/domain/SourceData.kt new file mode 100644 index 000000000..28a8805b3 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/SourceData.kt @@ -0,0 +1,171 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.envers.Audited +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.io.Serializable +import java.util.* +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.ManyToOne +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern + +/** + * A SourceData. + */ +@Entity +@Audited +@Table(name = "source_data") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class SourceData : AbstractEntity(), Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + //SourceData type e.g. ACCELEROMETER, TEMPERATURE. + @JvmField + @Column(name = "source_data_type", nullable = false) + var sourceDataType: @NotNull String? = null + + // this will be the unique human readable identifier of + @JvmField + @Column(name = "source_data_name", nullable = false, unique = true) + var sourceDataName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + //Default data frequency + @JvmField + @Column(name = "frequency") + var frequency: String? = null + + //Measurement unit. + @JvmField + @Column(name = "unit") + var unit: String? = null + + // Define if the samples are RAW data or instead they the result of some computation + @JvmField + @Column(name = "processing_state") + var processingState: String? = null + + // the storage + @JvmField + @Column(name = "data_class") + var dataClass: String? = null + + @JvmField + @Column(name = "key_schema") + var keySchema: String? = null + + @JvmField + @Column(name = "value_schema") + var valueSchema: String? = null + + // source data topic + @JvmField + @Column(name = "topic") + var topic: String? = null + + // app provider + @JvmField + @Column(name = "provider") + var provider: String? = null + + @Column(name = "enabled") + var isEnabled = true + + @JvmField + @ManyToOne(fetch = FetchType.LAZY) + @JsonIgnoreProperties("sourceData") // avoids infinite recursion in JSON serialization + var sourceType: SourceType? = null + fun sourceDataType(sourceDataType: String?): SourceData { + this.sourceDataType = sourceDataType + return this + } + + fun sourceDataName(sourceDataName: String?): SourceData { + this.sourceDataName = sourceDataName + return this + } + + fun processingState(processingState: String?): SourceData { + this.processingState = processingState + return this + } + + fun keySchema(keySchema: String?): SourceData { + this.keySchema = keySchema + return this + } + + fun frequency(frequency: String?): SourceData { + this.frequency = frequency + return this + } + + fun sourceType(sourceType: SourceType?): SourceData { + this.sourceType = sourceType + return this + } + + fun unit(unit: String?): SourceData { + this.unit = unit + return this + } + + fun valueSchema(valueSchema: String?): SourceData { + this.valueSchema = valueSchema + return this + } + + fun topic(topic: String?): SourceData { + this.topic = topic + return this + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val sourceData = o as SourceData + return if (sourceData.id == null || id == null) { + false + } else id == sourceData.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("SourceData{" + "id=" + id + ", sourceDataType='" + sourceDataType + '\'' + + ", frequency='" + + frequency + '\'' + ", unit='" + unit + '\'' + ", processingState=" + + processingState + + ", dataClass='" + dataClass + '\'' + ", keySchema='" + keySchema + '\'' + + ", valueSchema='" + valueSchema + '\'' + ", topic='" + topic + '\'' + + ", provider='" + + provider + '\'' + ", enabled=" + isEnabled + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/SourceType.java b/src/main/java/org/radarbase/management/domain/SourceType.java deleted file mode 100644 index e2c86f11a..000000000 --- a/src/main/java/org/radarbase/management/domain/SourceType.java +++ /dev/null @@ -1,270 +0,0 @@ -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import javax.persistence.FetchType; - -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.CascadeType; -import org.hibernate.envers.Audited; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToMany; -import javax.persistence.OneToMany; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import java.io.Serializable; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -/** - * A SourceType. - */ -@Entity -@Audited -@Table(name = "source_type") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class SourceType extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "producer") - private String producer; - - @Column(name = "name") - private String name; - - @Column(name = "description") - private String description; - - @Column(name = "assessment_type") - private String assessmentType; - - @Column(name = "app_provider") - private String appProvider; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "model", nullable = false) - private String model; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Column(name = "catalog_version", nullable = false) - private String catalogVersion; - - @NotNull - @Column(name = "source_type_scope", nullable = false) - private String sourceTypeScope; - - @NotNull - @Column(name = "dynamic_registration", nullable = false) - private Boolean canRegisterDynamically = false; - - @OneToMany(mappedBy = "sourceType", orphanRemoval = true, fetch = FetchType.LAZY) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @Cascade({CascadeType.DELETE, CascadeType.SAVE_UPDATE}) - private Set sourceData = new HashSet<>(); - - @ManyToMany(mappedBy = "sourceTypes", fetch = FetchType.LAZY) - @JsonIgnore - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - private Set projects = new HashSet<>(); - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getProducer() { - return producer; - } - - public SourceType producer(String producer) { - this.producer = producer; - return this; - } - - public void setProducer(String producer) { - this.producer = producer; - } - - public String getModel() { - return model; - } - - public SourceType model(String model) { - this.model = model; - return this; - } - - public void setModel(String model) { - this.model = model; - } - - public String getCatalogVersion() { - return catalogVersion; - } - - public void setCatalogVersion(String catalogVersion) { - this.catalogVersion = catalogVersion; - } - - public SourceType catalogVersion(String catalogVersion) { - this.catalogVersion = catalogVersion; - return this; - } - - public String getSourceTypeScope() { - return sourceTypeScope; - } - - public SourceType sourceTypeScope(String sourceTypeScope) { - this.sourceTypeScope = sourceTypeScope; - return this; - } - - public void setSourceTypeScope(String sourceTypeScope) { - this.sourceTypeScope = sourceTypeScope; - } - - public Set getSourceData() { - return sourceData; - } - - public SourceType sourceData(Set sourceData) { - this.sourceData = sourceData; - return this; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setSourceData(Set sourceData) { - this.sourceData = sourceData; - } - - public Set getProjects() { - return projects; - } - - public SourceType projects(Set projects) { - this.projects = projects; - return this; - } - - public Boolean getCanRegisterDynamically() { - return canRegisterDynamically; - } - - public void setCanRegisterDynamically(Boolean canRegisterDynamically) { - this.canRegisterDynamically = canRegisterDynamically; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getAssessmentType() { - return assessmentType; - } - - public void setAssessmentType(String assessmentType) { - this.assessmentType = assessmentType; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setProjects(Set projects) { - this.projects = projects; - } - - public String getAppProvider() { - return appProvider; - } - - public void setAppProvider(String appProvider) { - this.appProvider = appProvider; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - SourceType sourceType = (SourceType) o; - if (sourceType.id == null || id == null) { - return false; - } - return Objects.equals(id, sourceType.id) - && Objects.equals(producer, sourceType.producer) - && Objects.equals(model, sourceType.model) - && Objects.equals(catalogVersion, sourceType.catalogVersion) - && Objects.equals(canRegisterDynamically, sourceType.canRegisterDynamically) - && Objects.equals(sourceTypeScope, sourceType.sourceTypeScope) - && Objects.equals(name, sourceType.name) - && Objects.equals(description, sourceType.description) - && Objects.equals(appProvider, sourceType.appProvider) - && Objects.equals(assessmentType, sourceType.assessmentType); - } - - @Override - public int hashCode() { - return Objects.hash(id, model, producer, catalogVersion, canRegisterDynamically, - sourceTypeScope, name, description, appProvider, assessmentType); - } - - @Override - public String toString() { - return "SourceType{" - + "id=" + id - + ", producer='" + producer + '\'' - + ", model='" + model + '\'' - + ", catalogVersion='" + catalogVersion + '\'' - + ", sourceTypeScope=" + sourceTypeScope - + ", canRegisterDynamically=" + canRegisterDynamically - + ", name='" + name + '\'' - + ", description=" + description - + ", appProvider=" + appProvider - + ", assessmentType=" + assessmentType - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/domain/SourceType.kt b/src/main/java/org/radarbase/management/domain/SourceType.kt new file mode 100644 index 000000000..cb89cefd7 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/SourceType.kt @@ -0,0 +1,163 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.annotations.Cascade +import org.hibernate.annotations.CascadeType +import org.hibernate.envers.Audited +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.io.Serializable +import java.util.* +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.ManyToMany +import javax.persistence.OneToMany +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern + +/** + * A SourceType. + */ +@Entity +@Audited +@Table(name = "source_type") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class SourceType : AbstractEntity(), Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @JvmField + @Column(name = "producer") + var producer: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + @JvmField + @Column(name = "name") + var name: String? = null + + @JvmField + @Column(name = "description") + var description: String? = null + + @JvmField + @Column(name = "assessment_type") + var assessmentType: String? = null + + @JvmField + @Column(name = "app_provider") + var appProvider: String? = null + + @JvmField + @Column(name = "model", nullable = false) + var model: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + @JvmField + @Column(name = "catalog_version", nullable = false) + var catalogVersion: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + + @JvmField + @Column(name = "source_type_scope", nullable = false) + var sourceTypeScope: @NotNull String? = null + + @JvmField + @Column(name = "dynamic_registration", nullable = false) + var canRegisterDynamically: @NotNull Boolean? = false + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @OneToMany(mappedBy = "sourceType", orphanRemoval = true, fetch = FetchType.LAZY) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @Cascade( + CascadeType.DELETE, CascadeType.SAVE_UPDATE + ) + var sourceData: Set = HashSet() + + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ManyToMany(mappedBy = "sourceTypes", fetch = FetchType.LAZY) + @JsonIgnore + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + var projects: Set = HashSet() + fun producer(producer: String?): SourceType { + this.producer = producer + return this + } + + fun model(model: String?): SourceType { + this.model = model + return this + } + + fun catalogVersion(catalogVersion: String?): SourceType { + this.catalogVersion = catalogVersion + return this + } + + fun sourceTypeScope(sourceTypeScope: String?): SourceType { + this.sourceTypeScope = sourceTypeScope + return this + } + + fun sourceData(sourceData: Set): SourceType { + this.sourceData = sourceData + return this + } + + fun projects(projects: Set): SourceType { + this.projects = projects + return this + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val sourceType = o as SourceType + return if (sourceType.id == null || id == null) { + false + } else id == sourceType.id && producer == sourceType.producer && model == sourceType.model && catalogVersion == sourceType.catalogVersion && canRegisterDynamically == sourceType.canRegisterDynamically && sourceTypeScope == sourceType.sourceTypeScope && name == sourceType.name && description == sourceType.description && appProvider == sourceType.appProvider && assessmentType == sourceType.assessmentType + } + + override fun hashCode(): Int { + return Objects.hash( + id, model, producer, catalogVersion, canRegisterDynamically, + sourceTypeScope, name, description, appProvider, assessmentType + ) + } + + override fun toString(): String { + return ("SourceType{" + + "id=" + id + + ", producer='" + producer + '\'' + + ", model='" + model + '\'' + + ", catalogVersion='" + catalogVersion + '\'' + + ", sourceTypeScope=" + sourceTypeScope + + ", canRegisterDynamically=" + canRegisterDynamically + + ", name='" + name + '\'' + + ", description=" + description + + ", appProvider=" + appProvider + + ", assessmentType=" + assessmentType + + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/Subject.java b/src/main/java/org/radarbase/management/domain/Subject.java deleted file mode 100644 index c05b743f9..000000000 --- a/src/main/java/org/radarbase/management/domain/Subject.java +++ /dev/null @@ -1,292 +0,0 @@ -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import org.hibernate.annotations.BatchSize; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.CascadeType; -import org.hibernate.envers.Audited; -import org.hibernate.envers.RelationTargetAuditMode; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.MapKeyColumn; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import java.io.Serializable; -import java.time.LocalDate; -import java.time.ZonedDateTime; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; - -import static org.radarbase.auth.authorization.RoleAuthority.INACTIVE_PARTICIPANT; -import static org.radarbase.auth.authorization.RoleAuthority.PARTICIPANT; - -/** - * A Subject. - */ -@Entity -@Audited -@Table(name = "subject") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class Subject extends AbstractEntity implements Serializable { - private static final long serialVersionUID = 1L; - private static final Set PARTICIPANT_TYPES = Set.of( - PARTICIPANT.getAuthority(), - INACTIVE_PARTICIPANT.getAuthority()); - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @Column(name = "external_link") - private String externalLink; - - @Column(name = "external_id") - private String externalId; - - @NotNull - @Column(name = "removed", nullable = false) - private Boolean removed = false; - - @OneToOne - @JoinColumn(unique = true, name = "user_id") - @Cascade(CascadeType.ALL) - private User user; - - @OneToMany(mappedBy = "subject", fetch = FetchType.LAZY) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @Cascade(CascadeType.SAVE_UPDATE) - private Set sources = new HashSet<>(); - - @ElementCollection(fetch = FetchType.EAGER) - @MapKeyColumn(name = "attribute_key") - @Column(name = "attribute_value") - @CollectionTable(name = "subject_metadata", joinColumns = @JoinColumn(name = "id")) - @Cascade(CascadeType.ALL) - @BatchSize(size = 50) - private Map attributes = new HashMap<>(); - - @OneToMany(mappedBy = "subject", orphanRemoval = true, fetch = FetchType.LAZY) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @JsonIgnore - private final Set metaTokens = new HashSet<>(); - - @ManyToOne(fetch = FetchType.EAGER) - @JoinColumn(name = "group_id") - @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) - private Group group; - - @Column(name = "date_of_birth") - private LocalDate dateOfBirth; - - @Column(name = "enrollment_date") - private ZonedDateTime enrollmentDate; - - @Column(name = "person_name") - private String personName; - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getExternalLink() { - return externalLink; - } - - public Subject externalLink(String externalLink) { - this.externalLink = externalLink; - return this; - } - - public void setExternalLink(String externalLink) { - this.externalLink = externalLink; - } - - public String getExternalId() { - return externalId; - } - - public Subject externalId(String enternalId) { - this.externalId = enternalId; - return this; - } - - public void setExternalId(String externalId) { - this.externalId = externalId; - } - - public Boolean isRemoved() { - return removed; - } - - public Subject removed(Boolean removed) { - this.removed = removed; - return this; - } - - public void setRemoved(Boolean removed) { - this.removed = removed; - } - - public User getUser() { - return user; - } - - public Subject user(User usr) { - this.user = usr; - return this; - } - - public void setUser(User usr) { - this.user = usr; - } - - public Set getSources() { - return sources; - } - - public Subject sources(Set sources) { - this.sources = sources; - return this; - } - - public void setSources(Set sources) { - this.sources = sources; - } - - public Map getAttributes() { - return attributes; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - public Set getMetaTokens() { - return metaTokens; - } - - public void setGroup(Group group) { - this.group = group; - } - - public Group getGroup() { - return this.group; - } - - public void setDateOfBirth(LocalDate dateOfBirth) { - this.dateOfBirth = dateOfBirth; - } - - public LocalDate getDateOfBirth() { - return this.dateOfBirth; - } - - public void setEnrollmentDate(ZonedDateTime enrollmentDate) { - this.enrollmentDate = enrollmentDate; - } - - public ZonedDateTime getEnrollmentDate() { - return this.enrollmentDate; - } - - public void setPersonName(String personName) { - this.personName = personName; - } - - public String getPersonName() { - return this.personName; - } - - /** - * Gets the active project of subject. - * - *

There can be only one role with PARTICIPANT authority - * and the project that is related to that role is the active role.

- * - * @return {@link Project} currently active project of subject. - */ - public Optional getActiveProject() { - return this.getUser().getRoles().stream() - .filter(r -> r.getAuthority().getName().equals(PARTICIPANT.getAuthority())) - .findFirst() - .map(Role::getProject); - } - - /** - * Get the active project of a subject, and otherwise the - * inactive project. - * @return the project a subject belongs to, if any. - */ - public Optional getAssociatedProject() { - return this.getUser().getRoles().stream() - .filter(r -> PARTICIPANT_TYPES.contains(r.getAuthority().getName())) - .max(Comparator.comparing(r -> r.getAuthority().getName())) - .map(Role::getProject); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Subject subject = (Subject) o; - if (subject.id == null || id == null) { - return false; - } - return Objects.equals(id, subject.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "Subject{" - + "id=" + id - + ", externalLink='" + externalLink + '\'' - + ", externalId='" + externalId + '\'' - + ", removed=" + removed - + ", user=" + user - + ", sources=" + sources - + ", attributes=" + attributes - + ", group=" + group - + "}"; - } -} diff --git a/src/main/java/org/radarbase/management/domain/Subject.kt b/src/main/java/org/radarbase/management/domain/Subject.kt new file mode 100644 index 000000000..e5e1217e7 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/Subject.kt @@ -0,0 +1,207 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import org.hibernate.annotations.BatchSize +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.annotations.Cascade +import org.hibernate.annotations.CascadeType +import org.hibernate.envers.Audited +import org.hibernate.envers.RelationTargetAuditMode +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.domain.support.AbstractEntityListener +import java.io.Serializable +import java.time.LocalDate +import java.time.ZonedDateTime +import java.util.* +import javax.persistence.CollectionTable +import javax.persistence.Column +import javax.persistence.ElementCollection +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne +import javax.persistence.MapKeyColumn +import javax.persistence.OneToMany +import javax.persistence.OneToOne +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.NotNull + +/** + * A Subject. + */ +@Entity +@Audited +@Table(name = "subject") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class Subject( + @Id @GeneratedValue( + strategy = GenerationType.SEQUENCE, + generator = "sequenceGenerator" + ) @SequenceGenerator( + name = "sequenceGenerator", + initialValue = 1000, + sequenceName = "hibernate_sequence" + ) override var id: Long? = null +) : AbstractEntity(), Serializable { + + @JvmField + @Column(name = "external_link") + var externalLink: String? = null + + @JvmField + @Column(name = "external_id") + var externalId: String? = null + + @Column(name = "removed", nullable = false) + var isRemoved: @NotNull Boolean? = false + + @JvmField + @OneToOne + @JoinColumn(unique = true, name = "user_id") + @Cascade(CascadeType.ALL) + var user: User? = null + + @JvmField + @OneToMany(mappedBy = "subject", fetch = FetchType.LAZY) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @Cascade( + CascadeType.SAVE_UPDATE + ) + var sources: MutableSet = HashSet() + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ElementCollection(fetch = FetchType.EAGER) + @MapKeyColumn(name = "attribute_key") + @Column(name = "attribute_value") + @CollectionTable(name = "subject_metadata", joinColumns = [JoinColumn(name = "id")]) + @Cascade( + CascadeType.ALL + ) + @BatchSize(size = 50) + var attributes: Map = HashMap() + + @OneToMany(mappedBy = "subject", orphanRemoval = true, fetch = FetchType.LAZY) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @JsonIgnore + val metaTokens: Set = HashSet() + + @JvmField + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "group_id") + @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) + var group: Group? = null + + @JvmField + @Column(name = "date_of_birth") + var dateOfBirth: LocalDate? = null + + @JvmField + @Column(name = "enrollment_date") + var enrollmentDate: ZonedDateTime? = null + + @JvmField + @Column(name = "person_name") + var personName: String? = null + fun externalLink(externalLink: String?): Subject { + this.externalLink = externalLink + return this + } + + fun externalId(enternalId: String?): Subject { + externalId = enternalId + return this + } + + fun removed(removed: Boolean?): Subject { + isRemoved = removed + return this + } + + fun user(usr: User?): Subject { + user = usr + return this + } + + fun sources(sources: MutableSet): Subject { + this.sources = sources + return this + } + + val activeProject: Project? + /** + * Gets the active project of subject. + * + * + * There can be only one role with PARTICIPANT authority + * and the project that is related to that role is the active role. + * + * @return [Project] currently active project of subject. + */ + get() = user?.roles + ?.first { r -> r.authority?.name == RoleAuthority.PARTICIPANT.authority } + ?.project + val associatedProject: Project? + /** + * Get the active project of a subject, and otherwise the + * inactive project. + * @return the project a subject belongs to, if any. + */ + get() { + val user = user ?: return null + return user.roles?.asIterable() + ?.filter { r -> PARTICIPANT_TYPES.contains(r.authority?.name) } + ?.sortedBy { it.authority?.name }?.first() + .let { obj: Role? -> obj?.project } + + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val subject = other as Subject + return if (subject.id == null || id == null) { + false + } else id == subject.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("Subject{" + + "id=" + id + + ", externalLink='" + externalLink + '\'' + + ", externalId='" + externalId + '\'' + + ", removed=" + isRemoved + + ", user=" + user + + ", sources=" + sources + + ", attributes=" + attributes + + ", group=" + group + + "}") + } + + companion object { + private const val serialVersionUID = 1L + private val PARTICIPANT_TYPES = java.util.Set.of( + RoleAuthority.PARTICIPANT.authority, + RoleAuthority.INACTIVE_PARTICIPANT.authority + ) + } +} diff --git a/src/main/java/org/radarbase/management/domain/User.java b/src/main/java/org/radarbase/management/domain/User.java deleted file mode 100644 index 67a977f10..000000000 --- a/src/main/java/org/radarbase/management/domain/User.java +++ /dev/null @@ -1,248 +0,0 @@ -package org.radarbase.management.domain; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; -import org.hibernate.annotations.BatchSize; -import org.hibernate.annotations.Cache; -import org.hibernate.annotations.CacheConcurrencyStrategy; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.CascadeType; -import org.hibernate.envers.Audited; -import org.hibernate.validator.constraints.Email; -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.support.AbstractEntityListener; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; -import java.io.Serializable; -import java.time.ZonedDateTime; -import java.util.HashSet; -import java.util.Locale; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * A user. - */ -@Entity -@Audited -@Table(name = "radar_user") -@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -@EntityListeners({AbstractEntityListener.class}) -public class User extends AbstractEntity implements Serializable { - - private static final long serialVersionUID = 1L; - - @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") - @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, - sequenceName = "hibernate_sequence") - private Long id; - - @NotNull - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Size(min = 1, max = 50) - @Column(length = 50, unique = true, nullable = false) - private String login; - - @JsonIgnore - @NotNull - @Size(min = 60, max = 60) - @Column(name = "password_hash", length = 60) - private String password; - - @Size(max = 50) - @Column(name = "first_name", length = 50) - private String firstName; - - @Size(max = 50) - @Column(name = "last_name", length = 50) - private String lastName; - - @Email - @Size(min = 5, max = 100) - @Column(length = 100, unique = true, nullable = true) - private String email; - - @NotNull - @Column(nullable = false) - private boolean activated = false; - - @Size(min = 2, max = 5) - @Column(name = "lang_key", length = 5) - private String langKey; - - @Size(max = 20) - @Column(name = "activation_key", length = 20) - @JsonIgnore - private String activationKey; - - @Size(max = 20) - @Column(name = "reset_key", length = 20) - private String resetKey; - - @Column(name = "reset_date") - private ZonedDateTime resetDate = null; - - @ManyToMany(fetch = FetchType.EAGER) - @JoinTable( - name = "role_users", - joinColumns = {@JoinColumn(name = "users_id", referencedColumnName = "id")}, - inverseJoinColumns = {@JoinColumn(name = "roles_id", referencedColumnName = "id")}) - @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) - @BatchSize(size = 20) - @Cascade(CascadeType.SAVE_UPDATE) - private Set roles = new HashSet<>(); - - @Override - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getLogin() { - return login; - } - - //Lowercase the login before saving it in database - public void setLogin(String login) { - this.login = login.toLowerCase(Locale.ENGLISH); - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public boolean getActivated() { - return activated; - } - - public void setActivated(boolean activated) { - this.activated = activated; - } - - public String getActivationKey() { - return activationKey; - } - - public void setActivationKey(String activationKey) { - this.activationKey = activationKey; - } - - public String getResetKey() { - return resetKey; - } - - public void setResetKey(String resetKey) { - this.resetKey = resetKey; - } - - public ZonedDateTime getResetDate() { - return resetDate; - } - - public void setResetDate(ZonedDateTime resetDate) { - this.resetDate = resetDate; - } - - public String getLangKey() { - return langKey; - } - - public void setLangKey(String langKey) { - this.langKey = langKey; - } - - public Set getRoles() { - return roles; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setRoles(Set roles) { - this.roles = roles; - } - - /** Authorities tha ta user has. */ - public Set getAuthorities() { - return roles.stream() - .map(Role::getAuthority) - .collect(Collectors.toSet()); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - User user = (User) o; - - return login.equals(user.login); - } - - @Override - public int hashCode() { - return login.hashCode(); - } - - @Override - public String toString() { - return "User{" - + "login='" + login + '\'' - + ", firstName='" + firstName + '\'' - + ", lastName='" + lastName + '\'' - + ", email='" + email + '\'' - + ", activated='" + activated + '\'' - + ", langKey='" + langKey + '\'' - + ", activationKey='" + activationKey + '\'' - + "}"; - } -} diff --git a/src/main/java/org/radarbase/management/domain/User.kt b/src/main/java/org/radarbase/management/domain/User.kt new file mode 100644 index 000000000..ddf37bf9b --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/User.kt @@ -0,0 +1,146 @@ +package org.radarbase.management.domain + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import org.hibernate.annotations.BatchSize +import org.hibernate.annotations.Cache +import org.hibernate.annotations.CacheConcurrencyStrategy +import org.hibernate.annotations.Cascade +import org.hibernate.annotations.CascadeType +import org.hibernate.envers.Audited +import org.radarbase.management.domain.support.AbstractEntityListener +import org.radarbase.management.security.Constants +import java.io.Serializable +import java.time.ZonedDateTime +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.EntityListeners +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.JoinTable +import javax.persistence.ManyToMany +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.validation.constraints.Email +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern +import javax.validation.constraints.Size + +/** + * A user. + */ +@Entity +@Audited +@Table(name = "radar_user") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) +@EntityListeners( + AbstractEntityListener::class +) +class User : AbstractEntity(), Serializable { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator") + @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") + override var id: Long? = null + + @Column(length = 50, unique = true, nullable = false) + var login: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) String? = null + private set + + @JvmField + @JsonIgnore + @Column(name = "password_hash", length = 60) + var password: @NotNull @Size(min = 60, max = 60) String? = null + + @JvmField + @Column(name = "first_name", length = 50) + var firstName: @Size(max = 50) String? = null + + @JvmField + @Column(name = "last_name", length = 50) + var lastName: @Size(max = 50) String? = null + + @JvmField + @Column(length = 100, unique = true, nullable = true) + var email: @Email @Size(min = 5, max = 100) String? = null + + @JvmField + @Column(nullable = false) + var activated: @NotNull Boolean = false + + @JvmField + @Column(name = "lang_key", length = 5) + var langKey: @Size(min = 2, max = 5) String? = null + + @JvmField + @Column(name = "activation_key", length = 20) + @JsonIgnore + var activationKey: @Size(max = 20) String? = null + + @JvmField + @Column(name = "reset_key", length = 20) + var resetKey: @Size(max = 20) String? = null + + @JvmField + @Column(name = "reset_date") + var resetDate: ZonedDateTime? = null + + @JvmField + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable( + name = "role_users", + joinColumns = [JoinColumn(name = "users_id", referencedColumnName = "id")], + inverseJoinColumns = [JoinColumn(name = "roles_id", referencedColumnName = "id")] + ) + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) + @BatchSize(size = 20) + @Cascade( + CascadeType.SAVE_UPDATE + ) + //TODO remove ? + var roles: MutableSet? = HashSet() + + //Lowercase the login before saving it in database + fun setLogin(login: String) { + this.login = login.lowercase() + } + + val authorities: Set? + /** Authorities that a user has. */ + get() = roles?.map { obj: Role? -> obj?.authority }?.toSet() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val user = other as User + return login == user.login + } + + override fun hashCode(): Int { + return login.hashCode() + } + + override fun toString(): String { + return ("User{" + + "login='" + login + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", email='" + email + '\'' + + ", activated='" + activated + '\'' + + ", langKey='" + langKey + '\'' + + ", activationKey='" + activationKey + '\'' + + "}") + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt index e6c749397..0cf7486dc 100644 --- a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt +++ b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt @@ -1,115 +1,85 @@ -package org.radarbase.management.domain.audit; - -import org.hibernate.annotations.Fetch; -import org.hibernate.annotations.FetchMode; -import org.hibernate.envers.ModifiedEntityNames; -import org.hibernate.envers.RevisionEntity; -import org.hibernate.envers.RevisionNumber; -import org.hibernate.envers.RevisionTimestamp; -import org.radarbase.management.config.audit.CustomRevisionListener; - -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.SequenceGenerator; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import java.io.Serializable; -import java.util.Date; -import java.util.Objects; -import java.util.Set; +package org.radarbase.management.domain.audit + +import org.hibernate.annotations.Fetch +import org.hibernate.annotations.FetchMode +import org.hibernate.envers.ModifiedEntityNames +import org.hibernate.envers.RevisionEntity +import org.hibernate.envers.RevisionNumber +import org.hibernate.envers.RevisionTimestamp +import org.radarbase.management.config.audit.CustomRevisionListener +import java.io.Serializable +import java.util.* +import javax.persistence.Column +import javax.persistence.ElementCollection +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.JoinTable +import javax.persistence.SequenceGenerator +import javax.persistence.Table +import javax.persistence.Temporal +import javax.persistence.TemporalType @Entity -@RevisionEntity(CustomRevisionListener.class) +@RevisionEntity(CustomRevisionListener::class) @Table(name = "_revisions_info") -public class CustomRevisionEntity implements Serializable { - private static final long serialVersionUID = 8530213963961662300L; - +class CustomRevisionEntity : Serializable { + @JvmField @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "revisionGenerator") - @SequenceGenerator(name = "revisionGenerator", initialValue = 2, allocationSize = 50, - sequenceName = "sequence_revision") + @SequenceGenerator( + name = "revisionGenerator", + initialValue = 2, + allocationSize = 50, + sequenceName = "sequence_revision" + ) @RevisionNumber - private int id; + var id = 0 + @JvmField + @get:Temporal(TemporalType.TIMESTAMP) @RevisionTimestamp - private Date timestamp; - - private String auditor; + var timestamp: Date? = null + @JvmField + var auditor: String? = null + @JvmField @ElementCollection(fetch = FetchType.EAGER) - @JoinTable(name = "REVCHANGES", joinColumns = @JoinColumn(name = "REV")) + @JoinTable(name = "REVCHANGES", joinColumns = [JoinColumn(name = "REV")]) @Column(name = "ENTITYNAME") - @Fetch(FetchMode.JOIN) + @Fetch( + FetchMode.JOIN + ) @ModifiedEntityNames - private Set modifiedEntityNames; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - @Temporal(TemporalType.TIMESTAMP) - public Date getTimestamp() { - return timestamp; - } - - public void setTimestamp(Date timestamp) { - this.timestamp = timestamp; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + var modifiedEntityNames: Set? = null + override fun equals(o: Any?): Boolean { + if (this === o) { + return true } - if (!(o instanceof CustomRevisionEntity)) { - return false; + if (o !is CustomRevisionEntity) { + return false } - CustomRevisionEntity that = (CustomRevisionEntity) o; - return id == that.id && Objects.equals(timestamp, that.timestamp) && Objects - .equals(auditor, that.auditor) && Objects - .equals(modifiedEntityNames, that.modifiedEntityNames); + val that = o + return id == that.id && timestamp == that.timestamp && auditor == that.auditor && modifiedEntityNames == that.modifiedEntityNames } - @Override - public int hashCode() { - return Objects.hash(id, timestamp, auditor, modifiedEntityNames); + override fun hashCode(): Int { + return Objects.hash(id, timestamp, auditor, modifiedEntityNames) } - @Override - public String toString() { - return "CustomRevisionEntity{" + override fun toString(): String { + return ("CustomRevisionEntity{" + "id=" + id + ", timestamp=" + timestamp + ", auditor='" + auditor + '\'' + ", modifiedEntityNames=" + modifiedEntityNames - + '}'; - } - - public String getAuditor() { - return auditor; - } - - public void setAuditor(String auditor) { - this.auditor = auditor; - } - - public Set getModifiedEntityNames() { - return modifiedEntityNames; + + '}') } - public void setModifiedEntityNames(Set modifiedEntityNames) { - this.modifiedEntityNames = modifiedEntityNames; + companion object { + private const val serialVersionUID = 8530213963961662300L } } diff --git a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt index cc978c922..d23f92927 100644 --- a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt +++ b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt @@ -1,61 +1,52 @@ -package org.radarbase.management.domain.audit; +package org.radarbase.management.domain.audit -import org.springframework.data.history.RevisionMetadata; -import org.springframework.util.Assert; +import org.springframework.data.history.RevisionMetadata +import org.springframework.util.Assert +import java.time.Instant +import java.util.* -import java.time.Instant; -import java.util.Optional; - -public class CustomRevisionMetadata implements RevisionMetadata { - - private final CustomRevisionEntity entity; +class CustomRevisionMetadata(entity: CustomRevisionEntity) : RevisionMetadata { + private val entity: CustomRevisionEntity /** - * Creates a new {@link CustomRevisionMetadata}. + * Creates a new [CustomRevisionMetadata]. * - * @param entity must not be {@literal null}. + * @param entity must not be null. */ - public CustomRevisionMetadata(CustomRevisionEntity entity) { - Assert.notNull(entity, "The CustomRevisionEntity can not be null"); - this.entity = entity; + init { + Assert.notNull(entity, "The CustomRevisionEntity can not be null") + this.entity = entity } /* * (non-Javadoc) * @see org.springframework.data.history.RevisionMetadata#getRevisionNumber() */ - @Override - public Optional getRevisionNumber() { - return Optional.of(entity.getId()); + override fun getRevisionNumber(): Optional { + return Optional.of(entity.id) } - @Override - public Integer getRequiredRevisionNumber() { - return RevisionMetadata.super.getRequiredRevisionNumber(); + override fun getRequiredRevisionNumber(): Int { + return super.getRequiredRevisionNumber() } - @Override - public Optional getRevisionInstant() { - return Optional.ofNullable(entity.getTimestamp()).map(ts -> ts.toInstant()); + override fun getRevisionInstant(): Optional { + return Optional.ofNullable(entity.timestamp).map { ts: Date -> ts.toInstant() } } - @Override - public Instant getRequiredRevisionInstant() { - return RevisionMetadata.super.getRequiredRevisionInstant(); + override fun getRequiredRevisionInstant(): Instant { + return super.getRequiredRevisionInstant() } /* * (non-Javadoc) * @see org.springframework.data.history.RevisionMetadata#getDelegate() */ - @SuppressWarnings("unchecked") - @Override - public T getDelegate() { - return (T) entity; + override fun getDelegate(): T { + return entity as T } - @Override - public RevisionType getRevisionType() { - return RevisionMetadata.super.getRevisionType(); + override fun getRevisionType(): RevisionMetadata.RevisionType { + return super.getRevisionType() } } diff --git a/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt b/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt index 742aeed78..cd1d2b73d 100644 --- a/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt +++ b/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt @@ -1,83 +1,62 @@ -package org.radarbase.management.domain.audit; +package org.radarbase.management.domain.audit -import java.time.ZonedDateTime; -import java.util.Objects; +import java.time.ZonedDateTime /** * POJO only used to easily get entity audit information, i.e. created by, created at, modified * by and modified at. */ -public class EntityAuditInfo { - private ZonedDateTime createdAt; - private String createdBy; - private ZonedDateTime lastModifiedAt; - private String lastModifiedBy; +class EntityAuditInfo { + var createdAt: ZonedDateTime? = null + private set + var createdBy: String? = null + private set + var lastModifiedAt: ZonedDateTime? = null + private set + var lastModifiedBy: String? = null + private set - public ZonedDateTime getCreatedAt() { - return createdAt; + fun setCreatedAt(createdAt: ZonedDateTime?): EntityAuditInfo { + this.createdAt = createdAt + return this } - public EntityAuditInfo setCreatedAt(ZonedDateTime createdAt) { - this.createdAt = createdAt; - return this; + fun setCreatedBy(createdBy: String?): EntityAuditInfo { + this.createdBy = createdBy + return this } - public String getCreatedBy() { - return createdBy; + fun setLastModifiedAt(lastModifiedAt: ZonedDateTime?): EntityAuditInfo { + this.lastModifiedAt = lastModifiedAt + return this } - public EntityAuditInfo setCreatedBy(String createdBy) { - this.createdBy = createdBy; - return this; + fun setLastModifiedBy(lastModifiedBy: String?): EntityAuditInfo { + this.lastModifiedBy = lastModifiedBy + return this } - public ZonedDateTime getLastModifiedAt() { - return lastModifiedAt; - } - - public EntityAuditInfo setLastModifiedAt(ZonedDateTime lastModifiedAt) { - this.lastModifiedAt = lastModifiedAt; - return this; - } - - public String getLastModifiedBy() { - return lastModifiedBy; - } - - public EntityAuditInfo setLastModifiedBy(String lastModifiedBy) { - this.lastModifiedBy = lastModifiedBy; - return this; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + override fun equals(o: Any?): Boolean { + if (this === o) { + return true } - if (o == null || getClass() != o.getClass()) { - return false; + if (o == null || javaClass != o.javaClass) { + return false } - - EntityAuditInfo that = (EntityAuditInfo) o; - - return Objects.equals(createdAt, that.createdAt) - && Objects.equals(createdBy, that.createdBy) - && Objects.equals(lastModifiedAt, that.lastModifiedAt) - && Objects.equals(lastModifiedBy, that.lastModifiedBy); + val that = o as EntityAuditInfo + return createdAt == that.createdAt && createdBy == that.createdBy && lastModifiedAt == that.lastModifiedAt && lastModifiedBy == that.lastModifiedBy } - @Override - public int hashCode() { - return lastModifiedAt != null ? lastModifiedAt.hashCode() : 0; + override fun hashCode(): Int { + return if (lastModifiedAt != null) lastModifiedAt.hashCode() else 0 } - @Override - public String toString() { - return "EntityAuditInfo{" + override fun toString(): String { + return ("EntityAuditInfo{" + "createdAt=" + createdAt + ", createdBy='" + createdBy + '\'' + ", lastModifiedAt=" + lastModifiedAt + ", lastModifiedBy='" + lastModifiedBy + '\'' - + '}'; + + '}') } } diff --git a/src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.kt b/src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.kt index 710a74c68..568e9a8f0 100644 --- a/src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.kt +++ b/src/main/java/org/radarbase/management/domain/enumeration/ProjectStatus.kt @@ -1,8 +1,10 @@ -package org.radarbase.management.domain.enumeration; +package org.radarbase.management.domain.enumeration /** * The ProjectStatus enumeration. */ -public enum ProjectStatus { - PLANNING, ONGOING, ENDED +enum class ProjectStatus { + PLANNING, + ONGOING, + ENDED } diff --git a/src/main/java/org/radarbase/management/domain/enumeration/Role.kt b/src/main/java/org/radarbase/management/domain/enumeration/Role.kt index 5d10fc809..58b1cc2b8 100644 --- a/src/main/java/org/radarbase/management/domain/enumeration/Role.kt +++ b/src/main/java/org/radarbase/management/domain/enumeration/Role.kt @@ -1,9 +1,9 @@ -package org.radarbase.management.domain.enumeration; +package org.radarbase.management.domain.enumeration /** * The Role enumeration. */ -public enum Role { +enum class Role { ROLE_ADMIN, ROLE_USER, ROLE_SYS_ADMIN, diff --git a/src/main/java/org/radarbase/management/domain/package-info.java b/src/main/java/org/radarbase/management/domain/package-info.java deleted file mode 100644 index 9a9323dd8..000000000 --- a/src/main/java/org/radarbase/management/domain/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * JPA domain objects. - */ -package org.radarbase.management.domain; diff --git a/src/main/java/org/radarbase/management/domain/package-info.kt b/src/main/java/org/radarbase/management/domain/package-info.kt new file mode 100644 index 000000000..302bbf388 --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/package-info.kt @@ -0,0 +1,5 @@ +/** + * JPA domain objects. + */ +package org.radarbase.management.domain + diff --git a/src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.java b/src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.java deleted file mode 100644 index 410c0391f..000000000 --- a/src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.java +++ /dev/null @@ -1,85 +0,0 @@ -package org.radarbase.management.domain.support; - -import org.radarbase.management.security.Constants; -import org.radarbase.management.domain.AbstractEntity; -import org.radarbase.management.security.SpringSecurityAuditorAware; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import javax.persistence.PostPersist; -import javax.persistence.PostRemove; -import javax.persistence.PostUpdate; - -/** - * Entity listener that contains all listeners that should fire on AbstractEntity's. This - * listener will publish entity events to log, to have a uniform, centralized logging of entity - * operations. Also, it will populate the created_by, created_at, last_modified_by and - * last_modified_at fields using Envers audits when an entity is loaded. - */ -@Component -public class AbstractEntityListener { - - public static final String ENTITY_CREATED = "ENTITY_CREATED"; - public static final String ENTITY_UPDATED = "ENTITY_UPDATED"; - public static final String ENTITY_REMOVED = "ENTITY_REMOVED"; - - private static final Logger log = LoggerFactory.getLogger(AbstractEntityListener.class); - private static final String TEMPLATE = "[{}] by {}: entityClass={}, entity={}"; - - @Autowired - private SpringSecurityAuditorAware springSecurityAuditorAware; - - /** - * Event listener to log a persist event. - * - * @param entity the entity that is persisted - */ - @PostPersist - public void publishPersistEvent(AbstractEntity entity) { - AutowireHelper.autowire(this, springSecurityAuditorAware); - log.info(TEMPLATE, ENTITY_CREATED, springSecurityAuditorAware.getCurrentAuditor() - .orElse(Constants.SYSTEM_ACCOUNT), - entity.getClass().getName(), entity.toString()); - } - - /** - * Event listener to log an update event. - * - * @param entity the entity that is updated - */ - @PostUpdate - public void publishUpdateEvent(AbstractEntity entity) { - AutowireHelper.autowire(this, springSecurityAuditorAware); - log.info(TEMPLATE, ENTITY_UPDATED, springSecurityAuditorAware.getCurrentAuditor() - .orElse(Constants.SYSTEM_ACCOUNT), - entity.getClass().getName(), entity.toString()); - } - - /** - * Event listener to log a remove event. - * - * @param entity the entity that is removed - */ - @PostRemove - public void publishRemoveEvent(AbstractEntity entity) { - AutowireHelper.autowire(this, springSecurityAuditorAware); - log.info(TEMPLATE, ENTITY_REMOVED, springSecurityAuditorAware.getCurrentAuditor() - .orElse(Constants.SYSTEM_ACCOUNT), - entity.getClass().getName(), entity.toString()); - } - - /** - * When an entity is loaded, find out the repository of the entity, load the revision log, - * and use it to populate the created and last modified fields. - * - * @param entity the entity that was loaded. - *//* - @PostLoad - public void populateAuditMetaData(AbstractEntity entity) { - - }*/ - - -} diff --git a/src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.kt b/src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.kt new file mode 100644 index 000000000..affea0bbd --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/support/AbstractEntityListener.kt @@ -0,0 +1,87 @@ +package org.radarbase.management.domain.support + +import org.radarbase.management.domain.AbstractEntity +import org.radarbase.management.security.Constants +import org.radarbase.management.security.SpringSecurityAuditorAware +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component +import javax.persistence.PostPersist +import javax.persistence.PostRemove +import javax.persistence.PostUpdate + +/** + * Entity listener that contains all listeners that should fire on AbstractEntity's. This + * listener will publish entity events to log, to have a uniform, centralized logging of entity + * operations. Also, it will populate the created_by, created_at, last_modified_by and + * last_modified_at fields using Envers audits when an entity is loaded. + */ +@Component +class AbstractEntityListener { + @Autowired + private val springSecurityAuditorAware: SpringSecurityAuditorAware? = null + + /** + * Event listener to log a persist event. + * + * @param entity the entity that is persisted + */ + @PostPersist + fun publishPersistEvent(entity: AbstractEntity) { + AutowireHelper.autowire(this, springSecurityAuditorAware) + log.info( + TEMPLATE, ENTITY_CREATED, springSecurityAuditorAware!!.currentAuditor + .orElse(Constants.SYSTEM_ACCOUNT), + entity.javaClass.getName(), entity.toString() + ) + } + + /** + * Event listener to log an update event. + * + * @param entity the entity that is updated + */ + @PostUpdate + fun publishUpdateEvent(entity: AbstractEntity) { + AutowireHelper.autowire(this, springSecurityAuditorAware) + log.info( + TEMPLATE, ENTITY_UPDATED, springSecurityAuditorAware!!.currentAuditor + .orElse(Constants.SYSTEM_ACCOUNT), + entity.javaClass.getName(), entity.toString() + ) + } + + /** + * Event listener to log a remove event. + * + * @param entity the entity that is removed + */ + @PostRemove + fun publishRemoveEvent(entity: AbstractEntity) { + AutowireHelper.autowire(this, springSecurityAuditorAware) + log.info( + TEMPLATE, ENTITY_REMOVED, springSecurityAuditorAware!!.currentAuditor + .orElse(Constants.SYSTEM_ACCOUNT), + entity.javaClass.getName(), entity.toString() + ) + } + + /** + * When an entity is loaded, find out the repository of the entity, load the revision log, + * and use it to populate the created and last modified fields. + * + * @param entity the entity that was loaded. + */ + /* + @PostLoad + public void populateAuditMetaData(AbstractEntity entity) { + + }*/ + companion object { + const val ENTITY_CREATED = "ENTITY_CREATED" + const val ENTITY_UPDATED = "ENTITY_UPDATED" + const val ENTITY_REMOVED = "ENTITY_REMOVED" + private val log = LoggerFactory.getLogger(AbstractEntityListener::class.java) + private const val TEMPLATE = "[{}] by {}: entityClass={}, entity={}" + } +} diff --git a/src/main/java/org/radarbase/management/domain/support/AutowireHelper.java b/src/main/java/org/radarbase/management/domain/support/AutowireHelper.java deleted file mode 100644 index fa9881a01..000000000 --- a/src/main/java/org/radarbase/management/domain/support/AutowireHelper.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.radarbase.management.domain.support; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.stereotype.Component; - -/** - * Class to inject dependencies into classes that do not support Autowire, such as JPA event - * listeners. - */ -@Component -public final class AutowireHelper implements ApplicationContextAware { - - private static final AutowireHelper INSTANCE = new AutowireHelper(); - private static ApplicationContext applicationContext; - - private AutowireHelper() { - // Utility class - } - - /** - * Tries to autowire the specified instance of the class if one of the specified beans which - * need to be autowired are null. - * - * @param classToAutowire the instance of the class which holds @Autowire annotations - * @param beansToAutowireInClass the beans which have the @Autowire annotation in the specified - * {#classToAutowire} - */ - public static void autowire(Object classToAutowire, Object... beansToAutowireInClass) { - for (Object bean : beansToAutowireInClass) { - if (bean == null) { - applicationContext.getAutowireCapableBeanFactory().autowireBean(classToAutowire); - return; - } - } - } - - @Override - public void setApplicationContext(final ApplicationContext applicationContext) { - AutowireHelper.applicationContext = applicationContext; - } - - /** - * Get the singleton instance. - * - * @return the singleton instance. - */ - public static AutowireHelper getInstance() { - return INSTANCE; - } -} diff --git a/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt b/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt new file mode 100644 index 000000000..defda715f --- /dev/null +++ b/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt @@ -0,0 +1,43 @@ +package org.radarbase.management.domain.support + +import org.springframework.context.ApplicationContext +import org.springframework.context.ApplicationContextAware +import org.springframework.stereotype.Component + +/** + * Class to inject dependencies into classes that do not support Autowire, such as JPA event + * listeners. + */ +@Component +class AutowireHelper private constructor() : ApplicationContextAware { + override fun setApplicationContext(applicationContext: ApplicationContext) { + Companion.applicationContext = applicationContext + } + + companion object { + /** + * Get the singleton instance. + * + * @return the singleton instance. + */ + val instance = AutowireHelper() + private var applicationContext: ApplicationContext? = null + + /** + * Tries to autowire the specified instance of the class if one of the specified beans which + * need to be autowired are null. + * + * @param classToAutowire the instance of the class which holds @Autowire annotations + * @param beansToAutowireInClass the beans which have the @Autowire annotation in the specified + * {#classToAutowire} + */ + fun autowire(classToAutowire: Any?, vararg beansToAutowireInClass: Any?) { + for (bean in beansToAutowireInClass) { + if (bean == null) { + applicationContext!!.autowireCapableBeanFactory.autowireBean(classToAutowire) + return + } + } + } + } +} diff --git a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java index 3c9e2af1d..48af8daa1 100644 --- a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java +++ b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java @@ -52,10 +52,10 @@ public void add(AuditEvent event) { if (!AUTHORIZATION_FAILURE.equals(eventType) && !Constants.ANONYMOUS_USER.equals(event.getPrincipal())) { PersistentAuditEvent persistentAuditEvent = new PersistentAuditEvent(); - persistentAuditEvent.setPrincipal(event.getPrincipal()); - persistentAuditEvent.setAuditEventType(eventType); - persistentAuditEvent.setAuditEventDate(LocalDateTime.ofInstant(event.getTimestamp(), - ZoneId.systemDefault())); + persistentAuditEvent.principal = event.getPrincipal(); + persistentAuditEvent.auditEventType = eventType; + persistentAuditEvent.auditEventDate = LocalDateTime.ofInstant(event.getTimestamp(), + ZoneId.systemDefault()); persistentAuditEvent.setData(auditEventConverter.convertDataToStrings(event.getData())); persistenceAuditEventRepository.save(persistentAuditEvent); } diff --git a/src/main/java/org/radarbase/management/repository/GroupRepository.java b/src/main/java/org/radarbase/management/repository/GroupRepository.java deleted file mode 100644 index 538286b9d..000000000 --- a/src/main/java/org/radarbase/management/repository/GroupRepository.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.repository; - -import org.radarbase.management.domain.Group; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -import java.util.Optional; - -@RepositoryDefinition(domainClass = Group.class, idClass = Long.class) -public interface GroupRepository extends JpaRepository, - RevisionRepository { - @Query("SELECT group FROM Group group " - + "WHERE group.project.id = :project_id " - + "AND group.name = :group_name") - Optional findByProjectIdAndName( - @Param("project_id") Long id, - @Param("group_name") String groupName); - - @Query("SELECT group FROM Group group " - + "LEFT JOIN Project project on group.project = project " - + "WHERE group.project.projectName = :project_name " - + "AND group.name = :group_name") - Optional findByProjectNameAndName( - @Param("project_name") String projectName, - @Param("group_name") String groupName); -} diff --git a/src/main/java/org/radarbase/management/repository/GroupRepository.kt b/src/main/java/org/radarbase/management/repository/GroupRepository.kt new file mode 100644 index 000000000..cd704bf5c --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/GroupRepository.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Group +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param + +@RepositoryDefinition(domainClass = Group::class, idClass = Long::class) +interface GroupRepository : JpaRepository, RevisionRepository { + @Query( + "SELECT group FROM Group group " + + "WHERE group.project.id = :project_id " + + "AND group.name = :group_name" + ) + fun findByProjectIdAndName( + @Param("project_id") id: Long?, + @Param("group_name") groupName: String? + ): Group? + + @Query( + "SELECT group FROM Group group " + + "LEFT JOIN Project project on group.project = project " + + "WHERE group.project.projectName = :project_name " + + "AND group.name = :group_name" + ) + fun findByProjectNameAndName( + @Param("project_name") projectName: String?, + @Param("group_name") groupName: String? + ): Group? +} diff --git a/src/main/java/org/radarbase/management/repository/ProjectRepository.java b/src/main/java/org/radarbase/management/repository/ProjectRepository.java deleted file mode 100644 index a6f81ee60..000000000 --- a/src/main/java/org/radarbase/management/repository/ProjectRepository.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.radarbase.management.repository; - -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.SourceType; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -import java.util.Collection; -import java.util.List; -import java.util.Optional; - -/** - * Spring Data JPA repository for the Project entity. - */ -@SuppressWarnings("unused") -@RepositoryDefinition(domainClass = Project.class, idClass = Long.class) -public interface ProjectRepository extends JpaRepository, - RevisionRepository { - @Query(value = "select distinct project from Project project " - + "left join fetch project.sourceTypes", - countQuery = "select distinct count(project) from Project project") - Page findAllWithEagerRelationships(Pageable pageable); - - @Query(value = "select distinct project from Project project " - + "left join fetch project.sourceTypes " - + "WHERE project.projectName in (:projectNames) " - + "OR project.organization.name in (:organizationNames)", - countQuery = "select distinct count(project) from Project project " - + "WHERE project.projectName in (:projectNames) " - + "OR project.organization.name in (:organizationNames)") - Page findAllWithEagerRelationshipsInOrganizationsOrProjects( - Pageable pageable, - @Param("organizationNames") Collection organizationNames, - @Param("projectNames") Collection projectNames); - - @Query("select project from Project project " - + "WHERE project.organization.name = :organization_name") - List findAllByOrganizationName( - @Param("organization_name") String organizationName); - - @Query("select project from Project project " - + "left join fetch project.sourceTypes s " - + "left join fetch project.groups " - + "left join fetch project.organization " - + "where project.id = :id") - Optional findOneWithEagerRelationships(@Param("id") Long id); - - @Query("select project from Project project " - + "left join fetch project.organization " - + "where project.id = :id") - Optional findByIdWithOrganization(@Param("id") Long id); - - @Query("select project from Project project " - + "left join fetch project.sourceTypes " - + "left join fetch project.groups " - + "left join fetch project.organization " - + "where project.projectName = :name") - Optional findOneWithEagerRelationshipsByName(@Param("name") String name); - - @Query("select project.id from Project project " - + "where project.projectName =:name") - Optional findProjectIdByName(@Param("name") String name); - - @Query("select project from Project project " - + "left join fetch project.groups " - + "where project.projectName = :name") - Optional findOneWithGroupsByName(@Param("name") String name); - - @Query("select project.sourceTypes from Project project WHERE project.id = :id") - List findSourceTypesByProjectId(@Param("id") Long id); - - @Query("select distinct sourceType from Project project " - + "left join project.sourceTypes sourceType " - + "where project.id =:id " - + "and sourceType.id = :sourceTypeId ") - Optional findSourceTypeByProjectIdAndSourceTypeId(@Param("id") Long id, - @Param("sourceTypeId") Long sourceTypeId); -} diff --git a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt new file mode 100644 index 000000000..bc0e44b8f --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt @@ -0,0 +1,101 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.SourceType +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param +import java.util.* + +/** + * Spring Data JPA repository for the Project entity. + */ +@Suppress("unused") +@RepositoryDefinition(domainClass = Project::class, idClass = Long::class) +interface ProjectRepository : JpaRepository, RevisionRepository { + @Query( + value = "select distinct project from Project project " + + "left join fetch project.sourceTypes", + countQuery = "select distinct count(project) from Project project" + ) + fun findAllWithEagerRelationships(pageable: Pageable?): Page? + + @Query( + value = "select distinct project from Project project " + + "left join fetch project.sourceTypes " + + "WHERE project.projectName in (:projectNames) " + + "OR project.organization.name in (:organizationNames)", + countQuery = "select distinct count(project) from Project project " + + "WHERE project.projectName in (:projectNames) " + + "OR project.organization.name in (:organizationNames)" + ) + fun findAllWithEagerRelationshipsInOrganizationsOrProjects( + pageable: Pageable?, + @Param("organizationNames") organizationNames: Collection?, + @Param("projectNames") projectNames: Collection? + ): Page? + + @Query( + "select project from Project project " + + "WHERE project.organization.name = :organization_name" + ) + fun findAllByOrganizationName( + @Param("organization_name") organizationName: String? + ): List? + + @Query( + "select project from Project project " + + "left join fetch project.sourceTypes s " + + "left join fetch project.groups " + + "left join fetch project.organization " + + "where project.id = :id" + ) + fun findOneWithEagerRelationships(@Param("id") id: Long?): Project? + + @Query( + "select project from Project project " + + "left join fetch project.organization " + + "where project.id = :id" + ) + fun findByIdWithOrganization(@Param("id") id: Long?): Project? + + @Query( + "select project from Project project " + + "left join fetch project.sourceTypes " + + "left join fetch project.groups " + + "left join fetch project.organization " + + "where project.projectName = :name" + ) + fun findOneWithEagerRelationshipsByName(@Param("name") name: String?): Project? + + @Query( + "select project.id from Project project " + + "where project.projectName =:name" + ) + fun findProjectIdByName(@Param("name") name: String?): Long? + + @Query( + "select project from Project project " + + "left join fetch project.groups " + + "where project.projectName = :name" + ) + fun findOneWithGroupsByName(@Param("name") name: String?): Project? + + @Query("select project.sourceTypes from Project project WHERE project.id = :id") + fun findSourceTypesByProjectId(@Param("id") id: Long?): List? + + @Query( + "select distinct sourceType from Project project " + + "left join project.sourceTypes sourceType " + + "where project.id =:id " + + "and sourceType.id = :sourceTypeId " + ) + fun findSourceTypeByProjectIdAndSourceTypeId( + @Param("id") id: Long?, + @Param("sourceTypeId") sourceTypeId: Long? + ): Optional? +} diff --git a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java index fc3a3a553..2382e7067 100644 --- a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java +++ b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java @@ -71,14 +71,14 @@ public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, userRepository.findOneByLogin(userName) .ifPresent(user -> { - var roles = user.getRoles().stream() + var roles = user.roles.stream() .map(role -> { - var auth = role.getAuthority().getName(); + var auth = role.authority.name; return switch (role.getRole().getScope()) { case GLOBAL -> auth; - case ORGANIZATION -> role.getOrganization().getName() + case ORGANIZATION -> role.organization.name + ":" + auth; - case PROJECT -> role.getProject().getProjectName() + case PROJECT -> role.project.projectName + ":" + auth; }; }) @@ -90,7 +90,7 @@ public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, Set newScopes = currentScopes.stream() .filter(scope -> { Permission permission = Permission.ofScope(scope); - var roleAuthorities = user.getRoles().stream() + var roleAuthorities = user.roles.stream() .map(Role::getRole) .collect(Collectors.toCollection(() -> EnumSet.noneOf(RoleAuthority.class))); @@ -107,7 +107,7 @@ public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, List assignedSources = subjectRepository.findSourcesBySubjectLogin(userName); List sourceIds = assignedSources.stream() - .map(s -> s.getSourceId().toString()) + .map(s -> s.sourceId.toString()) .toList(); additionalInfo.put(SOURCES_CLAIM, sourceIds); } diff --git a/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java b/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java index 3accf81bb..14a85f33f 100644 --- a/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java +++ b/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java @@ -39,18 +39,18 @@ public UserDetails loadUserByUsername(final String login) { User user = userRepository.findOneWithRolesByLogin(lowercaseLogin) .orElseThrow(() -> new UsernameNotFoundException( "User " + lowercaseLogin + " was not found in the database")); - if (!user.getActivated()) { + if (!user.activated) { throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated"); } List grantedAuthorities = user.getAuthorities().stream() - .map(authority -> new SimpleGrantedAuthority(authority.getName())) + .map(authority -> new SimpleGrantedAuthority(authority.name)) .collect(Collectors.toList()); return new org.springframework.security.core.userdetails.User( lowercaseLogin, - user.getPassword(), + user.password, grantedAuthorities); } } diff --git a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt index fd72bbb6a..6abd75069 100644 --- a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt +++ b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt @@ -5,24 +5,21 @@ import org.radarbase.auth.authorization.AuthorityReference import org.radarbase.auth.authorization.RoleAuthority import org.radarbase.auth.exception.TokenValidationException import org.radarbase.auth.token.RadarToken -import org.radarbase.management.config.OAuth2ServerConfiguration import org.radarbase.management.domain.Role import org.radarbase.management.domain.User import org.radarbase.management.repository.UserRepository import org.slf4j.LoggerFactory import org.springframework.http.HttpHeaders import org.springframework.http.HttpMethod -import org.springframework.security.authentication.AnonymousAuthenticationToken import org.springframework.security.authentication.AuthenticationManager import org.springframework.security.core.Authentication -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.security.core.context.SecurityContextHolder import org.springframework.security.oauth2.provider.OAuth2Authentication import org.springframework.security.web.util.matcher.AntPathRequestMatcher import org.springframework.web.cors.CorsUtils import org.springframework.web.filter.OncePerRequestFilter import java.io.IOException +import java.io.Serializable import java.time.Instant import javax.annotation.Nonnull import javax.servlet.FilterChain @@ -189,15 +186,16 @@ class JwtAuthenticationFilter @JvmOverloads constructor( * from the database. * @return set of authority references. */ - val User.authorityReferences: Set - get() = roles.mapTo(HashSet()) { role: Role -> - val auth = role.role - val referent = when (auth.scope) { + val User.authorityReferences: Set? + get() = roles?.mapTo(HashSet()) { role: Role? -> + val auth = role?.role + val referent = when (auth?.scope) { RoleAuthority.Scope.GLOBAL -> null - RoleAuthority.Scope.ORGANIZATION -> role.organization.name - RoleAuthority.Scope.PROJECT -> role.project.projectName + RoleAuthority.Scope.ORGANIZATION -> role.organization?.name + RoleAuthority.Scope.PROJECT -> role.project?.projectName + null -> null } - AuthorityReference(auth, referent) + AuthorityReference(auth!!, referent) } diff --git a/src/main/java/org/radarbase/management/service/GroupService.java b/src/main/java/org/radarbase/management/service/GroupService.java deleted file mode 100644 index 016349e3f..000000000 --- a/src/main/java/org/radarbase/management/service/GroupService.java +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.service; - -import org.radarbase.management.domain.Group; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.repository.GroupRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.service.dto.GroupDTO; -import org.radarbase.management.service.mapper.GroupMapper; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ConflictException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.radarbase.management.web.rest.vm.GroupPatchOperation; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import javax.transaction.Transactional; -import java.util.ArrayList; -import java.util.List; - -import static org.radarbase.management.web.rest.errors.EntityName.GROUP; -import static org.radarbase.management.web.rest.errors.EntityName.PROJECT; -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_GROUP_EXISTS; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_GROUP_NOT_FOUND; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_VALIDATION; - -/** - * Service to manage project groups. - */ -@Service -public class GroupService { - @Autowired - private GroupRepository groupRepository; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private GroupMapper groupMapper; - - /** - * Get the group by name. - * @param projectName project name - * @param groupName group name - * @return group - * @throws NotFoundException if the project or group is not found. - */ - @Transactional - public GroupDTO getGroup(String projectName, String groupName) { - return groupMapper.groupToGroupDTOFull(groupRepository.findByProjectNameAndName(projectName, - groupName) - .orElseThrow(() -> new NotFoundException( - "Group " + groupName + " not found in project " + projectName, - GROUP, ERR_GROUP_NOT_FOUND))); - } - - /** - * Delete the group by name. - * @param projectName project name - * @param groupName group name - * @param unlinkSubjects unset group for each linked subject - * @throws NotFoundException if the project or group is not found. - */ - @Transactional - public void deleteGroup(String projectName, String groupName, boolean unlinkSubjects) { - Group group = groupRepository.findByProjectNameAndName(projectName, groupName) - .orElseThrow(() -> new NotFoundException( - "Group " + groupName + " not found in project " + projectName, - GROUP, ERR_GROUP_NOT_FOUND)); - - if (!unlinkSubjects) { - var subjectCount = subjectRepository.countByGroupId(group.getId()); - if (subjectCount > 0) { - var msg = "Group " + groupName + " has subjects. " - + "Add `unlinkSubjects=true` query param to confirm deletion"; - throw new ConflictException(msg, GROUP, ERR_VALIDATION); - } - } - groupRepository.delete(group); - } - - /** - * Create the group. - * @param projectName project name - * @param groupDto group values - * @throws NotFoundException if the project is not found. - * @throws ConflictException if the group name already exists. - */ - @Transactional - public GroupDTO createGroup(String projectName, GroupDTO groupDto) { - Project project = projectRepository.findOneWithGroupsByName(projectName) - .orElseThrow(() -> new NotFoundException( - "Project with name " + projectName + " not found", - PROJECT, ERR_PROJECT_NAME_NOT_FOUND)); - - if (project.getGroups().stream() - .anyMatch(g -> g.getName().equals(groupDto.getName()))) { - throw new ConflictException( - "Group " + groupDto.getName() + " already exists in project " + projectName, - GROUP, ERR_GROUP_EXISTS); - } - Group group = groupMapper.groupDTOToGroup(groupDto); - group.setProject(project); - - GroupDTO groupDtoResult = groupMapper.groupToGroupDTOFull(groupRepository.save(group)); - project.getGroups().add(group); - projectRepository.save(project); - return groupDtoResult; - } - - /** - * List all groups in a project. - * @param projectName project name - * @throws NotFoundException if the project is not found. - */ - public List listGroups(String projectName) { - Project project = projectRepository.findOneWithGroupsByName(projectName) - .orElseThrow(() -> new NotFoundException( - "Project with name " + projectName + " not found", - PROJECT, ERR_PROJECT_NAME_NOT_FOUND)); - return groupMapper.groupToGroupDTOs(project.getGroups()); - } - - /** - * Add subjects to group. - * @param projectName project name - * @param groupName group name - * @param subjectsToAdd patch items for subjects to be added - * @param subjectsToRemove patch items for subjects to be removed - * @throws NotFoundException if the project or group is not found. - */ - @Transactional - public void updateGroupSubjects( - String projectName, String groupName, - List subjectsToAdd, - List subjectsToRemove - ) { - Group group = groupRepository - .findByProjectNameAndName(projectName, groupName) - .orElseThrow(() -> new NotFoundException( - "Group " + groupName + " not found in project " + projectName, - GROUP, ERR_GROUP_NOT_FOUND)); - - List entitiesToAdd = getSubjectEntities(projectName, subjectsToAdd); - List entitiesToRemove = getSubjectEntities(projectName, subjectsToRemove); - - if (!entitiesToAdd.isEmpty()) { - List idsToAdd = entitiesToAdd.stream() - .map(Subject::getId) - .toList(); - subjectRepository.setGroupIdByIds(group.getId(), idsToAdd); - } - - if (!entitiesToRemove.isEmpty()) { - List idsToRemove = entitiesToRemove.stream() - .map(Subject::getId) - .toList(); - subjectRepository.unsetGroupIdByIds(idsToRemove); - } - } - - private List getSubjectEntities( - String projectName, - List subjectsToModify - ) { - List logins = new ArrayList<>(); - List ids = new ArrayList<>(); - - extractSubjectIdentities(subjectsToModify, logins, ids); - - List subjectEntities = new ArrayList<>(subjectsToModify.size()); - if (!ids.isEmpty()) { - subjectEntities.addAll(subjectRepository.findAllById(ids)); - } - if (!logins.isEmpty()) { - subjectEntities.addAll(subjectRepository.findAllBySubjectLogins(logins)); - } - - for (Subject s : subjectEntities) { - String login = s.getUser().getLogin(); - if (s.getActiveProject().isEmpty()) { - throw new BadRequestException( - "Subject " + login + " is not assigned to a project", - SUBJECT, ERR_VALIDATION); - } - if (!projectName.equals(s.getActiveProject().get().getProjectName())) { - throw new BadRequestException( - "Subject " + login + " belongs to a different project", - SUBJECT, ERR_VALIDATION); - } - } - - return subjectEntities; - } - - private void extractSubjectIdentities( - List subjectsToModify, - List logins, - List ids - ) { - // Each item should specify either a login or an ID, - // since having both will require an extra validation step - // to reject e.g. {id: 1, login: "subject-id-42"}. - // Whether the IDs and logins exist and belong to the project - // should be checked later - for (var item : subjectsToModify) { - String login = item.getLogin(); - Long id = item.getId(); - if (id == null && login == null) { - throw new BadRequestException( - "Subject identification must be specified", - GROUP, ERR_VALIDATION); - } - if (id != null && login != null) { - throw new BadRequestException( - "Subject identification must be specify either ID or Login. " - + "Do not provide both values to avoid potential confusion.", - GROUP, ERR_VALIDATION); - } - - if (id != null) { - ids.add(id); - } - if (login != null) { - logins.add(login); - } - } - } -} diff --git a/src/main/java/org/radarbase/management/service/GroupService.kt b/src/main/java/org/radarbase/management/service/GroupService.kt new file mode 100644 index 000000000..b30b94195 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/GroupService.kt @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.service + +import org.radarbase.management.domain.Group +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.GroupRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.service.dto.GroupDTO +import org.radarbase.management.service.mapper.GroupMapper +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.ConflictException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.radarbase.management.web.rest.vm.GroupPatchOperation.SubjectPatchValue +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import javax.transaction.Transactional + +/** + * Service to manage project groups. + */ +@Service +open class GroupService( + @Autowired private val groupRepository: GroupRepository, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val groupMapper: GroupMapper +) { + + /** + * Get the group by name. + * @param projectName project name + * @param groupName group name + * @return group + * @throws NotFoundException if the project or group is not found. + */ + @Throws(NotFoundException::class) + @Transactional + open fun getGroup(projectName: String, groupName: String): GroupDTO { + return groupMapper.groupToGroupDTOFull( + groupRepository.findByProjectNameAndName( + projectName, + groupName + ) + ?: throw NotFoundException( + "Group $groupName not found in project $projectName", + EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + ) + ) + } + + /** + * Delete the group by name. + * @param projectName project name + * @param groupName group name + * @param unlinkSubjects unset group for each linked subject + * @throws NotFoundException if the project or group is not found. + */ + @Transactional + open fun deleteGroup(projectName: String, groupName: String, unlinkSubjects: Boolean) { + val group = groupRepository.findByProjectNameAndName(projectName, groupName) + ?: throw NotFoundException( + "Group $groupName not found in project $projectName", + EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + ) + if (!unlinkSubjects) { + val subjectCount = subjectRepository.countByGroupId(group.id) + if (subjectCount > 0) { + val msg = ("Group " + groupName + " has subjects. " + + "Add `unlinkSubjects=true` query param to confirm deletion") + throw ConflictException(msg, EntityName.GROUP, ErrorConstants.ERR_VALIDATION) + } + } + groupRepository.delete(group) + } + + /** + * Create the group. + * @param projectName project name + * @param groupDto group values + * @throws NotFoundException if the project is not found. + * @throws ConflictException if the group name already exists. + */ + @Transactional + open fun createGroup(projectName: String, groupDto: GroupDTO): GroupDTO { + val project = projectRepository.findOneWithGroupsByName(projectName) + ?: throw NotFoundException( + "Project with name $projectName not found", + EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND + ) + if (project.groups.stream() + .anyMatch { g: Group -> g.name == groupDto.name } + ) { + throw ConflictException( + "Group " + groupDto.name + " already exists in project " + projectName, + EntityName.GROUP, ErrorConstants.ERR_GROUP_EXISTS + ) + } + val group = groupMapper.groupDTOToGroup(groupDto) + group.project = project + val groupDtoResult = groupMapper.groupToGroupDTOFull(groupRepository.save(group)) + project.groups.add(group) + projectRepository.save(project) + return groupDtoResult + } + + /** + * List all groups in a project. + * @param projectName project name + * @throws NotFoundException if the project is not found. + */ + fun listGroups(projectName: String): List { + val project = projectRepository.findOneWithGroupsByName(projectName) + ?: throw NotFoundException( + "Project with name $projectName not found", + EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND + ) + return groupMapper.groupToGroupDTOs(project.groups) + } + + /** + * Add subjects to group. + * @param projectName project name + * @param groupName group name + * @param subjectsToAdd patch items for subjects to be added + * @param subjectsToRemove patch items for subjects to be removed + * @throws NotFoundException if the project or group is not found. + */ + @Transactional + open fun updateGroupSubjects( + projectName: String, groupName: String, + subjectsToAdd: List, + subjectsToRemove: List + ) { + + groupRepository ?: throw NullPointerException() + + val group = groupRepository.findByProjectNameAndName(projectName, groupName) + ?: throw NotFoundException( + "Group $groupName not found in project $projectName", + EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + ) + + val entitiesToAdd = getSubjectEntities(projectName, subjectsToAdd) + val entitiesToRemove = getSubjectEntities(projectName, subjectsToRemove) + if (entitiesToAdd.isNotEmpty()) { + val idsToAdd = entitiesToAdd.stream() + .map(Subject::id) + .toList() + subjectRepository.setGroupIdByIds(group.id, idsToAdd) + } + if (entitiesToRemove.isNotEmpty()) { + val idsToRemove = entitiesToRemove.stream() + .map(Subject::id) + .toList() + subjectRepository.unsetGroupIdByIds(idsToRemove) + } + } + + private fun getSubjectEntities( + projectName: String, + subjectsToModify: List + ): List { + val logins: MutableList = ArrayList() + val ids: MutableList = ArrayList() + extractSubjectIdentities(subjectsToModify, logins, ids) + val subjectEntities: MutableList = ArrayList(subjectsToModify.size) + if (!ids.isEmpty()) { + subjectEntities.addAll(subjectRepository.findAllById(ids)) + } + if (!logins.isEmpty()) { + subjectEntities.addAll(subjectRepository.findAllBySubjectLogins(logins)) + } + for (s in subjectEntities) { + val login = s.user!!.login + s.activeProject ?: throw BadRequestException( + "Subject $login is not assigned to a project", + EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION + ) + if (projectName != s.activeProject!!.projectName) { + throw BadRequestException( + "Subject $login belongs to a different project", + EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION + ) + } + } + return subjectEntities + } + + private fun extractSubjectIdentities( + subjectsToModify: List, + logins: MutableList, + ids: MutableList + ) { + // Each item should specify either a login or an ID, + // since having both will require an extra validation step + // to reject e.g. {id: 1, login: "subject-id-42"}. + // Whether the IDs and logins exist and belong to the project + // should be checked later + for (item in subjectsToModify) { + val login = item.login + val id = item.id + if (id == null && login == null) { + throw BadRequestException( + "Subject identification must be specified", + EntityName.GROUP, ErrorConstants.ERR_VALIDATION + ) + } + if (id != null && login != null) { + throw BadRequestException( + "Subject identification must be specify either ID or Login. " + + "Do not provide both values to avoid potential confusion.", + EntityName.GROUP, ErrorConstants.ERR_VALIDATION + ) + } + if (id != null) { + ids.add(id) + } + if (login != null) { + logins.add(login) + } + } + } +} diff --git a/src/main/java/org/radarbase/management/service/MailService.java b/src/main/java/org/radarbase/management/service/MailService.java index 5dbcb30d6..788222773 100644 --- a/src/main/java/org/radarbase/management/service/MailService.java +++ b/src/main/java/org/radarbase/management/service/MailService.java @@ -81,15 +81,15 @@ public void sendEmail(String to, String subject, String content, boolean isMulti */ @Async public void sendActivationEmail(User user) { - log.debug("Sending activation email to '{}'", user.getEmail()); - Locale locale = Locale.forLanguageTag(user.getLangKey()); + log.debug("Sending activation email to '{}'", user.email); + Locale locale = Locale.forLanguageTag(user.langKey); Context context = new Context(locale); context.setVariable(USER, user); context.setVariable(BASE_URL, managementPortalProperties.getCommon().getManagementPortalBaseUrl()); String content = templateEngine.process("activationEmail", context); String subject = messageSource.getMessage("email.activation.title", null, locale); - sendEmail(user.getEmail(), subject, content, false, true); + sendEmail(user.email, subject, content, false, true); } /** @@ -98,8 +98,8 @@ public void sendActivationEmail(User user) { */ @Async public void sendCreationEmail(User user, long duration) { - log.debug("Sending creation email to '{}'", user.getEmail()); - Locale locale = Locale.forLanguageTag(user.getLangKey()); + log.debug("Sending creation email to '{}'", user.email); + Locale locale = Locale.forLanguageTag(user.langKey); Context context = new Context(locale); context.setVariable(USER, user); context.setVariable(BASE_URL, @@ -107,7 +107,7 @@ public void sendCreationEmail(User user, long duration) { context.setVariable(EXPIRY, Duration.ofSeconds(duration).toHours()); String content = templateEngine.process("creationEmail", context); String subject = messageSource.getMessage("email.activation.title", null, locale); - sendEmail(user.getEmail(), subject, content, false, true); + sendEmail(user.email, subject, content, false, true); } /** @@ -118,7 +118,7 @@ public void sendCreationEmail(User user, long duration) { @Async public void sendCreationEmailForGivenEmail(User user, String email) { log.debug("Sending creation email to '{}'", email); - Locale locale = Locale.forLanguageTag(user.getLangKey()); + Locale locale = Locale.forLanguageTag(user.langKey); Context context = new Context(locale); context.setVariable(USER, user); context.setVariable(BASE_URL, @@ -134,14 +134,14 @@ public void sendCreationEmailForGivenEmail(User user, String email) { */ @Async public void sendPasswordResetMail(User user) { - log.debug("Sending password reset email to '{}'", user.getEmail()); - Locale locale = Locale.forLanguageTag(user.getLangKey()); + log.debug("Sending password reset email to '{}'", user.email); + Locale locale = Locale.forLanguageTag(user.langKey); Context context = new Context(locale); context.setVariable(USER, user); context.setVariable(BASE_URL, managementPortalProperties.getCommon().getManagementPortalBaseUrl()); String content = templateEngine.process("passwordResetEmail", context); String subject = messageSource.getMessage("email.reset.title", null, locale); - sendEmail(user.getEmail(), subject, content, false, true); + sendEmail(user.email, subject, content, false, true); } } diff --git a/src/main/java/org/radarbase/management/service/MetaTokenService.java b/src/main/java/org/radarbase/management/service/MetaTokenService.java deleted file mode 100644 index 248c07a9f..000000000 --- a/src/main/java/org/radarbase/management/service/MetaTokenService.java +++ /dev/null @@ -1,236 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.MetaToken; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.repository.MetaTokenRepository; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.dto.ClientPairInfoDTO; -import org.radarbase.management.service.dto.TokenDTO; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.InvalidStateException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.radarbase.management.web.rest.errors.RequestGoneException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.validation.ConstraintViolationException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.time.Duration; -import java.time.Instant; -import java.time.format.DateTimeParseException; -import java.util.Collections; - -import static org.radarbase.management.domain.MetaToken.LONG_ID_LENGTH; -import static org.radarbase.management.domain.MetaToken.SHORT_ID_LENGTH; -import static org.radarbase.management.web.rest.MetaTokenResource.DEFAULT_META_TOKEN_TIMEOUT; -import static org.radarbase.management.web.rest.MetaTokenResource.DEFAULT_PERSISTENT_META_TOKEN_TIMEOUT; -import static org.radarbase.management.web.rest.errors.EntityName.META_TOKEN; -import static org.radarbase.management.web.rest.errors.EntityName.OAUTH_CLIENT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_PERSISTENT_TOKEN_DISABLED; - -/** - * Created by nivethika. - * - *

Service to delegate MetaToken handling.

- * - */ -@Service -@Transactional -public class MetaTokenService { - - private static final Logger log = LoggerFactory.getLogger(MetaTokenService.class); - - @Autowired - private MetaTokenRepository metaTokenRepository; - - @Autowired - private OAuthClientService oAuthClientService; - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Autowired - private SubjectService subjectService; - - /** - * Save a metaToken. - * - * @param metaToken the entity to save - * @return the persisted entity - */ - public MetaToken save(MetaToken metaToken) { - log.debug("Request to save MetaToken : {}", metaToken); - return metaTokenRepository.save(metaToken); - } - - /** - * Get one project by id. - * - * @param tokenName the id of the entity - * @return the entity - */ - public TokenDTO fetchToken(String tokenName) throws MalformedURLException { - log.debug("Request to get Token : {}", tokenName); - MetaToken metaToken = getToken(tokenName); - // process the response if the token is not fetched or not expired - if (metaToken.isValid()) { - String refreshToken = oAuthClientService.createAccessToken( - metaToken.getSubject().getUser(), - metaToken.getClientId()) - .getRefreshToken() - .getValue(); - - // create response - TokenDTO result = new TokenDTO(refreshToken, - new URL(managementPortalProperties.getCommon().getBaseUrl()), - subjectService.getPrivacyPolicyUrl(metaToken.getSubject())); - - // change fetched status to true. - if (!metaToken.isFetched()) { - metaToken.fetched(true); - save(metaToken); - } - return result; - } else { - throw new RequestGoneException("Token " + tokenName + " already fetched or expired. ", - META_TOKEN, "error.TokenCannotBeSent"); - } - } - - /** - * Gets a token from databased using the tokenName. - * - * @param tokenName tokenName. - * @return fetched token as {@link MetaToken}. - */ - @Transactional(readOnly = true) - public MetaToken getToken(String tokenName) { - return metaTokenRepository.findOneByTokenName(tokenName) - .orElseThrow(() -> new NotFoundException("Meta token not found with tokenName", - META_TOKEN, - ErrorConstants.ERR_TOKEN_NOT_FOUND, - Collections.singletonMap("tokenName", tokenName))); - } - - /** - * Saves a unique meta-token instance, by checking for token-name collision. - * If a collision is detection, we try to save the token with a new tokenName - * @return an unique token - */ - public MetaToken saveUniqueToken(Subject subject, String clientId, Boolean - fetched, Instant expiryTime, boolean persistent) { - MetaToken metaToken = new MetaToken() - .generateName(persistent ? LONG_ID_LENGTH : SHORT_ID_LENGTH) - .fetched(fetched) - .expiryDate(expiryTime) - .subject(subject) - .clientId(clientId) - .persistent(persistent); - - try { - return metaTokenRepository.save(metaToken); - } catch (ConstraintViolationException e) { - log.warn("Unique constraint violation catched... Trying to save with new tokenName"); - return saveUniqueToken(subject, clientId, fetched, expiryTime, persistent); - } - } - - /** - * Creates meta token for oauth-subject pair. - * @param subject to create token for - * @param clientId using which client id - * @param persistent whether to persist the token after it is has been fetched - * @return {@link ClientPairInfoDTO} to return. - * @throws URISyntaxException when token URI cannot be formed properly. - * @throws MalformedURLException when token URL cannot be formed properly. - */ - public ClientPairInfoDTO createMetaToken(Subject subject, String clientId, boolean persistent) - throws URISyntaxException, MalformedURLException, NotAuthorizedException { - Duration timeout = getMetaTokenTimeout(persistent, subject.getActiveProject() - .orElseThrow(() -> new NotAuthorizedException( - "Cannot calculate meta-token duration without configured project"))); - - // tokenName should be generated - MetaToken metaToken = saveUniqueToken(subject, clientId, false, - Instant.now().plus(timeout), persistent); - - if (metaToken.getId() != null && metaToken.getTokenName() != null) { - // get base url from settings - String baseUrl = managementPortalProperties.getCommon().getManagementPortalBaseUrl(); - // create complete uri string - String tokenUrl = baseUrl + ResourceUriService.getUri(metaToken).getPath(); - // create response - return new ClientPairInfoDTO(new URL(baseUrl), metaToken.getTokenName(), - new URL(tokenUrl), timeout); - } else { - throw new InvalidStateException("Could not create a valid token", OAUTH_CLIENT, - "error.couldNotCreateToken"); - } - } - - /** - * Gets the meta-token timeout from config file. If the config is not mentioned or in wrong - * format, it will return default value. - * - * @return meta-token timeout duration. - * @throws BadRequestException if a persistent token is requested but it is not configured. - */ - public Duration getMetaTokenTimeout(boolean persistent, Project project) { - String timeoutConfig; - Duration defaultTimeout; - - if (persistent) { - timeoutConfig = managementPortalProperties.getOauth().getPersistentMetaTokenTimeout(); - if (timeoutConfig == null || timeoutConfig.isEmpty()) { - throw new BadRequestException( - "Cannot create persistent token: not supported in configuration.", - META_TOKEN, ERR_PERSISTENT_TOKEN_DISABLED); - } - defaultTimeout = DEFAULT_PERSISTENT_META_TOKEN_TIMEOUT; - } else { - timeoutConfig = managementPortalProperties.getOauth().getMetaTokenTimeout(); - defaultTimeout = DEFAULT_META_TOKEN_TIMEOUT; - if (timeoutConfig == null || timeoutConfig.isEmpty()) { - return defaultTimeout; - } - } - - try { - return Duration.parse(timeoutConfig); - } catch (DateTimeParseException e) { - // if the token timeout cannot be read, log the error and use the default value. - log.warn("Cannot parse meta-token timeout config. Using default value {}", - defaultTimeout, e); - return defaultTimeout; - } - } - - /** - * Expired and fetched tokens are deleted after 1 month. - *

This is scheduled to get triggered first day of the month.

- */ - @Scheduled(cron = "0 0 0 1 * ?") - public void removeStaleTokens() { - log.info("Scheduled scan for expired and fetched meta-tokens starting now"); - - metaTokenRepository.findAllByFetchedOrExpired(Instant.now()) - .forEach(metaToken -> { - log.info("Deleting deleting expired or fetched token {}", - metaToken.getTokenName()); - metaTokenRepository.delete(metaToken); - }); - } - - public void delete(MetaToken token) { - metaTokenRepository.delete(token); - } -} diff --git a/src/main/java/org/radarbase/management/service/MetaTokenService.kt b/src/main/java/org/radarbase/management/service/MetaTokenService.kt new file mode 100644 index 000000000..9a8bfe961 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/MetaTokenService.kt @@ -0,0 +1,253 @@ +package org.radarbase.management.service + +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.MetaToken +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.MetaTokenRepository +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.dto.ClientPairInfoDTO +import org.radarbase.management.service.dto.TokenDTO +import org.radarbase.management.web.rest.MetaTokenResource +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidStateException +import org.radarbase.management.web.rest.errors.NotFoundException +import org.radarbase.management.web.rest.errors.RequestGoneException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.net.MalformedURLException +import java.net.URISyntaxException +import java.net.URL +import java.time.Duration +import java.time.Instant +import java.time.format.DateTimeParseException +import java.util.* +import java.util.function.Consumer +import javax.validation.ConstraintViolationException + +/** + * Created by nivethika. + * + * + * Service to delegate MetaToken handling. + * + */ +@Service +@Transactional +open class MetaTokenService { + @Autowired + private val metaTokenRepository: MetaTokenRepository? = null + + @Autowired + private val oAuthClientService: OAuthClientService? = null + + @Autowired + private val managementPortalProperties: ManagementPortalProperties? = null + + @Autowired + private val subjectService: SubjectService? = null + + /** + * Save a metaToken. + * + * @param metaToken the entity to save + * @return the persisted entity + */ + fun save(metaToken: MetaToken): MetaToken { + log.debug("Request to save MetaToken : {}", metaToken) + return metaTokenRepository!!.save(metaToken) + } + + /** + * Get one project by id. + * + * @param tokenName the id of the entity + * @return the entity + */ + @Throws(MalformedURLException::class) + fun fetchToken(tokenName: String): TokenDTO { + log.debug("Request to get Token : {}", tokenName) + val metaToken = getToken(tokenName) + // process the response if the token is not fetched or not expired + return if (metaToken.isValid) { + val refreshToken = oAuthClientService!!.createAccessToken( + metaToken.subject!!.user, + metaToken.clientId + ) + .refreshToken + .value + + // create response + val result = TokenDTO( + refreshToken, + URL(managementPortalProperties!!.common.baseUrl), + subjectService!!.getPrivacyPolicyUrl(metaToken.subject!!) + ) + + // change fetched status to true. + if (!metaToken.isFetched()) { + metaToken.fetched(true) + save(metaToken) + } + result + } else { + throw RequestGoneException( + "Token $tokenName already fetched or expired. ", + EntityName.META_TOKEN, "error.TokenCannotBeSent" + ) + } + } + + /** + * Gets a token from databased using the tokenName. + * + * @param tokenName tokenName. + * @return fetched token as [MetaToken]. + */ + @Transactional(readOnly = true) + open fun getToken(tokenName: String): MetaToken { + return metaTokenRepository!!.findOneByTokenName(tokenName) + .orElseThrow { + NotFoundException( + "Meta token not found with tokenName", + EntityName.META_TOKEN, + ErrorConstants.ERR_TOKEN_NOT_FOUND, + Collections.singletonMap("tokenName", tokenName) + ) + } + } + + /** + * Saves a unique meta-token instance, by checking for token-name collision. + * If a collision is detection, we try to save the token with a new tokenName + * @return an unique token + */ + fun saveUniqueToken( + subject: Subject?, + clientId: String?, + fetched: Boolean?, + expiryTime: Instant?, + persistent: Boolean + ): MetaToken { + val metaToken = MetaToken() + .generateName(if (persistent) MetaToken.LONG_ID_LENGTH else MetaToken.SHORT_ID_LENGTH) + .fetched(fetched!!) + .expiryDate(expiryTime) + .subject(subject) + .clientId(clientId) + .persistent(persistent) + return try { + metaTokenRepository!!.save(metaToken) + } catch (e: ConstraintViolationException) { + log.warn("Unique constraint violation catched... Trying to save with new tokenName") + saveUniqueToken(subject, clientId, fetched, expiryTime, persistent) + } + } + + /** + * Creates meta token for oauth-subject pair. + * @param subject to create token for + * @param clientId using which client id + * @param persistent whether to persist the token after it is has been fetched + * @return [ClientPairInfoDTO] to return. + * @throws URISyntaxException when token URI cannot be formed properly. + * @throws MalformedURLException when token URL cannot be formed properly. + */ + @Throws(URISyntaxException::class, MalformedURLException::class, NotAuthorizedException::class) + fun createMetaToken(subject: Subject, clientId: String?, persistent: Boolean): ClientPairInfoDTO { + val timeout = getMetaTokenTimeout(persistent, project = subject.activeProject + ?:throw NotAuthorizedException("Cannot calculate meta-token duration without configured project") + ) + + // tokenName should be generated + val metaToken = saveUniqueToken( + subject, clientId, false, + Instant.now().plus(timeout), persistent + ) + return if (metaToken.id != null && metaToken.tokenName != null) { + // get base url from settings + val baseUrl = managementPortalProperties!!.common.managementPortalBaseUrl + // create complete uri string + val tokenUrl = baseUrl + ResourceUriService.getUri(metaToken).getPath() + // create response + ClientPairInfoDTO( + URL(baseUrl), metaToken.tokenName, + URL(tokenUrl), timeout + ) + } else { + throw InvalidStateException( + "Could not create a valid token", EntityName.OAUTH_CLIENT, + "error.couldNotCreateToken" + ) + } + } + + /** + * Gets the meta-token timeout from config file. If the config is not mentioned or in wrong + * format, it will return default value. + * + * @return meta-token timeout duration. + * @throws BadRequestException if a persistent token is requested but it is not configured. + */ + fun getMetaTokenTimeout(persistent: Boolean, project: Project?): Duration { + val timeoutConfig: String? + val defaultTimeout: Duration + if (persistent) { + timeoutConfig = managementPortalProperties!!.oauth.persistentMetaTokenTimeout + if (timeoutConfig == null || timeoutConfig.isEmpty()) { + throw BadRequestException( + "Cannot create persistent token: not supported in configuration.", + EntityName.META_TOKEN, ErrorConstants.ERR_PERSISTENT_TOKEN_DISABLED + ) + } + defaultTimeout = MetaTokenResource.DEFAULT_PERSISTENT_META_TOKEN_TIMEOUT + } else { + timeoutConfig = managementPortalProperties!!.oauth.metaTokenTimeout + defaultTimeout = MetaTokenResource.DEFAULT_META_TOKEN_TIMEOUT + if (timeoutConfig == null || timeoutConfig.isEmpty()) { + return defaultTimeout + } + } + return try { + Duration.parse(timeoutConfig) + } catch (e: DateTimeParseException) { + // if the token timeout cannot be read, log the error and use the default value. + log.warn( + "Cannot parse meta-token timeout config. Using default value {}", + defaultTimeout, e + ) + defaultTimeout + } + } + + /** + * Expired and fetched tokens are deleted after 1 month. + * + * This is scheduled to get triggered first day of the month. + */ + @Scheduled(cron = "0 0 0 1 * ?") + fun removeStaleTokens() { + log.info("Scheduled scan for expired and fetched meta-tokens starting now") + metaTokenRepository!!.findAllByFetchedOrExpired(Instant.now()) + .forEach(Consumer { metaToken: MetaToken -> + log.info( + "Deleting deleting expired or fetched token {}", + metaToken.tokenName + ) + metaTokenRepository.delete(metaToken) + }) + } + + fun delete(token: MetaToken) { + metaTokenRepository!!.delete(token) + } + + companion object { + private val log = LoggerFactory.getLogger(MetaTokenService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/service/OAuthClientService.java b/src/main/java/org/radarbase/management/service/OAuthClientService.java index cf79f846d..afc8fcf2e 100644 --- a/src/main/java/org/radarbase/management/service/OAuthClientService.java +++ b/src/main/java/org/radarbase/management/service/OAuthClientService.java @@ -163,7 +163,7 @@ public ClientDetails createClientDetail(ClientDetailsDTO clientDetailsDto) { */ public OAuth2AccessToken createAccessToken(User user, String clientId) { Set authorities = user.getAuthorities().stream() - .map(a -> new SimpleGrantedAuthority(a.getName())) + .map(a -> new SimpleGrantedAuthority(a.name)) .collect(Collectors.toSet()); // lookup the OAuth client // getOAuthClient checks if the id exists diff --git a/src/main/java/org/radarbase/management/service/OrganizationService.java b/src/main/java/org/radarbase/management/service/OrganizationService.java index df6c66cbc..b1d7a1703 100644 --- a/src/main/java/org/radarbase/management/service/OrganizationService.java +++ b/src/main/java/org/radarbase/management/service/OrganizationService.java @@ -122,7 +122,7 @@ public List findAllProjectsByOrganizationName(String organizationNam projectStream = projectRepository.findAllByOrganizationName(organizationName).stream(); } else if (referents.hasAnyProjects()) { projectStream = projectRepository.findAllByOrganizationName(organizationName).stream() - .filter(project -> referents.hasAnyProject(project.getProjectName())); + .filter(project -> referents.hasAnyProject(project.projectName)); } else { return List.of(); } diff --git a/src/main/java/org/radarbase/management/service/ProjectService.java b/src/main/java/org/radarbase/management/service/ProjectService.java deleted file mode 100644 index ef55bd111..000000000 --- a/src/main/java/org/radarbase/management/service/ProjectService.java +++ /dev/null @@ -1,143 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.service.mapper.SourceTypeMapper; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collections; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.PROJECT_READ; -import static org.radarbase.management.web.rest.errors.EntityName.PROJECT; - -/** - * Service Implementation for managing Project. - */ -@Service -@Transactional -public class ProjectService { - - private static final Logger log = LoggerFactory.getLogger(ProjectService.class); - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private ProjectMapper projectMapper; - - @Autowired - private SourceTypeMapper sourceTypeMapper; - - @Autowired - private AuthService authService; - - - /** - * Save a project. - * - * @param projectDto the entity to save - * @return the persisted entity - */ - public ProjectDTO save(ProjectDTO projectDto) { - log.debug("Request to save Project : {}", projectDto); - Project project = projectMapper.projectDTOToProject(projectDto); - project = projectRepository.save(project); - return projectMapper.projectToProjectDTO(project); - } - - /** - * Get all the projects. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public Page findAll(Boolean fetchMinimal, Pageable pageable) { - Page projects; - - var referents = authService.referentsByScope(PROJECT_READ); - if (referents.isEmpty()) { - projects = new PageImpl<>(List.of()); - } else if (referents.getGlobal()) { - projects = projectRepository.findAllWithEagerRelationships(pageable); - } else { - projects = projectRepository.findAllWithEagerRelationshipsInOrganizationsOrProjects( - pageable, referents.getOrganizations(), referents.getAllProjects()); - } - - if (!fetchMinimal) { - return projects.map(projectMapper::projectToProjectDTO); - } else { - return projects.map(projectMapper::projectToMinimalProjectDetailsDTO); - } - } - - /** - * Get one project by id. - * - * @param id the id of the entity - * @return the entity - */ - @Transactional(readOnly = true) - public ProjectDTO findOne(Long id) { - log.debug("Request to get Project : {}", id); - return projectRepository.findOneWithEagerRelationships(id) - .map(projectMapper::projectToProjectDTO) - .orElseThrow(() -> new NotFoundException("Project not found with id", PROJECT, - ErrorConstants.ERR_PROJECT_ID_NOT_FOUND, - Collections.singletonMap("id", id.toString()))); - } - - /** - * Get one project by name. - * - * @param name the name of the entity - * @return the entity - */ - @Transactional(readOnly = true) - public ProjectDTO findOneByName(String name) { - log.debug("Request to get Project by name: {}", name); - return projectRepository.findOneWithEagerRelationshipsByName(name) - .map(projectMapper::projectToProjectDTO) - .orElseThrow(() -> new NotFoundException( - "Project not found with projectName " + name, - PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND, - Collections.singletonMap("projectName", name))); - } - - /** - * Get source-types assigned to a project. - * - * @param id the id of the project - * @return the list of source-types assigned. - */ - @Transactional(readOnly = true) - public List findSourceTypesByProjectId(Long id) { - log.debug("Request to get Project.sourceTypes of project: {}", id); - List sourceTypes = projectRepository.findSourceTypesByProjectId(id); - return sourceTypeMapper.sourceTypesToSourceTypeDTOs(sourceTypes); - } - - /** - * Delete the project by id. - * - * @param id the id of the entity - */ - public void delete(Long id) { - log.debug("Request to delete Project : {}", id); - projectRepository.deleteById(id); - } -} diff --git a/src/main/java/org/radarbase/management/service/ProjectService.kt b/src/main/java/org/radarbase/management/service/ProjectService.kt new file mode 100644 index 000000000..5f273f341 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/ProjectService.kt @@ -0,0 +1,134 @@ +package org.radarbase.management.service + +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.Project +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SourceTypeDTO +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.service.mapper.SourceTypeMapper +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Page +import org.springframework.data.domain.PageImpl +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.util.* + +/** + * Service Implementation for managing Project. + */ +@Service +@Transactional +open class ProjectService( + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val sourceTypeMapper: SourceTypeMapper, + @Autowired private val authService: AuthService +) { + + /** + * Save a project. + * + * @param projectDto the entity to save + * @return the persisted entity + */ + fun save(projectDto: ProjectDTO?): ProjectDTO { + log.debug("Request to save Project : {}", projectDto) + var project = projectMapper.projectDTOToProject(projectDto) + project = projectRepository.save(project) + return projectMapper.projectToProjectDTO(project) + } + + /** + * Get all the projects. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(fetchMinimal: Boolean?, pageable: Pageable?): Page<*> { + val projects: Page? + val referents = authService.referentsByScope(Permission.PROJECT_READ) + projects = if (referents.isEmpty()) { + PageImpl(listOf()) + } else if (referents.global) { + projectRepository.findAllWithEagerRelationships(pageable) + } else { + projectRepository.findAllWithEagerRelationshipsInOrganizationsOrProjects( + pageable, referents.organizations, referents.allProjects + ) + } + return if (!fetchMinimal!!) { + projects!!.map { project: Project? -> projectMapper.projectToProjectDTO(project) } + } else { + projects!!.map { project: Project? -> projectMapper.projectToMinimalProjectDetailsDTO(project) } + } + } + + /** + * Get one project by id. + * + * @param id the id of the entity + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOne(id: Long): ProjectDTO { + log.debug("Request to get Project : {}", id) + return projectRepository.findOneWithEagerRelationships(id) + .let { project: Project? -> projectMapper.projectToProjectDTO(project) } ?: throw NotFoundException( + "Project not found with id", + EntityName.PROJECT, + ErrorConstants.ERR_PROJECT_ID_NOT_FOUND, + Collections.singletonMap("id", id.toString()) + ) + } + + /** + * Get one project by name. + * + * @param name the name of the entity + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOneByName(name: String): ProjectDTO { + log.debug("Request to get Project by name: {}", name) + return projectRepository.findOneWithEagerRelationshipsByName(name) + .let { project: Project? -> projectMapper.projectToProjectDTO(project) } ?: throw NotFoundException( + "Project not found with projectName $name", + EntityName.PROJECT, + ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND, + Collections.singletonMap("projectName", name) + ) + } + + /** + * Get source-types assigned to a project. + * + * @param id the id of the project + * @return the list of source-types assigned. + */ + @Transactional(readOnly = true) + open fun findSourceTypesByProjectId(id: Long?): List { + log.debug("Request to get Project.sourceTypes of project: {}", id) + val sourceTypes = projectRepository.findSourceTypesByProjectId(id) + return sourceTypeMapper.sourceTypesToSourceTypeDTOs(sourceTypes) + } + + /** + * Delete the project by id. + * + * @param id the id of the entity + */ + fun delete(id: Long) { + log.debug("Request to delete Project : {}", id) + projectRepository.deleteById(id) + } + + companion object { + private val log = LoggerFactory.getLogger(ProjectService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/service/ResourceUriService.java b/src/main/java/org/radarbase/management/service/ResourceUriService.java index f16481f85..1c23760c8 100644 --- a/src/main/java/org/radarbase/management/service/ResourceUriService.java +++ b/src/main/java/org/radarbase/management/service/ResourceUriService.java @@ -105,7 +105,7 @@ public static URI getUri(SourceDTO resource) throws URISyntaxException { * @throws URISyntaxException See {@link URI#URI(String)} */ public static URI getUri(Source resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "sources", resource.getSourceName())); + return new URI(HeaderUtil.buildPath("api", "sources", resource.sourceName)); } /** diff --git a/src/main/java/org/radarbase/management/service/RevisionService.java b/src/main/java/org/radarbase/management/service/RevisionService.java deleted file mode 100644 index 627cdaf17..000000000 --- a/src/main/java/org/radarbase/management/service/RevisionService.java +++ /dev/null @@ -1,391 +0,0 @@ -package org.radarbase.management.service; - -import static java.util.stream.Collectors.toList; -import static org.radarbase.management.web.rest.errors.EntityName.REVISION; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_REVISIONS_NOT_FOUND; -import static org.springframework.transaction.annotation.Isolation.REPEATABLE_READ; - -import java.lang.reflect.InvocationTargetException; -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.function.Function; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.NonUniqueResultException; -import javax.persistence.PersistenceContext; -import javax.validation.constraints.NotNull; -import org.hibernate.envers.AuditReader; -import org.hibernate.envers.AuditReaderFactory; -import org.hibernate.envers.RevisionType; -import org.hibernate.envers.exception.AuditException; -import org.hibernate.envers.query.AuditEntity; -import org.hibernate.envers.query.AuditQuery; -import org.hibernate.envers.query.criteria.AuditCriterion; -import org.mapstruct.Mapper; -import org.radarbase.management.domain.AbstractEntity; -import org.radarbase.management.domain.audit.CustomRevisionEntity; -import org.radarbase.management.domain.audit.CustomRevisionMetadata; -import org.radarbase.management.domain.audit.EntityAuditInfo; -import org.radarbase.management.repository.CustomRevisionEntityRepository; -import org.radarbase.management.service.dto.RevisionDTO; -import org.radarbase.management.service.dto.RevisionInfoDTO; -import org.radarbase.management.web.rest.errors.InvalidStateException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; -import org.springframework.core.type.filter.AnnotationTypeFilter; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.data.history.Revision; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional(isolation = REPEATABLE_READ, readOnly = true) -public class RevisionService implements ApplicationContextAware { - private static final Logger log = LoggerFactory.getLogger(RevisionService.class); - private static volatile ApplicationContext applicationContext; - - @PersistenceContext - private EntityManager entityManager; - private final CustomRevisionEntityRepository revisionEntityRepository; - - private final ConcurrentMap, Function> dtoMapperMap = - new ConcurrentHashMap<>(); - - public RevisionService(@Autowired CustomRevisionEntityRepository revisionEntityRepository) { - this.revisionEntityRepository = revisionEntityRepository; - } - - /** - * Find audit info for a given entity. The audit info includes created by, created at, last - * modified by and last modified at. - * - * @param entity the entity to look up - * @return the audit information. The fields in this object can be null if that information - * was not available. - */ - public EntityAuditInfo getAuditInfo(AbstractEntity entity) { - AuditReader auditReader = getAuditReader(); - try { - // find first revision of the entity - Object[] firstRevision = (Object[]) auditReader.createQuery() - .forRevisionsOfEntity(entity.getClass(), false, true) - .add(AuditEntity.id().eq(entity.getId())) - .add(AuditEntity.revisionNumber().minimize() - .computeAggregationInInstanceContext()) - .getSingleResult(); - CustomRevisionEntity first = (CustomRevisionEntity) firstRevision[1]; - - // find last revision of the entity - Object[] lastRevision = (Object[]) auditReader.createQuery() - .forRevisionsOfEntity(entity.getClass(), false, true) - .add(AuditEntity.id().eq(entity.getId())) - .add(AuditEntity.revisionNumber().maximize() - .computeAggregationInInstanceContext()) - .getSingleResult(); - CustomRevisionEntity last = (CustomRevisionEntity) lastRevision[1]; - - // now populate the result object and return it - return new EntityAuditInfo() - .setCreatedAt(ZonedDateTime.ofInstant(first.getTimestamp().toInstant(), - ZoneId.systemDefault())) - .setCreatedBy(first.getAuditor()) - .setLastModifiedAt(ZonedDateTime.ofInstant(last.getTimestamp().toInstant(), - ZoneId.systemDefault())) - .setLastModifiedBy(last.getAuditor()); - } catch (NonUniqueResultException ex) { - // should not happen since we call 'minimize' - throw new IllegalStateException("Query for revision returned a " - + "non-unique result. Please report this to the administrator together with " - + "the request issued.", ex); - } catch (NoResultException ex) { - // we did not find any auditing info, so we just return an empty object - return new EntityAuditInfo(); - } - } - - /** - * Find a specific revision of a specific entity. The repository methods seem not to be able - * to find back a deleted entity with their findRevision method. - * - * @param revisionNb the revision number - * @param id the entity id - * @param clazz the entity class - * @param the entity class - * @return the entity at the specified revision - */ - @SuppressWarnings("unchecked") - public R findRevision( - Integer revisionNb, - Long id, - Class clazz, - Function dtoMapper - ) { - T value = (T) getAuditReader().createQuery() - .forRevisionsOfEntity(clazz, true, true) - .add(AuditEntity.id().eq(id)) - .add(AuditEntity.revisionNumber().eq(revisionNb)) - .getSingleResult(); - return value != null ? dtoMapper.apply(value) : null; - } - - /** - * Get a page of revisions. - * - * @param pageable Page information - * @return the page of revisions {@link RevisionInfoDTO} - */ - public Page getRevisions(Pageable pageable) { - return revisionEntityRepository.findAll(pageable) - .map(rev -> RevisionInfoDTO.from(rev, getChangesForRevision(rev.getId()))); - } - - /** - * Get a page of revisions for a given entity. - * - * @param pageable the page information - * @param entity the entity for which to get the revisions - * @return the requested page of revisions for the given entity - */ - public Page getRevisionsForEntity(Pageable pageable, AbstractEntity entity) { - AuditReader auditReader = getAuditReader(); - Number count = (Number) auditReader.createQuery() - .forRevisionsOfEntity(entity.getClass(), false, true) - .add(AuditEntity.id().eq(entity.getId())) - .addProjection(AuditEntity.revisionNumber().count()) - .getSingleResult(); - - // find all revisions of the entity class that have the correct id - AuditQuery query = auditReader.createQuery() - .forRevisionsOfEntity(entity.getClass(), false, true) - .add(AuditEntity.id().eq(entity.getId())); - - // add the page sorting information to the query - if (pageable.getSort() != null) { - pageable.getSort() - .forEach(order -> query.addOrder(order.getDirection().isAscending() - ? AuditEntity.property(order.getProperty()).asc() - : AuditEntity.property(order.getProperty()).desc())); - } - - // add the page constraints (offset and amount of results) - query.setFirstResult(Math.toIntExact(pageable.getOffset())) - .setMaxResults(Math.toIntExact(pageable.getPageSize())); - - Function dtoMapper = getDtoMapper(entity.getClass()); - - @SuppressWarnings("unchecked") - List resultList = (List) query.getResultList(); - @SuppressWarnings({"unchecked", "rawtypes"}) - List revisionDtos = resultList.stream() - .map(objArray -> new RevisionDTO( - Revision.of( - new CustomRevisionMetadata((CustomRevisionEntity) objArray[1]), - objArray[0]), - (RevisionType) objArray[2], - dtoMapper.apply(objArray[0]))) - .collect(toList()); - - return new PageImpl<>(revisionDtos, pageable, count.longValue()); - } - - /** - * Get a single revision. - * - * @param revision the revision number - * @return the revision - * @throws NotFoundException if the revision number does not exist - */ - public RevisionInfoDTO getRevision(Integer revision) throws NotFoundException { - CustomRevisionEntity revisionEntity = revisionEntityRepository.findById(revision) - .orElse(null); - if (revisionEntity == null) { - throw new NotFoundException("Revision not found with revision id", REVISION, - ERR_REVISIONS_NOT_FOUND, - Collections.singletonMap("revision-id", revision.toString())); - } - return RevisionInfoDTO.from(revisionEntity, getChangesForRevision(revision)); - } - - /** - * Get changes for a specific revision number, ordered by revision type. - * - * @param revision the revision number - * @return A map with as keys the revision types, and as values the list of changed objects - * of that type - */ - public Map> getChangesForRevision(Integer revision) { - // Custom implementation not using crosstyperevisionchangesreader. - // It seems we need to clear the entitymanager before using the - // crosstyperevisionchangesreader, or we get incorrect results: deleted entities do not - // show up in revisions where they were still around. However clearing for every request - // causes the revisions api to be quite slow so we retrieve the changes manually using - // the AuditReader. - CustomRevisionEntity revisionEntity = revisionEntityRepository.findById(revision) - .orElse(null); - if (revisionEntity == null) { - throw new NotFoundException("The requested revision could not be found.", REVISION, - ERR_REVISIONS_NOT_FOUND, - Collections.singletonMap("revision-id", revision.toString())); - } - AuditReader auditReader = getAuditReader(); - - Map> result = new HashMap<>(5); - - for (RevisionType revisionType : RevisionType.values()) { - result.put(revisionType, new ArrayList<>()); - } - - for (String entityName : revisionEntity.getModifiedEntityNames()) { - String cleanedEntityName = entityName.replace("org.radarcns.", "org.radarbase."); - Class entityClass = classForEntityName(cleanedEntityName); - Function dtoMapper = getDtoMapper(entityClass); - - for (RevisionType revisionType : RevisionType.values()) { - //noinspection unchecked - result.get(revisionType) - .addAll((List)auditReader.createQuery() - .forEntitiesModifiedAtRevision(entityClass, revision) - .add(AuditEntity.revisionType().eq(revisionType)) - .getResultList() - .stream() - .map(dtoMapper) - .filter(Objects::nonNull) - .collect(toList())); - } - } - - return result; - } - - /** - * Dynamically find the Mapstruct mapper that can map the entity to it's DTO counterpart, - * then do the mapping and return the DTO. - * - * @param entity the entity to map to it's DTO form - * @return the DTO form of the given entity - */ - private Object toDto(Object entity) { - return entity != null ? getDtoMapper(entity.getClass()).apply(entity) : null; - } - - private Function getDtoMapper(@NotNull Class entity) { - return dtoMapperMap.computeIfAbsent(entity, this::addMapperForClass); - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - RevisionService.applicationContext = applicationContext; - } - - /** - *

Find the latest revision of an entity of a given class, that matches given criteria. This - * is useful for finding deleted entities by properties other than their primary key. The - * criteria should be defined such that zero or one entities match.

- * - *

Example: {@code getLatestRevisionForEntity(Subject.class, Arrays.asList(AuditEntity - * .property("user.login").eq(requestedLogin)))}.

- * @param clazz The entity class - * @param criteria The list of criteria that will be added to the audit query - * @return The DTO version of the latest revision of the requested entity, or an empty - * optional if no entity was found matching the given criteria. - * @throws AuditException if the entity is not audited - * @throws NonUniqueResultException if multiple enities match the criteria - */ - public Optional getLatestRevisionForEntity( - Class clazz, - List criteria - ) throws AuditException, NonUniqueResultException { - AuditQuery query = getAuditReader().createQuery() - .forRevisionsOfEntity(clazz, true, true) - .add(AuditEntity.revisionNumber().maximize() - .computeAggregationInInstanceContext()); - criteria.forEach(query::add); - try { - return Optional.ofNullable(toDto(query.getSingleResult())); - } catch (NoResultException ex) { - log.debug("No entity of type " + clazz.getName() + " found in the revision history " - + "with the given criteria", ex); - return Optional.empty(); - } - } - - private Function addMapperForClass(Class clazz) { - // get a list of @Mapper annotated components - ClassPathScanningCandidateComponentProvider scanner = new - ClassPathScanningCandidateComponentProvider(true); - scanner.addIncludeFilter(new AnnotationTypeFilter(Mapper.class)); - // look only in the mapper package - return scanner.findCandidateComponents("org.radarbase.management.service.mapper").stream() - .flatMap(bd -> { - final Object mapper = beanFromDefinition(bd); - // now we look for the correct method in the bean - return Arrays.stream(mapper.getClass().getMethods()) - // look for methods that return our entity's DTO, and take exactly one - // argument of the same type as our entity - .filter(m -> - m.getGenericReturnType().getTypeName().endsWith( - clazz.getSimpleName() + "DTO") - && m.getGenericParameterTypes().length == 1 - && m.getGenericParameterTypes()[0].getTypeName().equals( - clazz.getTypeName())) - .>map(method -> obj -> { - if (obj == null) { - return null; - } - try { - return method.invoke(mapper, obj); - } catch (IllegalAccessException | InvocationTargetException ex) { - log.error(ex.getMessage(), ex); - return null; - } - }); - }) - .findAny() - .orElse(obj -> null); - } - - private Object beanFromDefinition(BeanDefinition beanDefinition) { - String className = beanDefinition.getBeanClassName(); - // get the bean for the given class - try { - return applicationContext.getBean(Class.forName(className)); - } catch (ClassNotFoundException ex) { - // should not happen, we got the classname from the bean definition - throw new InvalidStateException( - ex.getMessage(), REVISION, "error.classNotFound"); - } - } - - private Class classForEntityName(String entityName) { - try { - return Class.forName(entityName); - } catch (ClassNotFoundException ex) { - // this should not happen - log.error("Unable to load class for modified entity", ex); - throw new InvalidStateException(ex.getMessage(), REVISION, "error.classNotFound"); - } - } - - private AuditReader getAuditReader() { - return AuditReaderFactory.get(entityManager); - } -} diff --git a/src/main/java/org/radarbase/management/service/RevisionService.kt b/src/main/java/org/radarbase/management/service/RevisionService.kt new file mode 100644 index 000000000..dcf742280 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/RevisionService.kt @@ -0,0 +1,401 @@ +package org.radarbase.management.service + +import org.hibernate.envers.AuditReader +import org.hibernate.envers.AuditReaderFactory +import org.hibernate.envers.RevisionType +import org.hibernate.envers.exception.AuditException +import org.hibernate.envers.query.AuditEntity +import org.hibernate.envers.query.criteria.AuditCriterion +import org.mapstruct.Mapper +import org.radarbase.management.domain.AbstractEntity +import org.radarbase.management.domain.audit.CustomRevisionEntity +import org.radarbase.management.domain.audit.CustomRevisionMetadata +import org.radarbase.management.domain.audit.EntityAuditInfo +import org.radarbase.management.repository.CustomRevisionEntityRepository +import org.radarbase.management.service.dto.RevisionDTO +import org.radarbase.management.service.dto.RevisionInfoDTO +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidStateException +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.BeansException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.config.BeanDefinition +import org.springframework.context.ApplicationContext +import org.springframework.context.ApplicationContextAware +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider +import org.springframework.core.type.filter.AnnotationTypeFilter +import org.springframework.data.domain.Page +import org.springframework.data.domain.PageImpl +import org.springframework.data.domain.Pageable +import org.springframework.data.domain.Sort +import org.springframework.data.history.Revision +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Isolation +import org.springframework.transaction.annotation.Transactional +import java.lang.reflect.InvocationTargetException +import java.lang.reflect.Method +import java.time.ZoneId +import java.time.ZonedDateTime +import java.util.* +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.ConcurrentMap +import java.util.function.Consumer +import java.util.function.Function +import java.util.stream.Collectors +import java.util.stream.Stream +import javax.persistence.EntityManager +import javax.persistence.NoResultException +import javax.persistence.NonUniqueResultException +import javax.persistence.PersistenceContext +import javax.validation.constraints.NotNull + +@Service +@Transactional(isolation = Isolation.REPEATABLE_READ, readOnly = true) +open class RevisionService(@param:Autowired private val revisionEntityRepository: CustomRevisionEntityRepository) : + ApplicationContextAware { + @PersistenceContext + private val entityManager: EntityManager? = null + private val dtoMapperMap: ConcurrentMap?, Function> = ConcurrentHashMap() + + /** + * Find audit info for a given entity. The audit info includes created by, created at, last + * modified by and last modified at. + * + * @param entity the entity to look up + * @return the audit information. The fields in this object can be null if that information + * was not available. + */ + fun getAuditInfo(entity: AbstractEntity): EntityAuditInfo { + val auditReader = auditReader + return try { + // find first revision of the entity + val firstRevision = auditReader.createQuery() + .forRevisionsOfEntity(entity.javaClass, false, true) + .add(AuditEntity.id().eq(entity.id)) + .add( + AuditEntity.revisionNumber().minimize() + .computeAggregationInInstanceContext() + ) + .singleResult as Array + val first = firstRevision[1] as CustomRevisionEntity + + // find last revision of the entity + val lastRevision = auditReader.createQuery() + .forRevisionsOfEntity(entity.javaClass, false, true) + .add(AuditEntity.id().eq(entity.id)) + .add( + AuditEntity.revisionNumber().maximize() + .computeAggregationInInstanceContext() + ) + .singleResult as Array + val last = lastRevision[1] as CustomRevisionEntity + + // now populate the result object and return it + EntityAuditInfo() + .setCreatedAt( + ZonedDateTime.ofInstant( + first.timestamp!!.toInstant(), + ZoneId.systemDefault() + ) + ) + .setCreatedBy(first.auditor) + .setLastModifiedAt( + ZonedDateTime.ofInstant( + last.timestamp!!.toInstant(), + ZoneId.systemDefault() + ) + ) + .setLastModifiedBy(last.auditor) + } catch (ex: NonUniqueResultException) { + // should not happen since we call 'minimize' + throw IllegalStateException( + "Query for revision returned a " + + "non-unique result. Please report this to the administrator together with " + + "the request issued.", ex + ) + } catch (ex: NoResultException) { + // we did not find any auditing info, so we just return an empty object + EntityAuditInfo() + } + } + + /** + * Find a specific revision of a specific entity. The repository methods seem not to be able + * to find back a deleted entity with their findRevision method. + * + * @param revisionNb the revision number + * @param id the entity id + * @param clazz the entity class + * @param the entity class + * @return the entity at the specified revision + */ + fun findRevision( + revisionNb: Int?, + id: Long?, + clazz: Class?, + dtoMapper: Function + ): R? { + val value: T? = auditReader.createQuery() + .forRevisionsOfEntity(clazz, true, true) + .add(AuditEntity.id().eq(id)) + .add(AuditEntity.revisionNumber().eq(revisionNb)) + .singleResult as T + return if (value != null) dtoMapper.apply(value) else null + } + + /** + * Get a page of revisions. + * + * @param pageable Page information + * @return the page of revisions [RevisionInfoDTO] + */ + fun getRevisions(pageable: Pageable?): Page { + return revisionEntityRepository.findAll(pageable) + .map { rev: CustomRevisionEntity -> RevisionInfoDTO.from(rev, getChangesForRevision(rev.id)) } + } + + /** + * Get a page of revisions for a given entity. + * + * @param pageable the page information + * @param entity the entity for which to get the revisions + * @return the requested page of revisions for the given entity + */ + fun getRevisionsForEntity(pageable: Pageable, entity: AbstractEntity): Page { + val auditReader = auditReader + val count = auditReader.createQuery() + .forRevisionsOfEntity(entity.javaClass, false, true) + .add(AuditEntity.id().eq(entity.id)) + .addProjection(AuditEntity.revisionNumber().count()) + .singleResult as Number + + // find all revisions of the entity class that have the correct id + val query = auditReader.createQuery() + .forRevisionsOfEntity(entity.javaClass, false, true) + .add(AuditEntity.id().eq(entity.id)) + + // add the page sorting information to the query + if (pageable.sort != null) { + pageable.sort + .forEach(Consumer { order: Sort.Order -> + query.addOrder( + if (order.direction.isAscending) AuditEntity.property( + order.property + ).asc() else AuditEntity.property(order.property).desc() + ) + }) + } + + // add the page constraints (offset and amount of results) + query.setFirstResult(Math.toIntExact(pageable.offset)) + .setMaxResults(Math.toIntExact(pageable.pageSize.toLong())) + val dtoMapper = getDtoMapper(entity.javaClass) + val resultList = query.resultList as List?> + val revisionDtos = resultList.stream() + .map { objArray: Array? -> + RevisionDTO( + Revision.of( + CustomRevisionMetadata((objArray!![1] as CustomRevisionEntity)), + objArray[0] + ), + objArray[2] as RevisionType, + dtoMapper.apply(objArray[0]) + ) + } + .collect(Collectors.toList()) + return PageImpl(revisionDtos, pageable, count.toLong()) + } + + /** + * Get a single revision. + * + * @param revision the revision number + * @return the revision + * @throws NotFoundException if the revision number does not exist + */ + @Throws(NotFoundException::class) + fun getRevision(revision: Int): RevisionInfoDTO { + val revisionEntity = revisionEntityRepository.findById(revision) + .orElse(null) + ?: throw NotFoundException( + "Revision not found with revision id", EntityName.REVISION, + ErrorConstants.ERR_REVISIONS_NOT_FOUND, + Collections.singletonMap("revision-id", revision.toString()) + ) + return RevisionInfoDTO.from(revisionEntity, getChangesForRevision(revision)) + } + + /** + * Get changes for a specific revision number, ordered by revision type. + * + * @param revision the revision number + * @return A map with as keys the revision types, and as values the list of changed objects + * of that type + */ + fun getChangesForRevision(revision: Int): Map> { + // Custom implementation not using crosstyperevisionchangesreader. + // It seems we need to clear the entitymanager before using the + // crosstyperevisionchangesreader, or we get incorrect results: deleted entities do not + // show up in revisions where they were still around. However, clearing for every request + // causes the revisions api to be quite slow, so we retrieve the changes manually using + // the AuditReader. + val revisionEntity = revisionEntityRepository.findById(revision) + .orElse(null) + ?: throw NotFoundException( + "The requested revision could not be found.", EntityName.REVISION, + ErrorConstants.ERR_REVISIONS_NOT_FOUND, + Collections.singletonMap("revision-id", revision.toString()) + ) + val auditReader = auditReader + val result: MutableMap> = HashMap(5) + for (revisionType in RevisionType.values()) { + result[revisionType] = ArrayList() + } + for (entityName in revisionEntity.modifiedEntityNames!!) { + val cleanedEntityName = entityName.replace("org.radarcns.", "org.radarbase.") + val entityClass = classForEntityName(cleanedEntityName) + val dtoMapper = getDtoMapper(entityClass) + for (revisionType in RevisionType.values()) { + result[revisionType] + ?.addAll( + (listOf(auditReader.createQuery() + .forEntitiesModifiedAtRevision(entityClass, revision) + .add(AuditEntity.revisionType().eq(revisionType)) + .resultList + .let { toDto(it) } as Collection<*>) + )) + } + } + return result + } + + /** + * Dynamically find the Mapstruct mapper that can map the entity to it's DTO counterpart, + * then do the mapping and return the DTO. + * + * @param entity the entity to map to it's DTO form + * @return the DTO form of the given entity + */ + private fun toDto(entity: Any?): Any? { + return if (entity != null) getDtoMapper(entity.javaClass).apply(entity) else null + } + + private fun getDtoMapper(entity: @NotNull Class<*>?): Function { + return dtoMapperMap.computeIfAbsent(entity) { clazz: Class<*>? -> addMapperForClass(clazz) } + } + + @Throws(BeansException::class) + override fun setApplicationContext(applicationContext: ApplicationContext) { + Companion.applicationContext = applicationContext + } + + /** + * + * Find the latest revision of an entity of a given class, that matches given criteria. This + * is useful for finding deleted entities by properties other than their primary key. The + * criteria should be defined such that zero or one entities match. + * + * + * Example: `getLatestRevisionForEntity(Subject.class, Arrays.asList(AuditEntity + * .property("user.login").eq(requestedLogin)))`. + * @param clazz The entity class + * @param criteria The list of criteria that will be added to the audit query + * @return The DTO version of the latest revision of the requested entity, or an empty + * optional if no entity was found matching the given criteria. + * @throws AuditException if the entity is not audited + * @throws NonUniqueResultException if multiple enities match the criteria + */ + @Throws(AuditException::class, NonUniqueResultException::class) + fun getLatestRevisionForEntity( + clazz: Class<*>, + criteria: List + ): Optional { + val query = auditReader.createQuery() + .forRevisionsOfEntity(clazz, true, true) + .add( + AuditEntity.revisionNumber().maximize() + .computeAggregationInInstanceContext() + ) + criteria.forEach(Consumer { criterion: AuditCriterion? -> query.add(criterion) }) + return try { + Optional.ofNullable(toDto(query.singleResult)) + } catch (ex: NoResultException) { + log.debug( + "No entity of type " + clazz.getName() + " found in the revision history " + + "with the given criteria", ex + ) + Optional.empty() + } + } + + private fun addMapperForClass(clazz: Class<*>?): Function { + // get a list of @Mapper annotated components + val scanner = ClassPathScanningCandidateComponentProvider(true) + scanner.addIncludeFilter(AnnotationTypeFilter(Mapper::class.java)) + // look only in the mapper package + return scanner.findCandidateComponents("org.radarbase.management.service.mapper").stream() + .flatMap(Function>> { bd: BeanDefinition -> + val mapper = beanFromDefinition(bd) + Arrays.stream(mapper.javaClass.getMethods()) // look for methods that return our entity's DTO, and take exactly one + // argument of the same type as our entity + .filter { m: Method -> + m.genericReturnType.typeName.endsWith( + clazz!!.getSimpleName() + "DTO" + ) && m.genericParameterTypes.size == 1 && m.genericParameterTypes[0].typeName == clazz.getTypeName() + } + .map(Function { method: Method -> + Function { obj: Any? -> + if (obj == null) { + return@Function null + } + try { + return@Function method.invoke(mapper, obj) + } catch (ex: IllegalAccessException) { + log.error(ex.message, ex) + return@Function null + } catch (ex: InvocationTargetException) { + log.error(ex.message, ex) + return@Function null + } + } + }) + }) + .findAny() + .orElse(Function { obj: Any? -> null }) + } + + private fun beanFromDefinition(beanDefinition: BeanDefinition): Any { + val className = beanDefinition.beanClassName + // get the bean for the given class + return try { + applicationContext!!.getBean(Class.forName(className)) + } catch (ex: ClassNotFoundException) { + // should not happen, we got the classname from the bean definition + throw InvalidStateException( + ex.message, EntityName.REVISION, "error.classNotFound" + ) + } + } + + private fun classForEntityName(entityName: String): Class<*> { + return try { + Class.forName(entityName) + } catch (ex: ClassNotFoundException) { + // this should not happen + log.error("Unable to load class for modified entity", ex) + throw InvalidStateException(ex.message, EntityName.REVISION, "error.classNotFound") + } + } + + private val auditReader: AuditReader + private get() = AuditReaderFactory.get(entityManager) + + companion object { + private val log = LoggerFactory.getLogger(RevisionService::class.java) + + @Volatile + private var applicationContext: ApplicationContext? = null + } +} diff --git a/src/main/java/org/radarbase/management/service/RoleService.java b/src/main/java/org/radarbase/management/service/RoleService.java deleted file mode 100644 index b12a329eb..000000000 --- a/src/main/java/org/radarbase/management/service/RoleService.java +++ /dev/null @@ -1,271 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.AuthorityRepository; -import org.radarbase.management.repository.OrganizationRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.RoleRepository; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.mapper.RoleMapper; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Consumer; - -import static org.radarbase.management.web.rest.errors.EntityName.USER; - -/** - * Service Implementation for managing Project. - */ -@Service -@Transactional -public class RoleService { - - private static final Logger log = LoggerFactory.getLogger(RoleService.class); - - @Autowired - private RoleRepository roleRepository; - - @Autowired - private AuthorityRepository authorityRepository; - - @Autowired - private OrganizationRepository organizationRepository; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private RoleMapper roleMapper; - - @Autowired - private UserService userService; - - /** - * Save a role. - * - * @param roleDto the entity to save - * @return the persisted entity - */ - public RoleDTO save(RoleDTO roleDto) { - log.debug("Request to save Role : {}", roleDto); - Role role = roleMapper.roleDTOToRole(roleDto); - role = roleRepository.save(role); - return roleMapper.roleToRoleDTO(role); - } - - /** - * Get the roles the currently authenticated user has access to. - * - *

A system administrator has access to all the roles. A project administrator has access - * to the roles in their own project.

- * - * @return the list of entities - */ - @Transactional(readOnly = true) - public List findAll() { - Optional optUser = userService.getUserWithAuthorities(); - if (optUser.isEmpty()) { - // return an empty list if we do not have a current user (e.g. with client credentials - // oauth2 grant) - return Collections.emptyList(); - } - User currentUser = optUser.get(); - List currentUserAuthorities = currentUser.getAuthorities().stream() - .map(Authority::getName) - .toList(); - - if (currentUserAuthorities.contains(RoleAuthority.SYS_ADMIN.getAuthority())) { - log.debug("Request to get all Roles"); - return roleRepository.findAll().stream() - .map(roleMapper::roleToRoleDTO) - .toList(); - } else if (currentUserAuthorities.contains(RoleAuthority.PROJECT_ADMIN.getAuthority())) { - log.debug("Request to get project admin's project Projects"); - return currentUser.getRoles().stream() - .filter(role -> RoleAuthority.PROJECT_ADMIN.getAuthority() - .equals(role.getAuthority().getName())) - .map(r -> r.getProject().getProjectName()) - .distinct() - .flatMap(name -> roleRepository.findAllRolesByProjectName(name).stream()) - .map(roleMapper::roleToRoleDTO) - .toList(); - } else { - return Collections.emptyList(); - } - } - - /** - * Get all Admin roles. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public List findSuperAdminRoles() { - log.debug("Request to get admin Roles"); - - return roleRepository - .findRolesByAuthorityName(RoleAuthority.SYS_ADMIN.getAuthority()).stream() - .map(roleMapper::roleToRoleDTO) - .toList(); - } - - /** - * Get one role by id. - * - * @param id the id of the entity - * @return the entity - */ - @Transactional(readOnly = true) - public RoleDTO findOne(Long id) { - log.debug("Request to get Role : {}", id); - Role role = roleRepository.findById(id).get(); - return roleMapper.roleToRoleDTO(role); - } - - /** - * Delete the role by id. - * - * @param id the id of the entity - */ - public void delete(Long id) { - log.debug("Request to delete Role : {}", id); - roleRepository.deleteById(id); - } - - /** - * Get the predefined role authority from a RoleDTO. - * @param roleDto roleDto to parse - * @return role authority - * @throws BadRequestException if the roleauthority is not found or does not correctly - * specify an organization or project ID. - */ - public static RoleAuthority getRoleAuthority(RoleDTO roleDto) { - RoleAuthority authority; - try { - authority = RoleAuthority.valueOfAuthority(roleDto.getAuthorityName()); - } catch (IllegalArgumentException ex) { - throw new BadRequestException("Authority not found with " - + "authorityName", USER, ErrorConstants.ERR_INVALID_AUTHORITY, - Collections.singletonMap("authorityName", - roleDto.getAuthorityName())); - } - if (authority.getScope() == RoleAuthority.Scope.ORGANIZATION - && roleDto.getOrganizationId() == null) { - throw new BadRequestException("Authority with " - + "authorityName should have organization ID", - USER, ErrorConstants.ERR_INVALID_AUTHORITY, - Collections.singletonMap("authorityName", roleDto.getAuthorityName())); - } - if (authority.getScope() == RoleAuthority.Scope.PROJECT - && roleDto.getProjectId() == null) { - throw new BadRequestException("Authority with " - + "authorityName should have project ID", - USER, ErrorConstants.ERR_INVALID_AUTHORITY, - Collections.singletonMap("authorityName", roleDto.getAuthorityName())); - } - return authority; - } - - /** - * Get or create given global role. - * @param role to get or create - * @return role from database - */ - public Role getGlobalRole(RoleAuthority role) { - return roleRepository.findRolesByAuthorityName(role.getAuthority()).stream() - .findAny() - .orElseGet(() -> createNewRole(role, r -> { })); - } - - /** - * Get or create given organization role. - * @param role to get or create - * @param organizationId organization ID - * @return role from database - */ - public Role getOrganizationRole(RoleAuthority role, Long organizationId) { - return roleRepository.findOneByOrganizationIdAndAuthorityName( - organizationId, role.getAuthority()) - .orElseGet(() -> createNewRole(role, r -> { - r.setOrganization(organizationRepository.findById(organizationId) - .orElseThrow(() -> new NotFoundException( - "Cannot find organization for authority", - USER, ErrorConstants.ERR_INVALID_AUTHORITY, - Map.of("authorityName", role.getAuthority(), - "projectId", - organizationId.toString())))); - })); - } - - /** - * Get or create given project role. - * @param role to get or create - * @param projectId organization ID - * @return role from database - */ - public Role getProjectRole(RoleAuthority role, Long projectId) { - return roleRepository.findOneByProjectIdAndAuthorityName( - projectId, role.getAuthority()) - .orElseGet(() -> createNewRole(role, r -> { - r.setProject(projectRepository.findByIdWithOrganization(projectId) - .orElseThrow(() -> new NotFoundException( - "Cannot find project for authority", - USER, ErrorConstants.ERR_INVALID_AUTHORITY, - Map.of("authorityName", role.getAuthority(), - "projectId", - projectId.toString())))); - })); - } - - /** - * Get all roles related to a project. - * @param projectName the project name - * @return the roles - */ - public List getRolesByProject(String projectName) { - log.debug("Request to get all Roles for projectName " + projectName); - - return roleRepository.findAllRolesByProjectName(projectName).stream() - .map(roleMapper::roleToRoleDTO) - .toList(); - } - - private Authority getAuthority(RoleAuthority role) { - return authorityRepository.findByAuthorityName(role.getAuthority()) - .orElseGet(() -> authorityRepository.saveAndFlush(new Authority(role))); - } - - private Role createNewRole(RoleAuthority role, Consumer apply) { - Role newRole = new Role(); - newRole.setAuthority(getAuthority(role)); - apply.accept(newRole); - return roleRepository.save(newRole); - } - - /** - * Get the role related to the given project with the given authority name. - * @param projectName the project name - * @param authorityName the authority name - * @return an {@link Optional} containing the role if it exists, and empty otherwise - */ - public Optional findOneByProjectNameAndAuthorityName(String projectName, - String authorityName) { - log.debug("Request to get role of project {} and authority {}", projectName, authorityName); - return roleRepository.findOneByProjectNameAndAuthorityName(projectName, authorityName) - .map(roleMapper::roleToRoleDTO); - } -} diff --git a/src/main/java/org/radarbase/management/service/RoleService.kt b/src/main/java/org/radarbase/management/service/RoleService.kt new file mode 100644 index 000000000..c350c19ea --- /dev/null +++ b/src/main/java/org/radarbase/management/service/RoleService.kt @@ -0,0 +1,270 @@ +package org.radarbase.management.service + +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.auth.authorization.RoleAuthority.Companion.valueOfAuthority +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.Role +import org.radarbase.management.repository.AuthorityRepository +import org.radarbase.management.repository.OrganizationRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.RoleRepository +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.mapper.RoleMapper +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.util.* +import java.util.Map +import java.util.function.Consumer + +/** + * Service Implementation for managing Project. + */ +@Service +@Transactional +open class RoleService { + @Autowired + private val roleRepository: RoleRepository? = null + + @Autowired + private val authorityRepository: AuthorityRepository? = null + + @Autowired + private val organizationRepository: OrganizationRepository? = null + + @Autowired + private val projectRepository: ProjectRepository? = null + + @Autowired + private val roleMapper: RoleMapper? = null + + @Autowired + private val userService: UserService? = null + + /** + * Save a role. + * + * @param roleDto the entity to save + * @return the persisted entity + */ + fun save(roleDto: RoleDTO?): RoleDTO { + log.debug("Request to save Role : {}", roleDto) + var role = roleMapper!!.roleDTOToRole(roleDto) + role = roleRepository!!.save(role) + return roleMapper.roleToRoleDTO(role) + } + + /** + * Get the roles the currently authenticated user has access to. + * + * + * A system administrator has access to all the roles. A project administrator has access + * to the roles in their own project. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(): List { + val optUser = userService!!.userWithAuthorities + if (optUser.isEmpty) { + // return an empty list if we do not have a current user (e.g. with client credentials + // oauth2 grant) + return emptyList() + } + val currentUser = optUser.get() + val currentUserAuthorities: List? = currentUser.authorities?.map { auth -> auth?.name!! } + return if (currentUserAuthorities?.contains(RoleAuthority.SYS_ADMIN.authority) == true) { + log.debug("Request to get all Roles") + roleRepository!!.findAll().stream().map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }.toList() + } else (if (currentUserAuthorities?.contains(RoleAuthority.PROJECT_ADMIN.authority) == true) { + log.debug("Request to get project admin's project Projects") + currentUser.roles?.filter { role: Role? -> + (RoleAuthority.PROJECT_ADMIN.authority == role?.authority?.name) + }?.map { r: Role? -> r?.project?.projectName }?.distinct() + ?.flatMap { name: String? -> roleRepository!!.findAllRolesByProjectName(name) } + ?.map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }?.toList() + } else { + emptyList() + }) as List + } + + /** + * Get all Admin roles. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findSuperAdminRoles(): List { + log.debug("Request to get admin Roles") + return roleRepository?.findRolesByAuthorityName(RoleAuthority.SYS_ADMIN.authority) + ?.map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }?.toList()!! + } + + /** + * Get one role by id. + * + * @param id the id of the entity + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOne(id: Long): RoleDTO { + log.debug("Request to get Role : {}", id) + val role = roleRepository!!.findById(id).get() + return roleMapper!!.roleToRoleDTO(role) + } + + /** + * Delete the role by id. + * + * @param id the id of the entity + */ + fun delete(id: Long) { + log.debug("Request to delete Role : {}", id) + roleRepository!!.deleteById(id) + } + + /** + * Get or create given global role. + * @param role to get or create + * @return role from database + */ + fun getGlobalRole(role: RoleAuthority): Role { + return roleRepository!!.findRolesByAuthorityName(role.authority).stream().findAny() + .orElseGet { createNewRole(role) { r: Role? -> } } + } + + /** + * Get or create given organization role. + * @param role to get or create + * @param organizationId organization ID + * @return role from database + */ + fun getOrganizationRole(role: RoleAuthority, organizationId: Long): Role { + return roleRepository!!.findOneByOrganizationIdAndAuthorityName( + organizationId, role.authority + ).orElseGet { + createNewRole(role) { r: Role -> + r.organization = organizationRepository!!.findById(organizationId).orElseThrow { + NotFoundException( + "Cannot find organization for authority", + EntityName.USER, + ErrorConstants.ERR_INVALID_AUTHORITY, + Map.of( + "authorityName", role.authority, "projectId", organizationId.toString() + ) + ) + } + } + } + } + + /** + * Get or create given project role. + * @param role to get or create + * @param projectId organization ID + * @return role from database + */ + fun getProjectRole(role: RoleAuthority, projectId: Long): Role { + return roleRepository!!.findOneByProjectIdAndAuthorityName( + projectId, role.authority + ).orElseGet { + createNewRole(role) { r: Role -> + r.project = projectRepository!!.findByIdWithOrganization(projectId) ?: throw NotFoundException( + "Cannot find project for authority", + EntityName.USER, + ErrorConstants.ERR_INVALID_AUTHORITY, + Map.of( + "authorityName", role.authority, "projectId", projectId.toString() + ) + ) + } + } + } + + /** + * Get all roles related to a project. + * @param projectName the project name + * @return the roles + */ + fun getRolesByProject(projectName: String): List { + log.debug("Request to get all Roles for projectName $projectName") + return roleRepository!!.findAllRolesByProjectName(projectName).stream() + .map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }.toList() + } + + private fun getAuthority(role: RoleAuthority): Authority { + return authorityRepository!!.findByAuthorityName(role.authority) + .orElseGet { authorityRepository.saveAndFlush(Authority(role)) } + } + + private fun createNewRole(role: RoleAuthority, apply: Consumer): Role { + val newRole = Role() + newRole.authority = getAuthority(role) + apply.accept(newRole) + return roleRepository!!.save(newRole) + } + + /** + * Get the role related to the given project with the given authority name. + * @param projectName the project name + * @param authorityName the authority name + * @return an [Optional] containing the role if it exists, and empty otherwise + */ + fun findOneByProjectNameAndAuthorityName( + projectName: String?, authorityName: String? + ): Optional { + log.debug("Request to get role of project {} and authority {}", projectName, authorityName) + return roleRepository!!.findOneByProjectNameAndAuthorityName(projectName, authorityName) + .map { role: Role? -> roleMapper!!.roleToRoleDTO(role) } + } + + companion object { + private val log = LoggerFactory.getLogger(RoleService::class.java) + + /** + * Get the predefined role authority from a RoleDTO. + * @param roleDto roleDto to parse + * @return role authority + * @throws BadRequestException if the roleauthority is not found or does not correctly + * specify an organization or project ID. + */ + @JvmStatic + fun getRoleAuthority(roleDto: RoleDTO): RoleAuthority { + val authority: RoleAuthority + authority = try { + valueOfAuthority(roleDto.authorityName) + } catch (ex: IllegalArgumentException) { + throw BadRequestException( + "Authority not found with " + "authorityName", + EntityName.USER, + ErrorConstants.ERR_INVALID_AUTHORITY, + Collections.singletonMap( + "authorityName", roleDto.authorityName + ) + ) + } + if (authority.scope === RoleAuthority.Scope.ORGANIZATION && roleDto.organizationId == null) { + throw BadRequestException( + "Authority with " + "authorityName should have organization ID", + EntityName.USER, + ErrorConstants.ERR_INVALID_AUTHORITY, + Collections.singletonMap("authorityName", roleDto.authorityName) + ) + } + if (authority.scope === RoleAuthority.Scope.PROJECT && roleDto.projectId == null) { + throw BadRequestException( + "Authority with " + "authorityName should have project ID", + EntityName.USER, + ErrorConstants.ERR_INVALID_AUTHORITY, + Collections.singletonMap("authorityName", roleDto.authorityName) + ) + } + return authority + } + } +} diff --git a/src/main/java/org/radarbase/management/service/SourceService.java b/src/main/java/org/radarbase/management/service/SourceService.java deleted file mode 100644 index a63fe32ca..000000000 --- a/src/main/java/org/radarbase/management/service/SourceService.java +++ /dev/null @@ -1,261 +0,0 @@ -package org.radarbase.management.service; - - -import org.radarbase.management.domain.Source; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.SourceRepository; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.mapper.SourceMapper; -import org.radarbase.management.service.mapper.SourceTypeMapper; -import org.radarbase.management.web.rest.errors.InvalidRequestException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.history.Revision; -import org.springframework.data.history.Revisions; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - -import static org.hibernate.id.IdentifierGenerator.ENTITY_NAME; -import static org.radarbase.auth.authorization.Permission.SOURCE_UPDATE; -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE; - -/** - * Service Implementation for managing Source. - */ -@Service -@Transactional -public class SourceService { - - private static final Logger log = LoggerFactory.getLogger(SourceService.class); - - @Autowired - private SourceRepository sourceRepository; - - @Autowired - private SourceMapper sourceMapper; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private SourceTypeMapper sourceTypeMapper; - @Autowired - private AuthService authService; - - /** - * Save a Source. - * - * @param sourceDto the entity to save - * @return the persisted entity - */ - public SourceDTO save(SourceDTO sourceDto) { - log.debug("Request to save Source : {}", sourceDto); - Source source = sourceMapper.sourceDTOToSource(sourceDto); - source = sourceRepository.save(source); - return sourceMapper.sourceToSourceDTO(source); - } - - /** - * Get all the Sources. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public List findAll() { - return sourceRepository - .findAll() - .stream() - .map(sourceMapper::sourceToSourceDTO) - .toList(); - } - - /** - * Get all the sourceData with pagination. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public Page findAll(Pageable pageable) { - log.debug("Request to get SourceData with pagination"); - return sourceRepository - .findAll(pageable) - .map(sourceMapper::sourceToSourceDTO); - } - - /** - * Get one source by name. - * - * @param sourceName the name of the source - * @return the entity - */ - @Transactional(readOnly = true) - public Optional findOneByName(String sourceName) { - log.debug("Request to get Source : {}", sourceName); - return sourceRepository.findOneBySourceName(sourceName) - .map(sourceMapper::sourceToSourceDTO); - } - - /** - * Get one source by id. - * - * @param id the id of the source - * @return the entity - */ - @Transactional(readOnly = true) - public Optional findOneById(Long id) { - log.debug("Request to get Source by id: {}", id); - return Optional.ofNullable(sourceRepository.findById(id).orElse(null)) - .map(sourceMapper::sourceToSourceDTO); - } - - /** - * Delete the device by id. - * - * @param id the id of the entity - */ - @Transactional - public void delete(Long id) { - log.info("Request to delete Source : {}", id); - Revisions sourceHistory = sourceRepository.findRevisions(id); - List sources = sourceHistory.getContent().stream() - .map(Revision::getEntity) - .filter(Source::isAssigned) - .toList(); - if (sources.isEmpty()) { - sourceRepository.deleteById(id); - } else { - Map errorParams = new HashMap<>(); - errorParams.put("message", "Cannot delete source with sourceId "); - errorParams.put("id", Long.toString(id)); - throw new InvalidRequestException("Cannot delete a source that was once assigned.", - SOURCE, "error.usedSourceDeletion", errorParams); - } - } - - /** - * Returns all sources by project in {@link SourceDTO} format. - * - * @return list of sources - */ - public Page findAllByProjectId(Long projectId, Pageable pageable) { - return sourceRepository.findAllSourcesByProjectId(pageable, projectId) - .map(sourceMapper::sourceToSourceWithoutProjectDTO); - } - - /** - * Returns all sources by project in {@link MinimalSourceDetailsDTO} format. - * - * @return list of sources - */ - public Page findAllMinimalSourceDetailsByProject(Long projectId, - Pageable pageable) { - return sourceRepository.findAllSourcesByProjectId(pageable, projectId) - .map(sourceMapper::sourceToMinimalSourceDetailsDTO); - } - - /** - * Returns list of not-assigned sources by project id. - */ - public List findAllByProjectAndAssigned(Long projectId, boolean assigned) { - return sourceMapper.sourcesToSourceDTOs( - sourceRepository.findAllSourcesByProjectIdAndAssigned(projectId, assigned)); - } - - /** - * Returns list of not-assigned sources by project id. - */ - public List findAllMinimalSourceDetailsByProjectAndAssigned( - Long projectId, boolean assigned) { - return sourceRepository - .findAllSourcesByProjectIdAndAssigned(projectId, assigned) - .stream() - .map(sourceMapper::sourceToMinimalSourceDetailsDTO) - .toList(); - } - - /** - * This method does a safe update of source assigned to a subject. It will allow updates of - * attributes only. - * - * @param sourceToUpdate source fetched from database - * @param attributes value to update - * @return Updated {@link MinimalSourceDetailsDTO} of source - */ - public MinimalSourceDetailsDTO safeUpdateOfAttributes(Source sourceToUpdate, - Map attributes) { - - // update source attributes - Map updatedAttributes = new HashMap<>(); - updatedAttributes.putAll(sourceToUpdate.getAttributes()); - updatedAttributes.putAll(attributes); - - sourceToUpdate.setAttributes(updatedAttributes); - // rest of the properties should not be updated from this request. - return sourceMapper.sourceToMinimalSourceDetailsDTO(sourceRepository.save(sourceToUpdate)); - } - - /** - * Updates a source. - * Does not allow to transfer a source, if it is currently assigned. - * Does not allow to transfer if new project does not have valid source-type. - * - * @param sourceDto source details to update. - * @return updated source. - */ - @Transactional - public Optional updateSource(SourceDTO sourceDto) - throws NotAuthorizedException { - Optional existingSourceOpt = sourceRepository.findById(sourceDto.getId()); - if (existingSourceOpt.isEmpty()) { - return Optional.empty(); - } - Source existingSource = existingSourceOpt.get(); - authService.checkPermission(SOURCE_UPDATE, e -> { - e.source(existingSource.getSourceName()); - if (existingSource.getProject() != null) { - e.project(existingSource.getProject().getProjectName()); - } - if (existingSource.getSubject() != null - && existingSource.getSubject().getUser() != null) { - e.subject(existingSource.getSubject().getUser().getLogin()); - } - }); - - // if the source is being transferred to another project. - if (!existingSource.getProject().getId().equals(sourceDto.getProject().getId())) { - if (existingSource.isAssigned()) { - throw new InvalidRequestException("Cannot transfer an assigned source", SOURCE, - "error.sourceIsAssigned"); - } - - // check whether source-type of the device is assigned to the new project - // to be transferred. - Optional sourceType = projectRepository - .findSourceTypeByProjectIdAndSourceTypeId(sourceDto.getProject().getId(), - existingSource.getSourceType().getId()); - - if (sourceType.isEmpty()) { - throw new InvalidRequestException( - "Cannot transfer a source to a project which doesn't have compatible " - + "source-type", ENTITY_NAME, "error.invalidTransfer"); - } - // set old source-type, ensures compatibility - sourceDto.setSourceType( - sourceTypeMapper.sourceTypeToSourceTypeDTO(existingSource.getSourceType())); - - } - - return Optional.of(save(sourceDto)); - } -} diff --git a/src/main/java/org/radarbase/management/service/SourceService.kt b/src/main/java/org/radarbase/management/service/SourceService.kt new file mode 100644 index 000000000..a470c0393 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/SourceService.kt @@ -0,0 +1,267 @@ +package org.radarbase.management.service + +import org.hibernate.id.IdentifierGenerator +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.Source +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.SourceRepository +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.SourceDTO +import org.radarbase.management.service.mapper.SourceMapper +import org.radarbase.management.service.mapper.SourceTypeMapper +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.InvalidRequestException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.history.Revision +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.util.* + +/** + * Service Implementation for managing Source. + */ +@Service +@Transactional +open class SourceService { + @Autowired + private val sourceRepository: SourceRepository? = null + + @Autowired + private val sourceMapper: SourceMapper? = null + + @Autowired + private val projectRepository: ProjectRepository? = null + + @Autowired + private val sourceTypeMapper: SourceTypeMapper? = null + + @Autowired + private val authService: AuthService? = null + + /** + * Save a Source. + * + * @param sourceDto the entity to save + * @return the persisted entity + */ + fun save(sourceDto: SourceDTO?): SourceDTO { + log.debug("Request to save Source : {}", sourceDto) + var source = sourceMapper!!.sourceDTOToSource(sourceDto) + source = sourceRepository!!.save(source) + return sourceMapper.sourceToSourceDTO(source) + } + + /** + * Get all the Sources. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(): List? { + return sourceRepository + ?.findAll() + ?.stream() + ?.map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + ?.toList() + } + + /** + * Get all the sourceData with pagination. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(pageable: Pageable?): Page? { + log.debug("Request to get SourceData with pagination") + return pageable?.let { + sourceRepository + ?.findAll(it) + ?.map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + } + } + + /** + * Get one source by name. + * + * @param sourceName the name of the source + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOneByName(sourceName: String?): Optional { + log.debug("Request to get Source : {}", sourceName) + return sourceRepository!!.findOneBySourceName(sourceName) + .map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + } + + /** + * Get one source by id. + * + * @param id the id of the source + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOneById(id: Long): Optional { + log.debug("Request to get Source by id: {}", id) + return Optional.ofNullable(sourceRepository!!.findById(id).orElse(null)) + .map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + } + + /** + * Delete the device by id. + * + * @param id the id of the entity + */ + @Transactional + open fun delete(id: Long) { + log.info("Request to delete Source : {}", id) + val sourceHistory = sourceRepository!!.findRevisions(id) + val sources = sourceHistory.content + .map { obj: Revision -> obj.entity } + .filter{ it.isAssigned + ?: false } + .toList() + if (sources.isEmpty()) { + sourceRepository.deleteById(id) + } else { + val errorParams: MutableMap = HashMap() + errorParams["message"] = "Cannot delete source with sourceId " + errorParams["id"] = id.toString() + throw InvalidRequestException( + "Cannot delete a source that was once assigned.", + EntityName.SOURCE, "error.usedSourceDeletion", errorParams + ) + } + } + + /** + * Returns all sources by project in [SourceDTO] format. + * + * @return list of sources + */ + fun findAllByProjectId(projectId: Long?, pageable: Pageable?): Page { + return sourceRepository!!.findAllSourcesByProjectId(pageable, projectId) + .map { source: Source? -> sourceMapper!!.sourceToSourceWithoutProjectDTO(source) } + } + + /** + * Returns all sources by project in [MinimalSourceDetailsDTO] format. + * + * @return list of sources + */ + fun findAllMinimalSourceDetailsByProject( + projectId: Long?, + pageable: Pageable? + ): Page { + return sourceRepository!!.findAllSourcesByProjectId(pageable, projectId) + .map { source: Source? -> sourceMapper!!.sourceToMinimalSourceDetailsDTO(source) } + } + + /** + * Returns list of not-assigned sources by project id. + */ + fun findAllByProjectAndAssigned(projectId: Long?, assigned: Boolean): List { + return sourceMapper!!.sourcesToSourceDTOs( + sourceRepository!!.findAllSourcesByProjectIdAndAssigned(projectId, assigned) + ) + } + + /** + * Returns list of not-assigned sources by project id. + */ + fun findAllMinimalSourceDetailsByProjectAndAssigned( + projectId: Long?, assigned: Boolean + ): List { + return sourceRepository + ?.findAllSourcesByProjectIdAndAssigned(projectId, assigned) + ?.map { source -> sourceMapper!!.sourceToMinimalSourceDetailsDTO(source) } + ?.toList() + ?: listOf() + } + + /** + * This method does a safe update of source assigned to a subject. It will allow updates of + * attributes only. + * + * @param sourceToUpdate source fetched from database + * @param attributes value to update + * @return Updated [MinimalSourceDetailsDTO] of source + */ + fun safeUpdateOfAttributes( + sourceToUpdate: Source, + attributes: Map? + ): MinimalSourceDetailsDTO { + + // update source attributes + val updatedAttributes: MutableMap = HashMap() + updatedAttributes.putAll(sourceToUpdate.attributes) + updatedAttributes.putAll(attributes!!) + sourceToUpdate.attributes = updatedAttributes + // rest of the properties should not be updated from this request. + return sourceMapper!!.sourceToMinimalSourceDetailsDTO(sourceRepository!!.save(sourceToUpdate)) + } + + /** + * Updates a source. + * Does not allow to transfer a source, if it is currently assigned. + * Does not allow to transfer if new project does not have valid source-type. + * + * @param sourceDto source details to update. + * @return updated source. + */ + @Transactional + @Throws(NotAuthorizedException::class) + open fun updateSource(sourceDto: SourceDTO): Optional { + val existingSourceOpt = sourceRepository!!.findById(sourceDto.id) + if (existingSourceOpt.isEmpty) { + return Optional.empty() + } + val existingSource = existingSourceOpt.get() + authService!!.checkPermission(Permission.SOURCE_UPDATE, { (_, project, subject, _, source): EntityDetails -> + source + if (existingSource.project != null) { + project + } + if (existingSource.subject != null + && existingSource.subject!!.user != null + ) { + subject + } + }) + + // if the source is being transferred to another project. + if (existingSource.project!!.id != sourceDto.project.id) { + if (existingSource.isAssigned!!) { + throw InvalidRequestException( + "Cannot transfer an assigned source", EntityName.SOURCE, + "error.sourceIsAssigned" + ) + } + + // check whether source-type of the device is assigned to the new project + // to be transferred. + val sourceType = projectRepository + ?.findSourceTypeByProjectIdAndSourceTypeId( + sourceDto.project.id, + existingSource.sourceType!!.id + ) + if (sourceType!!.isEmpty) { + throw InvalidRequestException( + "Cannot transfer a source to a project which doesn't have compatible " + + "source-type", IdentifierGenerator.ENTITY_NAME, "error.invalidTransfer" + ) + } + // set old source-type, ensures compatibility + sourceDto.sourceType = sourceTypeMapper!!.sourceTypeToSourceTypeDTO(existingSource.sourceType) + } + return Optional.of(save(sourceDto)) + } + + companion object { + private val log = LoggerFactory.getLogger(SourceService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/service/SourceTypeService.java b/src/main/java/org/radarbase/management/service/SourceTypeService.java index 655c27fde..7cdc9d44a 100644 --- a/src/main/java/org/radarbase/management/service/SourceTypeService.java +++ b/src/main/java/org/radarbase/management/service/SourceTypeService.java @@ -65,11 +65,11 @@ public SourceTypeDTO save(SourceTypeDTO sourceTypeDto) { log.debug("Request to save SourceType : {}", sourceTypeDto); SourceType sourceType = sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDto); // populate the SourceType of our SourceData's - for (SourceData data : sourceType.getSourceData()) { - data.setSourceType(sourceType); + for (SourceData data : sourceType.sourceData) { + data.sourceType = sourceType; } sourceType = sourceTypeRepository.save(sourceType); - sourceDataRepository.saveAll(sourceType.getSourceData()); + sourceDataRepository.saveAll(sourceType.sourceData); return sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); } @@ -179,12 +179,12 @@ public void saveSourceTypesFromCatalogServer(List catalogSour // check whether a source-type is already available with given config if (sourceTypeRepository.hasOneByProducerAndModelAndVersion( - sourceType.getProducer(), sourceType.getModel(), - sourceType.getCatalogVersion())) { + sourceType.producer, sourceType.model, + sourceType.catalogVersion)) { // skip for existing source-types - log.info("Source-type {} is already available ", sourceType.getProducer() - + "_" + sourceType.getModel() - + "_" + sourceType.getCatalogVersion()); + log.info("Source-type {} is already available ", sourceType.producer + + "_" + sourceType.model + + "_" + sourceType.catalogVersion); } else { try { // create new source-type @@ -208,10 +208,10 @@ private void saveSourceData(SourceType sourceType, CatalogSourceData catalogSour .catalogSourceDataToSourceData(catalogSourceData); // sourceDataName should be unique // generated by combining sourceDataType and source-type configs - sourceData.sourceDataName(sourceType.getProducer() - + "_" + sourceType.getModel() - + "_" + sourceType.getCatalogVersion() - + "_" + sourceData.getSourceDataType()); + sourceData.sourceDataName(sourceType.producer + + "_" + sourceType.model + + "_" + sourceType.catalogVersion + + "_" + sourceData.sourceDataType); sourceData.sourceType(sourceType); sourceDataRepository.save(sourceData); } catch (RuntimeException ex) { @@ -220,21 +220,21 @@ private void saveSourceData(SourceType sourceType, CatalogSourceData catalogSour } private static boolean isSourceTypeValid(SourceType sourceType) { - if (sourceType.getProducer() == null) { + if (sourceType.producer == null) { log.warn("Catalog source-type {} does not have a vendor. " - + "Skipping importing this type", sourceType.getName()); + + "Skipping importing this type", sourceType.name); return false; } - if (sourceType.getModel() == null) { + if (sourceType.model == null) { log.warn("Catalog source-type {} does not have a model. " - + "Skipping importing this type", sourceType.getName()); + + "Skipping importing this type", sourceType.name); return false; } - if (sourceType.getCatalogVersion() == null) { + if (sourceType.catalogVersion == null) { log.warn("Catalog source-type {} does not have a version. " - + "Skipping importing this type", sourceType.getName()); + + "Skipping importing this type", sourceType.name); return false; } return true; diff --git a/src/main/java/org/radarbase/management/service/SubjectService.java b/src/main/java/org/radarbase/management/service/SubjectService.java deleted file mode 100644 index 6339760c3..000000000 --- a/src/main/java/org/radarbase/management/service/SubjectService.java +++ /dev/null @@ -1,546 +0,0 @@ -package org.radarbase.management.service; - -import org.hibernate.envers.query.AuditEntity; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.Group; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.Source; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.AuthorityRepository; -import org.radarbase.management.repository.GroupRepository; -import org.radarbase.management.repository.RoleRepository; -import org.radarbase.management.repository.SourceRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.repository.filters.SubjectSpecification; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.service.mapper.SourceMapper; -import org.radarbase.management.service.mapper.SubjectMapper; -import org.radarbase.management.web.rest.criteria.SubjectCriteria; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ConflictException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.InvalidStateException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.history.Revisions; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.annotation.Nonnull; -import java.net.MalformedURLException; -import java.net.URL; -import java.time.ZonedDateTime; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.radarbase.auth.authorization.Permission.SUBJECT_READ; -import static org.radarbase.auth.authorization.RoleAuthority.INACTIVE_PARTICIPANT; -import static org.radarbase.auth.authorization.RoleAuthority.PARTICIPANT; -import static org.radarbase.management.service.dto.ProjectDTO.PRIVACY_POLICY_URL; -import static org.radarbase.management.web.rest.errors.EntityName.GROUP; -import static org.radarbase.management.web.rest.errors.EntityName.OAUTH_CLIENT; -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE_TYPE; -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_GROUP_NOT_FOUND; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_NO_VALID_PRIVACY_POLICY_URL_CONFIGURED; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SOURCE_NOT_FOUND; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SUBJECT_NOT_FOUND; - -/** - * Created by nivethika on 26-5-17. - */ -@Service -@Transactional -public class SubjectService { - - private static final Logger log = LoggerFactory.getLogger(SubjectService.class); - - @Autowired - private SubjectMapper subjectMapper; - - @Autowired - private ProjectMapper projectMapper; - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private SourceRepository sourceRepository; - - @Autowired - private SourceMapper sourceMapper; - - @Autowired - private RoleRepository roleRepository; - - @Autowired - private GroupRepository groupRepository; - - @Autowired - private RevisionService revisionService; - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Autowired - private PasswordService passwordService; - - @Autowired - private AuthorityRepository authorityRepository; - - @Autowired - private AuthService authService; - - /** - * Create a new subject. - * - * @param subjectDto the subject information - * @return the newly created subject - */ - @Transactional - public SubjectDTO createSubject(SubjectDTO subjectDto) { - Subject subject = subjectMapper.subjectDTOToSubject(subjectDto); - //assign roles - User user = subject.getUser(); - Project project = projectMapper.projectDTOToProject(subjectDto.getProject()); - Role projectParticipantRole = getProjectParticipantRole(project, PARTICIPANT); - Set roles = user.getRoles(); - roles.add(projectParticipantRole); - - // Set group - subject.setGroup(getSubjectGroup(project, subjectDto.getGroup())); - - // set password and reset keys - user.setPassword(passwordService.generateEncodedPassword()); - user.setResetKey(passwordService.generateResetKey()); - // setting default language key to "en", required to set email context, Find a workaround - user.setLangKey("en"); - user.setResetDate(ZonedDateTime.now()); - // default subject is activated. - user.setActivated(true); - //set if any devices are set as assigned - if (subject.getSources() != null && !subject.getSources().isEmpty()) { - subject.getSources().forEach(s -> s.assigned(true).subject(subject)); - } - if (subject.getEnrollmentDate() == null) { - subject.setEnrollmentDate(ZonedDateTime.now()); - } - sourceRepository.saveAll(subject.getSources()); - return subjectMapper.subjectToSubjectReducedProjectDTO(subjectRepository.save(subject)); - } - - private Group getSubjectGroup(Project project, String groupName) { - if (project == null || groupName == null) { - return null; - } - return groupRepository.findByProjectIdAndName(project.getId(), groupName) - .orElseThrow(() -> new BadRequestException( - "Group " + groupName + " does not exist in project " - + project.getProjectName(), - GROUP, - ERR_GROUP_NOT_FOUND) - ); - } - - /** - * Fetch Participant role of the project if available, otherwise create a new Role and assign. - * - * @param project project subject is assigned to - * @return relevant Participant role - * @throws java.util.NoSuchElementException if the authority name is not in the database - */ - private Role getProjectParticipantRole(Project project, RoleAuthority authority) { - return roleRepository.findOneByProjectIdAndAuthorityName(project.getId(), - authority.getAuthority()) - .orElseGet(() -> { - Role subjectRole = new Role(); - Authority auth = authorityRepository.findByAuthorityName( - authority.getAuthority()) - .orElseGet(() -> authorityRepository.save(new Authority(authority))); - subjectRole.setAuthority(auth); - subjectRole.setProject(project); - return roleRepository.save(subjectRole); - }); - } - - - /** - * Update a subject's information. - * - * @param newSubjectDto the new subject information - * @return the updated subject - */ - @Transactional - public SubjectDTO updateSubject(SubjectDTO newSubjectDto) { - if (newSubjectDto.getId() == null) { - return createSubject(newSubjectDto); - } - Subject subjectFromDb = ensureSubject(newSubjectDto); - Set sourcesToUpdate = subjectFromDb.getSources(); - //set only the devices assigned to a subject as assigned - subjectMapper.safeUpdateSubjectFromDTO(newSubjectDto, subjectFromDb); - sourcesToUpdate.addAll(subjectFromDb.getSources()); - subjectFromDb.getSources() - .forEach(s -> s.subject(subjectFromDb).assigned(true)); - sourceRepository.saveAll(sourcesToUpdate); - // update participant role - subjectFromDb.getUser().setRoles(updateParticipantRoles(subjectFromDb, newSubjectDto)); - // Set group - subjectFromDb.setGroup(getSubjectGroup( - subjectFromDb.getActiveProject().orElse(null), - newSubjectDto.getGroup())); - return subjectMapper.subjectToSubjectReducedProjectDTO( - subjectRepository.save(subjectFromDb)); - } - - private Set updateParticipantRoles(Subject subject, SubjectDTO subjectDto) { - if (subjectDto.getProject() == null || subjectDto.getProject().getProjectName() == null) { - return subject.getUser().getRoles(); - } - - Stream existingRoles = subject.getUser().getRoles().stream() - .map(role -> { - // make participant inactive in projects that do not match the new project - if (role.getAuthority().getName().equals(PARTICIPANT.getAuthority()) - && !role.getProject().getProjectName().equals( - subjectDto.getProject().getProjectName())) { - return getProjectParticipantRole(role.getProject(), INACTIVE_PARTICIPANT); - } else { - // do not modify other roles. - return role; - } - }); - - // Ensure that given project is present - Stream newProjectRole = Stream.of(getProjectParticipantRole( - projectMapper.projectDTOToProject(subjectDto.getProject()), PARTICIPANT)); - - return Stream.concat(existingRoles, newProjectRole) - .collect(Collectors.toSet()); - } - - /** - * Discontinue the given subject. - * - *

A discontinued subject is not deleted from the database, but will be prevented from - * logging into the system, sending data, or otherwise interacting with the system.

- * - * @param subjectDto the subject to discontinue - * @return the discontinued subject - */ - public SubjectDTO discontinueSubject(SubjectDTO subjectDto) { - Subject subject = ensureSubject(subjectDto); - // reset all the sources assigned to a subject to unassigned - unassignAllSources(subject); - - // set the removed flag and deactivate the user to prevent them from refreshing their - // access token - subject.setRemoved(true); - subject.getUser().setActivated(false); - return subjectMapper.subjectToSubjectReducedProjectDTO(subjectRepository.save(subject)); - } - - private Subject ensureSubject(SubjectDTO subjectDto) { - return subjectRepository.findById(subjectDto.getId()) - .orElseThrow(() -> new NotFoundException( - "Subject with ID " + subjectDto.getId() + " not found.", - SUBJECT, ERR_SUBJECT_NOT_FOUND)); - } - - /** - * Unassign all sources from a subject. This method saves the unassigned sources, but does NOT - * save the subject in question. This is the responsibility of the caller. - * - * @param subject The subject for which to unassign all sources - */ - private void unassignAllSources(Subject subject) { - subject.getSources().forEach(source -> { - source.setAssigned(false); - source.setSubject(null); - source.setDeleted(true); - sourceRepository.save(source); - }); - subject.getSources().clear(); - } - - /** - * Creates or updates a source for a subject. It creates and assigns a source of a for a - * dynamicallyRegister-able sourceType. Currently, it is allowed to create only once source of a - * dynamicallyRegistrable sourceType per subject. Otherwise finds the matching source and - * updates meta-data. - */ - @Transactional - public MinimalSourceDetailsDTO assignOrUpdateSource(Subject subject, SourceType sourceType, - Project project, MinimalSourceDetailsDTO sourceRegistrationDto) { - Source assignedSource; - - if (sourceRegistrationDto.getSourceId() != null) { - // update meta-data and source-name for existing sources - assignedSource = updateSourceAssignedSubject(subject, sourceRegistrationDto); - - } else if (sourceType.getCanRegisterDynamically()) { - List sources = subjectRepository - .findSubjectSourcesBySourceType(subject.getUser().getLogin(), - sourceType.getProducer(), sourceType.getModel(), - sourceType.getCatalogVersion()); - // create a source and register meta data - // we allow only one source of a source-type per subject - if (sources.isEmpty()) { - Source source = new Source(sourceType) - .project(project) - .assigned(true) - .sourceType(sourceType) - .subject(subject); - source.getAttributes().putAll(sourceRegistrationDto.getAttributes()); - // if source name is provided update source name - if (sourceRegistrationDto.getSourceName() != null) { - // append the auto generated source-name to given source-name to avoid conflicts - source.setSourceName( - sourceRegistrationDto.getSourceName() + "_" + source.getSourceName()); - } - // make sure there is no source available on the same name. - if (sourceRepository.findOneBySourceName(source.getSourceName()).isPresent()) { - throw new ConflictException("SourceName already in use. Cannot create a " - + "source with existing source-name ", SUBJECT, - ErrorConstants.ERR_SOURCE_NAME_EXISTS, - Collections.singletonMap("source-name", source.getSourceName())); - } - source = sourceRepository.save(source); - - assignedSource = source; - subject.getSources().add(source); - } else { - throw new ConflictException( - "A Source of SourceType with the specified producer, model and version" - + " was already registered for subject login", - SUBJECT, ErrorConstants.ERR_SOURCE_TYPE_EXISTS, - sourceTypeAttributes(sourceType, subject)); - } - } else { - // new source since sourceId == null, but canRegisterDynamically == false - throw new BadRequestException("The source type is not eligible for dynamic " - + "registration", SOURCE_TYPE, "error.InvalidDynamicSourceRegistration", - sourceTypeAttributes(sourceType, subject)); - } - - subjectRepository.save(subject); - return sourceMapper.sourceToMinimalSourceDetailsDTO(assignedSource); - } - - private static Map sourceTypeAttributes(SourceType sourceType, - Subject subject) { - Map errorParams = new HashMap<>(); - errorParams.put("producer", sourceType.getProducer()); - errorParams.put("model", sourceType.getModel()); - errorParams.put("catalogVersion", sourceType.getCatalogVersion()); - errorParams.put("userId", subject.getUser().getLogin()); - return errorParams; - } - - /** - * Updates source name and attributes of the source assigned to subject. Otherwise returns - * {@link NotFoundException}. - * @param subject subject - * @param sourceRegistrationDto details of source which need to be updated. - * @return Updated {@link Source} instance. - */ - private Source updateSourceAssignedSubject(Subject subject, - MinimalSourceDetailsDTO sourceRegistrationDto) { - // for manually registered devices only add meta-data - Source source = subjectRepository.findSubjectSourcesBySourceId( - subject.getUser().getLogin(), sourceRegistrationDto.getSourceId()) - .orElseThrow(() -> { - Map errorParams = new HashMap<>(); - errorParams.put("sourceId", sourceRegistrationDto.getSourceId().toString()); - errorParams.put("subject-login", subject.getUser().getLogin()); - return new NotFoundException( "No source with source-id to assigned to the " - + "subject with subject-login", SUBJECT, ERR_SOURCE_NOT_FOUND, - errorParams); - }); - - if (sourceRegistrationDto.getSourceName() != null) { - source.setSourceName(sourceRegistrationDto.getSourceName()); - } - source.getAttributes().putAll(sourceRegistrationDto.getAttributes()); - source.setAssigned(true); - source.setSubject(subject); - - return sourceRepository.save(source); - } - - /** - * Gets all sources assigned to the subject identified by :login. - * - * @return list of sources - */ - public List getSources(Subject subject) { - List sources = subjectRepository.findSourcesBySubjectLogin(subject.getUser() - .getLogin()); - - return sourceMapper.sourcesToMinimalSourceDetailsDTOs(sources); - } - - /** - * Delete the subject with the given login from the database. - * - * @param login the login - */ - public void deleteSubject(String login) { - subjectRepository.findOneWithEagerBySubjectLogin(login).ifPresent(subject -> { - unassignAllSources(subject); - subjectRepository.delete(subject); - log.debug("Deleted Subject: {}", subject); - }); - } - - /** - * Finds all sources of subject including inactive sources. - * - * @param subject of whom the sources should be retrieved. - * @return list of {@link MinimalSourceDetailsDTO} of sources. - */ - public List findSubjectSourcesFromRevisions(Subject subject) { - Revisions revisions = subjectRepository.findRevisions(subject.getId()); - // collect distinct sources in a set - Set sources = revisions - .getContent().stream().flatMap(p -> p.getEntity().getSources().stream()) - .filter(distinctByKey(Source::getSourceId)) - .collect(Collectors.toSet()); - return sources.stream().map(p -> sourceMapper.sourceToMinimalSourceDetailsDTO(p)) - .toList(); - } - - /** - * Get a specific revision for a given subject. - * - * @param login the login of the subject - * @param revision the revision number - * @return the subject at the given revision - * @throws NotFoundException if there was no subject with the given login at the given - * revision number - */ - public SubjectDTO findRevision(String login, Integer revision) - throws NotFoundException, NotAuthorizedException { - // first get latest known version of the subject, if it's deleted we can't load the entity - // directly by e.g. findOneByLogin - SubjectDTO latest = getLatestRevision(login); - authService.checkPermission(SUBJECT_READ, e -> e - .project(latest.getProject().getProjectName()) - .subject(latest.getLogin())); - SubjectDTO sub = revisionService - .findRevision(revision, latest.getId(), Subject.class, - subjectMapper::subjectToSubjectReducedProjectDTO); - - if (sub == null) { - throw new NotFoundException("subject not found for given login and revision.", SUBJECT, - ERR_SUBJECT_NOT_FOUND, Collections.singletonMap("subjectLogin", login)); - } - return sub; - } - - /** - * Get latest known revision of a subject with the given login. - * - * @param login the login of the subject - * @return the latest revision for that subject - * @throws NotFoundException if no subject was found with the given login - */ - public SubjectDTO getLatestRevision(String login) throws NotFoundException { - UserDTO user = (UserDTO) revisionService.getLatestRevisionForEntity(User.class, - List.of(AuditEntity.property("login").eq(login))) - .orElseThrow(() -> new NotFoundException("Subject latest revision not found " - + "for login" , SUBJECT, ERR_SUBJECT_NOT_FOUND, - Collections.singletonMap("subjectLogin", login))); - return (SubjectDTO) revisionService.getLatestRevisionForEntity(Subject.class, - List.of(AuditEntity.property("user").eq(user))) - .orElseThrow(() -> new NotFoundException("Subject latest revision not found " - + "for login" , SUBJECT, ERR_SUBJECT_NOT_FOUND, - Collections.singletonMap("subjectLogin", login))); - } - - private static Predicate distinctByKey(Function keyExtractor) { - final Set seen = new HashSet<>(); - return t -> seen.add(keyExtractor.apply(t)); - } - - - /** - * Finds {@link Subject} from databased from login provided. - * @param login of subject to look for. - * @return {@link Subject} loaded. - */ - @Nonnull - public Subject findOneByLogin(String login) { - Optional subject = subjectRepository.findOneWithEagerBySubjectLogin(login); - return subject.orElseThrow(() -> - new NotFoundException("Subject not found with login", SUBJECT, - ERR_SUBJECT_NOT_FOUND) - ); - } - - /** - * Find all subjects matching given filter. - * @param criteria filter and sort for subjects. - * @return page of subjects matching filter. - */ - public Page findAll(SubjectCriteria criteria) { - // Pageable is required to set the page limit, - // but the page should always be zero - // since the lastLoadedId param defines the offset - // within the query specification - return subjectRepository.findAll(new SubjectSpecification(criteria), - criteria.getPageable()); - } - - /** - * Gets relevant privacy-policy-url for this subject. - *

- * If the active project of the subject has a valid privacy-policy-url returns that url. - * Otherwise, it loads the default URL from ManagementPortal configurations that is - * general. - *

- * @param subject to get relevant policy url - * @return URL of privacy policy for this token - */ - protected URL getPrivacyPolicyUrl(Subject subject) { - - // load default url from config - String policyUrl = subject.getActiveProject() - .map(p -> p.getAttributes().get(PRIVACY_POLICY_URL)) - .filter(u -> !u.isEmpty()) - .orElse(managementPortalProperties.getCommon().getPrivacyPolicyUrl()); - - try { - return new URL(policyUrl); - } catch (MalformedURLException e) { - Map params = new HashMap<>(); - params.put("url" , policyUrl); - params.put("message" , e.getMessage()); - throw new InvalidStateException("No valid privacy-policy Url configured. Please " - + "verify your project's privacy-policy url and/or general url config", - OAUTH_CLIENT, ERR_NO_VALID_PRIVACY_POLICY_URL_CONFIGURED, - params); - } - } -} diff --git a/src/main/java/org/radarbase/management/service/SubjectService.kt b/src/main/java/org/radarbase/management/service/SubjectService.kt new file mode 100644 index 000000000..56571a6b8 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/SubjectService.kt @@ -0,0 +1,516 @@ +package org.radarbase.management.service + +import org.hibernate.envers.query.AuditEntity +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.Group +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.Source +import org.radarbase.management.domain.SourceType +import org.radarbase.management.domain.Subject +import org.radarbase.management.domain.User +import org.radarbase.management.repository.AuthorityRepository +import org.radarbase.management.repository.GroupRepository +import org.radarbase.management.repository.RoleRepository +import org.radarbase.management.repository.SourceRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.repository.filters.SubjectSpecification +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.service.mapper.SourceMapper +import org.radarbase.management.service.mapper.SubjectMapper +import org.radarbase.management.web.rest.criteria.SubjectCriteria +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.ConflictException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidStateException +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Page +import org.springframework.data.history.Revision +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.net.MalformedURLException +import java.net.URL +import java.time.ZonedDateTime +import java.util.* +import java.util.function.Consumer +import java.util.function.Function +import java.util.function.Predicate +import javax.annotation.Nonnull + +/** + * Created by nivethika on 26-5-17. + */ +@Service +@Transactional +open class SubjectService( + @Autowired private val subjectMapper: SubjectMapper, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val sourceRepository: SourceRepository, + @Autowired private val sourceMapper: SourceMapper, + @Autowired private val roleRepository: RoleRepository, + @Autowired private val groupRepository: GroupRepository, + @Autowired private val revisionService: RevisionService, + @Autowired private val managementPortalProperties: ManagementPortalProperties, + @Autowired private val passwordService: PasswordService, + @Autowired private val authorityRepository: AuthorityRepository, + @Autowired private val authService: AuthService +) { + + /** + * Create a new subject. + * + * @param subjectDto the subject information + * @return the newly created subject + */ + @Transactional + open fun createSubject(subjectDto: SubjectDTO): SubjectDTO? { + val subject = subjectMapper.subjectDTOToSubject(subjectDto) + if (subject == null) throw NullPointerException() + //assign roles + val user = subject.user + val project = projectMapper.projectDTOToProject(subjectDto.project) + val projectParticipantRole = getProjectParticipantRole(project, RoleAuthority.PARTICIPANT) + val roles = user!!.roles + roles?.add(projectParticipantRole) + + // Set group + subject.group = getSubjectGroup(project, subjectDto.group) + + // set password and reset keys + user.password = passwordService.generateEncodedPassword() + user.resetKey = passwordService.generateResetKey() + // setting default language key to "en", required to set email context, Find a workaround + user.langKey = "en" + user.resetDate = ZonedDateTime.now() + // default subject is activated. + user.activated = true + //set if any devices are set as assigned + if (subject.sources.isNotEmpty()) { + subject.sources.forEach(Consumer { s: Source -> s.assigned(true).subject(subject) }) + } + if (subject.enrollmentDate == null) { + subject.enrollmentDate = ZonedDateTime.now() + } + sourceRepository.saveAll(subject.sources) + return subjectMapper.subjectToSubjectReducedProjectDTO(subjectRepository.save(subject)) + } + + private fun getSubjectGroup(project: Project?, groupName: String?): Group? { + return if (project == null || groupName == null) { + null + } else groupRepository.findByProjectIdAndName(project.id, groupName) ?: throw BadRequestException( + "Group " + groupName + " does not exist in project " + project.projectName, + EntityName.GROUP, + ErrorConstants.ERR_GROUP_NOT_FOUND + ) + } + + /** + * Fetch Participant role of the project if available, otherwise create a new Role and assign. + * + * @param project project subject is assigned to + * @return relevant Participant role + * @throws java.util.NoSuchElementException if the authority name is not in the database + */ + private fun getProjectParticipantRole(project: Project?, authority: RoleAuthority): Role { + return roleRepository.findOneByProjectIdAndAuthorityName( + project!!.id, authority.authority + ).orElseGet { + val subjectRole = Role() + val auth = authorityRepository.findByAuthorityName( + authority.authority + ).orElseGet { authorityRepository.save(Authority(authority)) } + subjectRole.authority = auth + subjectRole.project = project + roleRepository.save(subjectRole) + } + } + + /** + * Update a subject's information. + * + * @param newSubjectDto the new subject information + * @return the updated subject + */ + @Transactional + open fun updateSubject(newSubjectDto: SubjectDTO): SubjectDTO? { + if (newSubjectDto.id == null) { + return createSubject(newSubjectDto) + } + val subjectFromDb = ensureSubject(newSubjectDto) + val sourcesToUpdate = subjectFromDb.sources + //set only the devices assigned to a subject as assigned + subjectMapper.safeUpdateSubjectFromDTO(newSubjectDto, subjectFromDb) + sourcesToUpdate.addAll(subjectFromDb.sources) + subjectFromDb.sources.forEach(Consumer { s: Source -> s.subject(subjectFromDb).assigned(true) }) + sourceRepository.saveAll(sourcesToUpdate) + // update participant role + subjectFromDb.user!!.roles = updateParticipantRoles(subjectFromDb, newSubjectDto) + // Set group + subjectFromDb.group = getSubjectGroup( + subjectFromDb.activeProject, newSubjectDto.group + ) + return subjectMapper.subjectToSubjectReducedProjectDTO( + subjectRepository.save(subjectFromDb) + ) + } + + private fun updateParticipantRoles(subject: Subject, subjectDto: SubjectDTO): MutableSet? { + if (subjectDto.project == null || subjectDto.project.projectName == null) { + return subject.user!!.roles + } + val existingRoles = subject.user!!.roles?.map { + // make participant inactive in projects that do not match the new project + if (it.authority!!.name == RoleAuthority.PARTICIPANT.authority && it.project!!.projectName != subjectDto.project.projectName) { + return@map getProjectParticipantRole(it.project, RoleAuthority.INACTIVE_PARTICIPANT) + } else { + // do not modify other roles. + return@map it + } + }?.toMutableSet() + + // Ensure that given project is present + val newProjectRole = + getProjectParticipantRole(projectMapper.projectDTOToProject(subjectDto.project), RoleAuthority.PARTICIPANT) + existingRoles?.add(newProjectRole) + + return existingRoles + + } + + /** + * Discontinue the given subject. + * + * + * A discontinued subject is not deleted from the database, but will be prevented from + * logging into the system, sending data, or otherwise interacting with the system. + * + * @param subjectDto the subject to discontinue + * @return the discontinued subject + */ + fun discontinueSubject(subjectDto: SubjectDTO): SubjectDTO? { + val subject = ensureSubject(subjectDto) + // reset all the sources assigned to a subject to unassigned + unassignAllSources(subject) + + // set the removed flag and deactivate the user to prevent them from refreshing their + // access token + subject.isRemoved = true + subject.user!!.activated = false + return subjectMapper.subjectToSubjectReducedProjectDTO(subjectRepository.save(subject)) + } + + private fun ensureSubject(subjectDto: SubjectDTO): Subject { + return subjectRepository.findById(subjectDto.id).orElseThrow { + NotFoundException( + "Subject with ID " + subjectDto.id + " not found.", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND + ) + } + } + + /** + * Unassign all sources from a subject. This method saves the unassigned sources, but does NOT + * save the subject in question. This is the responsibility of the caller. + * + * @param subject The subject for which to unassign all sources + */ + private fun unassignAllSources(subject: Subject) { + subject.sources.forEach(Consumer { source: Source -> + source.isAssigned = false + source.subject = null + source.isDeleted = true + sourceRepository.save(source) + }) + subject.sources.clear() + } + + /** + * Creates or updates a source for a subject. It creates and assigns a source of a for a + * dynamicallyRegister-able sourceType. Currently, it is allowed to create only once source of a + * dynamicallyRegistrable sourceType per subject. Otherwise finds the matching source and + * updates meta-data. + */ + @Transactional + open fun assignOrUpdateSource( + subject: Subject, sourceType: SourceType, project: Project?, sourceRegistrationDto: MinimalSourceDetailsDTO + ): MinimalSourceDetailsDTO { + val assignedSource: Source + if (sourceRegistrationDto.sourceId != null) { + // update meta-data and source-name for existing sources + assignedSource = updateSourceAssignedSubject(subject, sourceRegistrationDto) + } else if (sourceType.canRegisterDynamically!!) { + val sources = subjectRepository.findSubjectSourcesBySourceType( + subject.user!!.login, sourceType.producer, sourceType.model, sourceType.catalogVersion + ) + // create a source and register metadata + // we allow only one source of a source-type per subject + if (sources.isNullOrEmpty()) { + var source = Source(sourceType).project(project).assigned(true).sourceType(sourceType).subject(subject) + source.attributes += sourceRegistrationDto.attributes + // if source name is provided update source name + if (sourceRegistrationDto.sourceName != null) { + // append the auto generated source-name to given source-name to avoid conflicts + source.sourceName = sourceRegistrationDto.sourceName + "_" + source.sourceName + } + // make sure there is no source available on the same name. + if (sourceRepository.findOneBySourceName(source.sourceName).isPresent) { + throw ConflictException( + "SourceName already in use. Cannot create a " + "source with existing source-name ", + EntityName.SUBJECT, + ErrorConstants.ERR_SOURCE_NAME_EXISTS, + Collections.singletonMap("source-name", source.sourceName) + ) + } + source = sourceRepository.save(source) + assignedSource = source + subject.sources.add(source) + } else { + throw ConflictException( + "A Source of SourceType with the specified producer, model and version" + " was already registered for subject login", + EntityName.SUBJECT, + ErrorConstants.ERR_SOURCE_TYPE_EXISTS, + sourceTypeAttributes(sourceType, subject) + ) + } + } else { + // new source since sourceId == null, but canRegisterDynamically == false + throw BadRequestException( + "The source type is not eligible for dynamic " + "registration", + EntityName.SOURCE_TYPE, + "error.InvalidDynamicSourceRegistration", + sourceTypeAttributes(sourceType, subject) + ) + } + subjectRepository.save(subject) + return sourceMapper.sourceToMinimalSourceDetailsDTO(assignedSource) + } + + /** + * Updates source name and attributes of the source assigned to subject. Otherwise returns + * [NotFoundException]. + * @param subject subject + * @param sourceRegistrationDto details of source which need to be updated. + * @return Updated [Source] instance. + */ + private fun updateSourceAssignedSubject( + subject: Subject, sourceRegistrationDto: MinimalSourceDetailsDTO + ): Source { + // for manually registered devices only add meta-data + val source = subjectRepository.findSubjectSourcesBySourceId( + subject.user!!.login, sourceRegistrationDto.sourceId + ).orElseThrow { + val errorParams: MutableMap = HashMap() + errorParams["sourceId"] = sourceRegistrationDto.sourceId.toString() + errorParams["subject-login"] = subject.user!!.login + NotFoundException( + "No source with source-id to assigned to the " + "subject with subject-login", + EntityName.SUBJECT, + ErrorConstants.ERR_SOURCE_NOT_FOUND, + errorParams + ) + } + if (sourceRegistrationDto.sourceName != null) { + source.sourceName = sourceRegistrationDto.sourceName + } + source.attributes += sourceRegistrationDto.attributes + source.isAssigned = true + source.subject = subject + return sourceRepository.save(source) + } + + /** + * Gets all sources assigned to the subject identified by :login. + * + * @return list of sources + */ + fun getSources(subject: Subject): List { + val sources = subjectRepository.findSourcesBySubjectLogin( + subject.user?.login + ) + return sourceMapper.sourcesToMinimalSourceDetailsDTOs(sources) + } + + /** + * Delete the subject with the given login from the database. + * + * @param login the login + */ + fun deleteSubject(login: String?) { + subjectRepository.findOneWithEagerBySubjectLogin(login).ifPresent { subject: Subject -> + unassignAllSources(subject) + subjectRepository.delete(subject) + log.debug("Deleted Subject: {}", subject) + } + } + + /** + * Finds all sources of subject including inactive sources. + * + * @param subject of whom the sources should be retrieved. + * @return list of [MinimalSourceDetailsDTO] of sources. + */ + fun findSubjectSourcesFromRevisions(subject: Subject): List? { + val revisions = subject.id?.let { subjectRepository.findRevisions(it) } + // collect distinct sources in a set + val sources: List? = revisions?.content?.flatMap { p: Revision -> p.entity.sources } + ?.distinctBy { obj: Source -> obj.sourceId } + + return sources?.map { p: Source? -> sourceMapper.sourceToMinimalSourceDetailsDTO(p) }?.toList() + } + + /** + * Get a specific revision for a given subject. + * + * @param login the login of the subject + * @param revision the revision number + * @return the subject at the given revision + * @throws NotFoundException if there was no subject with the given login at the given + * revision number + */ + @Throws(NotFoundException::class, NotAuthorizedException::class) + fun findRevision(login: String?, revision: Int?): SubjectDTO { + // first get latest known version of the subject, if it's deleted we can't load the entity + // directly by e.g. findOneByLogin + val latest = getLatestRevision(login) + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> + e.project(latest.project.projectName).subject(latest.getLogin()) + }) + return revisionService.findRevision( + revision, + latest.id, + Subject::class.java, + subjectMapper::subjectToSubjectReducedProjectDTO + ) ?: throw NotFoundException( + "subject not found for given login and revision.", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) + } + + /** + * Get latest known revision of a subject with the given login. + * + * @param login the login of the subject + * @return the latest revision for that subject + * @throws NotFoundException if no subject was found with the given login + */ + @Throws(NotFoundException::class) + fun getLatestRevision(login: String?): SubjectDTO { + val user = revisionService.getLatestRevisionForEntity( + User::class.java, java.util.List.of(AuditEntity.property("login").eq(login)) + ).orElseThrow { + NotFoundException( + "Subject latest revision not found " + "for login", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) + } as UserDTO + return revisionService.getLatestRevisionForEntity( + Subject::class.java, java.util.List.of(AuditEntity.property("user").eq(user)) + ).orElseThrow { + NotFoundException( + "Subject latest revision not found " + "for login", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) + } as SubjectDTO + } + + /** + * Finds [Subject] from databased from login provided. + * @param login of subject to look for. + * @return [Subject] loaded. + */ + @Nonnull + fun findOneByLogin(login: String?): Subject { + val subject = subjectRepository.findOneWithEagerBySubjectLogin(login) + return subject.orElseThrow { + NotFoundException( + "Subject not found with login", EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND + ) + } + } + + /** + * Find all subjects matching given filter. + * @param criteria filter and sort for subjects. + * @return page of subjects matching filter. + */ + fun findAll(criteria: SubjectCriteria): Page { + // Pageable is required to set the page limit, + // but the page should always be zero + // since the lastLoadedId param defines the offset + // within the query specification + return subjectRepository.findAll( + SubjectSpecification(criteria), criteria.pageable + ) + } + + /** + * Gets relevant privacy-policy-url for this subject. + * + * + * If the active project of the subject has a valid privacy-policy-url returns that url. + * Otherwise, it loads the default URL from ManagementPortal configurations that is + * general. + * + * @param subject to get relevant policy url + * @return URL of privacy policy for this token + */ + fun getPrivacyPolicyUrl(subject: Subject): URL { + + // load default url from config + val policyUrl: String = subject.activeProject?.attributes?.get(ProjectDTO.PRIVACY_POLICY_URL) + ?: managementPortalProperties.common.privacyPolicyUrl + return try { + URL(policyUrl) + } catch (e: MalformedURLException) { + val params: MutableMap = HashMap() + params["url"] = policyUrl + params["message"] = e.message + throw InvalidStateException( + "No valid privacy-policy Url configured. Please " + "verify your project's privacy-policy url and/or general url config", + EntityName.OAUTH_CLIENT, + ErrorConstants.ERR_NO_VALID_PRIVACY_POLICY_URL_CONFIGURED, + params + ) + } + } + + companion object { + private val log = LoggerFactory.getLogger(SubjectService::class.java) + private fun sourceTypeAttributes( + sourceType: SourceType, subject: Subject + ): Map { + val errorParams: MutableMap = HashMap() + errorParams["producer"] = sourceType.producer + errorParams["model"] = sourceType.model + errorParams["catalogVersion"] = sourceType.catalogVersion + errorParams["userId"] = subject.user!!.login + return errorParams + } + + private fun distinctByKey(keyExtractor: Function): Predicate { + val seen: MutableSet = HashSet() + return Predicate { t: T -> seen.add(keyExtractor.apply(t)) } + } + } +} diff --git a/src/main/java/org/radarbase/management/service/UserService.java b/src/main/java/org/radarbase/management/service/UserService.java deleted file mode 100644 index 5968685b2..000000000 --- a/src/main/java/org/radarbase/management/service/UserService.java +++ /dev/null @@ -1,434 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.repository.filters.UserFilter; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.security.SecurityUtils; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.UserMapper; -import org.radarbase.management.web.rest.errors.ConflictException; -import org.radarbase.management.web.rest.errors.InvalidRequestException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.time.Period; -import java.time.ZonedDateTime; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.radarbase.auth.authorization.Permission.ROLE_UPDATE; -import static org.radarbase.auth.authorization.RoleAuthority.INACTIVE_PARTICIPANT; -import static org.radarbase.auth.authorization.RoleAuthority.PARTICIPANT; -import static org.radarbase.management.service.RoleService.getRoleAuthority; -import static org.radarbase.management.web.rest.errors.EntityName.USER; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_EMAIL_EXISTS; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_ENTITY_NOT_FOUND; - -/** - * Service class for managing users. - */ -@Service -@Transactional -public class UserService { - - private static final Logger log = LoggerFactory.getLogger(UserService.class); - - @Autowired - private UserRepository userRepository; - - @Autowired - private PasswordService passwordService; - - @Autowired - private RoleService roleService; - - @Autowired - private UserMapper userMapper; - - @Autowired - private RevisionService revisionService; - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Autowired - private AuthService authService; - - /** - * Activate a user with the given activation key. - * @param key the activation key - * @return an {@link Optional} which is populated with the activated user if the registration - * key was found, and is empty otherwise. - */ - public Optional activateRegistration(String key) { - log.debug("Activating user for activation key {}", key); - return userRepository.findOneByActivationKey(key) - .map(user -> { - // activate given user for the registration key. - user.setActivated(true); - user.setActivationKey(null); - log.debug("Activated user: {}", user); - return user; - }); - } - - /** - * Update a user password with a given reset key. - * @param newPassword the updated password - * @param key the reset key - * @return an {@link Optional} which is populated with the user whose password was reset if - * the reset key was found, and is empty otherwise - */ - public Optional completePasswordReset(String newPassword, String key) { - log.debug("Reset user password for reset key {}", key); - - return userRepository.findOneByResetKey(key) - .filter(user -> { - ZonedDateTime oneDayAgo = ZonedDateTime.now() - .minusSeconds(managementPortalProperties.getCommon() - .getActivationKeyTimeoutInSeconds()); - return user.getResetDate().isAfter(oneDayAgo); - }) - .map(user -> { - user.setPassword(passwordService.encode(newPassword)); - user.setResetKey(null); - user.setResetDate(null); - user.setActivated(true); - return user; - }); - } - - /** - * Find the deactivated user and set the user's reset key to a new random value and set their - * reset date to now. - * Note: We do not use activation key for activating an account. It happens by resetting - * generated password. Resetting activation is by resetting reset-key and reset-date to now. - * @param login the login of the user - * @return an {@link Optional} which holds the user if an deactivated user was found with the - * given login, and is empty otherwise - */ - public Optional requestActivationReset(String login) { - return userRepository.findOneByLogin(login) - .filter((p) -> !p.getActivated()) - .map(user -> { - user.setResetKey(passwordService.generateResetKey()); - user.setResetDate(ZonedDateTime.now()); - return user; - }); - } - - /** - * Set a user's reset key to a new random value and set their reset date to now. - * @param mail the email address of the user - * @return an {@link Optional} which holds the user if an activated user was found with the - * given email address, and is empty otherwise - */ - public Optional requestPasswordReset(String mail) { - return userRepository.findOneByEmail(mail) - .filter(User::getActivated) - .map(user -> { - user.setResetKey(passwordService.generateResetKey()); - user.setResetDate(ZonedDateTime.now()); - return user; - }); - } - - /** - * Add a new user to the database. - * - *

The new user will not be activated and have a random password assigned. It is the - * responsibility of the caller to make sure the new user has a means of activating their - * account.

- * @param userDto the user information - * @return the newly created user - */ - public User createUser(UserDTO userDto) throws NotAuthorizedException { - User user = new User(); - user.setLogin(userDto.getLogin()); - user.setFirstName(userDto.getFirstName()); - user.setLastName(userDto.getLastName()); - user.setEmail(userDto.getEmail()); - if (userDto.getLangKey() == null) { - user.setLangKey("en"); // default language - } else { - user.setLangKey(userDto.getLangKey()); - } - user.setPassword(passwordService.generateEncodedPassword()); - user.setResetKey(passwordService.generateResetKey()); - user.setResetDate(ZonedDateTime.now()); - user.setActivated(false); - - user.setRoles(getUserRoles(userDto.getRoles(), Set.of())); - user = userRepository.save(user); - log.debug("Created Information for User: {}", user); - return user; - } - - private Set getUserRoles(Set roleDtos, Set oldRoles) - throws NotAuthorizedException { - if (roleDtos == null) { - return null; - } - var roles = roleDtos.stream() - .map(roleDto -> { - RoleAuthority authority = getRoleAuthority(roleDto); - return switch (authority.getScope()) { - case GLOBAL -> roleService.getGlobalRole(authority); - case ORGANIZATION -> roleService.getOrganizationRole(authority, - roleDto.getOrganizationId()); - case PROJECT -> roleService.getProjectRole(authority, - roleDto.getProjectId()); - }; - }) - .collect(Collectors.toSet()); - - checkAuthorityForRoleChange(roles, oldRoles); - - return roles; - } - - private void checkAuthorityForRoleChange(Set roles, Set oldRoles) - throws NotAuthorizedException { - var updatedRoles = new HashSet<>(roles); - updatedRoles.removeAll(oldRoles); - for (Role r : updatedRoles) { - checkAuthorityForRoleChange(r); - } - - var removedRoles = new HashSet<>(oldRoles); - removedRoles.removeAll(roles); - for (Role r : removedRoles) { - checkAuthorityForRoleChange(r); - } - } - - private void checkAuthorityForRoleChange(Role role) - throws NotAuthorizedException { - authService.checkPermission(ROLE_UPDATE, e -> { - switch (role.getRole().getScope()) { - case GLOBAL -> { } - case ORGANIZATION -> e.organization(role.getOrganization().getName()); - case PROJECT -> { - if (role.getProject().getOrganization() != null) { - e.organization(role.getProject().getOrganization().getName()); - } - e.project(role.getProject().getProjectName()); - } - default -> throw new IllegalStateException("Unknown authority scope."); - } - }); - } - - /** - * Update basic information (first name, last name, email, language) for the current user. - * - * @param firstName first name of user - * @param lastName last name of user - * @param email email id of user - * @param langKey language key - */ - public void updateUser(String userName, String firstName, String lastName, - String email, String langKey) { - Optional userWithEmail = userRepository.findOneByEmail(email); - User user; - if (userWithEmail.isPresent()) { - user = userWithEmail.get(); - if (!user.getLogin().equalsIgnoreCase(userName)) { - throw new ConflictException("Email address " + email + " already in use", USER, - ERR_EMAIL_EXISTS, Map.of("email", email)); - } - } else { - user = userRepository.findOneByLogin(userName) - .orElseThrow(() -> new NotFoundException( - "User with login " + userName + " not found", USER, - ERR_ENTITY_NOT_FOUND, Map.of("user", userName))); - } - - user.setFirstName(firstName); - user.setLastName(lastName); - user.setEmail(email); - user.setLangKey(langKey); - log.debug("Changed Information for User: {}", user); - userRepository.save(user); - } - - /** - * Update all information for a specific user, and return the modified user. - * - * @param userDto user to update - * @return updated user - */ - @Transactional - public Optional updateUser(UserDTO userDto) throws NotAuthorizedException { - Optional userOpt = userRepository.findById(userDto.getId()); - if (userOpt.isPresent()) { - User user = userOpt.get(); - user.setFirstName(userDto.getFirstName()); - user.setLastName(userDto.getLastName()); - user.setEmail(userDto.getEmail()); - user.setActivated(userDto.isActivated()); - user.setLangKey(userDto.getLangKey()); - Set managedRoles = user.getRoles(); - Set oldRoles = Set.copyOf(managedRoles); - managedRoles.clear(); - managedRoles.addAll(getUserRoles(userDto.getRoles(), oldRoles)); - - user = userRepository.save(user); - log.debug("Changed Information for User: {}", user); - return Optional.of(userMapper.userToUserDTO(user)); - } else { - return Optional.empty(); - } - } - - /** - * Delete the user with the given login. - * @param login the login to delete - */ - public void deleteUser(String login) { - userRepository.findOneByLogin(login).ifPresent(user -> { - userRepository.delete(user); - log.debug("Deleted User: {}", user); - }); - } - - /** - * Change the password of the user with the given login. - * @param password the new password - */ - public void changePassword(String password) { - String currentUser = SecurityUtils.getCurrentUserLogin() - .orElseThrow(() -> new InvalidRequestException( - "Cannot change password of unknown user", null, - ERR_ENTITY_NOT_FOUND)); - changePassword(currentUser, password); - } - - /** - * Change the user's password. - * @param password the new password - * @param login of the user to change password - */ - public void changePassword(String login, String password) { - userRepository.findOneByLogin(login).ifPresent(user -> { - String encryptedPassword = passwordService.encode(password); - user.setPassword(encryptedPassword); - log.debug("Changed password for User: {}", user); - }); - } - - /** - * Get a page of users. - * @param pageable the page information - * @return the requested page of users - */ - @Transactional(readOnly = true) - public Page getAllManagedUsers(Pageable pageable) { - log.debug("Request to get all Users"); - return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER) - .map(userMapper::userToUserDTO); - } - - /** - * Get the user with the given login. - * @param login the login - * @return an {@link Optional} which holds the user if one was found with the given login, - * and is empty otherwise - */ - @Transactional(readOnly = true) - public Optional getUserWithAuthoritiesByLogin(String login) { - return userRepository.findOneWithRolesByLogin(login).map(userMapper::userToUserDTO); - } - - /** - * Get the current user. - * @return the currently authenticated user, or null if no user is currently authenticated - */ - @Transactional(readOnly = true) - public Optional getUserWithAuthorities() { - return SecurityUtils.getCurrentUserLogin() - .flatMap(currentUser -> userRepository.findOneWithRolesByLogin(currentUser)); - } - - - /** - * Not activated users should be automatically deleted after 3 days.

This is scheduled to - * get fired everyday, at 01:00 (am). This is aimed at users, not subjects. So filter our - * users with *PARTICIPANT role and perform the action.

- */ - @Scheduled(cron = "0 0 1 * * ?") - public void removeNotActivatedUsers() { - log.info("Scheduled scan for expired user accounts starting now"); - ZonedDateTime cutoff = ZonedDateTime.now().minus(Period.ofDays(3)); - - List authorities = Arrays.asList( - PARTICIPANT.getAuthority(), INACTIVE_PARTICIPANT.getAuthority()); - - userRepository.findAllByActivatedAndAuthoritiesNot(false, authorities).stream() - .filter(user -> revisionService.getAuditInfo(user).getCreatedAt().isBefore(cutoff)) - .forEach(user -> { - try { - userRepository.delete(user); - log.info("Deleted not activated user after 3 days: {}", user.getLogin()); - } catch (DataIntegrityViolationException ex) { - log.error("Could not delete user with login " + user.getLogin(), ex); - } - }); - } - - /** - * Find all user with given filter. - * - * @param userFilter filtering for users. - * @param pageable paging information - * @param includeProvenance whether to include created and modification fields. - * @return page of users. - */ - public Page findUsers(UserFilter userFilter, Pageable pageable, - boolean includeProvenance) { - return userRepository.findAll(userFilter, pageable) - .map(includeProvenance - ? userMapper::userToUserDTO - : userMapper::userToUserDTONoProvenance); - } - - /** - * Update the roles of the given user. - * @param login user login - * @param roleDtos new roles to set - * @throws NotAuthorizedException if the current user is not allowed to modify the roles - * of the target user. - */ - @Transactional - public void updateRoles(String login, Set roleDtos) throws NotAuthorizedException { - var user = userRepository.findOneByLogin(login) - .orElseThrow(() -> new NotFoundException( - "User with login " + login + " not found", USER, - ERR_ENTITY_NOT_FOUND, Map.of("user", login))); - - Set managedRoles = user.getRoles(); - Set oldRoles = Set.copyOf(managedRoles); - managedRoles.clear(); - managedRoles.addAll(getUserRoles(roleDtos, oldRoles)); - userRepository.save(user); - } -} diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt new file mode 100644 index 000000000..36c8355cb --- /dev/null +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -0,0 +1,428 @@ +package org.radarbase.management.service + +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.User +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.repository.filters.UserFilter +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.security.SecurityUtils +import org.radarbase.management.service.RoleService.Companion.getRoleAuthority +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.UserMapper +import org.radarbase.management.web.rest.errors.ConflictException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidRequestException +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.dao.DataIntegrityViolationException +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.time.Period +import java.time.ZonedDateTime +import java.util.* +import java.util.Map +import java.util.function.Function +import java.util.stream.Collectors +import kotlin.collections.HashSet +import kotlin.collections.MutableSet +import kotlin.collections.Set +import kotlin.collections.setOf + +/** + * Service class for managing users. + */ +@Service +@Transactional +open class UserService( + @Autowired private val userRepository: UserRepository, + @Autowired private val passwordService: PasswordService, + @Autowired private val roleService: RoleService, + @Autowired private val userMapper: UserMapper, + @Autowired private val revisionService: RevisionService, + @Autowired private val managementPortalProperties: ManagementPortalProperties, + @Autowired private val authService: AuthService +) { + + /** + * Activate a user with the given activation key. + * @param key the activation key + * @return an [Optional] which is populated with the activated user if the registration + * key was found, and is empty otherwise. + */ + fun activateRegistration(key: String?): Optional { + log.debug("Activating user for activation key {}", key) + return userRepository.findOneByActivationKey(key).map { user: User -> + // activate given user for the registration key. + user.activated = true + user.activationKey = null + log.debug("Activated user: {}", user) + user + } + } + + /** + * Update a user password with a given reset key. + * @param newPassword the updated password + * @param key the reset key + * @return an [Optional] which is populated with the user whose password was reset if + * the reset key was found, and is empty otherwise + */ + fun completePasswordReset(newPassword: String?, key: String?): Optional { + log.debug("Reset user password for reset key {}", key) + return userRepository.findOneByResetKey(key).filter { user: User -> + val oneDayAgo = ZonedDateTime.now().minusSeconds( + managementPortalProperties.common.activationKeyTimeoutInSeconds.toLong() + ) + user.resetDate!!.isAfter(oneDayAgo) + }.map { user: User -> + user.password = passwordService.encode(newPassword) + user.resetKey = null + user.resetDate = null + user.activated = true + user + } + } + + /** + * Find the deactivated user and set the user's reset key to a new random value and set their + * reset date to now. + * Note: We do not use activation key for activating an account. It happens by resetting + * generated password. Resetting activation is by resetting reset-key and reset-date to now. + * @param login the login of the user + * @return an [Optional] which holds the user if an deactivated user was found with the + * given login, and is empty otherwise + */ + fun requestActivationReset(login: String?): Optional { + return userRepository.findOneByLogin(login).filter { p: User -> !p.activated }.map { user: User -> + user.resetKey = passwordService.generateResetKey() + user.resetDate = ZonedDateTime.now() + user + } + } + + /** + * Set a user's reset key to a new random value and set their reset date to now. + * @param mail the email address of the user + * @return an [Optional] which holds the user if an activated user was found with the + * given email address, and is empty otherwise + */ + fun requestPasswordReset(mail: String?): Optional { + return userRepository.findOneByEmail(mail).filter(User::activated).map { user: User -> + user.resetKey = passwordService.generateResetKey() + user.resetDate = ZonedDateTime.now() + user + } + } + + /** + * Add a new user to the database. + * + * + * The new user will not be activated and have a random password assigned. It is the + * responsibility of the caller to make sure the new user has a means of activating their + * account. + * @param userDto the user information + * @return the newly created user + */ + @Throws(NotAuthorizedException::class) + fun createUser(userDto: UserDTO): User { + var user = User() + user.setLogin(userDto.login) + user.firstName = userDto.firstName + user.lastName = userDto.lastName + user.email = userDto.email + if (userDto.langKey == null) { + user.langKey = "en" // default language + } else { + user.langKey = userDto.langKey + } + user.password = passwordService.generateEncodedPassword() + user.resetKey = passwordService.generateResetKey() + user.resetDate = ZonedDateTime.now() + user.activated = false + user.roles = getUserRoles(userDto.roles, setOf()) + user = userRepository.save(user) + log.debug("Created Information for User: {}", user) + return user + } + + @Throws(NotAuthorizedException::class) + private fun getUserRoles(roleDtos: Set?, oldRoles: Set): MutableSet? { + if (roleDtos == null) { + return null + } + val roles = roleDtos.stream().map { roleDto: RoleDTO -> + val authority = getRoleAuthority(roleDto) + when (authority.scope) { + RoleAuthority.Scope.GLOBAL -> roleService.getGlobalRole(authority) + RoleAuthority.Scope.ORGANIZATION -> roleService.getOrganizationRole( + authority, roleDto.organizationId + ) + + RoleAuthority.Scope.PROJECT -> roleService.getProjectRole( + authority, roleDto.projectId + ) + } + }.collect(Collectors.toSet()) + checkAuthorityForRoleChange(roles, oldRoles) + return roles + } + + @Throws(NotAuthorizedException::class) + private fun checkAuthorityForRoleChange(roles: Set, oldRoles: Set) { + val updatedRoles = HashSet(roles) + updatedRoles.removeAll(oldRoles) + for (r in updatedRoles) { + checkAuthorityForRoleChange(r) + } + val removedRoles = HashSet(oldRoles) + removedRoles.removeAll(roles) + for (r in removedRoles) { + checkAuthorityForRoleChange(r) + } + } + + @Throws(NotAuthorizedException::class) + private fun checkAuthorityForRoleChange(role: Role) { + authService.checkPermission(Permission.ROLE_UPDATE, { e: EntityDetails -> + when (role.role?.scope) { + RoleAuthority.Scope.GLOBAL -> {} + RoleAuthority.Scope.ORGANIZATION -> e.organization(role.organization?.name) + RoleAuthority.Scope.PROJECT -> { + if (role.project?.organization != null) { + e.organization(role.project?.organization?.name) + } + e.project(role.project?.projectName) + } + + else -> throw IllegalStateException("Unknown authority scope.") + } + }) + } + + /** + * Update basic information (first name, last name, email, language) for the current user. + * + * @param firstName first name of user + * @param lastName last name of user + * @param email email id of user + * @param langKey language key + */ + fun updateUser( + userName: String, firstName: String?, lastName: String?, email: String, langKey: String? + ) { + val userWithEmail = userRepository.findOneByEmail(email) + val user: User + if (userWithEmail.isPresent) { + user = userWithEmail.get() + if (!user.login.equals(userName, ignoreCase = true)) { + throw ConflictException( + "Email address $email already in use", + EntityName.USER, + ErrorConstants.ERR_EMAIL_EXISTS, + Map.of("email", email) + ) + } + } else { + user = userRepository.findOneByLogin(userName).orElseThrow { + NotFoundException( + "User with login $userName not found", + EntityName.USER, + ErrorConstants.ERR_ENTITY_NOT_FOUND, + Map.of("user", userName) + ) + } + } + user.firstName = firstName + user.lastName = lastName + user.email = email + user.langKey = langKey + log.debug("Changed Information for User: {}", user) + userRepository.save(user) + } + + /** + * Update all information for a specific user, and return the modified user. + * + * @param userDto user to update + * @return updated user + */ + @Transactional + @Throws(NotAuthorizedException::class) + open fun updateUser(userDto: UserDTO): UserDTO? { + val userOpt = userRepository.findById(userDto.id) + return if (userOpt.isPresent) { + var user = userOpt.get() + user.firstName = userDto.firstName + user.lastName = userDto.lastName + user.email = userDto.email + user.activated = userDto.isActivated + user.langKey = userDto.langKey + val managedRoles = user.roles + val oldRoles = java.util.Set.copyOf(managedRoles) + managedRoles?.clear() + managedRoles?.addAll(getUserRoles(userDto.roles, oldRoles)!!) + user = userRepository.save(user) + log.debug("Changed Information for User: {}", user) + userMapper.userToUserDTO(user) + } else { + null + } + } + + /** + * Delete the user with the given login. + * @param login the login to delete + */ + fun deleteUser(login: String?) { + userRepository.findOneByLogin(login).ifPresent { user: User -> + userRepository.delete(user) + log.debug("Deleted User: {}", user) + } + } + + /** + * Change the password of the user with the given login. + * @param password the new password + */ + fun changePassword(password: String?) { + val currentUser = SecurityUtils.getCurrentUserLogin().orElseThrow { + InvalidRequestException( + "Cannot change password of unknown user", null, ErrorConstants.ERR_ENTITY_NOT_FOUND + ) + } + changePassword(currentUser, password) + } + + /** + * Change the user's password. + * @param password the new password + * @param login of the user to change password + */ + fun changePassword(login: String?, password: String?) { + userRepository.findOneByLogin(login).ifPresent { user: User -> + val encryptedPassword = passwordService.encode(password) + user.password = encryptedPassword + log.debug("Changed password for User: {}", user) + } + } + + /** + * Get a page of users. + * @param pageable the page information + * @return the requested page of users + */ + @Transactional(readOnly = true) + open fun getAllManagedUsers(pageable: Pageable?): Page { + log.debug("Request to get all Users") + return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER) + .map { user: User? -> userMapper.userToUserDTO(user) } + } + + /** + * Get the user with the given login. + * @param login the login + * @return an [Optional] which holds the user if one was found with the given login, + * and is empty otherwise + */ + @Transactional(readOnly = true) + open fun getUserWithAuthoritiesByLogin(login: String?): Optional { + return userRepository.findOneWithRolesByLogin(login).map { user: User? -> userMapper.userToUserDTO(user) } + } + + @get:Transactional(readOnly = true) + open val userWithAuthorities: Optional + /** + * Get the current user. + * @return the currently authenticated user, or null if no user is currently authenticated + */ + get() = SecurityUtils.getCurrentUserLogin() + .flatMap { currentUser: String? -> userRepository.findOneWithRolesByLogin(currentUser) } + + /** + * Not activated users should be automatically deleted after 3 days. + * + * This is scheduled to + * get fired everyday, at 01:00 (am). This is aimed at users, not subjects. So filter our + * users with *PARTICIPANT role and perform the action. + */ + @Scheduled(cron = "0 0 1 * * ?") + fun removeNotActivatedUsers() { + log.info("Scheduled scan for expired user accounts starting now") + val cutoff = ZonedDateTime.now().minus(Period.ofDays(3)) + val authorities = Arrays.asList( + RoleAuthority.PARTICIPANT.authority, RoleAuthority.INACTIVE_PARTICIPANT.authority + ) + userRepository.findAllByActivatedAndAuthoritiesNot(false, authorities).stream() + .filter { user: User? -> user?.let { revisionService.getAuditInfo(it).createdAt }!!.isBefore(cutoff) } + .forEach { user: User -> + try { + userRepository.delete(user) + log.info("Deleted not activated user after 3 days: {}", user.login) + } catch (ex: DataIntegrityViolationException) { + log.error("Could not delete user with login " + user.login, ex) + } + } + } + + /** + * Find all user with given filter. + * + * @param userFilter filtering for users. + * @param pageable paging information + * @param includeProvenance whether to include created and modification fields. + * @return page of users. + */ + fun findUsers( + userFilter: UserFilter, pageable: Pageable?, includeProvenance: Boolean + ): Page? { + return pageable?.let { + userRepository.findAll(userFilter, it) + .map(if (includeProvenance) Function { user: User? -> userMapper.userToUserDTO(user) } else Function { user: User? -> + userMapper.userToUserDTONoProvenance( + user + ) + }) + } + } + + /** + * Update the roles of the given user. + * @param login user login + * @param roleDtos new roles to set + * @throws NotAuthorizedException if the current user is not allowed to modify the roles + * of the target user. + */ + @Transactional + @Throws(NotAuthorizedException::class) + open fun updateRoles(login: String, roleDtos: Set?) { + val user = userRepository.findOneByLogin(login).orElseThrow { + NotFoundException( + "User with login $login not found", + EntityName.USER, + ErrorConstants.ERR_ENTITY_NOT_FOUND, + Map.of("user", login) + ) + } + val managedRoles = user.roles + val oldRoles = java.util.Set.copyOf(managedRoles) + managedRoles?.clear() + managedRoles?.addAll(getUserRoles(roleDtos, oldRoles)!!) + userRepository.save(user) + } + + companion object { + private val log = LoggerFactory.getLogger(UserService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java b/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java index acbbc51f7..9cf948d11 100644 --- a/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java +++ b/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java @@ -26,7 +26,7 @@ public RevisionDTO() { public RevisionDTO(Revision revision, RevisionType revisionType, Object entity) { id = revision.getRequiredRevisionNumber().intValue(); timestamp = revision.getRequiredRevisionInstant(); - author = ((CustomRevisionEntity) revision.getMetadata().getDelegate()).getAuditor(); + author = ((CustomRevisionEntity) revision.getMetadata().getDelegate()).auditor; this.entity = entity; this.revisionType = revisionType; } diff --git a/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java b/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java index 93b4bb9c0..1b957e1de 100644 --- a/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java +++ b/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java @@ -73,9 +73,9 @@ public void setChanges(Map>> changes) { public static RevisionInfoDTO from(CustomRevisionEntity revisionEntity, Map> changes) { RevisionInfoDTO result = new RevisionInfoDTO(); - result.setAuthor(revisionEntity.getAuditor()); - result.setTimestamp(revisionEntity.getTimestamp()); - result.setId(revisionEntity.getId()); + result.setAuthor(revisionEntity.auditor); + result.setTimestamp(revisionEntity.timestamp); + result.setId(revisionEntity.id); result.setChanges(changes.entrySet().stream() .filter(e -> e.getValue() != null) .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream() diff --git a/src/main/java/org/radarbase/management/service/mapper/SubjectMapper.java b/src/main/java/org/radarbase/management/service/mapper/SubjectMapper.kt similarity index 65% rename from src/main/java/org/radarbase/management/service/mapper/SubjectMapper.java rename to src/main/java/org/radarbase/management/service/mapper/SubjectMapper.kt index 14a1fd3e1..efeaa0eb1 100644 --- a/src/main/java/org/radarbase/management/service/mapper/SubjectMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/SubjectMapper.kt @@ -1,24 +1,26 @@ -package org.radarbase.management.service.mapper; +package org.radarbase.management.service.mapper -import java.util.List; -import org.mapstruct.DecoratedWith; -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.MappingTarget; -import org.mapstruct.Named; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.mapper.decorator.SubjectMapperDecorator; +import org.mapstruct.DecoratedWith +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.MappingTarget +import org.mapstruct.Named +import org.radarbase.management.domain.Subject +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.mapper.decorator.SubjectMapperDecorator /** * Mapper for the entity Subject and its DTO SubjectDTO. */ -@Mapper(componentModel = "spring", uses = {UserMapper.class, ProjectMapper.class, - SourceMapper.class, RoleMapper.class}) -@DecoratedWith(SubjectMapperDecorator.class) -public interface SubjectMapper { - +@Mapper( + componentModel = "spring", + uses = [UserMapper::class, ProjectMapper::class, SourceMapper::class, RoleMapper::class] +) +@DecoratedWith( + SubjectMapperDecorator::class +) +interface SubjectMapper { @Mapping(source = "user.login", target = "login") @Mapping(target = "status", ignore = true) @Mapping(target = "project", ignore = true) @@ -28,7 +30,7 @@ public interface SubjectMapper { @Mapping(target = "lastModifiedBy", ignore = true) @Mapping(target = "lastModifiedDate", ignore = true) @Mapping(source = "user.roles", target = "roles") - SubjectDTO subjectToSubjectDTO(Subject subject); + fun subjectToSubjectDTO(subject: Subject?): SubjectDTO? @Mapping(source = "user.login", target = "login") @Mapping(source = "group.name", target = "group") @@ -39,7 +41,7 @@ public interface SubjectMapper { @Mapping(target = "lastModifiedBy", ignore = true) @Mapping(target = "lastModifiedDate", ignore = true) @Mapping(source = "user.roles", target = "roles") - SubjectDTO subjectToSubjectReducedProjectDTO(Subject subject); + fun subjectToSubjectReducedProjectDTO(subject: Subject?): SubjectDTO? @Named(value = "subjectReducedProjectDTO") @Mapping(source = "user.login", target = "login") @@ -51,25 +53,25 @@ public interface SubjectMapper { @Mapping(target = "lastModifiedBy", ignore = true) @Mapping(target = "lastModifiedDate", ignore = true) @Mapping(source = "user.roles", target = "roles") - SubjectDTO subjectToSubjectWithoutProjectDTO(Subject subject); + fun subjectToSubjectWithoutProjectDTO(subject: Subject?): SubjectDTO? - @IterableMapping(qualifiedByName = "subjectReducedProjectDTO") - List subjectsToSubjectReducedProjectDTOs(List subjects); + @IterableMapping(qualifiedByName = ["subjectReducedProjectDTO"]) + fun subjectsToSubjectReducedProjectDTOs(subjects: List?): List? @Mapping(source = "login", target = "user.login") @Mapping(target = "group", ignore = true) @Mapping(target = "user.email", ignore = true) @Mapping(target = "user.activated", ignore = true) @Mapping(target = "removed", ignore = true) - @Mapping(source = "roles" , target = "user.roles") + @Mapping(source = "roles", target = "user.roles") @Mapping(target = "metaTokens", ignore = true) - Subject subjectDTOToSubject(SubjectDTO subjectDto); + fun subjectDTOToSubject(subjectDto: SubjectDTO?): Subject? @Mapping(target = "user", ignore = true) @Mapping(target = "removed", ignore = true) @Mapping(target = "metaTokens", ignore = true) @Mapping(target = "group", ignore = true) - Subject safeUpdateSubjectFromDTO(SubjectDTO subjectDto, @MappingTarget Subject subject); + fun safeUpdateSubjectFromDTO(subjectDto: SubjectDTO?, @MappingTarget subject: Subject?): Subject? /** * Generating the fromId for all mappers if the databaseType is sql, as the class has @@ -79,15 +81,12 @@ public interface SubjectMapper { * @param id id of the entity * @return the entity instance */ - - default Subject subjectFromId(Long id) { + fun subjectFromId(id: Long?): Subject? { if (id == null) { - return null; + return null } - Subject subject = new Subject(); - subject.setId(id); - return subject; + val subject = Subject() + subject.id = id + return subject } - - } diff --git a/src/main/java/org/radarbase/management/service/mapper/UserMapper.java b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt similarity index 51% rename from src/main/java/org/radarbase/management/service/mapper/UserMapper.java rename to src/main/java/org/radarbase/management/service/mapper/UserMapper.kt index 9ba2236cb..affe9f120 100644 --- a/src/main/java/org/radarbase/management/service/mapper/UserMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt @@ -1,56 +1,55 @@ -package org.radarbase.management.service.mapper; +package org.radarbase.management.service.mapper -import org.mapstruct.DecoratedWith; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.MappingConstants; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.User; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.decorator.UserMapperDecorator; - -import java.util.Set; -import java.util.stream.Collectors; +import org.mapstruct.DecoratedWith +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.MappingConstants +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.User +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.decorator.UserMapperDecorator +import javax.validation.constraints.NotNull +import javax.validation.constraints.Pattern +import javax.validation.constraints.Size /** * Mapper for the entity User and its DTO UserDTO. */ -@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, - uses = {ProjectMapper.class, RoleMapper.class}) -@DecoratedWith(UserMapperDecorator.class) -public interface UserMapper { - +@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, uses = [ProjectMapper::class, RoleMapper::class]) +@DecoratedWith( + UserMapperDecorator::class +) +interface UserMapper { @Mapping(target = "createdBy", ignore = true) @Mapping(target = "createdDate", ignore = true) @Mapping(target = "lastModifiedBy", ignore = true) @Mapping(target = "lastModifiedDate", ignore = true) @Mapping(target = "accessToken", ignore = true) - UserDTO userToUserDTO(User user); + fun userToUserDTO(user: User?): UserDTO? @Mapping(target = "createdBy", ignore = true) @Mapping(target = "createdDate", ignore = true) @Mapping(target = "lastModifiedBy", ignore = true) @Mapping(target = "lastModifiedDate", ignore = true) @Mapping(target = "accessToken", ignore = true) - UserDTO userToUserDTONoProvenance(User user); + fun userToUserDTONoProvenance(user: User?): UserDTO? @Mapping(target = "activationKey", ignore = true) @Mapping(target = "resetKey", ignore = true) @Mapping(target = "resetDate", ignore = true) @Mapping(target = "password", ignore = true) @Mapping(target = "authorities", ignore = true) - User userDTOToUser(UserDTO userDto); + fun userDTOToUser(userDto: UserDTO?): User? /** - * Map a set of {@link Authority}s to a set of strings that are the authority names. + * Map a set of [Authority]s to a set of strings that are the authority names. * @param authorities the authorities to map * @return the set of strings if authorities is not null, null otherwise */ - default Set stringsFromAuthorities(Set authorities) { - if (authorities == null) { - return null; - } - return authorities.stream().map(Authority::getName) - .collect(Collectors.toSet()); + fun stringsFromAuthorities(authorities: Set?): Set<@NotNull @Size( + max = 50, + min = 0 + ) @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") String?>? { + return authorities?.map{ it?.name }?.toSet() } } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java index 91219392c..4d60d9afa 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java @@ -43,7 +43,7 @@ public ProjectDTO projectToProjectDTO(Project project) { } ProjectDTO dto = delegate.projectToProjectDTO(project); - dto.setHumanReadableProjectName(project.getAttributes().get(HUMAN_READABLE_PROJECT_NAME)); + dto.setHumanReadableProjectName(project.attributes.get(HUMAN_READABLE_PROJECT_NAME)); try { dto.setPersistentTokenTimeout( @@ -62,7 +62,7 @@ public ProjectDTO projectToProjectDTOReduced(Project project) { return null; } ProjectDTO dto = delegate.projectToProjectDTOReduced(project); - dto.setHumanReadableProjectName(project.getAttributes().get(HUMAN_READABLE_PROJECT_NAME)); + dto.setHumanReadableProjectName(project.attributes.get(HUMAN_READABLE_PROJECT_NAME)); dto.setSourceTypes(null); return dto; } @@ -76,7 +76,7 @@ public Project projectDTOToProject(ProjectDTO projectDto) { Project project = delegate.projectDTOToProject(projectDto); String projectName = projectDto.getHumanReadableProjectName(); if (projectName != null && !projectName.isEmpty()) { - project.getAttributes().put(HUMAN_READABLE_PROJECT_NAME, projectName); + project.attributes.put(HUMAN_READABLE_PROJECT_NAME, projectName); } var orgDto = projectDto.getOrganization(); @@ -86,7 +86,7 @@ public Project projectDTOToProject(ProjectDTO projectDto) { ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, Collections.singletonMap("name", orgDto.getName()))); - project.setOrganization(org); + project.organization = org; } return project; diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java index 0c7b8c481..581ca9995 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java @@ -32,8 +32,8 @@ public Role roleDTOToRole(RoleDTO roleDto) { Role role = delegate.roleDTOToRole(roleDto); - if (role.getAuthority() == null) { - role.setAuthority(authorityRepository.getById(roleDto.getAuthorityName())); + if (role.authority == null) { + role.authority = authorityRepository.getById(roleDto.getAuthorityName()); } return role; diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java index 0980bb6fb..fd69ec511 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java @@ -54,11 +54,11 @@ public Source sourceDTOToSource(SourceDTO sourceDto) { SOURCE, ERR_SOURCE_NOT_FOUND, Map.of("sourceId", sourceDto.getId().toString()))); if (sourceDto.getSubjectLogin() == null) { - source.setSubject(existingSource.getSubject()); + source.subject = existingSource.subject; } else { - source.setSubject(subjectRepository + source.subject = subjectRepository .findOneWithEagerBySubjectLogin(sourceDto.getSubjectLogin()) - .orElseThrow(NoSuchElementException::new)); + .orElseThrow(NoSuchElementException::new); } } return source; diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.java deleted file mode 100644 index 0d52e8024..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.java +++ /dev/null @@ -1,173 +0,0 @@ -package org.radarbase.management.service.mapper.decorator; - -import org.mapstruct.MappingTarget; -import org.radarbase.management.domain.Group; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.domain.audit.EntityAuditInfo; -import org.radarbase.management.repository.GroupRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.service.RevisionService; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.dto.SubjectDTO.SubjectStatus; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.service.mapper.SubjectMapper; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_GROUP_NOT_FOUND; - -/** - * Created by nivethika on 30-8-17. - */ -public abstract class SubjectMapperDecorator implements SubjectMapper { - - @Autowired - @Qualifier("delegate") - private SubjectMapper delegate; - - @Autowired - private ProjectMapper projectMapper; - - @Autowired - private RevisionService revisionService; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private GroupRepository groupRepository; - - @Override - public SubjectDTO subjectToSubjectDTO(Subject subject) { - if (subject == null) { - return null; - } - SubjectDTO dto = subjectToSubjectWithoutProjectDTO(subject); - Project project = subject.getActiveProject() - .flatMap(p -> projectRepository.findOneWithEagerRelationships(p.getId())) - .orElse(null); - dto.setProject(projectMapper.projectToProjectDTO(project)); - - addAuditInfo(subject, dto); - - return dto; - } - - @Override - public SubjectDTO subjectToSubjectReducedProjectDTO(Subject subject) { - if (subject == null) { - return null; - } - SubjectDTO dto = subjectToSubjectWithoutProjectDTO(subject); - - subject.getActiveProject() - .ifPresent(project -> dto.setProject( - projectMapper.projectToProjectDTOReduced(project))); - - addAuditInfo(subject, dto); - - return dto; - } - - private void addAuditInfo(Subject subject, SubjectDTO dto) { - EntityAuditInfo auditInfo = revisionService.getAuditInfo(subject); - dto.setCreatedDate(auditInfo.getCreatedAt()); - dto.setCreatedBy(auditInfo.getCreatedBy()); - dto.setLastModifiedDate(auditInfo.getLastModifiedAt()); - dto.setLastModifiedBy(auditInfo.getLastModifiedBy()); - } - - @Override - public SubjectDTO subjectToSubjectWithoutProjectDTO(Subject subject) { - if (subject == null) { - return null; - } - SubjectDTO dto = delegate.subjectToSubjectWithoutProjectDTO(subject); - dto.setStatus(getSubjectStatus(subject)); - - return dto; - } - - @Override - public Subject subjectDTOToSubject(SubjectDTO subjectDto) { - if (subjectDto == null) { - return null; - } - - Subject subject = delegate.subjectDTOToSubject(subjectDto); - setSubjectStatus(subjectDto, subject); - subject.setGroup(getGroup(subjectDto)); - - return subject; - } - - private Group getGroup(SubjectDTO subjectDto) { - if (subjectDto.getGroup() == null) { - return null; - } else if (subjectDto.getProject().getId() != null) { - return groupRepository.findByProjectIdAndName( - subjectDto.getProject().getId(), subjectDto.getGroup()) - .orElseThrow(() -> new BadRequestException( - "Group " + subjectDto.getGroup() + " not found in project " - + subjectDto.getProject().getId(), - SUBJECT, ERR_GROUP_NOT_FOUND)); - } else if (subjectDto.getProject().getProjectName() != null) { - return groupRepository.findByProjectNameAndName( - subjectDto.getProject().getProjectName(), subjectDto.getGroup()) - .orElseThrow(() -> new BadRequestException( - "Group " + subjectDto.getGroup() + " not found in project " - + subjectDto.getProject().getProjectName(), - SUBJECT, ERR_GROUP_NOT_FOUND)); - } else { - throw new BadRequestException( - "Group " + subjectDto.getGroup() + " cannot be found without a project", - SUBJECT, ERR_GROUP_NOT_FOUND); - } - } - - @Override - public Subject safeUpdateSubjectFromDTO(SubjectDTO subjectDto, @MappingTarget Subject subject) { - Subject subjectRetrieved = delegate.safeUpdateSubjectFromDTO(subjectDto, subject); - setSubjectStatus(subjectDto, subjectRetrieved); - subject.setGroup(getGroup(subjectDto)); - return subjectRetrieved; - } - - private SubjectStatus getSubjectStatus(Subject subject) { - if (!subject.getUser().getActivated() && !subject.isRemoved()) { - return SubjectStatus.DEACTIVATED; - } else if (subject.getUser().getActivated() && !subject.isRemoved()) { - return SubjectStatus.ACTIVATED; - } else if (!subject.getUser().getActivated() && subject.isRemoved()) { - return SubjectStatus.DISCONTINUED; - } - return SubjectStatus.INVALID; - } - - private void setSubjectStatus(SubjectDTO subjectDto, Subject subject) { - switch (subjectDto.getStatus()) { - case DEACTIVATED: - subject.getUser().setActivated(false); - subject.setRemoved(false); - break; - case ACTIVATED: - subject.getUser().setActivated(true); - subject.setRemoved(false); - break; - case DISCONTINUED: - subject.getUser().setActivated(false); - subject.setRemoved(true); - break; - case INVALID: - subject.getUser().setActivated(true); - subject.setRemoved(true); - break; - default: - break; - } - } - -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt new file mode 100644 index 000000000..b48f35bfc --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt @@ -0,0 +1,146 @@ +package org.radarbase.management.service.mapper.decorator + +import org.mapstruct.MappingTarget +import org.radarbase.management.domain.Group +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.GroupRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.RevisionService +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.dto.SubjectDTO.SubjectStatus +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.service.mapper.SubjectMapper +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier + +/** + * Created by nivethika on 30-8-17. + */ +abstract class SubjectMapperDecorator( + @Autowired @Qualifier("delegate") private val delegate: SubjectMapper, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val revisionService: RevisionService, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val groupRepository: GroupRepository +) : SubjectMapper { + + override fun subjectToSubjectDTO(subject: Subject?): SubjectDTO? { + if (subject == null) { + return null + } + val dto = subjectToSubjectWithoutProjectDTO(subject) + val project = subject.activeProject + .let { p -> projectRepository!!.findOneWithEagerRelationships(p?.id) } + dto!!.project = projectMapper!!.projectToProjectDTO(project) + addAuditInfo(subject, dto) + return dto + } + + override fun subjectToSubjectReducedProjectDTO(subject: Subject?): SubjectDTO? { + if (subject == null) { + return null + } + val dto = subjectToSubjectWithoutProjectDTO(subject) + subject.activeProject?.let { project -> dto!!.project = projectMapper!!.projectToProjectDTOReduced(project) } + addAuditInfo(subject, dto) + return dto + } + + private fun addAuditInfo(subject: Subject, dto: SubjectDTO?) { + val auditInfo = revisionService!!.getAuditInfo(subject) + dto!!.createdDate = auditInfo.createdAt + dto.createdBy = auditInfo.createdBy + dto.lastModifiedDate = auditInfo.lastModifiedAt + dto.lastModifiedBy = auditInfo.lastModifiedBy + } + + override fun subjectToSubjectWithoutProjectDTO(subject: Subject?): SubjectDTO? { + if (subject == null) { + return null + } + val dto = delegate!!.subjectToSubjectWithoutProjectDTO(subject) + dto!!.status = getSubjectStatus(subject) + return dto + } + + override fun subjectDTOToSubject(subjectDto: SubjectDTO?): Subject? { + if (subjectDto == null) { + return null + } + val subject = delegate!!.subjectDTOToSubject(subjectDto) + setSubjectStatus(subjectDto, subject) + subject!!.group = getGroup(subjectDto) + return subject + } + + private fun getGroup(subjectDto: SubjectDTO?): Group? { + return if (subjectDto!!.group == null) { + null + } else if (subjectDto.project.id != null) { + groupRepository.findByProjectIdAndName(subjectDto.project.id, subjectDto.group) + ?: throw BadRequestException( + "Group " + subjectDto.group + " not found in project " + + subjectDto.project.id, + EntityName.SUBJECT, ErrorConstants.ERR_GROUP_NOT_FOUND) + } else if (subjectDto.project.projectName != null) { + groupRepository.findByProjectNameAndName(subjectDto.project.projectName, subjectDto.group) + ?: throw BadRequestException( + "Group " + subjectDto.group + " not found in project " + + subjectDto.project.projectName, + EntityName.SUBJECT, ErrorConstants.ERR_GROUP_NOT_FOUND + ) + } else { + throw BadRequestException( + "Group " + subjectDto.group + " cannot be found without a project", + EntityName.SUBJECT, ErrorConstants.ERR_GROUP_NOT_FOUND + ) + } + } + + override fun safeUpdateSubjectFromDTO(subjectDto: SubjectDTO?, @MappingTarget subject: Subject?): Subject? { + val subjectRetrieved = delegate.safeUpdateSubjectFromDTO(subjectDto, subject) + setSubjectStatus(subjectDto, subjectRetrieved) + subject!!.group = getGroup(subjectDto) + return subjectRetrieved + } + + private fun getSubjectStatus(subject: Subject): SubjectStatus { + if (!subject.user!!.activated && !subject.isRemoved!!) { + return SubjectStatus.DEACTIVATED + } else if (subject.user!!.activated && !subject.isRemoved!!) { + return SubjectStatus.ACTIVATED + } else if (!subject.user!!.activated && subject.isRemoved!!) { + return SubjectStatus.DISCONTINUED + } + return SubjectStatus.INVALID + } + + private fun setSubjectStatus(subjectDto: SubjectDTO?, subject: Subject?) { + when (subjectDto!!.status) { + SubjectStatus.DEACTIVATED -> { + subject!!.user!!.activated = false + subject.isRemoved = false + } + + SubjectStatus.ACTIVATED -> { + subject!!.user!!.activated = true + subject.isRemoved = false + } + + SubjectStatus.DISCONTINUED -> { + subject!!.user!!.activated = false + subject.isRemoved = true + } + + SubjectStatus.INVALID -> { + subject!!.user!!.activated = true + subject.isRemoved = true + } + + else -> {} + } + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/MetaTokenResource.java b/src/main/java/org/radarbase/management/web/rest/MetaTokenResource.java deleted file mode 100644 index 39b68d62d..000000000 --- a/src/main/java/org/radarbase/management/web/rest/MetaTokenResource.java +++ /dev/null @@ -1,84 +0,0 @@ -package org.radarbase.management.web.rest; - - -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.domain.MetaToken; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.MetaTokenService; -import org.radarbase.management.service.dto.ClientPairInfoDTO; -import org.radarbase.management.service.dto.TokenDTO; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.net.MalformedURLException; -import java.time.Duration; - -import static org.radarbase.auth.authorization.Permission.SUBJECT_UPDATE; - -@RestController -@RequestMapping("/api") -public class MetaTokenResource { - - private static final Logger log = LoggerFactory.getLogger(OAuthClientsResource.class); - - public static final Duration DEFAULT_META_TOKEN_TIMEOUT = Duration.ofHours(1); - public static final Duration DEFAULT_PERSISTENT_META_TOKEN_TIMEOUT = Duration.ofDays(31); - - @Autowired - private MetaTokenService metaTokenService; - - @Autowired - private AuthService authService; - - /** - * GET /api/meta-token/:tokenName. - * - *

Get refresh-token available under this tokenName.

- * - * @param tokenName the tokenName given after pairing the subject with client - * @return the client as a {@link ClientPairInfoDTO} - */ - @GetMapping("/meta-token/{tokenName:" + Constants.TOKEN_NAME_REGEX + "}") - @Timed - public ResponseEntity getTokenByTokenName(@PathVariable("tokenName") String tokenName) - throws MalformedURLException { - log.info("Requesting token with tokenName {}", tokenName); - return ResponseEntity.ok().body(metaTokenService.fetchToken(tokenName)); - } - - /** - * DELETE /api/meta-token/:tokenName. - * - *

Delete refresh-token available under this tokenName.

- * - * @param tokenName the tokenName given after pairing the subject with client - * @return the client as a {@link ClientPairInfoDTO} - */ - @DeleteMapping("/meta-token/{tokenName:" + Constants.TOKEN_NAME_REGEX + "}") - @Timed - public ResponseEntity deleteTokenByTokenName(@PathVariable("tokenName") String tokenName) - throws NotAuthorizedException { - log.info("Requesting token with tokenName {}", tokenName); - MetaToken metaToken = metaTokenService.getToken(tokenName); - Subject subject = metaToken.getSubject(); - String project = subject.getActiveProject() - .orElseThrow(() -> new NotAuthorizedException( - "Cannot establish authority of subject without active project affiliation." - )) - .getProjectName(); - String user = subject.getUser().getLogin(); - authService.checkPermission(SUBJECT_UPDATE, e -> e.project(project).subject(user)); - metaTokenService.delete(metaToken); - return ResponseEntity.noContent().build(); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/MetaTokenResource.kt b/src/main/java/org/radarbase/management/web/rest/MetaTokenResource.kt new file mode 100644 index 000000000..bbf0a0b2b --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/MetaTokenResource.kt @@ -0,0 +1,91 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.MetaTokenService +import org.radarbase.management.service.dto.TokenDTO +import org.radarbase.management.web.rest.OAuthClientsResource +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import java.net.MalformedURLException +import java.time.Duration + +@RestController +@RequestMapping("/api") +class MetaTokenResource { + @Autowired + private val metaTokenService: MetaTokenService? = null + + @Autowired + private val authService: AuthService? = null + + /** + * GET /api/meta-token/:tokenName. + * + * + * Get refresh-token available under this tokenName. + * + * @param tokenName the tokenName given after pairing the subject with client + * @return the client as a [ClientPairInfoDTO] + */ + @GetMapping("/meta-token/{tokenName:" + Constants.TOKEN_NAME_REGEX + "}") + @Timed + @Throws( + MalformedURLException::class + ) + fun getTokenByTokenName(@PathVariable("tokenName") tokenName: String?): ResponseEntity { + log.info("Requesting token with tokenName {}", tokenName) + return ResponseEntity.ok().body(tokenName?.let { metaTokenService!!.fetchToken(it) }) + } + + /** + * DELETE /api/meta-token/:tokenName. + * + * + * Delete refresh-token available under this tokenName. + * + * @param tokenName the tokenName given after pairing the subject with client + * @return the client as a [ClientPairInfoDTO] + */ + @DeleteMapping("/meta-token/{tokenName:" + Constants.TOKEN_NAME_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun deleteTokenByTokenName(@PathVariable("tokenName") tokenName: String?): ResponseEntity { + log.info("Requesting token with tokenName {}", tokenName) + val metaToken = tokenName?.let { metaTokenService!!.getToken(it) } + val subject = metaToken?.subject + val project: String = subject!! + .activeProject + ?.projectName + ?: + throw NotAuthorizedException( + "Cannot establish authority of subject without active project affiliation." + ) + val user = subject.user!!.login + authService!!.checkPermission( + Permission.SUBJECT_UPDATE, + { e: EntityDetails -> e.project(project).subject(user) }) + metaTokenService?.delete(metaToken) + return ResponseEntity.noContent().build() + } + + companion object { + private val log = LoggerFactory.getLogger(OAuthClientsResource::class.java) + @JvmField + val DEFAULT_META_TOKEN_TIMEOUT = Duration.ofHours(1) + @JvmField + val DEFAULT_PERSISTENT_META_TOKEN_TIMEOUT = Duration.ofDays(31) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.java b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.java deleted file mode 100644 index 41a5cf880..000000000 --- a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.java +++ /dev/null @@ -1,224 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.domain.User; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.MetaTokenService; -import org.radarbase.management.service.OAuthClientService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.SubjectService; -import org.radarbase.management.service.UserService; -import org.radarbase.management.service.dto.ClientDetailsDTO; -import org.radarbase.management.service.dto.ClientPairInfoDTO; -import org.radarbase.management.service.mapper.ClientDetailsMapper; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.boot.actuate.audit.AuditEventRepository; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.OAUTHCLIENTS_CREATE; -import static org.radarbase.auth.authorization.Permission.OAUTHCLIENTS_DELETE; -import static org.radarbase.auth.authorization.Permission.OAUTHCLIENTS_READ; -import static org.radarbase.auth.authorization.Permission.OAUTHCLIENTS_UPDATE; -import static org.radarbase.auth.authorization.Permission.SUBJECT_UPDATE; -import static org.radarbase.management.service.OAuthClientService.checkProtected; -import static org.radarbase.management.web.rest.errors.EntityName.OAUTH_CLIENT; -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SUBJECT_NOT_FOUND; - -/** - * Created by dverbeec on 5/09/2017. - */ -@RestController -@RequestMapping("/api") -public class OAuthClientsResource { - - private static final Logger log = LoggerFactory.getLogger(OAuthClientsResource.class); - - - @Autowired - private OAuthClientService oAuthClientService; - - @Autowired - private MetaTokenService metaTokenService; - - @Autowired - private ClientDetailsMapper clientDetailsMapper; - - @Autowired - private SubjectService subjectService; - - @Autowired - private UserService userService; - - @Autowired - private AuditEventRepository eventRepository; - - @Autowired - private AuthService authService; - - /** - * GET /api/oauth-clients. - * - *

Retrieve a list of currently registered OAuth clients.

- * - * @return the list of registered clients as a list of {@link ClientDetailsDTO} - */ - @GetMapping("/oauth-clients") - @Timed - public ResponseEntity> getOAuthClients() throws NotAuthorizedException { - authService.checkPermission(OAUTHCLIENTS_READ); - return ResponseEntity.ok().body(clientDetailsMapper - .clientDetailsToClientDetailsDTO(oAuthClientService.findAllOAuthClients())); - } - - /** - * GET /api/oauth-clients/:id. - * - *

Get details on a specific client.

- * - * @param id the client id for which to fetch the details - * @return the client as a {@link ClientDetailsDTO} - */ - @GetMapping("/oauth-clients/{id:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity getOAuthClientById(@PathVariable("id") String id) - throws NotAuthorizedException { - authService.checkPermission(OAUTHCLIENTS_READ); - // getOAuthClient checks if the id exists - return ResponseEntity.ok().body(clientDetailsMapper - .clientDetailsToClientDetailsDTO(oAuthClientService.findOneByClientId(id))); - } - - /** - * PUT /api/oauth-clients. - * - *

Update an existing OAuth client.

- * - * @param clientDetailsDto The client details to update - * @return The updated OAuth client. - */ - @PutMapping("/oauth-clients") - @Timed - public ResponseEntity updateOAuthClient(@Valid @RequestBody ClientDetailsDTO - clientDetailsDto) throws NotAuthorizedException { - authService.checkPermission(OAUTHCLIENTS_UPDATE); - // getOAuthClient checks if the id exists - checkProtected(oAuthClientService.findOneByClientId(clientDetailsDto.getClientId())); - - ClientDetails updated = oAuthClientService.updateOauthClient(clientDetailsDto); - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(OAUTH_CLIENT, - clientDetailsDto.getClientId())) - .body(clientDetailsMapper.clientDetailsToClientDetailsDTO(updated)); - } - - /** - * DELETE /api/oauth-clients/:id. - * - *

Delete the OAuth client with the specified client id.

- * - * @param id The id of the client to delete - * @return a ResponseEntity indicating success or failure - */ - @DeleteMapping("/oauth-clients/{id:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity deleteOAuthClient(@PathVariable String id) - throws NotAuthorizedException { - authService.checkPermission(OAUTHCLIENTS_DELETE); - // getOAuthClient checks if the id exists - checkProtected(oAuthClientService.findOneByClientId(id)); - oAuthClientService.deleteClientDetails(id); - return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(OAUTH_CLIENT, id)) - .build(); - } - - /** - * POST /api/oauth-clients. - * - *

Register a new oauth client.

- * - * @param clientDetailsDto The OAuth client to be registered - * @return a response indicating success or failure - * @throws URISyntaxException if there was a problem formatting the URI to the new entity - */ - @PostMapping("/oauth-clients") - @Timed - public ResponseEntity createOAuthClient(@Valid @RequestBody ClientDetailsDTO - clientDetailsDto) throws URISyntaxException, NotAuthorizedException { - authService.checkPermission(OAUTHCLIENTS_CREATE); - ClientDetails created = oAuthClientService.createClientDetail(clientDetailsDto); - return ResponseEntity.created(ResourceUriService.getUri(clientDetailsDto)) - .headers(HeaderUtil.createEntityCreationAlert(OAUTH_CLIENT, created.getClientId())) - .body(clientDetailsMapper.clientDetailsToClientDetailsDTO(created)); - } - - /** - * GET /oauth-clients/pair. - * - *

Generates OAuth2 refresh tokens for the given user, to be used to bootstrap the - * authentication of client apps. This will generate a refresh token which can be used at the - * /oauth/token endpoint to get a new access token and refresh token.

- * - * @param login the login of the subject for whom to generate pairing information - * @param clientId the OAuth client id - * @return a ClientPairInfoDTO with status 200 (OK) - */ - @GetMapping("/oauth-clients/pair") - @Timed - public ResponseEntity getRefreshToken(@RequestParam String login, - @RequestParam(value = "clientId") String clientId, - @RequestParam(value = "persistent", defaultValue = "false") Boolean persistent) - throws NotAuthorizedException, URISyntaxException, MalformedURLException { - authService.checkScope(SUBJECT_UPDATE); - User currentUser = userService.getUserWithAuthorities() - // We only allow this for actual logged in users for now, not for client_credentials - .orElseThrow(() -> new AccessDeniedException( - "You must be a logged in user to access this resource")); - - // lookup the subject - Subject subject = subjectService.findOneByLogin(login); - String project = subject.getActiveProject() - .map(Project::getProjectName) - .orElseThrow(() -> new NotFoundException( - "Project for subject " + login + " not found", SUBJECT, - ERR_SUBJECT_NOT_FOUND)); - - // Users who can update a subject can also generate a refresh token for that subject - authService.checkPermission(SUBJECT_UPDATE, e -> e.project(project).subject(login)); - - ClientPairInfoDTO cpi = metaTokenService.createMetaToken(subject, clientId, persistent); - // generate audit event - eventRepository.add(new AuditEvent(currentUser.getLogin(), "PAIR_CLIENT_REQUEST", - "client_id=" + clientId, "subject_login=" + login)); - log.info("[{}] by {}: client_id={}, subject_login={}", "PAIR_CLIENT_REQUEST", currentUser - .getLogin(), clientId, login); - return new ResponseEntity<>(cpi, HttpStatus.OK); - } - -} diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt new file mode 100644 index 000000000..aecb4af9a --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt @@ -0,0 +1,243 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.MetaTokenService +import org.radarbase.management.service.OAuthClientService +import org.radarbase.management.service.ResourceUriService +import org.radarbase.management.service.SubjectService +import org.radarbase.management.service.UserService +import org.radarbase.management.service.dto.ClientDetailsDTO +import org.radarbase.management.service.dto.ClientPairInfoDTO +import org.radarbase.management.service.mapper.ClientDetailsMapper +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.radarbase.management.web.rest.util.HeaderUtil +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.boot.actuate.audit.AuditEventRepository +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.security.access.AccessDeniedException +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import java.net.MalformedURLException +import java.net.URISyntaxException +import javax.validation.Valid + +/** + * Created by dverbeec on 5/09/2017. + */ +@RestController +@RequestMapping("/api") +class OAuthClientsResource { + @Autowired + private val oAuthClientService: OAuthClientService? = null + + @Autowired + private val metaTokenService: MetaTokenService? = null + + @Autowired + private val clientDetailsMapper: ClientDetailsMapper? = null + + @Autowired + private val subjectService: SubjectService? = null + + @Autowired + private val userService: UserService? = null + + @Autowired + private val eventRepository: AuditEventRepository? = null + + @Autowired + private val authService: AuthService? = null + + @get:Throws(NotAuthorizedException::class) + @get:Timed + @get:GetMapping("/oauth-clients") + val oAuthClients: ResponseEntity> + /** + * GET /api/oauth-clients. + * + * + * Retrieve a list of currently registered OAuth clients. + * + * @return the list of registered clients as a list of [ClientDetailsDTO] + */ + get() { + authService!!.checkPermission(Permission.OAUTHCLIENTS_READ) + return ResponseEntity.ok().body( + clientDetailsMapper + ?.clientDetailsToClientDetailsDTO(oAuthClientService!!.findAllOAuthClients()) + ) + } + + /** + * GET /api/oauth-clients/:id. + * + * + * Get details on a specific client. + * + * @param id the client id for which to fetch the details + * @return the client as a [ClientDetailsDTO] + */ + @GetMapping("/oauth-clients/{id:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getOAuthClientById(@PathVariable("id") id: String?): ResponseEntity { + authService!!.checkPermission(Permission.OAUTHCLIENTS_READ) + // getOAuthClient checks if the id exists + return ResponseEntity.ok().body( + clientDetailsMapper + ?.clientDetailsToClientDetailsDTO(oAuthClientService!!.findOneByClientId(id)) + ) + } + + /** + * PUT /api/oauth-clients. + * + * + * Update an existing OAuth client. + * + * @param clientDetailsDto The client details to update + * @return The updated OAuth client. + */ + @PutMapping("/oauth-clients") + @Timed + @Throws(NotAuthorizedException::class) + fun updateOAuthClient(@RequestBody clientDetailsDto: @Valid ClientDetailsDTO?): ResponseEntity { + authService!!.checkPermission(Permission.OAUTHCLIENTS_UPDATE) + // getOAuthClient checks if the id exists + OAuthClientService.checkProtected(oAuthClientService!!.findOneByClientId(clientDetailsDto!!.clientId)) + val updated = oAuthClientService.updateOauthClient(clientDetailsDto) + return ResponseEntity.ok() + .headers( + HeaderUtil.createEntityUpdateAlert( + EntityName.OAUTH_CLIENT, + clientDetailsDto.clientId + ) + ) + .body(clientDetailsMapper!!.clientDetailsToClientDetailsDTO(updated)) + } + + /** + * DELETE /api/oauth-clients/:id. + * + * + * Delete the OAuth client with the specified client id. + * + * @param id The id of the client to delete + * @return a ResponseEntity indicating success or failure + */ + @DeleteMapping("/oauth-clients/{id:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun deleteOAuthClient(@PathVariable id: String?): ResponseEntity { + authService!!.checkPermission(Permission.OAUTHCLIENTS_DELETE) + // getOAuthClient checks if the id exists + OAuthClientService.checkProtected(oAuthClientService!!.findOneByClientId(id)) + oAuthClientService.deleteClientDetails(id) + return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(EntityName.OAUTH_CLIENT, id)) + .build() + } + + /** + * POST /api/oauth-clients. + * + * + * Register a new oauth client. + * + * @param clientDetailsDto The OAuth client to be registered + * @return a response indicating success or failure + * @throws URISyntaxException if there was a problem formatting the URI to the new entity + */ + @PostMapping("/oauth-clients") + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createOAuthClient(@RequestBody clientDetailsDto: @Valid ClientDetailsDTO?): ResponseEntity { + authService!!.checkPermission(Permission.OAUTHCLIENTS_CREATE) + val created = oAuthClientService!!.createClientDetail(clientDetailsDto) + return ResponseEntity.created(ResourceUriService.getUri(clientDetailsDto)) + .headers(HeaderUtil.createEntityCreationAlert(EntityName.OAUTH_CLIENT, created.clientId)) + .body(clientDetailsMapper!!.clientDetailsToClientDetailsDTO(created)) + } + + /** + * GET /oauth-clients/pair. + * + * + * Generates OAuth2 refresh tokens for the given user, to be used to bootstrap the + * authentication of client apps. This will generate a refresh token which can be used at the + * /oauth/token endpoint to get a new access token and refresh token. + * + * @param login the login of the subject for whom to generate pairing information + * @param clientId the OAuth client id + * @return a ClientPairInfoDTO with status 200 (OK) + */ + @GetMapping("/oauth-clients/pair") + @Timed + @Throws(NotAuthorizedException::class, URISyntaxException::class, MalformedURLException::class) + fun getRefreshToken( + @RequestParam login: String, + @RequestParam(value = "clientId") clientId: String, + @RequestParam(value = "persistent", defaultValue = "false") persistent: Boolean? + ): ResponseEntity { + authService!!.checkScope(Permission.SUBJECT_UPDATE) + val currentUser = + userService!!.userWithAuthorities // We only allow this for actual logged in users for now, not for client_credentials + .orElseThrow { + AccessDeniedException( + "You must be a logged in user to access this resource" + ) + } + + // lookup the subject + val subject = subjectService!!.findOneByLogin(login) + val project: String = subject.activeProject + ?.projectName + ?: throw NotFoundException( + "Project for subject $login not found", EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND + ) + + + // Users who can update a subject can also generate a refresh token for that subject + authService.checkPermission( + Permission.SUBJECT_UPDATE, + { e: EntityDetails -> e.subject(login) }) + val cpi = metaTokenService!!.createMetaToken(subject, clientId, persistent!!) + // generate audit event + eventRepository!!.add( + AuditEvent( + currentUser.login, "PAIR_CLIENT_REQUEST", + "client_id=$clientId", "subject_login=$login" + ) + ) + log.info( + "[{}] by {}: client_id={}, subject_login={}", "PAIR_CLIENT_REQUEST", currentUser + .login, clientId, login + ) + return ResponseEntity(cpi, HttpStatus.OK) + } + + companion object { + private val log = LoggerFactory.getLogger(OAuthClientsResource::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.java b/src/main/java/org/radarbase/management/web/rest/ProjectResource.java deleted file mode 100644 index c2b6ac1db..000000000 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.java +++ /dev/null @@ -1,367 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import io.swagger.v3.oas.annotations.Parameter; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ProjectService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.RoleService; -import org.radarbase.management.service.SourceService; -import org.radarbase.management.service.SubjectService; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.mapper.SubjectMapper; -import org.radarbase.management.web.rest.criteria.SubjectCriteria; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ErrorVM; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.PROJECT_CREATE; -import static org.radarbase.auth.authorization.Permission.PROJECT_DELETE; -import static org.radarbase.auth.authorization.Permission.PROJECT_READ; -import static org.radarbase.auth.authorization.Permission.PROJECT_UPDATE; -import static org.radarbase.auth.authorization.Permission.ROLE_READ; -import static org.radarbase.auth.authorization.Permission.SOURCE_READ; -import static org.radarbase.auth.authorization.Permission.SUBJECT_READ; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_PROJECT_NOT_EMPTY; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_VALIDATION; - -/** - * REST controller for managing Project. - */ -@RestController -@RequestMapping("/api") -public class ProjectResource { - - private static final Logger log = LoggerFactory.getLogger(ProjectResource.class); - - private static final String ENTITY_NAME = "project"; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private ProjectService projectService; - - @Autowired - private RoleService roleService; - - @Autowired - private SubjectMapper subjectMapper; - - @Autowired - private SubjectService subjectService; - - @Autowired - private SourceService sourceService; - - @Autowired - private AuthService authService; - - /** - * POST /projects : Create a new project. - * - * @param projectDto the projectDto to create - * @return the ResponseEntity with status 201 (Created) and with body the new projectDto, or - * with status 400 (Bad Request) if the project has already an ID - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PostMapping("/projects") - @Timed - public ResponseEntity createProject(@Valid @RequestBody ProjectDTO projectDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save Project : {}", projectDto); - var org = projectDto.getOrganization(); - if (org == null || org.getName() == null) { - throw new BadRequestException("Organization must be provided", - ENTITY_NAME, ERR_VALIDATION); - } - authService.checkPermission(PROJECT_CREATE, e -> e.organization(org.getName())); - - if (projectDto.getId() != null) { - return ResponseEntity.badRequest() - .headers(HeaderUtil.createFailureAlert( - ENTITY_NAME, "idexists", "A new project cannot already have an ID")) - .body(null); - } - if (projectRepository.findOneWithEagerRelationshipsByName(projectDto.getProjectName()) - .isPresent()) { - return ResponseEntity.badRequest() - .headers(HeaderUtil.createFailureAlert( - ENTITY_NAME, "nameexists", "A project with this name already exists")) - .body(null); - } - ProjectDTO result = projectService.save(projectDto); - return ResponseEntity.created(ResourceUriService.getUri(result)) - .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getProjectName())) - .body(result); - } - - /** - * PUT /projects : Updates an existing project. - * - * @param projectDto the projectDto to update - * @return the ResponseEntity with status 200 (OK) and with body the updated projectDto, or with - * status 400 (Bad Request) if the projectDto is not valid, or with status 500 (Internal - * Server Error) if the projectDto couldnt be updated - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PutMapping("/projects") - @Timed - public ResponseEntity updateProject(@Valid @RequestBody ProjectDTO projectDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update Project : {}", projectDto); - if (projectDto.getId() == null) { - return createProject(projectDto); - } - // When a client wants to link the project to the default organization, - // this must be done explicitly. - var org = projectDto.getOrganization(); - if (org == null || org.getName() == null) { - throw new BadRequestException("Organization must be provided", - ENTITY_NAME, ERR_VALIDATION); - } - // When clients want to transfer a project, - // they must have permissions to modify both new & old organizations - var existingProject = projectService.findOne(projectDto.getId()); - if (!existingProject.getProjectName().equals(projectDto.getProjectName())) { - throw new BadRequestException("The project name cannot be modified.", ENTITY_NAME, - ERR_VALIDATION); - } - - var newOrgName = org.getName(); - authService.checkPermission(PROJECT_UPDATE, e -> e - .organization(newOrgName) - .project(existingProject.getProjectName())); - - var oldOrgName = existingProject.getOrganization().getName(); - if (!newOrgName.equals(oldOrgName)) { - authService.checkPermission(PROJECT_UPDATE, e -> e.organization(oldOrgName)); - authService.checkPermission(PROJECT_UPDATE, e -> e.organization(newOrgName)); - } - - ProjectDTO result = projectService.save(projectDto); - return ResponseEntity.ok() - .headers(HeaderUtil - .createEntityUpdateAlert(ENTITY_NAME, projectDto.getProjectName())) - .body(result); - } - - /** - * GET /projects : get all the projects. - * - * @return the ResponseEntity with status 200 (OK) and the list of projects in body - */ - @GetMapping("/projects") - @Timed - public ResponseEntity getAllProjects( - @PageableDefault(size = Integer.MAX_VALUE) Pageable pageable, - @RequestParam(name = "minimized", required = false, defaultValue = "false") Boolean - minimized) throws NotAuthorizedException { - log.debug("REST request to get Projects"); - authService.checkPermission(PROJECT_READ); - Page page = projectService.findAll(minimized, pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/api/projects"); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } - - /** - * GET /projects/:projectName : get the project with this name. - * - * @param projectName the projectName of the projectDTO to retrieve - * @return the ResponseEntity with status 200 (OK) and with body the projectDTO, or with status - * 404 (Not Found) - */ - @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity getProject(@PathVariable String projectName) - throws NotAuthorizedException { - authService.checkScope(PROJECT_READ); - log.debug("REST request to get Project : {}", projectName); - ProjectDTO projectDto = projectService.findOneByName(projectName); - authService.checkPermission(PROJECT_READ, e -> e - .organization(projectDto.getOrganization().getName()) - .project(projectDto.getProjectName())); - return ResponseEntity.ok(projectDto); - } - - /** - * GET /projects/:projectName : get the "projectName" project. - * - * @param projectName the projectName of the projectDTO to retrieve - * @return the ResponseEntity with status 200 (OK) and with body the projectDTO, or with status - * 404 (Not Found) - */ - @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/source-types") - @Timed - public List getSourceTypesOfProject(@PathVariable String projectName) - throws NotAuthorizedException { - authService.checkScope(PROJECT_READ); - log.debug("REST request to get Project : {}", projectName); - ProjectDTO projectDto = projectService.findOneByName(projectName); - authService.checkPermission(PROJECT_READ, e -> e - .organization(projectDto.getOrganization().getName()) - .project(projectDto.getProjectName())); - return projectService.findSourceTypesByProjectId(projectDto.getId()); - } - - - /** - * DELETE /projects/:projectName : delete the "projectName" project. - * - * @param projectName the projectName of the projectDTO to delete - * @return the ResponseEntity with status 200 (OK) - */ - @DeleteMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity deleteProject(@PathVariable String projectName) - throws NotAuthorizedException { - authService.checkScope(PROJECT_DELETE); - log.debug("REST request to delete Project : {}", projectName); - ProjectDTO projectDto = projectService.findOneByName(projectName); - authService.checkPermission(PROJECT_DELETE, e -> e - .organization(projectDto.getOrganization().getName()) - .project(projectDto.getProjectName())); - - try { - projectService.delete(projectDto.getId()); - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, projectName)) - .build(); - } catch (DataIntegrityViolationException ex) { - return ResponseEntity.badRequest() - .body(new ErrorVM(ERR_PROJECT_NOT_EMPTY, ex.getMessage())); - } - } - - /** - * GET /projects/{projectName}/roles : get all the roles created for this project. - * - * @return the ResponseEntity with status 200 (OK) and the list of roles in body - */ - @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/roles") - @Timed - public ResponseEntity> getRolesByProject(@PathVariable String projectName) - throws NotAuthorizedException { - authService.checkScope(ROLE_READ); - log.debug("REST request to get all Roles for project {}", projectName); - ProjectDTO projectDto = projectService.findOneByName(projectName); - authService.checkPermission(ROLE_READ, e -> e - .organization(projectDto.getOrganization().getName()) - .project(projectDto.getProjectName())); - return ResponseEntity.ok(roleService.getRolesByProject(projectName)); - } - - /** - * GET /projects/{projectName}/sources : get all the sources by project. - * - * @return the ResponseEntity with status 200 (OK) and the list of sources in body - */ - @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/sources") - @Timed - public ResponseEntity getAllSourcesForProject(@Parameter Pageable pageable, - @PathVariable String projectName, - @RequestParam(value = "assigned", required = false) Boolean assigned, - @RequestParam(name = "minimized", required = false, defaultValue = "false") - Boolean minimized) throws NotAuthorizedException { - authService.checkScope(SOURCE_READ); - log.debug("REST request to get all Sources"); - ProjectDTO projectDto = projectService.findOneByName(projectName); - - authService.checkPermission(SOURCE_READ, e -> e - .organization(projectDto.getOrganization().getName()) - .project(projectDto.getProjectName())); - - if (assigned != null) { - if (minimized) { - return ResponseEntity.ok(sourceService - .findAllMinimalSourceDetailsByProjectAndAssigned( - projectDto.getId(), assigned)); - } else { - return ResponseEntity.ok(sourceService - .findAllByProjectAndAssigned(projectDto.getId(), assigned)); - } - } else { - if (minimized) { - Page page = sourceService - .findAllMinimalSourceDetailsByProject(projectDto.getId(), pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, HeaderUtil.buildPath("api", - "projects", projectName, "sources")); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } else { - Page page = sourceService - .findAllByProjectId(projectDto.getId(), pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, HeaderUtil.buildPath("api", - "projects", projectName, "sources")); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } - } - } - - /** - * Get /projects/{projectName}/subjects : get all subjects for a given project. - * - * @return The subjects in the project or 404 if there is no such project - */ - @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/subjects") - @Timed - public ResponseEntity> getAllSubjects( - @Valid SubjectCriteria subjectCriteria - ) throws NotAuthorizedException { - authService.checkScope(SUBJECT_READ); - String projectName = subjectCriteria.getProjectName(); - // this checks if the project exists - ProjectDTO projectDto = projectService.findOneByName(projectName); - authService.checkPermission(SUBJECT_READ, e -> e - .organization(projectDto.getOrganization().getName()) - .project(projectDto.getProjectName())); - - // this checks if the project exists - projectService.findOneByName(projectName); - subjectCriteria.setProjectName(projectName); - - log.debug("REST request to get all subjects for project {} using criteria {}", projectName, - subjectCriteria); - Page page = subjectService.findAll(subjectCriteria) - .map(subjectMapper::subjectToSubjectWithoutProjectDTO); - - String baseUri = HeaderUtil.buildPath("api", "projects", projectName, "subjects"); - HttpHeaders headers = PaginationUtil.generateSubjectPaginationHttpHeaders( - page, baseUri, subjectCriteria); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt new file mode 100644 index 000000000..d622155e6 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -0,0 +1,396 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import io.swagger.v3.oas.annotations.Parameter +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ProjectService +import org.radarbase.management.service.ResourceUriService +import org.radarbase.management.service.RoleService +import org.radarbase.management.service.SourceService +import org.radarbase.management.service.SubjectService +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.dto.SourceTypeDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.mapper.SubjectMapper +import org.radarbase.management.web.rest.criteria.SubjectCriteria +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.ErrorVM +import org.radarbase.management.web.rest.util.HeaderUtil +import org.radarbase.management.web.rest.util.HeaderUtil.* +import org.radarbase.management.web.rest.util.PaginationUtil +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.dao.DataIntegrityViolationException +import org.springframework.data.domain.Pageable +import org.springframework.data.web.PageableDefault +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import java.net.URISyntaxException +import javax.validation.Valid + +/** + * REST controller for managing Project. + */ +@RestController +@RequestMapping("/api") +class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val projectService: ProjectService, + @Autowired private val roleService: RoleService, + @Autowired private val subjectService: SubjectService, + @Autowired private val sourceService: SourceService, + @Autowired private val authService: AuthService +) { + + /** + * POST /projects : Create a new project. + * + * @param projectDto the projectDto to create + * @return the ResponseEntity with status 201 (Created) and with body the new projectDto, or + * with status 400 (Bad Request) if the project has already an ID + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/projects") + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity { + log.debug("REST request to save Project : {}", projectDto) + val org = projectDto!!.organization + if (org == null || org.name == null) { + throw BadRequestException( + "Organization must be provided", + ENTITY_NAME, ErrorConstants.ERR_VALIDATION + ) + } + authService.checkPermission( + Permission.PROJECT_CREATE, + { e: EntityDetails -> e.organization(org.name) }) + if (projectDto.id != null) { + return ResponseEntity.badRequest() + .headers( + createFailureAlert( + ENTITY_NAME, "idexists", "A new project cannot already have an ID" + ) + ) + .body(null) + } + if (projectRepository.findOneWithEagerRelationshipsByName(projectDto.projectName) != null) { + return ResponseEntity.badRequest() + .headers( + createFailureAlert( + ENTITY_NAME, "nameexists", "A project with this name already exists" + ) + ) + .body(null) + } + val result = projectService.save(projectDto) + return ResponseEntity.created(ResourceUriService.getUri(result)) + .headers( + createEntityCreationAlert( + ENTITY_NAME, + result.projectName + ) + ) + .body(result) + } + + /** + * PUT /projects : Updates an existing project. + * + * @param projectDto the projectDto to update + * @return the ResponseEntity with status 200 (OK) and with body the updated projectDto, or with + * status 400 (Bad Request) if the projectDto is not valid, or with status 500 (Internal + * Server Error) if the projectDto couldn't be updated + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PutMapping("/projects") + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun updateProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity { + log.debug("REST request to update Project : {}", projectDto) + if (projectDto!!.id == null) { + return createProject(projectDto) + } + // When a client wants to link the project to the default organization, + // this must be done explicitly. + val org = projectDto.organization + if (org == null || org.name == null) { + throw BadRequestException( + "Organization must be provided", + ENTITY_NAME, ErrorConstants.ERR_VALIDATION + ) + } + // When clients want to transfer a project, + // they must have permissions to modify both new & old organizations + val existingProject = projectService.findOne(projectDto.id) + if (existingProject.projectName != projectDto.projectName) { + throw BadRequestException( + "The project name cannot be modified.", ENTITY_NAME, + ErrorConstants.ERR_VALIDATION + ) + } + val newOrgName = org.name + authService.checkPermission( + Permission.PROJECT_UPDATE, + { e: EntityDetails -> + e.organization(newOrgName) + e.project(existingProject.projectName) + }) + val oldOrgName = existingProject.organization.name + if (newOrgName != oldOrgName) { + authService.checkPermission( + Permission.PROJECT_UPDATE, + { e: EntityDetails -> e.organization(oldOrgName) }) + authService.checkPermission( + Permission.PROJECT_UPDATE, + { e: EntityDetails -> e.organization(newOrgName) }) + } + val result = projectService.save(projectDto) + return ResponseEntity.ok() + .headers( + createEntityUpdateAlert(ENTITY_NAME, projectDto.projectName) + ) + .body(result) + } + + /** + * GET /projects : get all the projects. + * + * @return the ResponseEntity with status 200 (OK) and the list of projects in body + */ + @GetMapping("/projects") + @Timed + @Throws(NotAuthorizedException::class) + fun getAllProjects( + @PageableDefault(size = Int.MAX_VALUE) pageable: Pageable?, + @RequestParam(name = "minimized", required = false, defaultValue = "false") minimized: Boolean? + ): ResponseEntity<*> { + log.debug("REST request to get Projects") + authService.checkPermission(Permission.PROJECT_READ) + val page = projectService.findAll(minimized, pageable) + val headers = PaginationUtil + .generatePaginationHttpHeaders(page, "/api/projects") + return ResponseEntity(page.content, headers, HttpStatus.OK) + } + + /** + * GET /projects/:projectName : get the project with this name. + * + * @param projectName the projectName of the projectDTO to retrieve + * @return the ResponseEntity with status 200 (OK) and with body the projectDTO, or with status + * 404 (Not Found) + */ + @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getProject(@PathVariable projectName: String?): ResponseEntity { + authService.checkScope(Permission.PROJECT_READ) + log.debug("REST request to get Project : {}", projectName) + val projectDto = projectService.findOneByName(projectName!!) + authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> + e.organization(projectDto.organization.name) + e.project(projectDto.projectName) + }) + return ResponseEntity.ok(projectDto) + } + + /** + * GET /projects/:projectName : get the "projectName" project. + * + * @param projectName the projectName of the projectDTO to retrieve + * @return the ResponseEntity with status 200 (OK) and with body the projectDTO, or with status + * 404 (Not Found) + */ + @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/source-types") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getSourceTypesOfProject(@PathVariable projectName: String?): List { + authService.checkScope(Permission.PROJECT_READ) + log.debug("REST request to get Project : {}", projectName) + val projectDto = projectService.findOneByName(projectName!!) + authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> + e.organization(projectDto.organization.name) + e.project(projectDto.projectName) + }) + return projectService.findSourceTypesByProjectId(projectDto.id) + } + + /** + * DELETE /projects/:projectName : delete the "projectName" project. + * + * @param projectName the projectName of the projectDTO to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun deleteProject(@PathVariable projectName: String?): ResponseEntity<*> { + authService.checkScope(Permission.PROJECT_DELETE) + log.debug("REST request to delete Project : {}", projectName) + val projectDto = projectService.findOneByName(projectName!!) + authService.checkPermission(Permission.PROJECT_DELETE, { e: EntityDetails -> + e.organization(projectDto.organization.name) + e.project(projectDto.projectName) + }) + return try { + projectService.delete(projectDto.id) + ResponseEntity.ok() + .headers(createEntityDeletionAlert(ENTITY_NAME, projectName)) + .build() + } catch (ex: DataIntegrityViolationException) { + ResponseEntity.badRequest() + .body(ErrorVM(ErrorConstants.ERR_PROJECT_NOT_EMPTY, ex.message)) + } + } + + /** + * GET /projects/{projectName}/roles : get all the roles created for this project. + * + * @return the ResponseEntity with status 200 (OK) and the list of roles in body + */ + @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/roles") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getRolesByProject(@PathVariable projectName: String?): ResponseEntity> { + authService.checkScope(Permission.ROLE_READ) + log.debug("REST request to get all Roles for project {}", projectName) + val projectDto = projectService.findOneByName(projectName!!) + authService.checkPermission(Permission.ROLE_READ, { e: EntityDetails -> + e.organization(projectDto.organization.name) + e.project(projectDto.projectName) + }) + return ResponseEntity.ok(roleService.getRolesByProject(projectName)) + } + + /** + * GET /projects/{projectName}/sources : get all the sources by project. + * + * @return the ResponseEntity with status 200 (OK) and the list of sources in body + */ + @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/sources") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getAllSourcesForProject( + @Parameter pageable: Pageable?, + @PathVariable projectName: String?, + @RequestParam(value = "assigned", required = false) assigned: Boolean?, + @RequestParam(name = "minimized", required = false, defaultValue = "false") minimized: Boolean + ): ResponseEntity<*> { + authService.checkScope(Permission.SOURCE_READ) + log.debug("REST request to get all Sources") + val projectDto = projectService.findOneByName(projectName!!) + authService.checkPermission(Permission.SOURCE_READ, { e: EntityDetails -> + e.organization(projectDto.organization.name) + e.project(projectDto.projectName) + }) + return if (assigned != null) { + if (minimized) { + ResponseEntity.ok( + sourceService + .findAllMinimalSourceDetailsByProjectAndAssigned( + projectDto.id, assigned + ) + ) + } else { + ResponseEntity.ok( + sourceService + .findAllByProjectAndAssigned(projectDto.id, assigned) + ) + } + } else { + if (minimized) { + val page = sourceService + .findAllMinimalSourceDetailsByProject(projectDto.id, pageable) + val headers = PaginationUtil + .generatePaginationHttpHeaders( + page, buildPath( + "api", + "projects", projectName, "sources" + ) + ) + ResponseEntity(page.content, headers, HttpStatus.OK) + } else { + val page = sourceService + .findAllByProjectId(projectDto.id, pageable) + val headers = PaginationUtil + .generatePaginationHttpHeaders( + page, buildPath( + "api", + "projects", projectName, "sources" + ) + ) + ResponseEntity(page.content, headers, HttpStatus.OK) + } + } + } + + /** + * Get /projects/{projectName}/subjects : get all subjects for a given project. + * + * @return The subjects in the project or 404 if there is no such project + */ + @GetMapping("/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/subjects") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getAllSubjects( + subjectCriteria: @Valid SubjectCriteria? + ): ResponseEntity> { + authService.checkScope(Permission.SUBJECT_READ) + val projectName = subjectCriteria!!.projectName + // this checks if the project exists + val projectDto = projectService.findOneByName(projectName) + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> + e.organization(projectDto.organization.name) + e.project(projectDto.projectName) + }) + + // this checks if the project exists + projectService.findOneByName(projectName) + subjectCriteria.projectName = projectName + log.debug( + "REST request to get all subjects for project {} using criteria {}", projectName, + subjectCriteria + ) + val page = subjectService.findAll(subjectCriteria) + .map { subject: Subject? -> subjectMapper.subjectToSubjectWithoutProjectDTO(subject) } + val baseUri = buildPath("api", "projects", projectName, "subjects") + val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( + page, baseUri, subjectCriteria + ) + return ResponseEntity(page.content, headers, HttpStatus.OK) + } + + companion object { + private val log = LoggerFactory.getLogger(ProjectResource::class.java) + private const val ENTITY_NAME = "project" + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/SubjectResource.java b/src/main/java/org/radarbase/management/web/rest/SubjectResource.java deleted file mode 100644 index 14669330a..000000000 --- a/src/main/java/org/radarbase/management/web/rest/SubjectResource.java +++ /dev/null @@ -1,572 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.responses.ApiResponses; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Source; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.security.SecurityUtils; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.RevisionService; -import org.radarbase.management.service.SourceService; -import org.radarbase.management.service.SourceTypeService; -import org.radarbase.management.service.SubjectService; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.RevisionDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.mapper.SubjectMapper; -import org.radarbase.management.web.rest.criteria.SubjectCriteria; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.InvalidRequestException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.boot.actuate.audit.AuditEventRepository; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Stream; - -import static org.radarbase.auth.authorization.Permission.SUBJECT_CREATE; -import static org.radarbase.auth.authorization.Permission.SUBJECT_DELETE; -import static org.radarbase.auth.authorization.Permission.SUBJECT_READ; -import static org.radarbase.auth.authorization.Permission.SUBJECT_UPDATE; -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE; -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE_TYPE; -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_ACTIVE_PARTICIPANT_PROJECT_NOT_FOUND; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SOURCE_TYPE_NOT_PROVIDED; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SUBJECT_NOT_FOUND; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_VALIDATION; -import static tech.jhipster.web.util.ResponseUtil.wrapOrNotFound; - -/** - * REST controller for managing Subject. - */ -@RestController -@RequestMapping("/api") -public class SubjectResource { - - private static final Logger log = LoggerFactory.getLogger(SubjectResource.class); - - @Autowired - private SubjectService subjectService; - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private SubjectMapper subjectMapper; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private SourceTypeService sourceTypeService; - - @Autowired - private AuditEventRepository eventRepository; - - @Autowired - private RevisionService revisionService; - - @Autowired - private SourceService sourceService; - @Autowired - private AuthService authService; - - /** - * POST /subjects : Create a new subject. - * - * @param subjectDto the subjectDto to create - * @return the ResponseEntity with status 201 (Created) and with body the new subjectDto, or - * with status 400 (Bad Request) if the subject has already an ID - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PostMapping("/subjects") - @Timed - public ResponseEntity createSubject(@RequestBody SubjectDTO subjectDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save Subject : {}", subjectDto); - String projectName = getProjectName(subjectDto); - authService.checkPermission(SUBJECT_CREATE, e -> e.project(projectName)); - - if (subjectDto.getId() != null) { - throw new BadRequestException("A new subject cannot already have an ID", - SUBJECT, "idexists"); - } - if (subjectDto.getLogin() == null) { - throw new BadRequestException("A subject login is required", SUBJECT, "loginrequired"); - } - if (subjectDto.getExternalId() != null - && !subjectDto.getExternalId().isEmpty() - && subjectRepository.findOneByProjectNameAndExternalId( - projectName, subjectDto.getExternalId()).isPresent()) { - throw new BadRequestException("A subject with given project-id and" - + "external-id already exists", SUBJECT, "subjectExists"); - } - - SubjectDTO result = subjectService.createSubject(subjectDto); - return ResponseEntity.created(ResourceUriService.getUri(subjectDto)) - .headers(HeaderUtil.createEntityCreationAlert(SUBJECT, result.getLogin())) - .body(result); - } - - private String getProjectName(SubjectDTO subjectDto) { - if ( - subjectDto.getProject() == null - || subjectDto.getProject().getId() == null - || subjectDto.getProject().getProjectName() == null - ) { - throw new BadRequestException("A subject should be assigned to a project", SUBJECT, - "projectrequired"); - } - return subjectDto.getProject().getProjectName(); - } - - /** - * PUT /subjects : Updates an existing subject. - * - * @param subjectDto the subjectDto to update - * @return the ResponseEntity with status 200 (OK) and with body the updated subjectDto, or with - * status 400 (Bad Request) if the subjectDto is not valid, or with status 500 (Internal - * Server Error) if the subjectDto couldnt be updated - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PutMapping("/subjects") - @Timed - public ResponseEntity updateSubject(@RequestBody SubjectDTO subjectDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update Subject : {}", subjectDto); - if (subjectDto.getId() == null) { - return createSubject(subjectDto); - } - String projectName = getProjectName(subjectDto); - authService.checkPermission(SUBJECT_UPDATE, e -> e - .project(projectName) - .subject(subjectDto.getLogin())); - SubjectDTO result = subjectService.updateSubject(subjectDto); - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(SUBJECT, subjectDto.getLogin())) - .body(result); - } - - /** - * PUT /subjects/discontinue : Discontinue a subject. A discontinued subject is not allowed to - * send data to the system anymore. - * - * @param subjectDto the subjectDto to update - * @return the ResponseEntity with status 200 (OK) and with body the updated subjectDto, or with - * status 400 (Bad Request) if the subjectDto is not valid, or with status 500 (Internal - * Server Error) if the subjectDto couldnt be updated - */ - @PutMapping("/subjects/discontinue") - @Timed - public ResponseEntity discontinueSubject(@RequestBody SubjectDTO subjectDto) - throws NotAuthorizedException { - log.debug("REST request to update Subject : {}", subjectDto); - if (subjectDto.getId() == null) { - throw new BadRequestException("No subject found", SUBJECT, "subjectNotAvailable"); - } - - String projectName = getProjectName(subjectDto); - authService.checkPermission(SUBJECT_UPDATE, e -> e - .project(projectName) - .subject(subjectDto.getLogin())); - - // In principle this is already captured by the PostUpdate event listener, adding this - // event just makes it more clear a subject was discontinued. - eventRepository.add(new AuditEvent( - SecurityUtils.getCurrentUserLogin().orElse(null), - "SUBJECT_DISCONTINUE", "subject_login=" + subjectDto.getLogin())); - SubjectDTO result = subjectService.discontinueSubject(subjectDto); - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(SUBJECT, subjectDto.getLogin())) - .body(result); - } - - - /** - * GET /subjects : get all the subjects. - * - * @return the ResponseEntity with status 200 (OK) and the list of subjects in body - */ - @GetMapping("/subjects") - @Timed - public ResponseEntity> getAllSubjects( - @Valid SubjectCriteria subjectCriteria - ) throws NotAuthorizedException { - String projectName = subjectCriteria.getProjectName(); - authService.checkPermission(SUBJECT_READ, e -> e.project(projectName)); - - String externalId = subjectCriteria.getExternalId(); - log.debug("ProjectName {} and external {}", projectName, externalId); - // if not specified do not include inactive patients - List authoritiesToInclude = subjectCriteria.getAuthority().stream() - .filter(Objects::nonNull) - .map(Enum::name) - .toList(); - - if (projectName != null && externalId != null) { - Optional> subject = subjectRepository - .findOneByProjectNameAndExternalIdAndAuthoritiesIn( - projectName, externalId, authoritiesToInclude) - .map(s -> Collections.singletonList( - subjectMapper.subjectToSubjectReducedProjectDTO(s))); - return wrapOrNotFound(subject); - } else if (projectName == null && externalId != null) { - Page page = subjectService.findAll(subjectCriteria) - .map(s -> subjectMapper.subjectToSubjectWithoutProjectDTO(s)); - - HttpHeaders headers = PaginationUtil.generateSubjectPaginationHttpHeaders( - page, "/api/subjects", subjectCriteria); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } else { - Page page = subjectService.findAll(subjectCriteria) - .map(subjectMapper::subjectToSubjectWithoutProjectDTO); - - HttpHeaders headers = PaginationUtil.generateSubjectPaginationHttpHeaders( - page, "/api/subjects", subjectCriteria); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } - } - - /** - * GET /subjects/:login : get the "login" subject. - * - * @param login the login of the subjectDTO to retrieve - * @return the ResponseEntity with status 200 (OK) and with body the subjectDTO, or with status - * 404 (Not Found) - */ - @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity getSubject(@PathVariable String login) - throws NotAuthorizedException { - log.debug("REST request to get Subject : {}", login); - authService.checkScope(SUBJECT_READ); - Subject subject = subjectService.findOneByLogin(login); - Project project = subject.getActiveProject() - .flatMap(p -> projectRepository.findOneWithEagerRelationships(p.getId())) - .orElse(null); - - authService.checkPermission(SUBJECT_READ, e -> { - if (project != null) { - e.project(project.getProjectName()); - } - e.subject(subject.getUser().getLogin()); - }); - - SubjectDTO subjectDto = subjectMapper.subjectToSubjectDTO(subject); - - return ResponseEntity.ok(subjectDto); - } - - /** - * GET /subjects/:login/revisions : get all revisions for the "login" subject. - * - * @param login the login of the subjectDTO for which to retrieve the revisions - * @return the ResponseEntity with status 200 (OK) and with body the subjectDTO, or with status - * 404 (Not Found) - */ - @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/revisions") - @Timed - public ResponseEntity> getSubjectRevisions( - @Parameter Pageable pageable, - @PathVariable String login) throws NotAuthorizedException { - authService.checkScope(SUBJECT_READ); - - log.debug("REST request to get revisions for Subject : {}", login); - Subject subject = subjectService.findOneByLogin(login); - authService.checkPermission(SUBJECT_READ, e -> { - subject.getAssociatedProject() - .map(Project::getProjectName) - .ifPresent(e::project); - e.subject(login); - }); - - Page page = revisionService.getRevisionsForEntity(pageable, subject); - - return ResponseEntity.ok() - .headers(PaginationUtil.generatePaginationHttpHeaders(page, - HeaderUtil.buildPath("subjects", login, "revisions"))) - .body(page.getContent()); - } - - /** - * GET /subjects/:login/revisions/:revisionNb : get the "login" subject at revisionNb - * 'revisionNb'. - * - * @param login the login of the subjectDTO to retrieve - * @return the ResponseEntity with status 200 (OK) and with body the subjectDTO, or with status - * 404 (Not Found) - */ - @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}" - + "/revisions/{revisionNb:^[0-9]*$}") - @Timed - public ResponseEntity getSubjectRevision(@PathVariable String login, - @PathVariable Integer revisionNb) throws NotAuthorizedException { - authService.checkScope(SUBJECT_READ); - - log.debug("REST request to get Subject : {}, for revisionNb: {}", login, revisionNb); - SubjectDTO subjectDto = subjectService.findRevision(login, revisionNb); - authService.checkPermission(SUBJECT_READ, e -> e - .project(subjectDto.getProject().getProjectName()) - .subject(subjectDto.getLogin())); - return ResponseEntity.ok(subjectDto); - } - - /** - * DELETE /subjects/:login : delete the "login" subject. - * - * @param login the login of the subjectDTO to delete - * @return the ResponseEntity with status 200 (OK) - */ - @DeleteMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity deleteSubject(@PathVariable String login) - throws NotAuthorizedException { - log.debug("REST request to delete Subject : {}", login); - authService.checkScope(SUBJECT_DELETE); - Subject subject = subjectService.findOneByLogin(login); - - authService.checkPermission(SUBJECT_DELETE, e -> { - subject.getAssociatedProject() - .map(Project::getProjectName) - .ifPresent(e::project); - e.subject(subject.getUser().getLogin()); - }); - subjectService.deleteSubject(login); - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityDeletionAlert(SUBJECT, login)).build(); - } - - /** - * POST /subjects/:login/sources: Assign a source to the specified user. - * - *

The request body is a {@link MinimalSourceDetailsDTO}. At minimum, the source should - * define it's source type by either supplying the sourceTypeId, or the combination of - * (sourceTypeProducer, sourceTypeModel, sourceTypeCatalogVersion) fields. A source ID will be - * automatically generated. The source ID will be a new random UUID, and the source name, if not - * provided, will be the device model, appended with a dash and the first eight characters of - * the UUID. The sources will be created and assigned to the specified user.

- * - *

If you need to assign existing sources, simply specify either of id, sourceId, or - * sourceName fields.

- * - * @param sourceDto The {@link MinimalSourceDetailsDTO} specification - * @return The {@link MinimalSourceDetailsDTO} completed with all identifying fields. - */ - @PostMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/sources") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "An existing source was assigned"), - @ApiResponse(responseCode = "201", description = "A new source was created and" - + " assigned"), - @ApiResponse(responseCode = "400", description = "You must supply either a" - + " Source Type ID, or the combination of (sourceTypeProducer, sourceTypeModel," - + " catalogVersion)"), - @ApiResponse(responseCode = "404", description = "Either the subject or the source type" - + " was not found.") - }) - @Timed - public ResponseEntity assignSources(@PathVariable String login, - @RequestBody MinimalSourceDetailsDTO sourceDto) throws URISyntaxException, - NotAuthorizedException { - authService.checkScope(SUBJECT_UPDATE); - - // find out source type id of supplied source - Long sourceTypeId = sourceDto.getSourceTypeId(); - if (sourceTypeId == null) { - // check if combination (producer, model, version) is present - if (sourceDto.getSourceTypeProducer() == null - || sourceDto.getSourceTypeModel() == null - || sourceDto.getSourceTypeCatalogVersion() == null) { - throw new BadRequestException("Producer or model or version value for the " - + "source-type is null" , SOURCE_TYPE, ERR_VALIDATION); - } - sourceTypeId = sourceTypeService - .findByProducerAndModelAndVersion( - sourceDto.getSourceTypeProducer(), - sourceDto.getSourceTypeModel(), - sourceDto.getSourceTypeCatalogVersion()).getId(); - // also update the sourceDto, since we pass it on to SubjectService later - sourceDto.setSourceTypeId(sourceTypeId); - } - - // check the subject id - Subject sub = subjectService.findOneByLogin(login); - - // find the actively assigned project for this subject - Project currentProject = sub.getActiveProject() - .map(Project::getId) - .flatMap(projectRepository::findByIdWithOrganization) - .orElseThrow(() -> - new InvalidRequestException( - "Requested subject does not have an active project", - SUBJECT, ERR_ACTIVE_PARTICIPANT_PROJECT_NOT_FOUND)); - - authService.checkPermission(SUBJECT_UPDATE, e -> e - .project(currentProject.getProjectName()) - .subject(sub.getUser().getLogin())); - - // find whether the relevant source-type is available in the subject's project - SourceType sourceType = projectRepository - .findSourceTypeByProjectIdAndSourceTypeId(currentProject.getId(), sourceTypeId) - .orElseThrow(() -> new BadRequestException("No valid source-type found for project." - + " You must provide either valid source-type id or producer, model," - + " version of a source-type that is assigned to project", - SUBJECT, ERR_SOURCE_TYPE_NOT_PROVIDED) - ); - - // check if any of id, sourceID, sourceName were non-null - boolean existing = Stream.of(sourceDto.getId(), sourceDto.getSourceName(), - sourceDto.getSourceId()) - .anyMatch(Objects::nonNull); - - // handle the source registration - MinimalSourceDetailsDTO sourceRegistered = subjectService - .assignOrUpdateSource(sub, sourceType, currentProject, sourceDto); - - // Return the correct response type, either created if a new source was created, or ok if - // an existing source was provided. If an existing source was given but not found, the - // assignOrUpdateSource would throw an error, and we would not reach this point. - if (!existing) { - return ResponseEntity.created(ResourceUriService.getUri(sourceRegistered)) - .headers(HeaderUtil.createEntityCreationAlert(SOURCE, - sourceRegistered.getSourceName())) - .body(sourceRegistered); - } else { - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(SOURCE, - sourceRegistered.getSourceName())) - .body(sourceRegistered); - } - } - - /** - * Get sources assigned to a subject. - * - * @param login the subject login - * @return the sources - */ - @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/sources") - @Timed - public ResponseEntity> getSubjectSources( - @PathVariable String login, - @RequestParam(value = "withInactiveSources", required = false) - Boolean withInactiveSourcesParam) throws NotAuthorizedException { - authService.checkScope(SUBJECT_READ); - - boolean withInactiveSources = withInactiveSourcesParam != null && withInactiveSourcesParam; - // check the subject id - Subject subject = subjectRepository.findOneWithEagerBySubjectLogin(login) - .orElseThrow(NoSuchElementException::new); - - authService.checkPermission(SUBJECT_READ, e -> { - subject.getAssociatedProject() - .map(Project::getProjectName) - .ifPresent(e::project); - e.subject(login); - }); - - if (withInactiveSources) { - return ResponseEntity.ok(subjectService.findSubjectSourcesFromRevisions(subject)); - } else { - log.debug("REST request to get sources of Subject : {}", login); - - return ResponseEntity.ok(subjectService.getSources(subject)); - } - } - - - /** - * POST /subjects/:login/sources/:sourceName Update source attributes and source-name. - * - *

The request body is a {@link Map} of strings. This request allows - * update of attributes only. Attributes will be merged and if a new value is - * provided for an existing key, the new value will be updated. The request will be validated - * for SUBJECT.UPDATE permission. SUBJECT.UPDATE is expected to keep the permissions aligned - * with permissions from dynamic source registration and update instead of checking for - * SOURCE_UPDATE. - *

- * - * @param attributes The {@link Map} specification - * @return The {@link MinimalSourceDetailsDTO} completed with all identifying fields. - * @throws NotFoundException if the subject or the source not found using given ids. - */ - @PostMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/sources/{sourceName:" - + Constants.ENTITY_ID_REGEX + "}") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "An existing source was updated"), - @ApiResponse(responseCode = "400", description = "You must supply existing sourceId)"), - @ApiResponse(responseCode = "404", description = "Either the subject or the source was" - + " not found.") - }) - @Timed - public ResponseEntity updateSubjectSource(@PathVariable String login, - @PathVariable String sourceName, @RequestBody Map attributes) - throws NotFoundException, NotAuthorizedException { - authService.checkScope(SUBJECT_UPDATE); - - // check the subject id - Subject subject = subjectRepository.findOneWithEagerBySubjectLogin(login) - .orElseThrow(() -> new NotFoundException("Subject ID not found", - SUBJECT, ERR_SUBJECT_NOT_FOUND, - Collections.singletonMap("subjectLogin", login))); - - authService.checkPermission(SUBJECT_UPDATE, e -> { - subject.getAssociatedProject() - .map(Project::getProjectName) - .ifPresent(e::project); - e.subject(login); - }); - - // find source under subject - Source source = subject.getSources().stream() - .filter(s -> s.getSourceName().equals(sourceName)) - .findAny() - .orElseThrow(() -> { - Map errorParams = new HashMap<>(); - errorParams.put("subjectLogin", login); - errorParams.put("sourceName", sourceName); - return new NotFoundException("Source not found under assigned sources of " - + "subject", SUBJECT, ERR_SUBJECT_NOT_FOUND, - errorParams); - }); - - // there should be only one source under a source-name. - return ResponseEntity.ok(sourceService.safeUpdateOfAttributes(source, attributes)); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt new file mode 100644 index 000000000..11b049d16 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt @@ -0,0 +1,584 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.responses.ApiResponses +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Source +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.security.SecurityUtils +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ResourceUriService +import org.radarbase.management.service.RevisionService +import org.radarbase.management.service.SourceService +import org.radarbase.management.service.SourceTypeService +import org.radarbase.management.service.SubjectService +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.RevisionDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.mapper.SubjectMapper +import org.radarbase.management.web.rest.criteria.SubjectAuthority +import org.radarbase.management.web.rest.criteria.SubjectCriteria +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidRequestException +import org.radarbase.management.web.rest.errors.NotFoundException +import org.radarbase.management.web.rest.util.HeaderUtil +import org.radarbase.management.web.rest.util.PaginationUtil +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.boot.actuate.audit.AuditEventRepository +import org.springframework.data.domain.Pageable +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.io.Serializable +import java.net.URISyntaxException +import java.util.* +import java.util.stream.Stream +import javax.validation.Valid + +/** + * REST controller for managing Subject. + */ +@RestController +@RequestMapping("/api") +class SubjectResource( + @Autowired private val subjectService: SubjectService, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val subjectMapper: SubjectMapper, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val sourceTypeService: SourceTypeService, + @Autowired private val eventRepository: AuditEventRepository, + @Autowired private val revisionService: RevisionService, + @Autowired private val sourceService: SourceService, + @Autowired private val authService: AuthService +) { + + /** + * POST /subjects : Create a new subject. + * + * @param subjectDto the subjectDto to create + * @return the ResponseEntity with status 201 (Created) and with body the new subjectDto, or + * with status 400 (Bad Request) if the subject has already an ID + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/subjects") + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createSubject(@RequestBody subjectDto: SubjectDTO): ResponseEntity { + log.debug("REST request to save Subject : {}", subjectDto) + val projectName = getProjectName(subjectDto) + authService.checkPermission(Permission.SUBJECT_CREATE, { e: EntityDetails -> e.project(projectName) }) + if (subjectDto.id != null) { + throw BadRequestException( + "A new subject cannot already have an ID", + EntityName.SUBJECT, "idexists" + ) + } + if (subjectDto.getLogin() == null) { + throw BadRequestException("A subject login is required", EntityName.SUBJECT, "loginrequired") + } + if (subjectDto.externalId != null && subjectDto.externalId.isNotEmpty() + && subjectRepository.findOneByProjectNameAndExternalId( + projectName, subjectDto.externalId + ).isPresent + ) { + throw BadRequestException( + "A subject with given project-id and" + + "external-id already exists", EntityName.SUBJECT, "subjectExists" + ) + } + val result = subjectService.createSubject(subjectDto) + return ResponseEntity.created(ResourceUriService.getUri(subjectDto)) + .headers(HeaderUtil.createEntityCreationAlert(EntityName.SUBJECT, result?.getLogin())) + .body(result) + } + + private fun getProjectName(subjectDto: SubjectDTO): String { + if (subjectDto.project == null || subjectDto.project.id == null || subjectDto.project.projectName == null) { + throw BadRequestException( + "A subject should be assigned to a project", EntityName.SUBJECT, + "projectrequired" + ) + } + return subjectDto.project.projectName + } + + /** + * PUT /subjects : Updates an existing subject. + * + * @param subjectDto the subjectDto to update + * @return the ResponseEntity with status 200 (OK) and with body the updated subjectDto, or with + * status 400 (Bad Request) if the subjectDto is not valid, or with status 500 (Internal + * Server Error) if the subjectDto couldn't be updated + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PutMapping("/subjects") + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun updateSubject(@RequestBody subjectDto: SubjectDTO): ResponseEntity { + log.debug("REST request to update Subject : {}", subjectDto) + if (subjectDto.id == null) { + return createSubject(subjectDto) + } + val projectName = getProjectName(subjectDto) + authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> + e + .project(projectName) + .subject(subjectDto.getLogin()) + }) + val result = subjectService.updateSubject(subjectDto) + return ResponseEntity.ok() + .headers(HeaderUtil.createEntityUpdateAlert(EntityName.SUBJECT, subjectDto.getLogin())) + .body(result) + } + + /** + * PUT /subjects/discontinue : Discontinue a subject. A discontinued subject is not allowed to + * send data to the system anymore. + * + * @param subjectDto the subjectDto to update + * @return the ResponseEntity with status 200 (OK) and with body the updated subjectDto, or with + * status 400 (Bad Request) if the subjectDto is not valid, or with status 500 (Internal + * Server Error) if the subjectDto couldnt be updated + */ + @PutMapping("/subjects/discontinue") + @Timed + @Throws(NotAuthorizedException::class) + fun discontinueSubject(@RequestBody subjectDto: SubjectDTO): ResponseEntity { + log.debug("REST request to update Subject : {}", subjectDto) + if (subjectDto.id == null) { + throw BadRequestException("No subject found", EntityName.SUBJECT, "subjectNotAvailable") + } + val projectName = getProjectName(subjectDto) + authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> + e + .project(projectName) + .subject(subjectDto.getLogin()) + }) + + // In principle this is already captured by the PostUpdate event listener, adding this + // event just makes it more clear a subject was discontinued. + eventRepository.add( + AuditEvent( + SecurityUtils.getCurrentUserLogin().orElse(null), + "SUBJECT_DISCONTINUE", "subject_login=" + subjectDto.getLogin() + ) + ) + val result = subjectService.discontinueSubject(subjectDto) + return ResponseEntity.ok() + .headers(HeaderUtil.createEntityUpdateAlert(EntityName.SUBJECT, subjectDto.getLogin())) + .body(result) + } + + /** + * GET /subjects : get all the subjects. + * + * @return the ResponseEntity with status 200 (OK) and the list of subjects in body + */ + @GetMapping("/subjects") + @Timed + @Throws(NotAuthorizedException::class) + fun getAllSubjects( + subjectCriteria: @Valid SubjectCriteria? + ): ResponseEntity>? { + val projectName = subjectCriteria!!.projectName + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> e.project(projectName) }) + val externalId = subjectCriteria.externalId + log.debug("ProjectName {} and external {}", projectName, externalId) + // if not specified do not include inactive patients + val authoritiesToInclude = subjectCriteria.authority.stream() + .filter { obj: SubjectAuthority? -> Objects.nonNull(obj) } + .map { obj: SubjectAuthority -> obj.name } + .toList() + return if (projectName != null && externalId != null) { + val subject = subjectRepository + .findOneByProjectNameAndExternalIdAndAuthoritiesIn( + projectName, externalId, authoritiesToInclude + ) + ?.map { s: Subject? -> + listOf( + subjectMapper.subjectToSubjectReducedProjectDTO(s) + ) + } + ResponseUtil.wrapOrNotFound(subject) + } else if (projectName == null && externalId != null) { + val page = subjectService.findAll(subjectCriteria) + .map { s: Subject? -> subjectMapper.subjectToSubjectWithoutProjectDTO(s) } + val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( + page, "/api/subjects", subjectCriteria + ) + ResponseEntity(page.content, headers, HttpStatus.OK) + } else { + val page = subjectService.findAll(subjectCriteria) + .map { subject: Subject? -> subjectMapper.subjectToSubjectWithoutProjectDTO(subject) } + val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( + page, "/api/subjects", subjectCriteria + ) + ResponseEntity(page.content, headers, HttpStatus.OK) + } + } + + /** + * GET /subjects/:login : get the "login" subject. + * + * @param login the login of the subjectDTO to retrieve + * @return the ResponseEntity with status 200 (OK) and with body the subjectDTO, or with status + * 404 (Not Found) + */ + @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getSubject(@PathVariable login: String?): ResponseEntity { + log.debug("REST request to get Subject : {}", login) + authService.checkScope(Permission.SUBJECT_READ) + val subject = subjectService.findOneByLogin(login) + val project: Project? = subject.activeProject + ?.let { p -> projectRepository.findOneWithEagerRelationships(p.id) } + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> + if (project != null) { + e.project(project.projectName) + } + e.subject(subject.user?.login) + }) + val subjectDto = subjectMapper.subjectToSubjectDTO(subject) + return ResponseEntity.ok(subjectDto) + } + + /** + * GET /subjects/:login/revisions : get all revisions for the "login" subject. + * + * @param login the login of the subjectDTO for which to retrieve the revisions + * @return the ResponseEntity with status 200 (OK) and with body the subjectDTO, or with status + * 404 (Not Found) + */ + @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/revisions") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getSubjectRevisions( + @Parameter pageable: Pageable?, + @PathVariable login: String? + ): ResponseEntity> { + authService.checkScope(Permission.SUBJECT_READ) + log.debug("REST request to get revisions for Subject : {}", login) + val subject = subjectService.findOneByLogin(login) + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> + e.project(subject.associatedProject?.projectName) + e.subject(login) + }) + val page = pageable?.let { revisionService.getRevisionsForEntity(it, subject) } + return ResponseEntity.ok() + .headers( + PaginationUtil.generatePaginationHttpHeaders( + page, + HeaderUtil.buildPath("subjects", login, "revisions") + ) + ) + .body(page?.content) + } + + /** + * GET /subjects/:login/revisions/:revisionNb : get the "login" subject at revisionNb + * 'revisionNb'. + * + * @param login the login of the subjectDTO to retrieve + * @return the ResponseEntity with status 200 (OK) and with body the subjectDTO, or with status + * 404 (Not Found) + */ + @GetMapping( + "/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}" + + "/revisions/{revisionNb:^[0-9]*$}" + ) + @Timed + @Throws(NotAuthorizedException::class) + fun getSubjectRevision( + @PathVariable login: String?, + @PathVariable revisionNb: Int? + ): ResponseEntity { + authService.checkScope(Permission.SUBJECT_READ) + log.debug("REST request to get Subject : {}, for revisionNb: {}", login, revisionNb) + val subjectDto = subjectService.findRevision(login, revisionNb) + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> + e.project(subjectDto.project.projectName) + .subject(subjectDto.login) + }) + return ResponseEntity.ok(subjectDto) + } + + /** + * DELETE /subjects/:login : delete the "login" subject. + * + * @param login the login of the subjectDTO to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun deleteSubject(@PathVariable login: String?): ResponseEntity { + log.debug("REST request to delete Subject : {}", login) + authService.checkScope(Permission.SUBJECT_DELETE) + val subject = subjectService.findOneByLogin(login) + authService.checkPermission(Permission.SUBJECT_DELETE, { e: EntityDetails -> + e.project(subject.associatedProject?.projectName) + e.subject(login) + }) + subjectService.deleteSubject(login) + return ResponseEntity.ok() + .headers(HeaderUtil.createEntityDeletionAlert(EntityName.SUBJECT, login)).build() + } + + /** + * POST /subjects/:login/sources: Assign a source to the specified user. + * + * + * The request body is a [MinimalSourceDetailsDTO]. At minimum, the source should + * define it's source type by either supplying the sourceTypeId, or the combination of + * (sourceTypeProducer, sourceTypeModel, sourceTypeCatalogVersion) fields. A source ID will be + * automatically generated. The source ID will be a new random UUID, and the source name, if not + * provided, will be the device model, appended with a dash and the first eight characters of + * the UUID. The sources will be created and assigned to the specified user. + * + * + * If you need to assign existing sources, simply specify either of id, sourceId, or + * sourceName fields. + * + * @param sourceDto The [MinimalSourceDetailsDTO] specification + * @return The [MinimalSourceDetailsDTO] completed with all identifying fields. + */ + @PostMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/sources") + @ApiResponses( + ApiResponse(responseCode = "200", description = "An existing source was assigned"), ApiResponse( + responseCode = "201", description = "A new source was created and" + + " assigned" + ), ApiResponse( + responseCode = "400", description = "You must supply either a" + + " Source Type ID, or the combination of (sourceTypeProducer, sourceTypeModel," + + " catalogVersion)" + ), ApiResponse( + responseCode = "404", description = "Either the subject or the source type" + + " was not found." + ) + ) + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun assignSources( + @PathVariable login: String?, + @RequestBody sourceDto: MinimalSourceDetailsDTO + ): ResponseEntity { + authService.checkScope(Permission.SUBJECT_UPDATE) + + // find out source type id of supplied source + var sourceTypeId = sourceDto.sourceTypeId + if (sourceTypeId == null) { + // check if combination (producer, model, version) is present + if (sourceDto.sourceTypeProducer == null || sourceDto.sourceTypeModel == null || sourceDto.sourceTypeCatalogVersion == null) { + throw BadRequestException( + "Producer or model or version value for the " + + "source-type is null", EntityName.SOURCE_TYPE, ErrorConstants.ERR_VALIDATION + ) + } + sourceTypeId = sourceTypeService + .findByProducerAndModelAndVersion( + sourceDto.sourceTypeProducer, + sourceDto.sourceTypeModel, + sourceDto.sourceTypeCatalogVersion + )?.id + // also update the sourceDto, since we pass it on to SubjectService later + sourceDto.sourceTypeId = sourceTypeId + } + + // check the subject id + val sub = subjectService.findOneByLogin(login) + + // find the actively assigned project for this subject + val currentProject: Project = projectRepository.findByIdWithOrganization(sub.activeProject?.id) + ?: throw InvalidRequestException( + "Requested subject does not have an active project", + EntityName.SUBJECT, ErrorConstants.ERR_ACTIVE_PARTICIPANT_PROJECT_NOT_FOUND + ) + + authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> + e + .project(currentProject.projectName) + .subject(sub.user!!.login) + }) + + // find whether the relevant source-type is available in the subject's project + val sourceType = projectRepository + .findSourceTypeByProjectIdAndSourceTypeId(currentProject.id, sourceTypeId) + ?.orElseThrow { + BadRequestException( + "No valid source-type found for project." + + " You must provide either valid source-type id or producer, model," + + " version of a source-type that is assigned to project", + EntityName.SUBJECT, ErrorConstants.ERR_SOURCE_TYPE_NOT_PROVIDED + ) + } + + // check if any of id, sourceID, sourceName were non-null + val existing = Stream.of( + sourceDto.id, sourceDto.sourceName, + sourceDto.sourceId + ) + .anyMatch { obj: Serializable? -> Objects.nonNull(obj) } + + // handle the source registration + val sourceRegistered = subjectService + .assignOrUpdateSource(sub, sourceType!!, currentProject, sourceDto) + + // Return the correct response type, either created if a new source was created, or ok if + // an existing source was provided. If an existing source was given but not found, the + // assignOrUpdateSource would throw an error, and we would not reach this point. + return if (!existing) { + ResponseEntity.created(ResourceUriService.getUri(sourceRegistered)) + .headers( + HeaderUtil.createEntityCreationAlert( + EntityName.SOURCE, + sourceRegistered.sourceName + ) + ) + .body(sourceRegistered) + } else { + ResponseEntity.ok() + .headers( + HeaderUtil.createEntityUpdateAlert( + EntityName.SOURCE, + sourceRegistered.sourceName + ) + ) + .body(sourceRegistered) + } + } + + /** + * Get sources assigned to a subject. + * + * @param login the subject login + * @return the sources + */ + @GetMapping("/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/sources") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getSubjectSources( + @PathVariable login: String?, + @RequestParam(value = "withInactiveSources", required = false) withInactiveSourcesParam: Boolean? + ): ResponseEntity> { + authService.checkScope(Permission.SUBJECT_READ) + val withInactiveSources = withInactiveSourcesParam != null && withInactiveSourcesParam + // check the subject id + val subject = subjectRepository.findOneWithEagerBySubjectLogin(login) + .orElseThrow { NoSuchElementException() } + authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> + e + .project(subject.associatedProject?.projectName) + e.subject(login) + }) + return if (withInactiveSources) { + ResponseEntity.ok(subjectService.findSubjectSourcesFromRevisions(subject)) + } else { + log.debug("REST request to get sources of Subject : {}", login) + ResponseEntity.ok(subjectService.getSources(subject)) + } + } + + /** + * POST /subjects/:login/sources/:sourceName Update source attributes and source-name. + * + * + * The request body is a [Map] of strings. This request allows + * update of attributes only. Attributes will be merged and if a new value is + * provided for an existing key, the new value will be updated. The request will be validated + * for SUBJECT.UPDATE permission. SUBJECT.UPDATE is expected to keep the permissions aligned + * with permissions from dynamic source registration and update instead of checking for + * SOURCE_UPDATE. + * + * + * @param attributes The [Map] specification + * @return The [MinimalSourceDetailsDTO] completed with all identifying fields. + * @throws NotFoundException if the subject or the source not found using given ids. + */ + @PostMapping( + "/subjects/{login:" + Constants.ENTITY_ID_REGEX + "}/sources/{sourceName:" + + Constants.ENTITY_ID_REGEX + "}" + ) + @ApiResponses( + ApiResponse(responseCode = "200", description = "An existing source was updated"), + ApiResponse(responseCode = "400", description = "You must supply existing sourceId)"), + ApiResponse( + responseCode = "404", description = "Either the subject or the source was" + + " not found." + ) + ) + @Timed + @Throws(NotFoundException::class, NotAuthorizedException::class) + fun updateSubjectSource( + @PathVariable login: String, + @PathVariable sourceName: String, @RequestBody attributes: Map? + ): ResponseEntity { + authService.checkScope(Permission.SUBJECT_UPDATE) + + // check the subject id + val subject = subjectRepository.findOneWithEagerBySubjectLogin(login) + .orElseThrow { + NotFoundException( + "Subject ID not found", + EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) + } + authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> + e + .project(subject.associatedProject?.projectName) + e.subject(login) + }) + + // find source under subject + val source = subject.sources.stream() + .filter { s: Source -> s.sourceName == sourceName } + .findAny() + .orElseThrow { + val errorParams: MutableMap = HashMap() + errorParams["subjectLogin"] = login + errorParams["sourceName"] = sourceName + NotFoundException( + "Source not found under assigned sources of " + + "subject", EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND, + errorParams + ) + } + + // there should be only one source under a source-name. + return ResponseEntity.ok(sourceService.safeUpdateOfAttributes(source, attributes)) + } + + companion object { + private val log = LoggerFactory.getLogger(SubjectResource::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.java b/src/main/java/org/radarbase/management/web/rest/UserResource.java deleted file mode 100644 index 4624b7d75..000000000 --- a/src/main/java/org/radarbase/management/web/rest/UserResource.java +++ /dev/null @@ -1,282 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.repository.filters.UserFilter; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.MailService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.UserService; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.InvalidRequestException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.radarbase.management.web.rest.vm.ManagedUserVM; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import tech.jhipster.web.util.ResponseUtil; - -import java.net.URISyntaxException; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import java.util.Set; - -import static org.radarbase.auth.authorization.Permission.ROLE_READ; -import static org.radarbase.auth.authorization.Permission.ROLE_UPDATE; -import static org.radarbase.auth.authorization.Permission.USER_CREATE; -import static org.radarbase.auth.authorization.Permission.USER_DELETE; -import static org.radarbase.auth.authorization.Permission.USER_READ; -import static org.radarbase.auth.authorization.Permission.USER_UPDATE; -import static org.radarbase.management.web.rest.errors.EntityName.USER; - -/** - * REST controller for managing users. - * - *

This class accesses the User entity, and needs to fetch its collection of authorities.

- * - *

For a normal use-case, it would be better to have an eager relationship between User and - * Authority, and send everything to the client side: there would be no View Model and DTO, a lot - * less code, and an outer-join which would be good for performance.

- * - *

We use a View Model and a DTO for 3 reasons: - *

    - *
  • We want to keep a lazy association between the user and the authorities, because - * people will quite often do relationships with the user, and we don't want them to get the - * authorities all the time for nothing (for performance reasons). This is the #1 goal: we - * should not impact our users' application because of this use-case.
  • - *
  • Not having an outer join causes n+1 requests to the database. This is not a real - * issue as we have by default a second-level cache. This means on the first HTTP call we do - * the n+1 requests, but then all authorities come from the cache, so in fact it's much - * better than doing an outer join (which will get lots of data from the database, for each - * HTTP call).
  • - *
  • As this manages users, for security reasons, we'd rather have a DTO layer.
  • - *
- * - *

Another option would be to have a specific JPA entity graph to handle this case.

- */ -@RestController -@RequestMapping("/api") -public class UserResource { - - private static final Logger log = LoggerFactory.getLogger(UserResource.class); - - @Autowired - private UserRepository userRepository; - - @Autowired - private MailService mailService; - - @Autowired - private UserService userService; - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private ManagementPortalProperties managementPortalProperties; - @Autowired - private AuthService authService; - - /** - * POST /users : Creates a new user.

Creates a new user if the login and email are not - * already used, and sends an mail with an activation link. The user needs to be activated on - * creation.

- * - * @param managedUserVm the user to create - * @return the ResponseEntity with status 201 (Created) and with body the new user, or with - * status 400 (Bad Request) if the login or email is already in use - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PostMapping("/users") - @Timed - public ResponseEntity createUser(@RequestBody ManagedUserVM managedUserVm) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save User : {}", managedUserVm); - authService.checkPermission(USER_CREATE); - if (managedUserVm.getId() != null) { - return ResponseEntity.badRequest() - .headers(HeaderUtil.createFailureAlert(USER, "idexists", - "A new user cannot already have an ID")) - .body(null); - // Lowercase the user login before comparing with database - } else if (userRepository.findOneByLogin(managedUserVm.getLogin().toLowerCase(Locale.ROOT)) - .isPresent()) { - return ResponseEntity.badRequest() - .headers(HeaderUtil - .createFailureAlert(USER, "userexists", - "Login already in use")) - .body(null); - } else if (userRepository.findOneByEmail(managedUserVm.getEmail()).isPresent()) { - return ResponseEntity.badRequest() - .headers(HeaderUtil - .createFailureAlert(USER, "emailexists", - "Email already in use")) - .body(null); - } else { - User newUser = userService.createUser(managedUserVm); - mailService.sendCreationEmail(newUser, managementPortalProperties.getCommon() - .getActivationKeyTimeoutInSeconds()); - return ResponseEntity.created(ResourceUriService.getUri(newUser)) - .headers(HeaderUtil.createAlert("userManagement.created", newUser.getLogin())) - .body(newUser); - } - } - - /** - * PUT /users : Updates an existing User. - * - * @param managedUserVm the user to update - * @return the ResponseEntity with status 200 (OK) and with body the updated user, or with - * status 400 (Bad Request) if the login or email is already in use, or with status 500 - * (Internal Server Error) if the user couldn't be updated - */ - @PutMapping("/users") - @Timed - public ResponseEntity updateUser(@RequestBody ManagedUserVM managedUserVm) - throws NotAuthorizedException { - log.debug("REST request to update User : {}", managedUserVm); - authService.checkPermission(USER_UPDATE, e -> e.user(managedUserVm.getLogin())); - Optional existingUser = userRepository.findOneByEmail(managedUserVm.getEmail()); - if (existingUser.isPresent() && (!existingUser.get().getId() - .equals(managedUserVm.getId()))) { - throw new BadRequestException("Email already in use", USER, "emailexists"); - } - existingUser = userRepository.findOneByLogin(managedUserVm.getLogin() - .toLowerCase(Locale.US)); - if (existingUser.isPresent() && (!existingUser.get().getId() - .equals(managedUserVm.getId()))) { - throw new BadRequestException("Login already in use", USER, "emailexists"); - } - - Optional subject = subjectRepository - .findOneWithEagerBySubjectLogin(managedUserVm.getLogin()); - if (subject.isPresent() && managedUserVm.isActivated() && subject.get().isRemoved()) { - // if the subject is also a user, check if the removed/activated states are valid - throw new InvalidRequestException("Subject cannot be the user to request " - + "this changes", USER, "error.invalidsubjectstate"); - - } - - Optional updatedUser = userService.updateUser( - managedUserVm); - - return ResponseUtil.wrapOrNotFound(updatedUser, - HeaderUtil.createAlert("userManagement.updated", managedUserVm.getLogin())); - } - - /** - * GET /users : get all users. - * - * @param pageable the pagination information - * @param userFilter filter parameters as follows. - * projectName Optional, if specified return only users associated this project - * authority Optional, if specified return only users that have this authority - * login Optional, if specified return only users that have this login - * email Optional, if specified return only users that have this email - * @return the ResponseEntity with status 200 (OK) and with body all users - */ - @GetMapping("/users") - @Timed - public ResponseEntity> getUsers( - @PageableDefault(page = 0, size = Integer.MAX_VALUE) Pageable pageable, - UserFilter userFilter, - @RequestParam(defaultValue = "true") boolean includeProvenance) - throws NotAuthorizedException { - authService.checkPermission(USER_READ); - - Page page = userService.findUsers(userFilter, pageable, includeProvenance); - - return new ResponseEntity<>(page.getContent(), - PaginationUtil.generatePaginationHttpHeaders(page, "/api/users"), HttpStatus.OK); - } - - /** - * GET /users/:login : get the "login" user. - * - * @param login the login of the user to find - * @return the ResponseEntity with status 200 (OK) and with body the "login" user, or with - * status 404 (Not Found) - */ - @GetMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity getUser(@PathVariable String login) - throws NotAuthorizedException { - log.debug("REST request to get User : {}", login); - authService.checkPermission(USER_READ, e -> e.user(login)); - return ResponseUtil.wrapOrNotFound( - userService.getUserWithAuthoritiesByLogin(login)); - } - - /** - * DELETE /users/:login : delete the "login" User. - * - * @param login the login of the user to delete - * @return the ResponseEntity with status 200 (OK) - */ - @DeleteMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity deleteUser(@PathVariable String login) - throws NotAuthorizedException { - log.debug("REST request to delete User: {}", login); - authService.checkPermission(USER_DELETE, e -> e.user(login)); - userService.deleteUser(login); - return ResponseEntity.ok().headers(HeaderUtil.createAlert("userManagement.deleted", login)) - .build(); - } - - /** - * Get /users/:login/roles : get the "login" User roles. - * - * @param login the login of the user to get roles from - * @return the ResponseEntity with status 200 (OK) - */ - @GetMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}/roles") - @Timed - public ResponseEntity> getUserRoles(@PathVariable String login) - throws NotAuthorizedException { - log.debug("REST request to read User roles: {}", login); - authService.checkPermission(ROLE_READ, e -> e.user(login)); - return ResponseUtil.wrapOrNotFound(userService.getUserWithAuthoritiesByLogin(login) - .map(UserDTO::getRoles)); - } - - /** - * PUT /users/:login/roles : update the "login" User roles. - * - * @param login the login of the user to get roles from - * @return the ResponseEntity with status 200 (OK) - */ - @PutMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}/roles") - @Timed - public ResponseEntity putUserRoles(@PathVariable String login, - @RequestBody Set roleDtos) throws NotAuthorizedException { - log.debug("REST request to update User roles: {} to {}", login, roleDtos); - authService.checkPermission(ROLE_UPDATE, e -> e.user(login)); - userService.updateRoles(login, roleDtos); - return ResponseEntity.noContent().build(); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.kt b/src/main/java/org/radarbase/management/web/rest/UserResource.kt new file mode 100644 index 000000000..bae3ea2e4 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/UserResource.kt @@ -0,0 +1,280 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.User +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.repository.filters.UserFilter +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.MailService +import org.radarbase.management.service.ResourceUriService +import org.radarbase.management.service.UserService +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.InvalidRequestException +import org.radarbase.management.web.rest.util.HeaderUtil +import org.radarbase.management.web.rest.util.PaginationUtil +import org.radarbase.management.web.rest.vm.ManagedUserVM +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Pageable +import org.springframework.data.web.PageableDefault +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.net.URISyntaxException +import java.util.* + +/** + * REST controller for managing users. + * + * + * This class accesses the User entity, and needs to fetch its collection of authorities. + * + * + * For a normal use-case, it would be better to have an eager relationship between User and + * Authority, and send everything to the client side: there would be no View Model and DTO, a lot + * less code, and an outer-join which would be good for performance. + * + * + * We use a View Model and a DTO for 3 reasons: + * + * * We want to keep a lazy association between the user and the authorities, because + * people will quite often do relationships with the user, and we don't want them to get the + * authorities all the time for nothing (for performance reasons). This is the #1 goal: we + * should not impact our users' application because of this use-case. + * * Not having an outer join causes n+1 requests to the database. This is not a real + * issue as we have by default a second-level cache. This means on the first HTTP call we do + * the n+1 requests, but then all authorities come from the cache, so in fact it's much + * better than doing an outer join (which will get lots of data from the database, for each + * HTTP call). + * * As this manages users, for security reasons, we'd rather have a DTO layer. + * + * + * + * Another option would be to have a specific JPA entity graph to handle this case. + */ +@RestController +@RequestMapping("/api") +class UserResource( + @Autowired private val userRepository: UserRepository, + @Autowired private val mailService: MailService, + @Autowired private val userService: UserService, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val managementPortalProperties: ManagementPortalProperties, + @Autowired private val authService: AuthService +) { + + /** + * POST /users : Creates a new user. + * + * Creates a new user if the login and email are not + * already used, and sends an mail with an activation link. The user needs to be activated on + * creation. + * + * @param managedUserVm the user to create + * @return the ResponseEntity with status 201 (Created) and with body the new user, or with + * status 400 (Bad Request) if the login or email is already in use + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/users") + @Timed + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createUser(@RequestBody managedUserVm: ManagedUserVM): ResponseEntity { + log.debug("REST request to save User : {}", managedUserVm) + authService.checkPermission(Permission.USER_CREATE) + return if (managedUserVm.id != null) { + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + EntityName.USER, "idexists", "A new user cannot already have an ID" + ) + ).body(null) + // Lowercase the user login before comparing with database + } else if (userRepository.findOneByLogin(managedUserVm.login.lowercase()).isPresent) { + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + EntityName.USER, "userexists", "Login already in use" + ) + ).body(null) + } else if (userRepository.findOneByEmail(managedUserVm.email).isPresent) { + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + EntityName.USER, "emailexists", "Email already in use" + ) + ).body(null) + } else { + val newUser = userService.createUser(managedUserVm) + mailService.sendCreationEmail( + newUser, managementPortalProperties.common.activationKeyTimeoutInSeconds.toLong() + ) + ResponseEntity.created(ResourceUriService.getUri(newUser)).headers( + HeaderUtil.createAlert( + "userManagement.created", newUser.login + ) + ).body(newUser) + } + } + + /** + * PUT /users : Updates an existing User. + * + * @param managedUserVm the user to update + * @return the ResponseEntity with status 200 (OK) and with body the updated user, or with + * status 400 (Bad Request) if the login or email is already in use, or with status 500 + * (Internal Server Error) if the user couldn't be updated + */ + @PutMapping("/users") + @Timed + @Throws(NotAuthorizedException::class) + fun updateUser(@RequestBody managedUserVm: ManagedUserVM): ResponseEntity { + log.debug("REST request to update User : {}", managedUserVm) + authService.checkPermission(Permission.USER_UPDATE, { e: EntityDetails -> e.user(managedUserVm.login) }) + var existingUser = userRepository.findOneByEmail(managedUserVm.email) + if (existingUser.isPresent && existingUser.get().id != managedUserVm.id) { + throw BadRequestException("Email already in use", EntityName.USER, "emailexists") + } + existingUser = userRepository.findOneByLogin( + managedUserVm.login.lowercase() + ) + if (existingUser.isPresent && existingUser.get().id != managedUserVm.id) { + throw BadRequestException("Login already in use", EntityName.USER, "emailexists") + } + val subject = subjectRepository.findOneWithEagerBySubjectLogin(managedUserVm.login) + if (subject.isPresent && managedUserVm.isActivated && subject.get().isRemoved!!) { + // if the subject is also a user, check if the removed/activated states are valid + throw InvalidRequestException( + "Subject cannot be the user to request " + "this changes", EntityName.USER, "error.invalidsubjectstate" + ) + } + val updatedUser: UserDTO? = userService.updateUser( + managedUserVm + ) + return ResponseEntity.ok().headers( + HeaderUtil.createAlert("userManagement.updated", managedUserVm.login) + ).body( + updatedUser + ) + } + + /** + * GET /users : get all users. + * + * @param pageable the pagination information + * @param userFilter filter parameters as follows. + * projectName Optional, if specified return only users associated this project + * authority Optional, if specified return only users that have this authority + * login Optional, if specified return only users that have this login + * email Optional, if specified return only users that have this email + * @return the ResponseEntity with status 200 (OK) and with body all users + */ + @GetMapping("/users") + @Timed + @Throws(NotAuthorizedException::class) + fun getUsers( + @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable?, + userFilter: UserFilter?, + @RequestParam(defaultValue = "true") includeProvenance: Boolean + ): ResponseEntity> { + authService.checkPermission(Permission.USER_READ) + val page = userService.findUsers(userFilter!!, pageable, includeProvenance) + return ResponseEntity( + page!!.content, PaginationUtil.generatePaginationHttpHeaders(page, "/api/users"), HttpStatus.OK + ) + } + + /** + * GET /users/:login : get the "login" user. + * + * @param login the login of the user to find + * @return the ResponseEntity with status 200 (OK) and with body the "login" user, or with + * status 404 (Not Found) + */ + @GetMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getUser(@PathVariable login: String?): ResponseEntity { + log.debug("REST request to get User : {}", login) + authService.checkPermission(Permission.USER_READ, { e: EntityDetails -> e.user(login) }) + return ResponseUtil.wrapOrNotFound( + userService.getUserWithAuthoritiesByLogin(login) + ) + } + + /** + * DELETE /users/:login : delete the "login" User. + * + * @param login the login of the user to delete + * @return the ResponseEntity with status 200 (OK) + */ + @DeleteMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun deleteUser(@PathVariable login: String?): ResponseEntity { + log.debug("REST request to delete User: {}", login) + authService.checkPermission(Permission.USER_DELETE, { e: EntityDetails -> e.user(login) }) + userService.deleteUser(login) + return ResponseEntity.ok().headers(HeaderUtil.createAlert("userManagement.deleted", login)).build() + } + + /** + * Get /users/:login/roles : get the "login" User roles. + * + * @param login the login of the user to get roles from + * @return the ResponseEntity with status 200 (OK) + */ + @GetMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}/roles") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getUserRoles(@PathVariable login: String?): ResponseEntity> { + log.debug("REST request to read User roles: {}", login) + authService.checkPermission(Permission.ROLE_READ, { e: EntityDetails -> e.user(login) }) + return ResponseUtil.wrapOrNotFound(userService.getUserWithAuthoritiesByLogin(login) + .map { obj: UserDTO -> obj.roles }) + } + + /** + * PUT /users/:login/roles : update the "login" User roles. + * + * @param login the login of the user to get roles from + * @return the ResponseEntity with status 200 (OK) + */ + @PutMapping("/users/{login:" + Constants.ENTITY_ID_REGEX + "}/roles") + @Timed + @Throws( + NotAuthorizedException::class + ) + fun putUserRoles( + @PathVariable login: String?, @RequestBody roleDtos: Set? + ): ResponseEntity { + log.debug("REST request to update User roles: {} to {}", login, roleDtos) + authService.checkPermission(Permission.ROLE_UPDATE, { e: EntityDetails -> e.user(login) }) + userService.updateRoles(login!!, roleDtos) + return ResponseEntity.noContent().build() + } + + companion object { + private val log = LoggerFactory.getLogger(UserResource::class.java) + } +} diff --git a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.java b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.java index 740c59b65..2d2b3ca52 100644 --- a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.java +++ b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.java @@ -154,7 +154,7 @@ private static User createAdminUser() { User user = new User(); user.setId(1L); user.setLogin("admin"); - user.setActivated(true); + user.activated = true; user.setRoles(Set.of( new Role(new Authority("ROLE_SYS_ADMIN")) )); diff --git a/src/test/java/org/radarbase/management/service/UserServiceIntTest.java b/src/test/java/org/radarbase/management/service/UserServiceIntTest.java index f4fa5bc1f..263abfa37 100644 --- a/src/test/java/org/radarbase/management/service/UserServiceIntTest.java +++ b/src/test/java/org/radarbase/management/service/UserServiceIntTest.java @@ -116,12 +116,12 @@ public void setUp() { public static User createEntity(PasswordService passwordService) { User user = new User(); user.setLogin(DEFAULT_LOGIN); - user.setPassword(passwordService.generateEncodedPassword()); - user.setActivated(true); - user.setEmail(DEFAULT_EMAIL); - user.setFirstName(DEFAULT_FIRSTNAME); - user.setLastName(DEFAULT_LASTNAME); - user.setLangKey(DEFAULT_LANGKEY); + user.password = passwordService.generateEncodedPassword(); + user.activated = true; + user.email = DEFAULT_EMAIL; + user.firstName = DEFAULT_FIRSTNAME; + user.lastName = DEFAULT_LASTNAME; + user.langKey = DEFAULT_LANGKEY; return user; } @@ -133,9 +133,9 @@ void assertThatUserMustExistToResetPassword() { maybeUser = userService.requestPasswordReset("admin@localhost"); assertThat(maybeUser).isPresent(); - assertThat(maybeUser.get().getEmail()).isEqualTo("admin@localhost"); - assertThat(maybeUser.get().getResetDate()).isNotNull(); - assertThat(maybeUser.get().getResetKey()).isNotNull(); + assertThat(maybeUser.get().email).isEqualTo("admin@localhost"); + assertThat(maybeUser.get().resetDate).isNotNull(); + assertThat(maybeUser.get().resetKey).isNotNull(); } @Test @@ -152,14 +152,14 @@ void assertThatResetKeyMustNotBeOlderThan24Hours() throws NotAuthorizedException ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(25); String resetKey = passwordService.generateResetKey(); - user.setActivated(true); - user.setResetDate(daysAgo); - user.setResetKey(resetKey); + user.activated = true; + user.resetDate = daysAgo; + user.resetKey = resetKey; userRepository.save(user); Optional maybeUser = userService.completePasswordReset("johndoe2", - user.getResetKey()); + user.resetKey); assertThat(maybeUser).isNotPresent(); @@ -170,12 +170,12 @@ void assertThatResetKeyMustNotBeOlderThan24Hours() throws NotAuthorizedException void assertThatResetKeyMustBeValid() throws NotAuthorizedException { User user = userService.createUser(userDto); ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(25); - user.setActivated(true); - user.setResetDate(daysAgo); - user.setResetKey("1234"); + user.activated = true; + user.resetDate = daysAgo; + user.resetKey = "1234"; userRepository.save(user); Optional maybeUser = userService.completePasswordReset("johndoe2", - user.getResetKey()); + user.resetKey); assertThat(maybeUser).isNotPresent(); userRepository.delete(user); } @@ -183,19 +183,19 @@ void assertThatResetKeyMustBeValid() throws NotAuthorizedException { @Test void assertThatUserCanResetPassword() throws NotAuthorizedException { User user = userService.createUser(userDto); - final String oldPassword = user.getPassword(); + final String oldPassword = user.password; ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(2); String resetKey = passwordService.generateResetKey(); - user.setActivated(true); - user.setResetDate(daysAgo); - user.setResetKey(resetKey); + user.activated = true; + user.resetDate = daysAgo; + user.resetKey = resetKey; userRepository.save(user); Optional maybeUser = userService.completePasswordReset("johndoe2", - user.getResetKey()); + user.resetKey); assertThat(maybeUser).isPresent(); - assertThat(maybeUser.get().getResetDate()).isNull(); - assertThat(maybeUser.get().getResetKey()).isNull(); - assertThat(maybeUser.get().getPassword()).isNotEqualTo(oldPassword); + assertThat(maybeUser.get().resetDate).isNull(); + assertThat(maybeUser.get().resetKey).isNull(); + assertThat(maybeUser.get().password).isNotEqualTo(oldPassword); userRepository.delete(user); } @@ -216,12 +216,12 @@ void testFindNotActivatedUsersByCreationDateBefore() { .computeAggregationInInstanceContext()) .getSingleResult(); CustomRevisionEntity first = (CustomRevisionEntity) firstRevision[1]; - first.setTimestamp(Date.from(expDateTime.toInstant())); + first.timestamp = Date.from(expDateTime.toInstant()); entityManager.joinTransaction(); CustomRevisionEntity updated = entityManager.merge(first); commitTransactionAndStartNew(); - assertThat(updated.getTimestamp()).isEqualTo(first.getTimestamp()); - assertThat(updated.getTimestamp()).isEqualTo(Date.from(expDateTime.toInstant())); + assertThat(updated.timestamp).isEqualTo(first.timestamp); + assertThat(updated.timestamp).isEqualTo(Date.from(expDateTime.toInstant())); // make sure when we reload the expired user we have the new created date assertThat(revisionService.getAuditInfo(expiredUser).getCreatedAt()).isEqualTo(expDateTime); @@ -234,7 +234,7 @@ void testFindNotActivatedUsersByCreationDateBefore() { assertThat(numUsers - users.size()).isEqualTo(1); // remaining users should be either activated or have a created date less then 3 days ago ZonedDateTime cutoff = ZonedDateTime.now().minus(Period.ofDays(3)); - users.forEach(u -> assertThat(u.getActivated() || revisionService.getAuditInfo(u) + users.forEach(u -> assertThat(u.activated || revisionService.getAuditInfo(u) .getCreatedAt().isAfter(cutoff)).isTrue()); // commit the deletion, otherwise the deletion will be rolled back commitTransactionAndStartNew(); @@ -259,17 +259,17 @@ public User addExpiredUser(UserRepository userRepository) { Role adminRole = new Role(); adminRole.setId(1L); - adminRole.setAuthority(new Authority(SYS_ADMIN)); - adminRole.setProject(null); + adminRole.authority = new Authority(SYS_ADMIN); + adminRole.project = null; User user = new User(); user.setLogin("expired"); - user.setEmail("expired@expired"); - user.setFirstName("ex"); - user.setLastName("pired"); + user.email = "expired@expired"; + user.firstName = "ex"; + user.lastName = "pired"; user.setRoles(Collections.singleton(adminRole)); - user.setActivated(false); - user.setPassword(passwordService.generateEncodedPassword()); + user.activated = false; + user.password = passwordService.generateEncodedPassword(); return userRepository.save(user); } diff --git a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.java index 64fe2e69e..ae1ea69eb 100644 --- a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.java @@ -128,16 +128,16 @@ void testAuthenticatedUser() throws Exception { Set roles = new HashSet<>(); org.radarbase.management.domain.Role role = new org.radarbase.management.domain.Role(); Authority authority = new Authority(); - authority.setName(RoleAuthority.SYS_ADMIN.getAuthority()); - role.setAuthority(authority); + authority.name = RoleAuthority.SYS_ADMIN.getAuthority(); + role.authority = authority; roles.add(role); User user = new User(); user.setLogin("test"); - user.setFirstName("john"); - user.setLastName("doe"); - user.setEmail("john.doe@jhipster.com"); - user.setLangKey("en"); + user.firstName = "john"; + user.lastName = "doe"; + user.email = "john.doe@jhipster.com"; + user.langKey = "en"; user.setRoles(roles); when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.of(user)); @@ -164,16 +164,16 @@ void testGetExistingAccount() throws Exception { Set roles = new HashSet<>(); org.radarbase.management.domain.Role role = new org.radarbase.management.domain.Role(); Authority authority = new Authority(); - authority.setName(RoleAuthority.SYS_ADMIN.getAuthority()); - role.setAuthority(authority); + authority.name = RoleAuthority.SYS_ADMIN.getAuthority(); + role.authority = authority; roles.add(role); User user = new User(); user.setLogin("test"); - user.setFirstName("john"); - user.setLastName("doe"); - user.setEmail("john.doe@jhipster.com"); - user.setLangKey("en"); + user.firstName = "john"; + user.lastName = "doe"; + user.email = "john.doe@jhipster.com"; + user.langKey = "en"; user.setRoles(roles); when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.of(user)); diff --git a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.java index eed2114c7..c36f509e1 100644 --- a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.java @@ -95,9 +95,9 @@ public void setUp() throws ServletException { public void initTest() { auditEventRepository.deleteAll(); auditEvent = new PersistentAuditEvent(); - auditEvent.setAuditEventType(SAMPLE_TYPE); - auditEvent.setPrincipal(SAMPLE_PRINCIPAL); - auditEvent.setAuditEventDate(SAMPLE_TIMESTAMP); + auditEvent.auditEventType = SAMPLE_TYPE; + auditEvent.principal = SAMPLE_PRINCIPAL; + auditEvent.auditEventDate = SAMPLE_TIMESTAMP; } @Test @@ -118,7 +118,7 @@ void getAudit() throws Exception { auditEventRepository.save(auditEvent); // Get the audit - restAuditMockMvc.perform(get("/management/audits/{id}", auditEvent.getId())) + restAuditMockMvc.perform(get("/management/audits/{id}", auditEvent.id)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.principal").value(SAMPLE_PRINCIPAL)); diff --git a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.java index db4c03fae..31be75902 100644 --- a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.java @@ -127,7 +127,7 @@ public void setUp() throws ServletException { @AfterEach public void tearDown() { groupRepository.delete(group); - var roles = roleRepository.findAllRolesByProjectName(project.getProjectName()); + var roles = roleRepository.findAllRolesByProjectName(project.projectName); roleRepository.deleteAll(roles); projectRepository.delete(project); } @@ -137,8 +137,8 @@ public void tearDown() { */ private Group createEntity() { Group group = new Group(); - group.setName("group1"); - group.setProject(project); + group.name = "group1"; + group.project = project; return group; } @@ -147,17 +147,17 @@ void createGroup() throws Exception { // Create the Group var groupDto = groupMapper.groupToGroupDTO(group); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.getProjectName()) + project.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(groupDto))) .andExpect(status().isCreated()); var savedGroup = groupRepository.findByProjectNameAndName( - project.getProjectName(), groupDto.getName()).get(); + project.projectName, groupDto.getName()).get(); // Validate the Group in the database - assertThat(savedGroup.getProject().getId()).isEqualTo(project.getId()); - assertThat(savedGroup.getName()).isEqualTo("group1"); + assertThat(savedGroup.project.getId()).isEqualTo(project.getId()); + assertThat(savedGroup.name).isEqualTo("group1"); } @@ -168,7 +168,7 @@ void createGroupNonExistingProject() throws Exception { // Create the Group var groupDto = groupMapper.groupToGroupDTO(group); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.getProjectName()) + project.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(groupDto))) .andExpect(status().isNotFound()); @@ -179,13 +179,13 @@ void createGroupWithExistingName() throws Exception { // Create the Group var groupDto = groupMapper.groupToGroupDTO(group); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.getProjectName()) + project.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(groupDto))) .andExpect(status().isCreated()); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.getProjectName()) + project.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(groupDto))) .andExpect(status().isConflict()); @@ -195,53 +195,53 @@ void createGroupWithExistingName() throws Exception { @Test void createGroupWithExistingNameInDifferentProject() throws Exception { Project project2 = ProjectResourceIntTest.createEntity() - .projectName(project.getProjectName() + "2"); + .projectName(project.projectName + "2"); projectRepository.saveAndFlush(project2); Group group2 = new Group(); - group2.setName(group.getName()); - group2.setProject(project2); + group2.name = group.name; + group2.project = project2; // Create the Group var groupDto = groupMapper.groupToGroupDTO(group); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.getProjectName()) + project.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(groupDto))) .andExpect(status().isCreated()); var group2Dto = groupMapper.groupToGroupDTO(group2); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project2.getProjectName()) + project2.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(group2Dto))) .andExpect(status().isCreated()); // Validate groups are saved for both projects var savedGroup1 = groupRepository.findByProjectNameAndName( - project.getProjectName(), group.getName()).get(); + project.projectName, group.name).get(); var savedGroup2 = groupRepository.findByProjectNameAndName( - project2.getProjectName(), group2.getName()).get(); + project2.projectName, group2.name).get(); var groupList = Arrays.asList(savedGroup1, savedGroup2); assertThat(groupList).hasSize(2); assertThat(groupList).haveAtLeastOne(new Condition<>( - g -> project.getId().equals(g.getProject().getId()), "use project 1")); + g -> project.getId().equals(g.project.getId()), "use project 1")); assertThat(groupList).haveAtLeastOne(new Condition<>( - g -> project2.getId().equals(g.getProject().getId()), "use project 2")); + g -> project2.getId().equals(g.project.getId()), "use project 2")); assertThat(groupList).allSatisfy( - g -> assertThat(g.getName()).isEqualTo(group.getName())); + g -> assertThat(g.name).isEqualTo(group.name)); projectRepository.delete(project2); } @Test void checkGroupNameIsRequired() throws Exception { - group.setName(null); + group.name = null; // Create the Group GroupDTO groupDto = groupMapper.groupToGroupDTO(group); restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.getProjectName()) + project.projectName) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(groupDto))) .andExpect(status().isBadRequest()); @@ -254,7 +254,7 @@ void getAllGroups() throws Exception { // Get all the groups restGroupMockMvc.perform(get("/api/projects/{projectName}/groups", - project.getProjectName())) + project.projectName)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.[*].projectId").value( @@ -269,7 +269,7 @@ void getGroup() throws Exception { // Get the Group restGroupMockMvc.perform(get("/api/projects/{projectName}/groups/{groupName}", - project.getProjectName(), group.getName())) + project.projectName, group.name)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.name").value("group1")) @@ -280,7 +280,7 @@ void getGroup() throws Exception { void getNonExistingGroup() throws Exception { // Get the Group restGroupMockMvc.perform(get("/api/projects/{projectName}/groups/{groupName}", - project.getProjectName(), group.getName())) + project.projectName, group.name)) .andExpect(status().isNotFound()); } @@ -292,13 +292,13 @@ void deleteGroup() throws Exception { // Get the Group restGroupMockMvc.perform(delete( "/api/projects/{projectName}/groups/{groupName}", - project.getProjectName(), group.getName()) + project.projectName, group.name) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isNoContent()); // Validate the Group is not present in the database var savedGroup = groupRepository.findByProjectNameAndName( - project.getProjectName(), group.getName()); + project.projectName, group.name); assertThat(savedGroup).isEmpty(); } @@ -314,27 +314,27 @@ void deleteGroupWithSubjects() throws Exception { subjectDto.setExternalId("exId1"); subjectDto.setStatus(ACTIVATED); subjectDto.setProject(projectDto); - subjectDto.setGroup(group.getName()); + subjectDto.setGroup(group.name); var savedSubject = subjectService.createSubject(subjectDto); // Try to delete the Group (and fail) restGroupMockMvc.perform(delete( "/api/projects/{projectName}/groups/{groupName}", - project.getProjectName(), group.getName()) + project.projectName, group.name) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isConflict()); // Delete the Group (and unlink the subjects) restGroupMockMvc.perform(delete( "/api/projects/{projectName}/groups/{groupName}", - project.getProjectName(), group.getName()) + project.projectName, group.name) .param("unlinkSubjects", "true") .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isNoContent()); // Validate the Group is not present in the database var savedGroup = groupRepository.findByProjectNameAndName( - project.getProjectName(), group.getName()); + project.projectName, group.name); assertThat(savedGroup).isEmpty(); var storedSubject = subjectRepository.getOne(savedSubject.getId()); @@ -349,7 +349,7 @@ void deleteGroupNonExisting() throws Exception { // Get the Group restGroupMockMvc.perform(delete( "/api/projects/{projectName}/groups/{groupName}", - project.getProjectName(), group.getName() + "2") + project.projectName, group.name + "2") .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isNotFound()); @@ -366,7 +366,7 @@ void deleteGroupNonExistingProject() throws Exception { // Get the Group restGroupMockMvc.perform(delete( "/api/projects/{projectName}/groups/{groupName}", - project.getProjectName() + "2", group.getName()) + project.projectName + "2", group.name) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isNotFound()); @@ -414,7 +414,7 @@ void addSubjectsToGroup() throws Exception { // Get the Group restGroupMockMvc.perform(patch( "/api/projects/{projectName}/groups/{groupName}/subjects", - project.getProjectName(), group.getName()) + project.projectName, group.name) .contentType(TestUtil.APPLICATION_JSON_PATCH) .content(TestUtil.convertObjectToJsonBytes(body))) @@ -425,7 +425,7 @@ void addSubjectsToGroup() throws Exception { var subjects = subjectRepository.findAllBySubjectLogins(subjectLogins); assertThat(subjects).hasSize(2); assertThat(subjects).allSatisfy( - s -> assertThat(s.getGroup().getId()).isEqualTo(group.getId())); + s -> assertThat(s.group.getId()).isEqualTo(group.getId())); subjectRepository.deleteAll(subjects); } diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.java index a2f4d9ce4..34d847382 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.java @@ -96,7 +96,7 @@ public void setUp() throws ServletException { @AfterEach public void tearDown() { - var testOrg = organizationRepository.findOneByName(organization.getName()); + var testOrg = organizationRepository.findOneByName(organization.name); testOrg.ifPresent(organizationRepository::delete); } @@ -105,9 +105,9 @@ public void tearDown() { */ private Organization createEntity() { var org = new Organization(); - org.setName("org1"); - org.setDescription("Test Organization 1"); - org.setLocation("Somewhere"); + org.name = "org1"; + org.description = "Test Organization 1"; + org.location = "Somewhere"; return org; } @@ -168,7 +168,7 @@ void getOrganization() throws Exception { // Get the organization restOrganizationMockMvc.perform(get("/api/organizations/{name}", - organization.getName())) + organization.name)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.name").value("org1")); @@ -191,7 +191,7 @@ void editOrganization() throws Exception { // Get the organization restOrganizationMockMvc.perform(get("/api/organizations/{name}", - organization.getName())) + organization.name)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.location").value("Other location")); @@ -201,7 +201,7 @@ void editOrganization() throws Exception { void getNonExistingOrganization() throws Exception { // Get the organization restOrganizationMockMvc.perform(get("/api/organizations/{name}", - organization.getName())) + organization.name)) .andExpect(status().isNotFound()); } @@ -217,7 +217,7 @@ void getProjectsByOrganizationName() throws Exception { // Get projects of the organization restOrganizationMockMvc.perform(get("/api/organizations/{name}/projects", - organization.getName())) + organization.name)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.[*].projectName").value("organization_project")); diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.java index 36767833b..e62a5007e 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.java @@ -139,7 +139,7 @@ public void setUp() throws ServletException { public static Project createEntity() { Organization organization = new Organization(); organization.setId(1L); - organization.setName("main"); + organization.name = "main"; return new Project() .projectName(DEFAULT_PROJECT_NAME) .description(DEFAULT_DESCRIPTION) @@ -172,13 +172,13 @@ void createProject() throws Exception { List projectList = projectRepository.findAll(); assertThat(projectList).hasSize(databaseSizeBeforeCreate + 1); Project testProject = projectList.get(projectList.size() - 1); - assertThat(testProject.getProjectName()).isEqualTo(DEFAULT_PROJECT_NAME); - assertThat(testProject.getDescription()).isEqualTo(DEFAULT_DESCRIPTION); - assertThat(testProject.getOrganizationName()).isEqualTo(DEFAULT_ORGANIZATION); - assertThat(testProject.getLocation()).isEqualTo(DEFAULT_LOCATION); - assertThat(testProject.getStartDate()).isEqualTo(DEFAULT_START_DATE); - assertThat(testProject.getProjectStatus()).isEqualTo(DEFAULT_PROJECT_STATUS); - assertThat(testProject.getEndDate()).isEqualTo(DEFAULT_END_DATE); + assertThat(testProject.projectName).isEqualTo(DEFAULT_PROJECT_NAME); + assertThat(testProject.description).isEqualTo(DEFAULT_DESCRIPTION); + assertThat(testProject.organizationName).isEqualTo(DEFAULT_ORGANIZATION); + assertThat(testProject.location).isEqualTo(DEFAULT_LOCATION); + assertThat(testProject.startDate).isEqualTo(DEFAULT_START_DATE); + assertThat(testProject.projectStatus).isEqualTo(DEFAULT_PROJECT_STATUS); + assertThat(testProject.endDate).isEqualTo(DEFAULT_END_DATE); } @Test @@ -206,7 +206,7 @@ void createProjectWithExistingId() throws Exception { void checkProjectNameIsRequired() throws Exception { int databaseSizeBeforeTest = projectRepository.findAll().size(); // set the field null - project.setProjectName(null); + project.projectName = null; // Create the Project, which fails. ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); @@ -225,7 +225,7 @@ void checkProjectNameIsRequired() throws Exception { void checkDescriptionIsRequired() throws Exception { int databaseSizeBeforeTest = projectRepository.findAll().size(); // set the field null - project.setDescription(null); + project.description = null; // Create the Project, which fails. ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); @@ -244,7 +244,7 @@ void checkDescriptionIsRequired() throws Exception { void checkLocationIsRequired() throws Exception { int databaseSizeBeforeTest = projectRepository.findAll().size(); // set the field null - project.setLocation(null); + project.location = null; // Create the Project, which fails. ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); @@ -287,7 +287,7 @@ void getProject() throws Exception { projectRepository.saveAndFlush(project); // Get the project - restProjectMockMvc.perform(get("/api/projects/{projectName}", project.getProjectName())) + restProjectMockMvc.perform(get("/api/projects/{projectName}", project.projectName)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id").value(project.getId().intValue())) @@ -315,9 +315,9 @@ void updateProject() throws Exception { projectRepository.saveAndFlush(project); var org = new Organization(); - org.setName("org1"); - org.setDescription("Test Organization 1"); - org.setLocation("Somewhere"); + org.name = "org1"; + org.description = "Test Organization 1"; + org.location = "Somewhere"; organizationRepository.saveAndFlush(org); assertThat(org.getId()).isNotNull(); @@ -346,14 +346,14 @@ void updateProject() throws Exception { List projectList = projectRepository.findAll(); assertThat(projectList).hasSize(databaseSizeBeforeUpdate); Project testProject = projectList.get(projectList.size() - 1); - assertThat(testProject.getProjectName()).isEqualTo(UPDATED_PROJECT_NAME); - assertThat(testProject.getDescription()).isEqualTo(UPDATED_DESCRIPTION); - assertThat(testProject.getOrganizationName()).isEqualTo(UPDATED_ORGANIZATION); - assertThat(testProject.getOrganization()).isEqualTo(org); - assertThat(testProject.getLocation()).isEqualTo(UPDATED_LOCATION); - assertThat(testProject.getStartDate()).isEqualTo(UPDATED_START_DATE); - assertThat(testProject.getProjectStatus()).isEqualTo(UPDATED_PROJECT_STATUS); - assertThat(testProject.getEndDate()).isEqualTo(UPDATED_END_DATE); + assertThat(testProject.projectName).isEqualTo(UPDATED_PROJECT_NAME); + assertThat(testProject.description).isEqualTo(UPDATED_DESCRIPTION); + assertThat(testProject.organizationName).isEqualTo(UPDATED_ORGANIZATION); + assertThat(testProject.organization).isEqualTo(org); + assertThat(testProject.location).isEqualTo(UPDATED_LOCATION); + assertThat(testProject.startDate).isEqualTo(UPDATED_START_DATE); + assertThat(testProject.projectStatus).isEqualTo(UPDATED_PROJECT_STATUS); + assertThat(testProject.endDate).isEqualTo(UPDATED_END_DATE); organizationRepository.delete(org); } @@ -385,7 +385,7 @@ void deleteProject() throws Exception { int databaseSizeBeforeDelete = projectRepository.findAll().size(); // Get the project - restProjectMockMvc.perform(delete("/api/projects/{projectName}", project.getProjectName()) + restProjectMockMvc.perform(delete("/api/projects/{projectName}", project.projectName) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isOk()); diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.java index 9b02328c5..0cb98eaa4 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.java @@ -160,14 +160,14 @@ void createSourceData() throws Exception { List sourceDataList = sourceDataRepository.findAll(); assertThat(sourceDataList).hasSize(databaseSizeBeforeCreate + 1); SourceData testSourceData = sourceDataList.get(sourceDataList.size() - 1); - assertThat(testSourceData.getSourceDataType()).isEqualTo(DEFAULT_SOURCE_DATA_TYPE); - assertThat(testSourceData.getSourceDataName()).isEqualTo(DEFAULT_SOURCE_DATA_NAME); - assertThat(testSourceData.getProcessingState()).isEqualTo(DEFAULT_PROCESSING_STATE); - assertThat(testSourceData.getKeySchema()).isEqualTo(DEFAULT_KEY_SCHEMA); - assertThat(testSourceData.getValueSchema()).isEqualTo(DEFAULT_VALUE_SCHEMA); - assertThat(testSourceData.getFrequency()).isEqualTo(DEFAULT_FREQUENCY); - assertThat(testSourceData.getTopic()).isEqualTo(DEFAULT_TOPIC); - assertThat(testSourceData.getUnit()).isEqualTo(DEFAULT_UNTI); + assertThat(testSourceData.sourceDataType).isEqualTo(DEFAULT_SOURCE_DATA_TYPE); + assertThat(testSourceData.sourceDataName).isEqualTo(DEFAULT_SOURCE_DATA_NAME); + assertThat(testSourceData.processingState).isEqualTo(DEFAULT_PROCESSING_STATE); + assertThat(testSourceData.keySchema).isEqualTo(DEFAULT_KEY_SCHEMA); + assertThat(testSourceData.valueSchema).isEqualTo(DEFAULT_VALUE_SCHEMA); + assertThat(testSourceData.frequency).isEqualTo(DEFAULT_FREQUENCY); + assertThat(testSourceData.topic).isEqualTo(DEFAULT_TOPIC); + assertThat(testSourceData.unit).isEqualTo(DEFAULT_UNTI); } @Test @@ -195,7 +195,7 @@ void createSourceDataWithExistingId() throws Exception { void checkSourceDataTypeIsNotRequired() throws Exception { final int databaseSizeBeforeTest = sourceDataRepository.findAll().size(); // set the field null - sourceData.setSourceDataType(null); + sourceData.sourceDataType = null; // Create the SourceData, which fails. SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); @@ -215,8 +215,8 @@ void checkSourceDataTypeIsNotRequired() throws Exception { void checkSourceDataTypeOrTopicIsRequired() throws Exception { final int databaseSizeBeforeTest = sourceDataRepository.findAll().size(); // set the field null - sourceData.setSourceDataType(null); - sourceData.setTopic(null); + sourceData.sourceDataType = null; + sourceData.topic = null; // Create the SourceData, which fails. SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); @@ -285,7 +285,7 @@ void getSourceData() throws Exception { // Get the sourceData restSourceDataMockMvc.perform(get("/api/source-data/{sourceDataName}", - sourceData.getSourceDataName())) + sourceData.sourceDataName)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id").value(sourceData.getId().intValue())) @@ -337,14 +337,14 @@ void updateSourceData() throws Exception { List sourceDataList = sourceDataRepository.findAll(); assertThat(sourceDataList).hasSize(databaseSizeBeforeUpdate); SourceData testSourceData = sourceDataList.get(sourceDataList.size() - 1); - assertThat(testSourceData.getSourceDataType()).isEqualTo(UPDATED_SOURCE_DATA_TYPE); - assertThat(testSourceData.getSourceDataName()).isEqualTo(UPDATED_SOURCE_DATA_NAME); - assertThat(testSourceData.getProcessingState()).isEqualTo(UPDATED_PROCESSING_STATE); - assertThat(testSourceData.getKeySchema()).isEqualTo(UPDATED_KEY_SCHEMA); - assertThat(testSourceData.getValueSchema()).isEqualTo(UPDATED_VALUE_SCHEMA); - assertThat(testSourceData.getTopic()).isEqualTo(UPDATED_TOPIC); - assertThat(testSourceData.getUnit()).isEqualTo(UPDATED_UNIT); - assertThat(testSourceData.getFrequency()).isEqualTo(UPDATED_FREQUENCY); + assertThat(testSourceData.sourceDataType).isEqualTo(UPDATED_SOURCE_DATA_TYPE); + assertThat(testSourceData.sourceDataName).isEqualTo(UPDATED_SOURCE_DATA_NAME); + assertThat(testSourceData.processingState).isEqualTo(UPDATED_PROCESSING_STATE); + assertThat(testSourceData.keySchema).isEqualTo(UPDATED_KEY_SCHEMA); + assertThat(testSourceData.valueSchema).isEqualTo(UPDATED_VALUE_SCHEMA); + assertThat(testSourceData.topic).isEqualTo(UPDATED_TOPIC); + assertThat(testSourceData.unit).isEqualTo(UPDATED_UNIT); + assertThat(testSourceData.frequency).isEqualTo(UPDATED_FREQUENCY); } @Test @@ -375,7 +375,7 @@ void deleteSourceData() throws Exception { // Get the sourceData restSourceDataMockMvc.perform(delete("/api/source-data/{sourceDataName}", - sourceData.getSourceDataName()) + sourceData.sourceDataName) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isOk()); diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.java index 6bdb6c70b..625a7fec8 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.java @@ -139,7 +139,7 @@ public void initTest() { source = createEntity(); List sourceTypeDtos = sourceTypeService.findAll(); assertThat(sourceTypeDtos.size()).isPositive(); - source.setSourceType(sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDtos.get(0))); + source.sourceType = sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDtos.get(0)); project = projectRepository.findById(1L).get(); source.project(project); } @@ -161,8 +161,8 @@ void createSource() throws Exception { assertThat(sourceList).hasSize(databaseSizeBeforeCreate + 1); Source testSource = sourceList.get(sourceList.size() - 1); assertThat(testSource.isAssigned()).isEqualTo(DEFAULT_ASSIGNED); - assertThat(testSource.getSourceName()).isEqualTo(DEFAULT_SOURCE_NAME); - assertThat(testSource.getProject().getProjectName()).isEqualTo(project.getProjectName()); + assertThat(testSource.sourceName).isEqualTo(DEFAULT_SOURCE_NAME); + assertThat(testSource.project.projectName).isEqualTo(project.projectName); } @Test @@ -190,7 +190,7 @@ void createSourceWithExistingId() throws Exception { void checkSourcePhysicalIdIsGenerated() throws Exception { int databaseSizeBeforeTest = sourceRepository.findAll().size(); // set the field null - source.setSourceId(null); + source.sourceId = null; // Create the Source SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(source); @@ -205,13 +205,13 @@ void checkSourcePhysicalIdIsGenerated() throws Exception { // find our created source Source createdSource = sourceList.stream() - .filter(s -> s.getSourceName().equals(DEFAULT_SOURCE_NAME)) + .filter(s -> s.sourceName.equals(DEFAULT_SOURCE_NAME)) .findFirst() .orElse(null); assertThat(createdSource).isNotNull(); // check source id - assertThat(createdSource.getSourceId()).isNotNull(); + assertThat(createdSource.sourceId).isNotNull(); } @Test @@ -256,7 +256,7 @@ void getSource() throws Exception { sourceRepository.saveAndFlush(source); // Get the source - restDeviceMockMvc.perform(get("/api/sources/{sourceName}", source.getSourceName())) + restDeviceMockMvc.perform(get("/api/sources/{sourceName}", source.sourceName)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id").value(source.getId().intValue())) @@ -295,7 +295,7 @@ void updateSource() throws Exception { List sourceList = sourceRepository.findAll(); assertThat(sourceList).hasSize(databaseSizeBeforeUpdate); Source testSource = sourceList.get(sourceList.size() - 1); - assertThat(testSource.getSourceId()).isEqualTo(UPDATED_SOURCE_PHYSICAL_ID); + assertThat(testSource.sourceId).isEqualTo(UPDATED_SOURCE_PHYSICAL_ID); assertThat(testSource.isAssigned()).isEqualTo(UPDATED_ASSIGNED); } @@ -326,7 +326,7 @@ void deleteSource() throws Exception { int databaseSizeBeforeDelete = sourceRepository.findAll().size(); // Get the source - restDeviceMockMvc.perform(delete("/api/sources/{sourceName}", source.getSourceName()) + restDeviceMockMvc.perform(delete("/api/sources/{sourceName}", source.sourceName) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isOk()); diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.java index f11b33b53..73d8864ea 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.java @@ -163,18 +163,18 @@ void createSourceType() throws Exception { List sourceTypeList = sourceTypeRepository.findAll(); assertThat(sourceTypeList).hasSize(databaseSizeBeforeCreate + 1); SourceType testSourceType = sourceTypeList.get(sourceTypeList.size() - 1); - assertThat(testSourceType.getProducer()).isEqualTo(DEFAULT_PRODUCER); - assertThat(testSourceType.getModel()).isEqualTo(DEFAULT_MODEL); - assertThat(testSourceType.getSourceTypeScope()).isEqualTo(DEFAULT_SOURCE_TYPE_SCOPE); - assertThat(testSourceType.getCatalogVersion()).isEqualTo(DEFAULT_DEVICE_VERSION); - assertThat(testSourceType.getSourceData()).hasSize(1); - SourceData testSourceData = testSourceType.getSourceData().iterator().next(); - assertThat(testSourceData.getSourceDataType()).isEqualTo(sourceDataDto.getSourceDataType()); - assertThat(testSourceData.getSourceDataName()).isEqualTo(sourceDataDto.getSourceDataName()); - assertThat(testSourceData.getProcessingState()).isEqualTo( + assertThat(testSourceType.producer).isEqualTo(DEFAULT_PRODUCER); + assertThat(testSourceType.model).isEqualTo(DEFAULT_MODEL); + assertThat(testSourceType.sourceTypeScope).isEqualTo(DEFAULT_SOURCE_TYPE_SCOPE); + assertThat(testSourceType.catalogVersion).isEqualTo(DEFAULT_DEVICE_VERSION); + assertThat(testSourceType.sourceData).hasSize(1); + SourceData testSourceData = testSourceType.sourceData.iterator().next(); + assertThat(testSourceData.sourceDataType).isEqualTo(sourceDataDto.getSourceDataType()); + assertThat(testSourceData.sourceDataName).isEqualTo(sourceDataDto.getSourceDataName()); + assertThat(testSourceData.processingState).isEqualTo( sourceDataDto.getProcessingState()); - assertThat(testSourceData.getKeySchema()).isEqualTo(sourceDataDto.getKeySchema()); - assertThat(testSourceData.getFrequency()).isEqualTo(sourceDataDto.getFrequency()); + assertThat(testSourceData.keySchema).isEqualTo(sourceDataDto.getKeySchema()); + assertThat(testSourceData.frequency).isEqualTo(sourceDataDto.getFrequency()); } @Test @@ -202,7 +202,7 @@ void createSourceTypeWithExistingId() throws Exception { void checkModelIsRequired() throws Exception { int databaseSizeBeforeTest = sourceTypeRepository.findAll().size(); // set the field null - sourceType.setModel(null); + sourceType.model = null; // Create the SourceType, which fails. SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); @@ -221,7 +221,7 @@ void checkModelIsRequired() throws Exception { void checkSourceTypeIsRequired() throws Exception { int databaseSizeBeforeTest = sourceTypeRepository.findAll().size(); // set the field null - sourceType.setSourceTypeScope(null); + sourceType.sourceTypeScope = null; // Create the SourceType, which fails. SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); @@ -300,7 +300,7 @@ void getSourceType() throws Exception { // Get the sourceType restSourceTypeMockMvc.perform(get("/api/source-types/{prodcuer}/{model}/{version}", - sourceType.getProducer(), sourceType.getModel(), sourceType.getCatalogVersion())) + sourceType.producer, sourceType.model, sourceType.catalogVersion)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.id").value(sourceType.getId().intValue())) @@ -344,10 +344,10 @@ void updateSourceType() throws Exception { List sourceTypeList = sourceTypeRepository.findAll(); assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate); SourceType testSourceType = sourceTypeList.get(sourceTypeList.size() - 1); - assertThat(testSourceType.getProducer()).isEqualTo(UPDATED_PRODUCER); - assertThat(testSourceType.getModel()).isEqualTo(UPDATED_MODEL); - assertThat(testSourceType.getCatalogVersion()).isEqualTo(UPDATED_DEVICE_VERSION); - assertThat(testSourceType.getSourceTypeScope()).isEqualTo(UPDATED_SOURCE_TYPE_SCOPE); + assertThat(testSourceType.producer).isEqualTo(UPDATED_PRODUCER); + assertThat(testSourceType.model).isEqualTo(UPDATED_MODEL); + assertThat(testSourceType.catalogVersion).isEqualTo(UPDATED_DEVICE_VERSION); + assertThat(testSourceType.sourceTypeScope).isEqualTo(UPDATED_SOURCE_TYPE_SCOPE); } @Test @@ -378,7 +378,7 @@ void deleteSourceType() throws Exception { // Get the sourceType restSourceTypeMockMvc.perform(delete("/api/source-types/{prodcuer}/{model}/{version}", - sourceType.getProducer(), sourceType.getModel(), sourceType.getCatalogVersion()) + sourceType.producer, sourceType.model, sourceType.catalogVersion) .accept(TestUtil.APPLICATION_JSON_UTF8)) .andExpect(status().isOk()); diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.java index df305e1df..885cc19f1 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.java @@ -150,10 +150,10 @@ void createSubject() throws Exception { List subjectList = subjectRepository.findAll(); assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); Subject testSubject = subjectList.get(subjectList.size() - 1); - assertThat(testSubject.getExternalLink()).isEqualTo(DEFAULT_EXTERNAL_LINK); - assertThat(testSubject.getExternalId()).isEqualTo(DEFAULT_ENTERNAL_ID); + assertThat(testSubject.externalLink).isEqualTo(DEFAULT_EXTERNAL_LINK); + assertThat(testSubject.externalId).isEqualTo(DEFAULT_ENTERNAL_ID); assertThat(testSubject.isRemoved()).isEqualTo(DEFAULT_REMOVED); - assertEquals(1, testSubject.getUser().getRoles().size()); + assertEquals(1, testSubject.user.roles.size()); } @Test @@ -238,8 +238,8 @@ void updateSubject() throws Exception { List subjectList = subjectRepository.findAll(); assertThat(subjectList).hasSize(databaseSizeBeforeUpdate); Subject testSubject = subjectList.get(subjectList.size() - 1); - assertThat(testSubject.getExternalLink()).isEqualTo(UPDATED_EXTERNAL_LINK); - assertThat(testSubject.getExternalId()).isEqualTo(UPDATED_ENTERNAL_ID); + assertThat(testSubject.externalLink).isEqualTo(UPDATED_EXTERNAL_LINK); + assertThat(testSubject.externalId).isEqualTo(UPDATED_ENTERNAL_ID); assertThat(testSubject.isRemoved()).isEqualTo(UPDATED_REMOVED); } @@ -274,10 +274,10 @@ void updateSubjectWithNewProject() throws Exception { List subjectList = subjectRepository.findAll(); assertThat(subjectList).hasSize(databaseSizeBeforeUpdate); Subject testSubject = subjectList.get(subjectList.size() - 1); - assertThat(testSubject.getExternalLink()).isEqualTo(UPDATED_EXTERNAL_LINK); - assertThat(testSubject.getExternalId()).isEqualTo(UPDATED_ENTERNAL_ID); + assertThat(testSubject.externalLink).isEqualTo(UPDATED_EXTERNAL_LINK); + assertThat(testSubject.externalId).isEqualTo(UPDATED_ENTERNAL_ID); assertThat(testSubject.isRemoved()).isEqualTo(UPDATED_REMOVED); - assertThat(testSubject.getUser().getRoles().size()).isEqualTo(2); + assertThat(testSubject.user.roles.size()).isEqualTo(2); } @Test @@ -340,7 +340,7 @@ void dynamicSourceRegistrationWithId() throws Exception { assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); Subject testSubject = subjectList.get(subjectList.size() - 1); - String subjectLogin = testSubject.getUser().getLogin(); + String subjectLogin = testSubject.user.getLogin(); assertNotNull(subjectLogin); // Create a source description @@ -377,7 +377,7 @@ void dynamicSourceRegistrationWithoutId() throws Exception { assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); Subject testSubject = subjectList.get(subjectList.size() - 1); - String subjectLogin = testSubject.getUser().getLogin(); + String subjectLogin = testSubject.user.getLogin(); assertNotNull(subjectLogin); // Create a source description @@ -422,7 +422,7 @@ void dynamicSourceRegistrationWithoutDynamicRegistrationFlag() throws Exception assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); Subject testSubject = subjectList.get(subjectList.size() - 1); - String subjectLogin = testSubject.getUser().getLogin(); + String subjectLogin = testSubject.user.getLogin(); assertNotNull(subjectLogin); // Create a source description @@ -602,7 +602,7 @@ void testDynamicRegistrationAndUpdateSourceAttributes() throws Exception { assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); Subject testSubject = subjectList.get(subjectList.size() - 1); - String subjectLogin = testSubject.getUser().getLogin(); + String subjectLogin = testSubject.user.getLogin(); assertNotNull(subjectLogin); // Create a source description diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.java index 32398df8e..dbe5abfe3 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.java +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.java @@ -161,7 +161,7 @@ public void initTest() { .ifPresent(userRepository::delete); var roles = roleRepository .findRolesByAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()) - .stream().filter(r -> r.getProject() == null) + .stream().filter(r -> r.project == null) .collect(Collectors.toList()); roleRepository.deleteAll(roles); } @@ -189,10 +189,10 @@ void createUser() throws Exception { assertThat(userList).hasSize(databaseSizeBeforeCreate + 1); User testUser = userList.get(userList.size() - 1); assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN); - assertThat(testUser.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME); - assertThat(testUser.getLastName()).isEqualTo(DEFAULT_LASTNAME); - assertThat(testUser.getEmail()).isEqualTo(DEFAULT_EMAIL); - assertThat(testUser.getLangKey()).isEqualTo(DEFAULT_LANGKEY); + assertThat(testUser.firstName).isEqualTo(DEFAULT_FIRSTNAME); + assertThat(testUser.lastName).isEqualTo(DEFAULT_LASTNAME); + assertThat(testUser.email).isEqualTo(DEFAULT_EMAIL); + assertThat(testUser.langKey).isEqualTo(DEFAULT_LANGKEY); } @Test @@ -275,17 +275,17 @@ void getAllUsers() throws Exception { // Initialize the database org.radarbase.management.domain.Role adminRole = new org.radarbase.management.domain.Role(); adminRole.setId(1L); - adminRole.setAuthority(new Authority(SYS_ADMIN)); - adminRole.setProject(null); + adminRole.authority = new Authority(SYS_ADMIN); + adminRole.project = null; User userWithRole = new User(); userWithRole.setLogin(DEFAULT_LOGIN); - userWithRole.setPassword(passwordService.generateEncodedPassword()); - userWithRole.setActivated(true); - userWithRole.setEmail(DEFAULT_EMAIL); - userWithRole.setFirstName(DEFAULT_FIRSTNAME); - userWithRole.setLastName(DEFAULT_LASTNAME); - userWithRole.setLangKey(DEFAULT_LANGKEY); + userWithRole.password = passwordService.generateEncodedPassword(); + userWithRole.activated = true; + userWithRole.email = DEFAULT_EMAIL; + userWithRole.firstName = DEFAULT_FIRSTNAME; + userWithRole.lastName = DEFAULT_LASTNAME; + userWithRole.langKey = DEFAULT_LANGKEY; userWithRole.setRoles(Collections.singleton(adminRole)); userRepository.saveAndFlush(userWithRole); @@ -345,7 +345,7 @@ void updateUser() throws Exception { managedUserVm.setFirstName(UPDATED_FIRSTNAME); managedUserVm.setLastName(UPDATED_LASTNAME); managedUserVm.setEmail(UPDATED_EMAIL); - managedUserVm.setActivated(updatedUser.getActivated()); + managedUserVm.setActivated(updatedUser.activated); managedUserVm.setLangKey(UPDATED_LANGKEY); RoleDTO role = new RoleDTO(); @@ -362,10 +362,10 @@ void updateUser() throws Exception { List userList = userRepository.findAll(); assertThat(userList).hasSize(databaseSizeBeforeUpdate); User testUser = userList.get(userList.size() - 1); - assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); - assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); - assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); - assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY); + assertThat(testUser.firstName).isEqualTo(UPDATED_FIRSTNAME); + assertThat(testUser.lastName).isEqualTo(UPDATED_LASTNAME); + assertThat(testUser.email).isEqualTo(UPDATED_EMAIL); + assertThat(testUser.langKey).isEqualTo(UPDATED_LANGKEY); } @Test @@ -389,7 +389,7 @@ void updateUserLogin() throws Exception { managedUserVm.setFirstName(UPDATED_FIRSTNAME); managedUserVm.setLastName(UPDATED_LASTNAME); managedUserVm.setEmail(UPDATED_EMAIL); - managedUserVm.setActivated(updatedUser.getActivated()); + managedUserVm.setActivated(updatedUser.activated); managedUserVm.setLangKey(UPDATED_LANGKEY); RoleDTO role = new RoleDTO(); @@ -407,10 +407,10 @@ void updateUserLogin() throws Exception { assertThat(userList).hasSize(databaseSizeBeforeUpdate); User testUser = userList.get(userList.size() - 1); assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN); - assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME); - assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME); - assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL); - assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY); + assertThat(testUser.firstName).isEqualTo(UPDATED_FIRSTNAME); + assertThat(testUser.lastName).isEqualTo(UPDATED_LASTNAME); + assertThat(testUser.email).isEqualTo(UPDATED_EMAIL); + assertThat(testUser.langKey).isEqualTo(UPDATED_LANGKEY); } @Test @@ -423,12 +423,12 @@ void updateUserExistingEmail() throws Exception { User anotherUser = new User(); anotherUser.setLogin("jhipster"); - anotherUser.setPassword(passwordService.generateEncodedPassword()); - anotherUser.setActivated(true); - anotherUser.setEmail("jhipster@localhost"); - anotherUser.setFirstName("java"); - anotherUser.setLastName("hipster"); - anotherUser.setLangKey("en"); + anotherUser.password = passwordService.generateEncodedPassword(); + anotherUser.activated = true; + anotherUser.email = "jhipster@localhost"; + anotherUser.firstName = "java"; + anotherUser.lastName = "hipster"; + anotherUser.langKey = "en"; userRepository.saveAndFlush(anotherUser); // Update the user @@ -438,12 +438,12 @@ void updateUserExistingEmail() throws Exception { ManagedUserVM managedUserVm = new ManagedUserVM(); managedUserVm.setId(updatedUser.getId()); managedUserVm.setLogin(updatedUser.getLogin()); - managedUserVm.setPassword(updatedUser.getPassword()); - managedUserVm.setFirstName(updatedUser.getFirstName()); - managedUserVm.setLastName(updatedUser.getLastName()); + managedUserVm.setPassword(updatedUser.password); + managedUserVm.setFirstName(updatedUser.firstName); + managedUserVm.setLastName(updatedUser.lastName); managedUserVm.setEmail("jhipster@localhost"); - managedUserVm.setActivated(updatedUser.getActivated()); - managedUserVm.setLangKey(updatedUser.getLangKey()); + managedUserVm.setActivated(updatedUser.activated); + managedUserVm.setLangKey(updatedUser.langKey); RoleDTO role = new RoleDTO(); role.setProjectId(project.getId()); @@ -466,12 +466,12 @@ void updateUserExistingLogin() throws Exception { User anotherUser = new User(); anotherUser.setLogin("jhipster"); - anotherUser.setPassword(passwordService.generateEncodedPassword()); - anotherUser.setActivated(true); - anotherUser.setEmail("jhipster@localhost"); - anotherUser.setFirstName("java"); - anotherUser.setLastName("hipster"); - anotherUser.setLangKey("en"); + anotherUser.password = passwordService.generateEncodedPassword(); + anotherUser.activated = true; + anotherUser.email = "jhipster@localhost"; + anotherUser.firstName = "java"; + anotherUser.lastName = "hipster"; + anotherUser.langKey = "en"; userRepository.saveAndFlush(anotherUser); // Update the user @@ -481,12 +481,12 @@ void updateUserExistingLogin() throws Exception { ManagedUserVM managedUserVm = new ManagedUserVM(); managedUserVm.setId(updatedUser.getId()); managedUserVm.setLogin("jhipster"); - managedUserVm.setPassword(updatedUser.getPassword()); - managedUserVm.setFirstName(updatedUser.getFirstName()); - managedUserVm.setLastName(updatedUser.getLastName()); - managedUserVm.setEmail(updatedUser.getEmail()); - managedUserVm.setActivated(updatedUser.getActivated()); - managedUserVm.setLangKey(updatedUser.getLangKey()); + managedUserVm.setPassword(updatedUser.password); + managedUserVm.setFirstName(updatedUser.firstName); + managedUserVm.setLastName(updatedUser.lastName); + managedUserVm.setEmail(updatedUser.email); + managedUserVm.setActivated(updatedUser.activated); + managedUserVm.setLangKey(updatedUser.langKey); RoleDTO role = new RoleDTO(); role.setProjectId(project.getId()); From 4128e5878106a7b53d5f068c9830a7f7a3835061 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:19:52 +0200 Subject: [PATCH 089/158] Rename .java to .kt --- .../auth/authentication/{OAuthHelper.java => OAuthHelper.kt} | 0 .../{ManagementPortalTestApp.java => ManagementPortalTestApp.kt} | 0 ...cationFilterIntTest.java => JwtAuthenticationFilterIntTest.kt} | 0 .../{SecurityUtilsUnitTest.java => SecurityUtilsUnitTest.kt} | 0 .../{MetaTokenServiceTest.java => MetaTokenServiceTest.kt} | 0 ...thClientServiceTestUtil.java => OAuthClientServiceTestUtil.kt} | 0 .../service/{PasswordServiceTest.java => PasswordServiceTest.kt} | 0 ...elTest.java => RedcapIntegrationWorkFlowOnServiceLevelTest.kt} | 0 .../service/{SubjectServiceTest.java => SubjectServiceTest.kt} | 0 .../service/{UserServiceIntTest.java => UserServiceIntTest.kt} | 0 .../{AccountResourceIntTest.java => AccountResourceIntTest.kt} | 0 .../rest/{AuditResourceIntTest.java => AuditResourceIntTest.kt} | 0 .../rest/{GroupResourceIntTest.java => GroupResourceIntTest.kt} | 0 .../web/rest/{LogsResourceIntTest.java => LogsResourceIntTest.kt} | 0 ...ClientsResourceIntTest.java => OAuthClientsResourceIntTest.kt} | 0 ...izationResourceIntTest.java => OrganizationResourceIntTest.kt} | 0 ...fileInfoResourceIntTest.java => ProfileInfoResourceIntTest.kt} | 0 .../{ProjectResourceIntTest.java => ProjectResourceIntTest.kt} | 0 ...ourceDataResourceIntTest.java => SourceDataResourceIntTest.kt} | 0 .../rest/{SourceResourceIntTest.java => SourceResourceIntTest.kt} | 0 ...ourceTypeResourceIntTest.java => SourceTypeResourceIntTest.kt} | 0 .../{SubjectResourceIntTest.java => SubjectResourceIntTest.kt} | 0 .../radarbase/management/web/rest/{TestUtil.java => TestUtil.kt} | 0 .../web/rest/{UserResourceIntTest.java => UserResourceIntTest.kt} | 0 .../web/util/{HeaderUtilUnitTest.java => HeaderUtilUnitTest.kt} | 0 ...heckTranslationsUnitTest.java => CheckTranslationsUnitTest.kt} | 0 26 files changed, 0 insertions(+), 0 deletions(-) rename src/test/java/org/radarbase/auth/authentication/{OAuthHelper.java => OAuthHelper.kt} (100%) rename src/test/java/org/radarbase/management/{ManagementPortalTestApp.java => ManagementPortalTestApp.kt} (100%) rename src/test/java/org/radarbase/management/security/{JwtAuthenticationFilterIntTest.java => JwtAuthenticationFilterIntTest.kt} (100%) rename src/test/java/org/radarbase/management/security/{SecurityUtilsUnitTest.java => SecurityUtilsUnitTest.kt} (100%) rename src/test/java/org/radarbase/management/service/{MetaTokenServiceTest.java => MetaTokenServiceTest.kt} (100%) rename src/test/java/org/radarbase/management/service/{OAuthClientServiceTestUtil.java => OAuthClientServiceTestUtil.kt} (100%) rename src/test/java/org/radarbase/management/service/{PasswordServiceTest.java => PasswordServiceTest.kt} (100%) rename src/test/java/org/radarbase/management/service/{RedcapIntegrationWorkFlowOnServiceLevelTest.java => RedcapIntegrationWorkFlowOnServiceLevelTest.kt} (100%) rename src/test/java/org/radarbase/management/service/{SubjectServiceTest.java => SubjectServiceTest.kt} (100%) rename src/test/java/org/radarbase/management/service/{UserServiceIntTest.java => UserServiceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{AccountResourceIntTest.java => AccountResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{AuditResourceIntTest.java => AuditResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{GroupResourceIntTest.java => GroupResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{LogsResourceIntTest.java => LogsResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{OAuthClientsResourceIntTest.java => OAuthClientsResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{OrganizationResourceIntTest.java => OrganizationResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{ProfileInfoResourceIntTest.java => ProfileInfoResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{ProjectResourceIntTest.java => ProjectResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{SourceDataResourceIntTest.java => SourceDataResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{SourceResourceIntTest.java => SourceResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{SourceTypeResourceIntTest.java => SourceTypeResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{SubjectResourceIntTest.java => SubjectResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{TestUtil.java => TestUtil.kt} (100%) rename src/test/java/org/radarbase/management/web/rest/{UserResourceIntTest.java => UserResourceIntTest.kt} (100%) rename src/test/java/org/radarbase/management/web/util/{HeaderUtilUnitTest.java => HeaderUtilUnitTest.kt} (100%) rename src/test/java/org/radarbase/management/webapp/{CheckTranslationsUnitTest.java => CheckTranslationsUnitTest.kt} (100%) diff --git a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.java b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt similarity index 100% rename from src/test/java/org/radarbase/auth/authentication/OAuthHelper.java rename to src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt diff --git a/src/test/java/org/radarbase/management/ManagementPortalTestApp.java b/src/test/java/org/radarbase/management/ManagementPortalTestApp.kt similarity index 100% rename from src/test/java/org/radarbase/management/ManagementPortalTestApp.java rename to src/test/java/org/radarbase/management/ManagementPortalTestApp.kt diff --git a/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.java b/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.java rename to src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt diff --git a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.java b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.java rename to src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt diff --git a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.java b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/service/MetaTokenServiceTest.java rename to src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt diff --git a/src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.java b/src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.kt similarity index 100% rename from src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.java rename to src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.kt diff --git a/src/test/java/org/radarbase/management/service/PasswordServiceTest.java b/src/test/java/org/radarbase/management/service/PasswordServiceTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/service/PasswordServiceTest.java rename to src/test/java/org/radarbase/management/service/PasswordServiceTest.kt diff --git a/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.java b/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.java rename to src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt diff --git a/src/test/java/org/radarbase/management/service/SubjectServiceTest.java b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/service/SubjectServiceTest.java rename to src/test/java/org/radarbase/management/service/SubjectServiceTest.kt diff --git a/src/test/java/org/radarbase/management/service/UserServiceIntTest.java b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/service/UserServiceIntTest.java rename to src/test/java/org/radarbase/management/service/UserServiceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/rest/TestUtil.java b/src/test/java/org/radarbase/management/web/rest/TestUtil.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/TestUtil.java rename to src/test/java/org/radarbase/management/web/rest/TestUtil.kt diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.java b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.java rename to src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt diff --git a/src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.java b/src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.java rename to src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.kt diff --git a/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.java b/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt similarity index 100% rename from src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.java rename to src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt From d440f1dc4e0331b5ca1a6d55fa892402dc1fa664 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:19:53 +0200 Subject: [PATCH 090/158] all code converted and compiling --- .../auth/authentication/OAuthHelper.kt | 262 +++-- .../management/ManagementPortalTestApp.kt | 140 +-- .../JwtAuthenticationFilterIntTest.kt | 148 ++- .../security/SecurityUtilsUnitTest.kt | 39 +- .../service/MetaTokenServiceTest.kt | 261 ++--- .../service/OAuthClientServiceTestUtil.kt | 52 +- .../management/service/PasswordServiceTest.kt | 89 +- ...apIntegrationWorkFlowOnServiceLevelTest.kt | 150 ++- .../management/service/SubjectServiceTest.kt | 146 ++- .../management/service/UserServiceIntTest.kt | 444 ++++---- .../web/rest/AccountResourceIntTest.kt | 385 +++---- .../web/rest/AuditResourceIntTest.kt | 308 ++--- .../web/rest/GroupResourceIntTest.kt | 718 ++++++------ .../web/rest/LogsResourceIntTest.kt | 88 +- .../web/rest/OAuthClientsResourceIntTest.kt | 415 ++++--- .../web/rest/OrganizationResourceIntTest.kt | 372 +++--- .../web/rest/ProfileInfoResourceIntTest.kt | 107 +- .../web/rest/ProjectResourceIntTest.kt | 640 ++++++----- .../web/rest/SourceDataResourceIntTest.kt | 677 ++++++----- .../web/rest/SourceResourceIntTest.kt | 490 ++++---- .../web/rest/SourceTypeResourceIntTest.kt | 686 ++++++----- .../web/rest/SubjectResourceIntTest.kt | 1007 +++++++++-------- .../radarbase/management/web/rest/TestUtil.kt | 180 ++- .../web/rest/UserResourceIntTest.kt | 831 +++++++------- .../management/web/util/HeaderUtilUnitTest.kt | 36 +- .../webapp/CheckTranslationsUnitTest.kt | 260 ++--- 26 files changed, 4585 insertions(+), 4346 deletions(-) diff --git a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt index 2d2b3ca52..3c18fd705 100644 --- a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt +++ b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt @@ -1,81 +1,68 @@ -package org.radarbase.auth.authentication; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.algorithms.Algorithm; -import org.radarbase.auth.authorization.Permission; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.test.web.servlet.request.RequestPostProcessor; - -import java.io.InputStream; -import java.security.KeyStore; -import java.security.cert.Certificate; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.time.Instant; -import java.util.Date; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Stream; - -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.radarbase.auth.jwks.JwksTokenVerifierLoader.toTokenVerifier; -import static org.radarbase.management.security.jwt.ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL; +package org.radarbase.auth.authentication + +import com.auth0.jwt.JWT +import com.auth0.jwt.algorithms.Algorithm +import org.mockito.ArgumentMatchers +import org.mockito.Mockito +import org.radarbase.auth.authorization.Permission.Companion.scopes +import org.radarbase.auth.jwks.JwksTokenVerifierLoader.Companion.toTokenVerifier +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.User +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.security.JwtAuthenticationFilter +import org.radarbase.management.security.jwt.ManagementPortalJwtAccessTokenConverter +import org.slf4j.LoggerFactory +import org.springframework.mock.web.MockHttpServletRequest +import org.springframework.security.core.Authentication +import org.springframework.test.web.servlet.request.RequestPostProcessor +import java.security.KeyStore +import java.security.interfaces.ECPrivateKey +import java.security.interfaces.ECPublicKey +import java.security.interfaces.RSAPrivateKey +import java.security.interfaces.RSAPublicKey +import java.time.Instant +import java.util.* /** * Created by dverbeec on 29/06/2017. */ -public final class OAuthHelper { - private static final Logger logger = LoggerFactory.getLogger(OAuthHelper.class); - private static String validEcToken; - private static String validRsaToken; - - public static final String TEST_KEYSTORE_PASSWORD = "radarbase"; - public static final String TEST_SIGNKEY_ALIAS = "radarbase-managementportal-ec"; - public static final String TEST_CHECKKEY_ALIAS = "radarbase-managementportal-rsa"; - public static final String[] SCOPES = Permission.scopes(); - public static final String[] AUTHORITIES = {"ROLE_SYS_ADMIN"}; - public static final String[] ROLES = {"ROLE_SYS_ADMIN"}; - public static final String[] SOURCES = {}; - public static final String[] AUD = {RES_MANAGEMENT_PORTAL}; - public static final String CLIENT = "unit_test"; - public static final String USER = "admin"; - public static final String ISS = "RADAR"; - public static final String JTI = "some-jwt-id"; - private static List verifiers; - - static { +object OAuthHelper { + private val logger = LoggerFactory.getLogger(OAuthHelper::class.java) + private var validEcToken: String? = null + private var validRsaToken: String? = null + const val TEST_KEYSTORE_PASSWORD = "radarbase" + const val TEST_SIGNKEY_ALIAS = "radarbase-managementportal-ec" + const val TEST_CHECKKEY_ALIAS = "radarbase-managementportal-rsa" + val SCOPES = scopes() + val AUTHORITIES = arrayOf("ROLE_SYS_ADMIN") + val ROLES = arrayOf("ROLE_SYS_ADMIN") + val SOURCES = arrayOf() + val AUD = arrayOf(ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL) + const val CLIENT = "unit_test" + const val USER = "admin" + const val ISS = "RADAR" + const val JTI = "some-jwt-id" + private var verifiers: List? = null + + init { try { - setUp(); - } catch (Exception e) { - logger.error("Failed to set up OAuthHelper", e); + setUp() + } catch (e: Exception) { + logger.error("Failed to set up OAuthHelper", e) } } - private OAuthHelper() { - // utility class - } - /** * Create a request post processor that adds a valid bearer token to requests for use with * MockMVC. * @return the request post processor */ - public static RequestPostProcessor bearerToken() { - return mockRequest -> { - mockRequest.addHeader("Authorization", "Bearer " + validEcToken); - return mockRequest; - }; + fun bearerToken(): RequestPostProcessor { + return RequestPostProcessor { mockRequest: MockHttpServletRequest -> + mockRequest.addHeader("Authorization", "Bearer " + validEcToken) + mockRequest + } } /** @@ -83,50 +70,52 @@ public final class OAuthHelper { * MockMVC. * @return the request post processor */ - public static RequestPostProcessor rsaBearerToken() { - return mockRequest -> { - mockRequest.addHeader("Authorization", "Bearer " + validRsaToken); - return mockRequest; - }; + fun rsaBearerToken(): RequestPostProcessor { + return RequestPostProcessor { mockRequest: MockHttpServletRequest -> + mockRequest.addHeader("Authorization", "Bearer " + validRsaToken) + mockRequest + } } /** * Set up a keypair for signing the tokens, initialize all kinds of different tokens for tests. * @throws Exception If anything goes wrong during setup */ - public static void setUp() throws Exception { - KeyStore ks = KeyStore.getInstance("PKCS12"); - try (InputStream keyStream = Thread.currentThread().getContextClassLoader() - .getResourceAsStream("config/keystore.p12")) { - if (keyStream == null) { - throw new IllegalStateException("Cannot find keystore to set up OAuth"); + @Throws(Exception::class) + fun setUp() { + val ks = KeyStore.getInstance("PKCS12") + Thread.currentThread().getContextClassLoader() + .getResourceAsStream("config/keystore.p12").use { keyStream -> + checkNotNull(keyStream) { "Cannot find keystore to set up OAuth" } + ks.load(keyStream, TEST_KEYSTORE_PASSWORD.toCharArray()) + + // get the EC keypair for signing + val privateKey = ks.getKey( + TEST_SIGNKEY_ALIAS, + TEST_KEYSTORE_PASSWORD.toCharArray() + ) as ECPrivateKey + val cert = ks.getCertificate(TEST_SIGNKEY_ALIAS) + val publicKey = cert.publicKey as ECPublicKey + val ecdsa = Algorithm.ECDSA256(publicKey, privateKey) + validEcToken = createValidToken(ecdsa) + + // also get an RSA keypair to test accepting multiple keys + val rsaPrivateKey = ks.getKey( + TEST_CHECKKEY_ALIAS, + TEST_KEYSTORE_PASSWORD.toCharArray() + ) as RSAPrivateKey + val rsaPublicKey = ks.getCertificate(TEST_CHECKKEY_ALIAS) + .publicKey as RSAPublicKey + val rsa = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey) + validRsaToken = createValidToken(rsa) + val verifierList = listOf(ecdsa, rsa) + .map{ alg: Algorithm? -> + alg?.toTokenVerifier(ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL) + } + .requireNoNulls() + .toList() + verifiers = listOf(StaticTokenVerifierLoader(verifierList)) } - - ks.load(keyStream, TEST_KEYSTORE_PASSWORD.toCharArray()); - - // get the EC keypair for signing - ECPrivateKey privateKey = (ECPrivateKey) ks.getKey(TEST_SIGNKEY_ALIAS, - TEST_KEYSTORE_PASSWORD.toCharArray()); - Certificate cert = ks.getCertificate(TEST_SIGNKEY_ALIAS); - ECPublicKey publicKey = (ECPublicKey) cert.getPublicKey(); - - Algorithm ecdsa = Algorithm.ECDSA256(publicKey, privateKey); - validEcToken = createValidToken(ecdsa); - - // also get an RSA keypair to test accepting multiple keys - RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) ks.getKey(TEST_CHECKKEY_ALIAS, - TEST_KEYSTORE_PASSWORD.toCharArray()); - RSAPublicKey rsaPublicKey = (RSAPublicKey) ks.getCertificate(TEST_CHECKKEY_ALIAS) - .getPublicKey(); - Algorithm rsa = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey); - validRsaToken = createValidToken(rsa); - - var verifierList = Stream.of(ecdsa, rsa) - .map(alg -> toTokenVerifier(alg, RES_MANAGEMENT_PORTAL)) - .toList(); - - verifiers = List.of(new StaticTokenVerifierLoader(verifierList)); - } } /** @@ -134,10 +123,14 @@ public final class OAuthHelper { * * @return an initialized JwtAuthenticationFilter */ - public static JwtAuthenticationFilter createAuthenticationFilter() { - UserRepository userRepository = mock(UserRepository.class); - when(userRepository.findOneByLogin(anyString())).thenReturn(Optional.of(createAdminUser())); - return new JwtAuthenticationFilter(createTokenValidator(), auth -> auth, userRepository); + fun createAuthenticationFilter(): JwtAuthenticationFilter { + val userRepository = Mockito.mock(UserRepository::class.java) + Mockito.`when`(userRepository.findOneByLogin(ArgumentMatchers.anyString())).thenReturn( + Optional.of( + createAdminUser() + ) + ) + return JwtAuthenticationFilter(createTokenValidator(), { auth: Authentication? -> auth }, userRepository) } /** @@ -145,40 +138,39 @@ public final class OAuthHelper { * * @return configured TokenValidator */ - public static TokenValidator createTokenValidator() { + fun createTokenValidator(): TokenValidator { // Use tokenValidator with known JWTVerifier which signs. - return new TokenValidator(verifiers); + return TokenValidator(verifiers!!) } - private static User createAdminUser() { - User user = new User(); - user.setId(1L); - user.setLogin("admin"); - user.activated = true; - user.setRoles(Set.of( - new Role(new Authority("ROLE_SYS_ADMIN")) - )); - return user; + private fun createAdminUser(): User { + val user = User() + user.id = 1L + user.setLogin("admin") + user.activated = true + user.roles = mutableSetOf(Role(Authority("ROLE_SYS_ADMIN"))) + + return user } - private static String createValidToken(Algorithm algorithm) { - Instant exp = Instant.now().plusSeconds(30 * 60); - Instant iat = Instant.now(); + private fun createValidToken(algorithm: Algorithm): String { + val exp = Instant.now().plusSeconds((30 * 60).toLong()) + val iat = Instant.now() return JWT.create() - .withIssuer(ISS) - .withIssuedAt(Date.from(iat)) - .withExpiresAt(Date.from(exp)) - .withAudience("res_ManagementPortal") - .withSubject(USER) - .withArrayClaim("scope", SCOPES) - .withArrayClaim("authorities", AUTHORITIES) - .withArrayClaim("roles", ROLES) - .withArrayClaim("sources", SOURCES) - .withArrayClaim("aud", AUD) - .withClaim("client_id", CLIENT) - .withClaim("user_name", USER) - .withClaim("jti", JTI) - .withClaim("grant_type", "password") - .sign(algorithm); + .withIssuer(ISS) + .withIssuedAt(Date.from(iat)) + .withExpiresAt(Date.from(exp)) + .withAudience("res_ManagementPortal") + .withSubject(USER) + .withArrayClaim("scope", SCOPES) + .withArrayClaim("authorities", AUTHORITIES) + .withArrayClaim("roles", ROLES) + .withArrayClaim("sources", SOURCES) + .withArrayClaim("aud", AUD) + .withClaim("client_id", CLIENT) + .withClaim("user_name", USER) + .withClaim("jti", JTI) + .withClaim("grant_type", "password") + .sign(algorithm) } } diff --git a/src/test/java/org/radarbase/management/ManagementPortalTestApp.kt b/src/test/java/org/radarbase/management/ManagementPortalTestApp.kt index 8255e99ec..aaf36d733 100644 --- a/src/test/java/org/radarbase/management/ManagementPortalTestApp.kt +++ b/src/test/java/org/radarbase/management/ManagementPortalTestApp.kt @@ -1,87 +1,91 @@ -package org.radarbase.management; +package org.radarbase.management -import org.radarbase.management.config.ApplicationProperties; -import org.radarbase.management.config.ManagementPortalProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.core.env.Environment; -import org.springframework.core.env.Profiles; -import tech.jhipster.config.JHipsterConstants; - -import javax.annotation.PostConstruct; -import java.net.InetAddress; -import java.net.UnknownHostException; +import org.radarbase.management.config.ApplicationProperties +import org.radarbase.management.config.ManagementPortalProperties +import org.slf4j.LoggerFactory +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.context.annotation.ComponentScan +import org.springframework.core.env.Environment +import org.springframework.core.env.Profiles +import tech.jhipster.config.JHipsterConstants +import java.net.InetAddress +import java.net.UnknownHostException +import javax.annotation.PostConstruct /** * This is the application configuration that excludes CommandLineRunner(i.e the sourceTypeLoader). * This is used for testing to replicate the application setup without SourceTypeLoader. */ -@ComponentScan({ - "org.radarbase.management.config", - "org.radarbase.management.domain.support", - "org.radarbase.management.filters", - "org.radarbase.management.repository", - "org.radarbase.management.service", - "org.radarbase.management.security", - "org.radarbase.management.web" -}) +@ComponentScan( + "org.radarbase.management.config", + "org.radarbase.management.domain.support", + "org.radarbase.management.filters", + "org.radarbase.management.repository", + "org.radarbase.management.service", + "org.radarbase.management.security", + "org.radarbase.management.web" +) @EnableAutoConfiguration -@EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class, - ManagementPortalProperties.class}) -public class ManagementPortalTestApp { - - private static final Logger log = LoggerFactory.getLogger(ManagementPortalTestApp.class); - - private final Environment env; - - public ManagementPortalTestApp(Environment env) { - this.env = env; - } - +@EnableConfigurationProperties( + LiquibaseProperties::class, ApplicationProperties::class, ManagementPortalProperties::class +) +class ManagementPortalTestApp(private val env: Environment) { /** * Initializes ManagementPortal. * - *

Spring profiles can be configured with a program arguments - * --spring.profiles.active=your-active-profile

* - *

You can find more information on how profiles work with JHipster on - * - * http://jhipster.github.io/profiles/ - *

. + * Spring profiles can be configured with a program arguments + * --spring.profiles.active=your-active-profile + * + * + * You can find more information on how profiles work with JHipster on + * [ + * http://jhipster.github.io/profiles/ +](http://jhipster.github.io/profiles/) * . */ @PostConstruct - public void initApplication() { + fun initApplication() { if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) - && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_PRODUCTION))) { - log.error("You have misconfigured your application! It should not run " - + "with both the 'dev' and 'prod' profiles at the same time."); + && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) + ) { + log.error( + "You have misconfigured your application! It should not run " + + "with both the 'dev' and 'prod' profiles at the same time." + ) } if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) - && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_CLOUD))) { - log.error("You have misconfigured your application! It should not" - + "run with both the 'dev' and 'cloud' profiles at the same time."); + && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_CLOUD)) + ) { + log.error( + "You have misconfigured your application! It should not" + + "run with both the 'dev' and 'cloud' profiles at the same time." + ) } } - /** - * Main method, used to run the application. - * - * @param args the command line arguments - * @throws UnknownHostException if the local host name could not be resolved into an address - */ - public static void main(String[] args) throws UnknownHostException { - SpringApplication app = new SpringApplication(ManagementPortalTestApp.class); - Environment env = app.run(args).getEnvironment(); - String protocol = "http"; - if (env.getProperty("server.ssl.key-store") != null) { - protocol = "https"; - } - log.info("\n--------------------------------------------------\n\t" + companion object { + private val log = LoggerFactory.getLogger(ManagementPortalTestApp::class.java) + + /** + * Main method, used to run the application. + * + * @param args the command line arguments + * @throws UnknownHostException if the local host name could not be resolved into an address + */ + @Throws(UnknownHostException::class) + @JvmStatic + fun main(args: Array) { + val app = SpringApplication(ManagementPortalTestApp::class.java) + val env: Environment = app.run(*args).environment + var protocol = "http" + if (env.getProperty("server.ssl.key-store") != null) { + protocol = "https" + } + log.info( + "\n--------------------------------------------------\n\t" + "Application '{}' is running! Access URLs:\n\t" + "Local: \t\t{}://localhost:{}\n\t" + "External: \t{}://{}:{}\n\t" @@ -90,8 +94,10 @@ public class ManagementPortalTestApp { protocol, env.getProperty("server.port"), protocol, - InetAddress.getLocalHost().getHostAddress(), + InetAddress.getLocalHost().hostAddress, env.getProperty("server.port"), - env.getActiveProfiles()); + env.activeProfiles + ) + } } } diff --git a/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt b/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt index 9e8e39d56..ca746c255 100644 --- a/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt +++ b/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt @@ -1,95 +1,87 @@ -package org.radarbase.management.security; +package org.radarbase.management.security -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ProjectService; -import org.radarbase.management.web.rest.ProjectResource; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import javax.servlet.ServletException; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ProjectService +import org.radarbase.management.web.rest.ProjectResource +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import javax.servlet.ServletException /** * Test class for the JwtAuthenticationFilter class. * * @see JwtAuthenticationFilter */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class JwtAuthenticationFilterIntTest { - - @Autowired - private ProjectService projectService; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - private MockMvc rsaRestProjectMockMvc; - - private MockMvc ecRestProjectMockMvc; - @Autowired - private AuthService authService; +internal class JwtAuthenticationFilterIntTest( + @Autowired private val projectService: ProjectService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + private var rsaRestProjectMockMvc: MockMvc, + private var ecRestProjectMockMvc: MockMvc, + @Autowired private val authService: AuthService +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - ProjectResource projectResource = new ProjectResource(); - ReflectionTestUtils.setField(projectResource, "projectService", projectService); - ReflectionTestUtils.setField(projectResource, "authService", authService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.rsaRestProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/") - .with(OAuthHelper.rsaBearerToken())) - .build(); - - this.ecRestProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/") - .with(OAuthHelper.bearerToken())) - .build(); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val projectResource = ProjectResource + ReflectionTestUtils.setField(projectResource, "projectService", projectService) + ReflectionTestUtils.setField(projectResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + rsaRestProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest( + MockMvcRequestBuilders.get("/") + .with(OAuthHelper.rsaBearerToken()) + ) + .build() + ecRestProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest( + MockMvcRequestBuilders.get("/") + .with(OAuthHelper.bearerToken()) + ) + .build() } @Test - void testMultipleSigningKeys() throws Exception { + @Throws(Exception::class) + fun testMultipleSigningKeys() { // Check that we can get the project list with both RSA and EC signed token. We are testing // acceptance of the tokens, so no test on the content of the response is performed here. - rsaRestProjectMockMvc.perform(get("/api/projects?sort=id,desc")) - .andExpect(status().isOk()); - ecRestProjectMockMvc.perform(get("/api/projects?sort=id,desc")) - .andExpect(status().isOk()); + rsaRestProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + ecRestProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) } } diff --git a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt index 3e1008354..6bfdb36ce 100644 --- a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt +++ b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt @@ -1,26 +1,25 @@ -package org.radarbase.management.security; +package org.radarbase.management.security -import org.junit.jupiter.api.Test; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; - -import static org.assertj.core.api.Assertions.assertThat; +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.Test +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.context.SecurityContextHolder /** -* Test class for the SecurityUtils utility class. -* -* @see SecurityUtils -*/ -class SecurityUtilsUnitTest { - + * Test class for the SecurityUtils utility class. + * + * @see SecurityUtils + */ +internal class SecurityUtilsUnitTest { @Test - void testGetCurrentUserLogin() { - SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); - securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", - "admin")); - SecurityContextHolder.setContext(securityContext); - String login = SecurityUtils.getCurrentUserLogin().orElse(null); - assertThat(login).isEqualTo("admin"); + fun testGetCurrentUserLogin() { + val securityContext = SecurityContextHolder.createEmptyContext() + securityContext.authentication = UsernamePasswordAuthenticationToken( + "admin", + "admin" + ) + SecurityContextHolder.setContext(securityContext) + val login = SecurityUtils.getCurrentUserLogin().orElse(null) + Assertions.assertThat(login).isEqualTo("admin") } } diff --git a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt index bc39cd18f..b4f3f447d 100644 --- a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt @@ -1,171 +1,136 @@ -package org.radarbase.management.service; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.MetaToken; -import org.radarbase.management.repository.MetaTokenRepository; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.dto.TokenDTO; -import org.radarbase.management.service.mapper.SubjectMapper; -import org.radarbase.management.web.rest.errors.RadarWebApplicationException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.transaction.annotation.Transactional; - -import java.net.MalformedURLException; -import java.time.Duration; -import java.time.Instant; -import java.util.Arrays; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +package org.radarbase.management.service + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.MetaToken +import org.radarbase.management.repository.MetaTokenRepository +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.mapper.SubjectMapper +import org.radarbase.management.web.rest.errors.RadarWebApplicationException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.security.oauth2.provider.ClientDetails +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.transaction.annotation.Transactional +import java.net.MalformedURLException +import java.time.Duration +import java.time.Instant +import java.util.* /** * Test class for the MetaTokenService class. * * @see MetaTokenService */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -class MetaTokenServiceTest { - - - @Autowired - private MetaTokenService metaTokenService; - - @Autowired - private MetaTokenRepository metaTokenRepository; - - @Autowired - private SubjectService subjectService; - - @Autowired - private SubjectMapper subjectMapper; - - @Autowired - private OAuthClientService oAuthClientService; - - private ClientDetails clientDetails; - - private SubjectDTO subjectDto; +internal open class MetaTokenServiceTest( + @Autowired private val metaTokenService: MetaTokenService, + @Autowired private val metaTokenRepository: MetaTokenRepository, + @Autowired private val subjectService: SubjectService, + @Autowired private val subjectMapper: SubjectMapper, + @Autowired private val oAuthClientService: OAuthClientService, + private var clientDetails: ClientDetails, + private var subjectDto: SubjectDTO +) { @BeforeEach - public void setUp() { - subjectDto = SubjectServiceTest.createEntityDTO(); - subjectDto = subjectService.createSubject(subjectDto); - - clientDetails = oAuthClientService - .createClientDetail(OAuthClientServiceTestUtil.createClient()); + fun setUp() { + subjectDto = SubjectServiceTest.createEntityDTO() + subjectDto = subjectService.createSubject(subjectDto)!! + clientDetails = oAuthClientService.createClientDetail(OAuthClientServiceTestUtil.createClient())!! } @Test - void testSaveThenFetchMetaToken() throws MalformedURLException { - - MetaToken metaToken = new MetaToken() - .generateName(MetaToken.SHORT_ID_LENGTH) - .fetched(false) - .persistent(false) - .expiryDate(Instant.now().plus(Duration.ofHours(1))) - .subject(subjectMapper.subjectDTOToSubject(subjectDto)) - .clientId(clientDetails.getClientId()); - - MetaToken saved = metaTokenService.save(metaToken); - assertNotNull(saved.getId()); - assertNotNull(saved.getTokenName()); - assertFalse(saved.isFetched()); - assertTrue(saved.getExpiryDate().isAfter(Instant.now())); - - String tokenName = saved.getTokenName(); - TokenDTO fetchedToken = metaTokenService.fetchToken(tokenName); - - assertNotNull(fetchedToken); - assertNotNull(fetchedToken.getRefreshToken()); - + @Throws(MalformedURLException::class) + fun testSaveThenFetchMetaToken() { + val metaToken = MetaToken() + .generateName(MetaToken.SHORT_ID_LENGTH) + .fetched(false) + .persistent(false) + .expiryDate(Instant.now().plus(Duration.ofHours(1))) + .subject(subjectMapper.subjectDTOToSubject(subjectDto)) + .clientId(clientDetails.clientId) + val saved = metaTokenService.save(metaToken) + Assertions.assertNotNull(saved.id) + Assertions.assertNotNull(saved.tokenName) + Assertions.assertFalse(saved.isFetched()) + Assertions.assertTrue(saved.expiryDate!!.isAfter(Instant.now())) + val tokenName = saved.tokenName + val fetchedToken = metaTokenService.fetchToken(tokenName!!) + Assertions.assertNotNull(fetchedToken) + Assertions.assertNotNull(fetchedToken.refreshToken) } @Test - void testGetAFetchedMetaToken() throws MalformedURLException { - MetaToken token = new MetaToken() - .generateName(MetaToken.SHORT_ID_LENGTH) - .fetched(true) - .persistent(false) - .tokenName("something") - .expiryDate(Instant.now().plus(Duration.ofHours(1))) - .subject(subjectMapper.subjectDTOToSubject(subjectDto)); - - MetaToken saved = metaTokenService.save(token); - assertNotNull(saved.getId()); - assertNotNull(saved.getTokenName()); - assertTrue(saved.isFetched()); - assertTrue(saved.getExpiryDate().isAfter(Instant.now())); - - String tokenName = saved.getTokenName(); - Assertions.assertThrows(RadarWebApplicationException.class, - () -> metaTokenService.fetchToken(tokenName)); + @Throws(MalformedURLException::class) + fun testGetAFetchedMetaToken() { + val token = MetaToken() + .generateName(MetaToken.SHORT_ID_LENGTH) + .fetched(true) + .persistent(false) + .tokenName("something") + .expiryDate(Instant.now().plus(Duration.ofHours(1))) + .subject(subjectMapper.subjectDTOToSubject(subjectDto)) + val saved = metaTokenService.save(token) + Assertions.assertNotNull(saved.id) + Assertions.assertNotNull(saved.tokenName) + Assertions.assertTrue(saved.isFetched()) + Assertions.assertTrue(saved.expiryDate!!.isAfter(Instant.now())) + val tokenName = saved.tokenName + Assertions.assertThrows( + RadarWebApplicationException::class.java + ) { metaTokenService.fetchToken(tokenName!!) } } @Test - void testGetAnExpiredMetaToken() throws MalformedURLException { - MetaToken token = new MetaToken() - .generateName(MetaToken.SHORT_ID_LENGTH) - .fetched(false) - .persistent(false) - .tokenName("somethingelse") - .expiryDate(Instant.now().minus(Duration.ofHours(1))) - .subject(subjectMapper.subjectDTOToSubject(subjectDto)); - - MetaToken saved = metaTokenService.save(token); - - assertNotNull(saved.getId()); - assertNotNull(saved.getTokenName()); - assertFalse(saved.isFetched()); - assertTrue(saved.getExpiryDate().isBefore(Instant.now())); - - String tokenName = saved.getTokenName(); - - Assertions.assertThrows(RadarWebApplicationException.class, - () -> metaTokenService.fetchToken(tokenName)); + @Throws(MalformedURLException::class) + fun testGetAnExpiredMetaToken() { + val token = MetaToken() + .generateName(MetaToken.SHORT_ID_LENGTH) + .fetched(false) + .persistent(false) + .tokenName("somethingelse") + .expiryDate(Instant.now().minus(Duration.ofHours(1))) + .subject(subjectMapper.subjectDTOToSubject(subjectDto)) + val saved = metaTokenService.save(token) + Assertions.assertNotNull(saved.id) + Assertions.assertNotNull(saved.tokenName) + Assertions.assertFalse(saved.isFetched()) + Assertions.assertTrue(saved.expiryDate!!.isBefore(Instant.now())) + val tokenName = saved.tokenName + Assertions.assertThrows( + RadarWebApplicationException::class.java + ) { metaTokenService.fetchToken(tokenName!!) } } @Test - void testRemovingExpiredMetaToken() { - - MetaToken tokenFetched = new MetaToken() - .generateName(MetaToken.SHORT_ID_LENGTH) - .fetched(true) - .persistent(false) - .tokenName("something") - .expiryDate(Instant.now().plus(Duration.ofHours(1))); - - MetaToken tokenExpired = new MetaToken() - .generateName(MetaToken.SHORT_ID_LENGTH) - .fetched(false) - .persistent(false) - .tokenName("somethingelse") - .expiryDate(Instant.now().minus(Duration.ofHours(1))); - - MetaToken tokenNew = new MetaToken() - .generateName(MetaToken.SHORT_ID_LENGTH) - .fetched(false) - .persistent(false) - .tokenName("somethingelseandelse") - .expiryDate(Instant.now().plus(Duration.ofHours(1))); - - metaTokenRepository.saveAll(Arrays.asList(tokenFetched, tokenExpired, tokenNew)); - - metaTokenService.removeStaleTokens(); - - List availableTokens = metaTokenRepository.findAll(); - - assertEquals(1, availableTokens.size()); + fun testRemovingExpiredMetaToken() { + val tokenFetched = MetaToken() + .generateName(MetaToken.SHORT_ID_LENGTH) + .fetched(true) + .persistent(false) + .tokenName("something") + .expiryDate(Instant.now().plus(Duration.ofHours(1))) + val tokenExpired = MetaToken() + .generateName(MetaToken.SHORT_ID_LENGTH) + .fetched(false) + .persistent(false) + .tokenName("somethingelse") + .expiryDate(Instant.now().minus(Duration.ofHours(1))) + val tokenNew = MetaToken() + .generateName(MetaToken.SHORT_ID_LENGTH) + .fetched(false) + .persistent(false) + .tokenName("somethingelseandelse") + .expiryDate(Instant.now().plus(Duration.ofHours(1))) + metaTokenRepository.saveAll(Arrays.asList(tokenFetched, tokenExpired, tokenNew)) + metaTokenService.removeStaleTokens() + val availableTokens = metaTokenRepository.findAll() + Assertions.assertEquals(1, availableTokens.size) } } diff --git a/src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.kt b/src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.kt index 0000c425b..6f030ca8a 100644 --- a/src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.kt +++ b/src/test/java/org/radarbase/management/service/OAuthClientServiceTestUtil.kt @@ -1,41 +1,37 @@ -package org.radarbase.management.service; +package org.radarbase.management.service -import org.radarbase.management.service.dto.ClientDetailsDTO; - -import java.util.LinkedHashMap; -import java.util.Set; +import org.radarbase.management.service.dto.ClientDetailsDTO /** * Test class for the OAuthClientService class. * * @see OAuthClientService */ -public final class OAuthClientServiceTestUtil { - private OAuthClientServiceTestUtil() { - // utility class - } - +object OAuthClientServiceTestUtil { /** * Create an entity for this test. * - *

This is a static method, as tests for other entities might also need it, if they test an - * entity which requires the current entity.

+ * + * This is a static method, as tests for other entities might also need it, if they test an + * entity which requires the current entity. */ - public static ClientDetailsDTO createClient() { - ClientDetailsDTO result = new ClientDetailsDTO(); - result.setClientId("TEST_CLIENT"); - result.setClientSecret("TEST_SECRET"); - result.setScope(Set.of("scope-1", "scope-2")); - result.setResourceIds(Set.of("res-1", "res-2")); - result.setAutoApproveScopes(Set.of("scope-1")); - result.setAuthorizedGrantTypes(Set.of("password", "refresh_token", - "authorization_code")); - result.setAccessTokenValiditySeconds(3600L); - result.setRefreshTokenValiditySeconds(7200L); - result.setAuthorities(Set.of("AUTHORITY-1")); - var additionalInfo = new LinkedHashMap(); - additionalInfo.put("dynamic_registration", "true"); - result.setAdditionalInformation(additionalInfo); - return result; + fun createClient(): ClientDetailsDTO { + val result = ClientDetailsDTO() + result.clientId = "TEST_CLIENT" + result.clientSecret = "TEST_SECRET" + result.scope = setOf("scope-1", "scope-2") + result.resourceIds = setOf("res-1", "res-2") + result.autoApproveScopes = setOf("scope-1") + result.authorizedGrantTypes = setOf( + "password", "refresh_token", + "authorization_code" + ) + result.accessTokenValiditySeconds = 3600L + result.refreshTokenValiditySeconds = 7200L + result.authorities = setOf("AUTHORITY-1") + val additionalInfo = LinkedHashMap() + additionalInfo["dynamic_registration"] = "true" + result.additionalInformation = additionalInfo + return result } } diff --git a/src/test/java/org/radarbase/management/service/PasswordServiceTest.kt b/src/test/java/org/radarbase/management/service/PasswordServiceTest.kt index a7e0e66e9..2f9d60909 100644 --- a/src/test/java/org/radarbase/management/service/PasswordServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/PasswordServiceTest.kt @@ -6,63 +6,58 @@ * * See the file LICENSE in the root of this repository. */ - -package org.radarbase.management.service; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import java.util.Arrays; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) -class PasswordServiceTest { +package org.radarbase.management.service + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.web.rest.errors.BadRequestException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.junit.jupiter.SpringExtension +import java.util.* + +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) +internal class PasswordServiceTest { @Autowired - private PasswordService passwordService; - + private val passwordService: PasswordService? = null @Test - void encode() { - assertNotEquals("abc", passwordService.encode("abc")); + fun encode() { + Assertions.assertNotEquals("abc", passwordService!!.encode("abc")) } @Test - void generateEncodedPassword() { - String pass = passwordService.generateEncodedPassword(); - assertTrue(pass.length() >= 30); - assertTrue(pass.length() < 100); - assertDoesNotThrow(() -> passwordService.checkPasswordStrength(pass)); + fun generateEncodedPassword() { + val pass = passwordService!!.generateEncodedPassword() + Assertions.assertTrue(pass.length >= 30) + Assertions.assertTrue(pass.length < 100) + Assertions.assertDoesNotThrow { passwordService.checkPasswordStrength(pass) } } @Test - void generateResetKey() { - String resetKey = passwordService.generateResetKey(); - assertTrue(resetKey.length() > 16); - assertTrue(resetKey.length() < 100); + fun generateResetKey() { + val resetKey = passwordService!!.generateResetKey() + Assertions.assertTrue(resetKey.length > 16) + Assertions.assertTrue(resetKey.length < 100) } @Test - void checkPasswordStrength() { - assertDoesNotThrow(() -> passwordService.checkPasswordStrength("aA1aaaaaaaa")); - assertThrows(BadRequestException.class, () -> passwordService.checkPasswordStrength("a")); - byte[] tooLong = new byte[101]; - Arrays.fill(tooLong, (byte)'A'); - assertThrows(BadRequestException.class, () -> - passwordService.checkPasswordStrength("aA1" + new String(tooLong))); - assertThrows(BadRequestException.class, () -> - passwordService.checkPasswordStrength("aAaaaaaaaaa")); - assertThrows(BadRequestException.class, () -> - passwordService.checkPasswordStrength("a1aaaaaaaaa")); - assertThrows(BadRequestException.class, () -> - passwordService.checkPasswordStrength("aAaaaaaaaaa")); + fun checkPasswordStrength() { + Assertions.assertDoesNotThrow { passwordService!!.checkPasswordStrength("aA1aaaaaaaa") } + Assertions.assertThrows(BadRequestException::class.java) { passwordService!!.checkPasswordStrength("a") } + val tooLong = ByteArray(101) + Arrays.fill(tooLong, 'A'.code.toByte()) + Assertions.assertThrows(BadRequestException::class.java) { + passwordService!!.checkPasswordStrength( + "aA1" + String( + tooLong + ) + ) + } + Assertions.assertThrows(BadRequestException::class.java) { passwordService!!.checkPasswordStrength("aAaaaaaaaaa") } + Assertions.assertThrows(BadRequestException::class.java) { passwordService!!.checkPasswordStrength("a1aaaaaaaaa") } + Assertions.assertThrows(BadRequestException::class.java) { passwordService!!.checkPasswordStrength("aAaaaaaaaaa") } } } diff --git a/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt b/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt index 97dff1eee..a4461d7cb 100644 --- a/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt +++ b/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt @@ -1,119 +1,109 @@ -package org.radarbase.management.service; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.enumeration.ProjectStatus; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +package org.radarbase.management.service + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.enumeration.ProjectStatus +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.transaction.annotation.Transactional +import java.util.* /** * Created by nivethika on 31-8-17. */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -class RedcapIntegrationWorkFlowOnServiceLevelTest { - +internal class RedcapIntegrationWorkFlowOnServiceLevelTest { @Autowired - private ProjectService projectService; + private val projectService: ProjectService? = null @Autowired - private SubjectService subjectService; - + private val subjectService: SubjectService? = null @Test - void testRedcapIntegrationWorkFlowOnServiceLevel() { - final String externalProjectUrl = "MyUrl"; - final String externalProjectId = "MyId"; - final String projectLocation = "London"; - final String workPackage = "MDD"; - final String phase = "1"; - - ProjectDTO projectDto = new ProjectDTO(); - projectDto.setDescription("Test Project"); - projectDto.setLocation(projectLocation); - projectDto.setProjectName("test radar"); - projectDto.setProjectStatus(ProjectStatus.PLANNING); - - Map attributes = new HashMap<>(); - attributes.put(ProjectDTO.EXTERNAL_PROJECT_URL_KEY, externalProjectUrl); - attributes.put(ProjectDTO.EXTERNAL_PROJECT_ID_KEY, externalProjectId); - attributes.put(ProjectDTO.PHASE_KEY, phase); - attributes.put(ProjectDTO.WORK_PACKAGE_KEY, workPackage); - projectDto.setAttributes(attributes); + fun testRedcapIntegrationWorkFlowOnServiceLevel() { + val externalProjectUrl = "MyUrl" + val externalProjectId = "MyId" + val projectLocation = "London" + val workPackage = "MDD" + val phase = "1" + val projectDto = ProjectDTO() + projectDto.description = "Test Project" + projectDto.location = projectLocation + projectDto.projectName = "test radar" + projectDto.projectStatus = ProjectStatus.PLANNING + val attributes: MutableMap = HashMap() + attributes[ProjectDTO.EXTERNAL_PROJECT_URL_KEY] = externalProjectUrl + attributes[ProjectDTO.EXTERNAL_PROJECT_ID_KEY] = externalProjectId + attributes[ProjectDTO.PHASE_KEY] = phase + attributes[ProjectDTO.WORK_PACKAGE_KEY] = workPackage + projectDto.attributes = attributes // manually save - ProjectDTO saved = projectService.save(projectDto); - Long storedProjectId = saved.getId(); - assertTrue(storedProjectId > 0); + val saved = projectService!!.save(projectDto) + val storedProjectId = saved.id + Assertions.assertTrue(storedProjectId > 0) // Use ROLE_EXTERNAL_ERF_INTEGRATOR authority in your oauth2 client config // GET api/projects/{storedProjectId} - ProjectDTO retrievedById = projectService.findOne(storedProjectId); - assertEquals(retrievedById.getId(), storedProjectId); + val retrievedById = projectService.findOne(storedProjectId) + Assertions.assertEquals(retrievedById.id, storedProjectId) // retrieve required details // location is part of project property - final String locationRetrieved = projectDto.getLocation(); + val locationRetrieved = projectDto.location // work-package, phase are from meta-data - String workPackageRetrieved = ""; - String phaseRetrieved = ""; + var workPackageRetrieved = "" + var phaseRetrieved = "" // redcap-id from trigger - final String redcapRecordId = "1"; - for (Map.Entry attributeMapDto : retrievedById.getAttributes().entrySet()) { - switch (attributeMapDto.getKey()) { - case ProjectDTO.WORK_PACKAGE_KEY : - workPackageRetrieved = attributeMapDto.getValue(); - break; - case ProjectDTO.PHASE_KEY : - phaseRetrieved = attributeMapDto.getValue(); - break; - default: - break; + val redcapRecordId = "1" + for ((key, value) in retrievedById.attributes) { + when (key) { + ProjectDTO.WORK_PACKAGE_KEY -> workPackageRetrieved = value + ProjectDTO.PHASE_KEY -> phaseRetrieved = value + else -> {} } } // assert retrieved data - assertEquals(workPackage, workPackageRetrieved); - assertEquals(phase, phaseRetrieved); - assertEquals(projectLocation, locationRetrieved); + Assertions.assertEquals(workPackage, workPackageRetrieved) + Assertions.assertEquals(phase, phaseRetrieved) + Assertions.assertEquals(projectLocation, locationRetrieved) // create a new Subject - SubjectDTO newSubject = new SubjectDTO(); - newSubject.setLogin("53d8a54a"); // will be removed - newSubject.setProject(retrievedById); // set retrieved project - newSubject.setExternalId(redcapRecordId); // set redcap-record-id + val newSubject = SubjectDTO() + newSubject.login = "53d8a54a" // will be removed + newSubject.project = retrievedById // set retrieved project + newSubject.externalId = redcapRecordId // set redcap-record-id // create human-readable-id - String humanReadableId = String.join("-", workPackageRetrieved, phaseRetrieved, - locationRetrieved, redcapRecordId); + val humanReadableId = java.lang.String.join( + "-", workPackageRetrieved, phaseRetrieved, + locationRetrieved, redcapRecordId + ) //set meta-data to subject - newSubject.setAttributes(Collections.singletonMap(SubjectDTO.HUMAN_READABLE_IDENTIFIER_KEY, - humanReadableId)); + newSubject.attributes = Collections.singletonMap( + SubjectDTO.HUMAN_READABLE_IDENTIFIER_KEY, + humanReadableId + ) // create/save a subject // PUT api/subjects/ - SubjectDTO savedSubject = subjectService.createSubject(newSubject); - assertTrue(savedSubject.getId() > 0); + val savedSubject = subjectService!!.createSubject(newSubject) + Assertions.assertTrue(savedSubject!!.id > 0) // asset human-readable-id - for (Map.Entry attr : savedSubject.getAttributes().entrySet()) { - if (SubjectDTO.HUMAN_READABLE_IDENTIFIER_KEY .equals(attr.getKey())) { - assertEquals(humanReadableId, attr.getValue()); + for ((key, value) in savedSubject.attributes) { + if (SubjectDTO.HUMAN_READABLE_IDENTIFIER_KEY == key) { + Assertions.assertEquals(humanReadableId, value) } } } diff --git a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt index b9d6a7aaf..895b8ef2c 100644 --- a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt @@ -1,96 +1,80 @@ -package org.radarbase.management.service; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.transaction.annotation.Transactional; - -import java.net.URL; -import java.util.Collections; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.radarbase.management.service.dto.ProjectDTO.PRIVACY_POLICY_URL; -import static org.radarbase.management.service.dto.SubjectDTO.SubjectStatus.ACTIVATED; +package org.radarbase.management.service + +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.dto.SubjectDTO.SubjectStatus +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.transaction.annotation.Transactional +import java.util.* /** * Test class for the SubjectService class. * * @see SubjectService */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -public class SubjectServiceTest { - - public static final String DEFAULT_EXTERNAL_LINK = "AAAAAAAAAA"; - public static final String UPDATED_EXTERNAL_LINK = "BBBBBBBBBB"; - - public static final String DEFAULT_ENTERNAL_ID = "AAAAAAAAAA"; - public static final String UPDATED_ENTERNAL_ID = "BBBBBBBBBB"; - - public static final Boolean DEFAULT_REMOVED = false; - public static final Boolean UPDATED_REMOVED = true; - - public static final SubjectDTO.SubjectStatus DEFAULT_STATUS = ACTIVATED; - - public static final String MODEL = "App"; - public static final String PRODUCER = "THINC-IT"; - - public static final String DEFAULT_PROJECT_PRIVACY_POLICY_URL = - "http://info.thehyve.nl/radar-cns-privacy-policy"; - - +class SubjectServiceTest { @Autowired - private SubjectService subjectService; + private val subjectService: SubjectService? = null @Autowired - private ProjectService projectService; - - /** - * Create an entity for this test. - * - *

This is a static method, as tests for other entities might also need it, if they test an - * entity which requires the current entity.

- */ - public static SubjectDTO createEntityDTO() { - SubjectDTO subject = new SubjectDTO(); - subject.setExternalLink(DEFAULT_EXTERNAL_LINK); - subject.setExternalId(DEFAULT_ENTERNAL_ID); - subject.setStatus(ACTIVATED); - ProjectDTO projectDto = new ProjectDTO(); - projectDto.setId(1L); - projectDto.setProjectName("Radar"); - projectDto.setLocation("SOMEWHERE"); - projectDto.setDescription("test"); - projectDto.setAttributes(Collections.singletonMap(PRIVACY_POLICY_URL, - DEFAULT_PROJECT_PRIVACY_POLICY_URL)); - subject.setProject(projectDto); - - return subject; - } - + private val projectService: ProjectService? = null @Test @Transactional - void testGetPrivacyPolicyUrl() { - - projectService.save(createEntityDTO().getProject()); - SubjectDTO created = subjectService.createSubject(createEntityDTO()); - assertNotNull(created.getId()); - - Subject subject = subjectService.findOneByLogin(created.getLogin()); - assertNotNull(subject); - - URL privacyPolicyUrl = subjectService.getPrivacyPolicyUrl(subject); - assertNotNull(privacyPolicyUrl); - assertEquals(DEFAULT_PROJECT_PRIVACY_POLICY_URL, privacyPolicyUrl.toExternalForm()); - + fun testGetPrivacyPolicyUrl() { + projectService!!.save(createEntityDTO().project) + val created = subjectService!!.createSubject(createEntityDTO()) + Assertions.assertNotNull(created!!.id) + val subject = subjectService.findOneByLogin(created.getLogin()) + Assertions.assertNotNull(subject) + val privacyPolicyUrl = subjectService.getPrivacyPolicyUrl(subject) + Assertions.assertNotNull(privacyPolicyUrl) + Assertions.assertEquals(DEFAULT_PROJECT_PRIVACY_POLICY_URL, privacyPolicyUrl.toExternalForm()) } + companion object { + const val DEFAULT_EXTERNAL_LINK = "AAAAAAAAAA" + const val UPDATED_EXTERNAL_LINK = "BBBBBBBBBB" + const val DEFAULT_ENTERNAL_ID = "AAAAAAAAAA" + const val UPDATED_ENTERNAL_ID = "BBBBBBBBBB" + const val DEFAULT_REMOVED = false + const val UPDATED_REMOVED = true + val DEFAULT_STATUS = SubjectStatus.ACTIVATED + const val MODEL = "App" + const val PRODUCER = "THINC-IT" + const val DEFAULT_PROJECT_PRIVACY_POLICY_URL = "http://info.thehyve.nl/radar-cns-privacy-policy" + + /** + * Create an entity for this test. + * + * + * This is a static method, as tests for other entities might also need it, if they test an + * entity which requires the current entity. + */ + fun createEntityDTO(): SubjectDTO { + val subject = SubjectDTO() + subject.externalLink = DEFAULT_EXTERNAL_LINK + subject.externalId = DEFAULT_ENTERNAL_ID + subject.status = SubjectStatus.ACTIVATED + val projectDto = ProjectDTO() + projectDto.id = 1L + projectDto.projectName = "Radar" + projectDto.location = "SOMEWHERE" + projectDto.description = "test" + projectDto.attributes = Collections.singletonMap( + ProjectDTO.PRIVACY_POLICY_URL, + DEFAULT_PROJECT_PRIVACY_POLICY_URL + ) + subject.project = projectDto + return subject + } + } } diff --git a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt index 263abfa37..3fd29977a 100644 --- a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt +++ b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt @@ -1,253 +1,210 @@ -package org.radarbase.management.service; - -import org.hibernate.envers.AuditReader; -import org.hibernate.envers.AuditReaderFactory; -import org.hibernate.envers.query.AuditEntity; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.User; -import org.radarbase.management.domain.audit.CustomRevisionEntity; -import org.radarbase.management.repository.CustomRevisionEntityRepository; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.repository.filters.UserFilter; -import org.radarbase.management.security.Constants; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.UserMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.transaction.annotation.Transactional; - -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; -import java.time.Period; -import java.time.ZonedDateTime; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Optional; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.radarbase.auth.authorization.RoleAuthority.SYS_ADMIN; -import static org.radarbase.management.web.rest.TestUtil.commitTransactionAndStartNew; +package org.radarbase.management.service + +import org.assertj.core.api.Assertions +import org.hibernate.envers.AuditReaderFactory +import org.hibernate.envers.query.AuditEntity +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.User +import org.radarbase.management.domain.audit.CustomRevisionEntity +import org.radarbase.management.repository.CustomRevisionEntityRepository +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.repository.filters.UserFilter +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.UserMapper +import org.radarbase.management.web.rest.TestUtil +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.domain.PageRequest +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.transaction.annotation.Transactional +import java.time.Period +import java.time.ZonedDateTime +import java.util.* +import java.util.function.Consumer +import javax.persistence.EntityManager +import javax.persistence.EntityManagerFactory /** * Test class for the UserResource REST controller. * * @see UserService */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -public class UserServiceIntTest { - - public static final String DEFAULT_LOGIN = "johndoe"; - public static final String UPDATED_LOGIN = "jhipster"; - - public static final String DEFAULT_PASSWORD = "passjohndoe"; - public static final String UPDATED_PASSWORD = "passjhipster"; - - public static final String DEFAULT_EMAIL = "johndoe@localhost"; - public static final String UPDATED_EMAIL = "jhipster@localhost"; - - public static final String DEFAULT_FIRSTNAME = "john"; - public static final String UPDATED_FIRSTNAME = "jhipsterFirstName"; - - public static final String DEFAULT_LASTNAME = "doe"; - public static final String UPDATED_LASTNAME = "jhipsterLastName"; - - public static final String DEFAULT_LANGKEY = "en"; - public static final String UPDATED_LANGKEY = "fr"; - - @Autowired - private UserRepository userRepository; - - @Autowired - private UserMapper userMapper; - - @Autowired - private UserService userService; - - @Autowired - private RevisionService revisionService; - - @Autowired - private CustomRevisionEntityRepository revisionEntityRepository; - - @Autowired - private EntityManagerFactory entityManagerFactory; - - @Autowired - private PasswordService passwordService; - - private EntityManager entityManager; - - private UserDTO userDto; +open class UserServiceIntTest( + @Autowired private val userRepository: UserRepository, + @Autowired private val userMapper: UserMapper, + @Autowired private val userService: UserService, + @Autowired private val revisionService: RevisionService, + @Autowired private val revisionEntityRepository: CustomRevisionEntityRepository, + @Autowired private val entityManagerFactory: EntityManagerFactory, + @Autowired private val passwordService: PasswordService, + private var entityManager: EntityManager, + private var userDto: UserDTO? +) { @BeforeEach - public void setUp() { + fun setUp() { entityManager = entityManagerFactory.createEntityManager( - entityManagerFactory.getProperties()); - userDto = userMapper.userToUserDTO(createEntity(passwordService)); - ReflectionTestUtils.setField(revisionService, "revisionEntityRepository", - revisionEntityRepository); - ReflectionTestUtils.setField(revisionService, "entityManager", entityManager); - ReflectionTestUtils.setField(userService, "userMapper", userMapper); - ReflectionTestUtils.setField(userService, "userRepository", userRepository); - - userRepository.findOneByLogin(userDto.getLogin()) - .ifPresent(userRepository::delete); - } - - /** - * Create a User. - * - *

This is a static method, as tests for other entities might also need it, - * if they test an entity which has a required relationship to the User entity.

- */ - public static User createEntity(PasswordService passwordService) { - User user = new User(); - user.setLogin(DEFAULT_LOGIN); - user.password = passwordService.generateEncodedPassword(); - user.activated = true; - user.email = DEFAULT_EMAIL; - user.firstName = DEFAULT_FIRSTNAME; - user.lastName = DEFAULT_LASTNAME; - user.langKey = DEFAULT_LANGKEY; - return user; + entityManagerFactory.properties + ) + userDto = userMapper.userToUserDTO(createEntity(passwordService)) + ReflectionTestUtils.setField( + revisionService, "revisionEntityRepository", + revisionEntityRepository + ) + ReflectionTestUtils.setField(revisionService, "entityManager", entityManager) + ReflectionTestUtils.setField(userService, "userMapper", userMapper) + ReflectionTestUtils.setField(userService, "userRepository", userRepository) + userRepository.findOneByLogin(userDto!!.login) + .ifPresent { entity: User -> userRepository.delete(entity) } } @Test - void assertThatUserMustExistToResetPassword() { - Optional maybeUser = userService.requestPasswordReset("john.doe@localhost"); - assertThat(maybeUser).isNotPresent(); - - maybeUser = userService.requestPasswordReset("admin@localhost"); - assertThat(maybeUser).isPresent(); - - assertThat(maybeUser.get().email).isEqualTo("admin@localhost"); - assertThat(maybeUser.get().resetDate).isNotNull(); - assertThat(maybeUser.get().resetKey).isNotNull(); + fun assertThatUserMustExistToResetPassword() { + var maybeUser = userService.requestPasswordReset("john.doe@localhost") + Assertions.assertThat(maybeUser).isNotPresent() + maybeUser = userService.requestPasswordReset("admin@localhost") + Assertions.assertThat(maybeUser).isPresent() + Assertions.assertThat(maybeUser.get().email).isEqualTo("admin@localhost") + Assertions.assertThat(maybeUser.get().resetDate).isNotNull() + Assertions.assertThat(maybeUser.get().resetKey).isNotNull() } @Test - void assertThatOnlyActivatedUserCanRequestPasswordReset() throws NotAuthorizedException { - User user = userService.createUser(userDto); - Optional maybeUser = userService.requestPasswordReset(userDto.getEmail()); - assertThat(maybeUser).isNotPresent(); - userRepository.delete(user); + @Throws(NotAuthorizedException::class) + fun assertThatOnlyActivatedUserCanRequestPasswordReset() { + val user = userService.createUser(userDto!!) + val maybeUser = userService.requestPasswordReset( + userDto?.email + ) + Assertions.assertThat(maybeUser).isNotPresent() + userRepository.delete(user) } @Test - void assertThatResetKeyMustNotBeOlderThan24Hours() throws NotAuthorizedException { - User user = userService.createUser(userDto); - - ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(25); - String resetKey = passwordService.generateResetKey(); - user.activated = true; - user.resetDate = daysAgo; - user.resetKey = resetKey; - - userRepository.save(user); - - Optional maybeUser = userService.completePasswordReset("johndoe2", - user.resetKey); - - assertThat(maybeUser).isNotPresent(); - - userRepository.delete(user); + @Throws(NotAuthorizedException::class) + fun assertThatResetKeyMustNotBeOlderThan24Hours() { + val user = userService.createUser(userDto!!) + val daysAgo = ZonedDateTime.now().minusHours(25) + val resetKey = passwordService.generateResetKey() + user.activated = true + user.resetDate = daysAgo + user.resetKey = resetKey + userRepository.save(user) + val maybeUser = userService.completePasswordReset( + "johndoe2", + user.resetKey + ) + Assertions.assertThat(maybeUser).isNotPresent() + userRepository.delete(user) } @Test - void assertThatResetKeyMustBeValid() throws NotAuthorizedException { - User user = userService.createUser(userDto); - ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(25); - user.activated = true; - user.resetDate = daysAgo; - user.resetKey = "1234"; - userRepository.save(user); - Optional maybeUser = userService.completePasswordReset("johndoe2", - user.resetKey); - assertThat(maybeUser).isNotPresent(); - userRepository.delete(user); + @Throws(NotAuthorizedException::class) + fun assertThatResetKeyMustBeValid() { + val user = userService.createUser(userDto!!) + val daysAgo = ZonedDateTime.now().minusHours(25) + user.activated = true + user.resetDate = daysAgo + user.resetKey = "1234" + userRepository.save(user) + val maybeUser = userService.completePasswordReset( + "johndoe2", + user.resetKey + ) + Assertions.assertThat(maybeUser).isNotPresent() + userRepository.delete(user) } @Test - void assertThatUserCanResetPassword() throws NotAuthorizedException { - User user = userService.createUser(userDto); - final String oldPassword = user.password; - ZonedDateTime daysAgo = ZonedDateTime.now().minusHours(2); - String resetKey = passwordService.generateResetKey(); - user.activated = true; - user.resetDate = daysAgo; - user.resetKey = resetKey; - userRepository.save(user); - Optional maybeUser = userService.completePasswordReset("johndoe2", - user.resetKey); - assertThat(maybeUser).isPresent(); - assertThat(maybeUser.get().resetDate).isNull(); - assertThat(maybeUser.get().resetKey).isNull(); - assertThat(maybeUser.get().password).isNotEqualTo(oldPassword); - - userRepository.delete(user); + @Throws(NotAuthorizedException::class) + fun assertThatUserCanResetPassword() { + val user = userService.createUser(userDto!!) + val oldPassword = user.password + val daysAgo = ZonedDateTime.now().minusHours(2) + val resetKey = passwordService.generateResetKey() + user.activated = true + user.resetDate = daysAgo + user.resetKey = resetKey + userRepository.save(user) + val maybeUser = userService.completePasswordReset( + "johndoe2", + user.resetKey + ) + Assertions.assertThat(maybeUser).isPresent() + Assertions.assertThat(maybeUser.get().resetDate).isNull() + Assertions.assertThat(maybeUser.get().resetKey).isNull() + Assertions.assertThat(maybeUser.get().password).isNotEqualTo(oldPassword) + userRepository.delete(user) } @Test - void testFindNotActivatedUsersByCreationDateBefore() { - User expiredUser = addExpiredUser(userRepository); - commitTransactionAndStartNew(); - - // Update the timestamp of the revision so it appears to have been created 5 days ago - ZonedDateTime expDateTime = ZonedDateTime.now().minus(Period.ofDays(5)).withNano(0); - - AuditReader auditReader = AuditReaderFactory.get(entityManager); - Object[] firstRevision = (Object[]) auditReader.createQuery() - .forRevisionsOfEntity(expiredUser.getClass(), false, true) - .add(AuditEntity.id().eq(expiredUser.getId())) - .add(AuditEntity.revisionNumber().minimize() - .computeAggregationInInstanceContext()) - .getSingleResult(); - CustomRevisionEntity first = (CustomRevisionEntity) firstRevision[1]; - first.timestamp = Date.from(expDateTime.toInstant()); - entityManager.joinTransaction(); - CustomRevisionEntity updated = entityManager.merge(first); - commitTransactionAndStartNew(); - assertThat(updated.timestamp).isEqualTo(first.timestamp); - assertThat(updated.timestamp).isEqualTo(Date.from(expDateTime.toInstant())); + fun testFindNotActivatedUsersByCreationDateBefore() { + val expiredUser = addExpiredUser(userRepository) + TestUtil.commitTransactionAndStartNew() + + // Update the timestamp of the revision, so it appears to have been created 5 days ago + val expDateTime = ZonedDateTime.now().minus(Period.ofDays(5)).withNano(0) + val auditReader = AuditReaderFactory.get(entityManager) + val firstRevision = auditReader.createQuery() + .forRevisionsOfEntity(expiredUser.javaClass, false, true) + .add(AuditEntity.id().eq(expiredUser.id)) + .add( + AuditEntity.revisionNumber().minimize() + .computeAggregationInInstanceContext() + ) + .singleResult as Array<*> + val first = firstRevision[1] as CustomRevisionEntity + first.timestamp = Date.from(expDateTime.toInstant()) + entityManager.joinTransaction() + val updated = entityManager.merge(first) + TestUtil.commitTransactionAndStartNew() + Assertions.assertThat(updated.timestamp).isEqualTo(first.timestamp) + Assertions.assertThat(updated.timestamp).isEqualTo(Date.from(expDateTime.toInstant())) // make sure when we reload the expired user we have the new created date - assertThat(revisionService.getAuditInfo(expiredUser).getCreatedAt()).isEqualTo(expDateTime); + Assertions.assertThat(revisionService.getAuditInfo(expiredUser).createdAt).isEqualTo(expDateTime) // Now we know we have an 'old' user in the database, we can test our deletion method - int numUsers = userRepository.findAll().size(); - userService.removeNotActivatedUsers(); - List users = userRepository.findAll(); + val numUsers = userRepository.findAll().size + userService.removeNotActivatedUsers() + val users = userRepository.findAll() // make sure have actually deleted some users, otherwise this test is pointless - assertThat(numUsers - users.size()).isEqualTo(1); + Assertions.assertThat(numUsers - users.size).isEqualTo(1) // remaining users should be either activated or have a created date less then 3 days ago - ZonedDateTime cutoff = ZonedDateTime.now().minus(Period.ofDays(3)); - users.forEach(u -> assertThat(u.activated || revisionService.getAuditInfo(u) - .getCreatedAt().isAfter(cutoff)).isTrue()); + val cutoff = ZonedDateTime.now().minus(Period.ofDays(3)) + users.forEach(Consumer { u: User -> + Assertions.assertThat( + u.activated || revisionService.getAuditInfo(u) + .createdAt!!.isAfter(cutoff) + ).isTrue() + }) // commit the deletion, otherwise the deletion will be rolled back - commitTransactionAndStartNew(); + TestUtil.commitTransactionAndStartNew() } @Test - void assertThatAnonymousUserIsNotGet() { - final PageRequest pageable = PageRequest.of(0, (int) userRepository.count()); - final Page allManagedUsers = userService.findUsers(new UserFilter(), pageable, - false); - assertThat(allManagedUsers.getContent().stream() - .noneMatch(user -> Constants.ANONYMOUS_USER.equals(user.getLogin()))) - .isTrue(); + fun assertThatAnonymousUserIsNotGet() { + val pageable = PageRequest.of(0, userRepository.count().toInt()) + val allManagedUsers = userService.findUsers( + UserFilter(), pageable, + false + ) + Assertions.assertThat( + allManagedUsers!!.content.stream() + .noneMatch { user: UserDTO -> Constants.ANONYMOUS_USER == user.login }) + .isTrue() } /** @@ -255,22 +212,53 @@ public class UserServiceIntTest { * @param userRepository The UserRepository that will be used to save the object * @return the saved object */ - public User addExpiredUser(UserRepository userRepository) { - - Role adminRole = new Role(); - adminRole.setId(1L); - adminRole.authority = new Authority(SYS_ADMIN); - adminRole.project = null; - - User user = new User(); - user.setLogin("expired"); - user.email = "expired@expired"; - user.firstName = "ex"; - user.lastName = "pired"; - user.setRoles(Collections.singleton(adminRole)); - user.activated = false; - user.password = passwordService.generateEncodedPassword(); - return userRepository.save(user); + fun addExpiredUser(userRepository: UserRepository?): User { + val adminRole = Role() + adminRole.id = 1L + adminRole.authority = Authority(RoleAuthority.SYS_ADMIN) + adminRole.project = null + val user = User() + user.setLogin("expired") + user.email = "expired@expired" + user.firstName = "ex" + user.lastName = "pired" + user.roles = mutableSetOf(adminRole) + user.activated = false + user.password = passwordService.generateEncodedPassword() + return userRepository!!.save(user) } + companion object { + const val DEFAULT_LOGIN = "johndoe" + const val UPDATED_LOGIN = "jhipster" + const val DEFAULT_PASSWORD = "passjohndoe" + const val UPDATED_PASSWORD = "passjhipster" + const val DEFAULT_EMAIL = "johndoe@localhost" + const val UPDATED_EMAIL = "jhipster@localhost" + const val DEFAULT_FIRSTNAME = "john" + const val UPDATED_FIRSTNAME = "jhipsterFirstName" + const val DEFAULT_LASTNAME = "doe" + const val UPDATED_LASTNAME = "jhipsterLastName" + const val DEFAULT_LANGKEY = "en" + const val UPDATED_LANGKEY = "fr" + + /** + * Create a User. + * + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which has a required relationship to the User entity. + */ + fun createEntity(passwordService: PasswordService?): User { + val user = User() + user.setLogin(DEFAULT_LOGIN) + user.password = passwordService!!.generateEncodedPassword() + user.activated = true + user.email = DEFAULT_EMAIL + user.firstName = DEFAULT_FIRSTNAME + user.lastName = DEFAULT_LASTNAME + user.langKey = DEFAULT_LANGKEY + return user + } + } } diff --git a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt index ae1ea69eb..1b8092117 100644 --- a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt @@ -1,227 +1,218 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.auth.token.RadarToken; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.security.RadarAuthentication; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.MailService; -import org.radarbase.management.service.UserService; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.UserMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.radarbase.management.security.JwtAuthenticationFilter.setRadarToken; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.ArgumentMatchers +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.auth.token.RadarToken +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.User +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.security.JwtAuthenticationFilter.Companion.radarToken +import org.radarbase.management.security.RadarAuthentication +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.MailService +import org.radarbase.management.service.UserService +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.UserMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.MediaType +import org.springframework.mock.web.MockHttpServletRequest +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.transaction.annotation.Transactional +import java.util.* /** * Test class for the AccountResource REST controller. * * @see AccountResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) -class AccountResourceIntTest { - - @Autowired - private UserRepository userRepository; - - @Autowired - private UserService userService; - - @Autowired - private UserMapper userMapper; - - @Mock - private UserService mockUserService; - - @Mock - private MailService mockMailService; - - private MockMvc restUserMockMvc; - - @Autowired - private RadarToken radarToken; - - @Autowired - private AuthService authService; - - @Autowired - private ManagementPortalProperties managementPortalProperties; +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) +internal open class AccountResourceIntTest( + @Autowired private val userRepository: UserRepository, + @Autowired private val userService: UserService, + @Autowired private val userMapper: UserMapper, + @Mock private val mockUserService: UserService, + @Mock private val mockMailService: MailService, + private var restUserMockMvc: MockMvc, + @Autowired private val radarToken: RadarToken, + @Autowired private val authService: AuthService, + @Autowired private val managementPortalProperties: ManagementPortalProperties +) { @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); - doNothing().when(mockMailService).sendActivationEmail(any(User.class)); - - SecurityContextHolder.getContext().setAuthentication(new RadarAuthentication(radarToken)); - - AccountResource accountResource = new AccountResource(); - ReflectionTestUtils.setField(accountResource, "userService", userService); - ReflectionTestUtils.setField(accountResource, "userMapper", userMapper); - ReflectionTestUtils.setField(accountResource, "mailService", mockMailService); - ReflectionTestUtils.setField(accountResource, "authService", authService); - ReflectionTestUtils.setField(accountResource, "token", radarToken); - ReflectionTestUtils.setField(accountResource, "managementPortalProperties", - managementPortalProperties); - - AccountResource accountUserMockResource = new AccountResource(); - ReflectionTestUtils.setField(accountUserMockResource, "userService", mockUserService); - ReflectionTestUtils.setField(accountUserMockResource, "userMapper", userMapper); - ReflectionTestUtils.setField(accountUserMockResource, "mailService", mockMailService); - ReflectionTestUtils.setField(accountUserMockResource, "authService", authService); - ReflectionTestUtils.setField(accountUserMockResource, "token", radarToken); - ReflectionTestUtils.setField(accountUserMockResource, "managementPortalProperties", - managementPortalProperties); - - this.restUserMockMvc = MockMvcBuilders.standaloneSetup(accountUserMockResource).build(); + fun setUp() { + MockitoAnnotations.openMocks(this) + Mockito.doNothing().`when`(mockMailService).sendActivationEmail( + ArgumentMatchers.any( + User::class.java + ) + ) + SecurityContextHolder.getContext().authentication = RadarAuthentication(radarToken) + val accountResource = AccountResource() + ReflectionTestUtils.setField(accountResource, "userService", userService) + ReflectionTestUtils.setField(accountResource, "userMapper", userMapper) + ReflectionTestUtils.setField(accountResource, "mailService", mockMailService) + ReflectionTestUtils.setField(accountResource, "authService", authService) + ReflectionTestUtils.setField(accountResource, "token", radarToken) + ReflectionTestUtils.setField( + accountResource, "managementPortalProperties", + managementPortalProperties + ) + val accountUserMockResource = AccountResource() + ReflectionTestUtils.setField(accountUserMockResource, "userService", mockUserService) + ReflectionTestUtils.setField(accountUserMockResource, "userMapper", userMapper) + ReflectionTestUtils.setField(accountUserMockResource, "mailService", mockMailService) + ReflectionTestUtils.setField(accountUserMockResource, "authService", authService) + ReflectionTestUtils.setField(accountUserMockResource, "token", radarToken) + ReflectionTestUtils.setField( + accountUserMockResource, "managementPortalProperties", + managementPortalProperties + ) + restUserMockMvc = MockMvcBuilders.standaloneSetup(accountUserMockResource).build() } @AfterEach - public void tearDown() { - SecurityContextHolder.getContext().setAuthentication(null); + fun tearDown() { + SecurityContextHolder.getContext().authentication = null } @Test - void testNonAuthenticatedUser() throws Exception { - restUserMockMvc.perform(post("/api/login") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isForbidden()); + @Throws(Exception::class) + fun testNonAuthenticatedUser() { + restUserMockMvc.perform( + MockMvcRequestBuilders.post("/api/login") + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(MockMvcResultMatchers.status().isForbidden()) } @Test - void testAuthenticatedUser() throws Exception { - final RadarToken token = mock(RadarToken.class); - - Set roles = new HashSet<>(); - org.radarbase.management.domain.Role role = new org.radarbase.management.domain.Role(); - Authority authority = new Authority(); - authority.name = RoleAuthority.SYS_ADMIN.getAuthority(); - role.authority = authority; - roles.add(role); - - User user = new User(); - user.setLogin("test"); - user.firstName = "john"; - user.lastName = "doe"; - user.email = "john.doe@jhipster.com"; - user.langKey = "en"; - user.setRoles(roles); - when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.of(user)); - - restUserMockMvc.perform(post("/api/login") - .with(request -> { - setRadarToken(request, token); - request.setRemoteUser("test"); - return request; - }) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.login").value("test")) - .andExpect(jsonPath("$.firstName").value("john")) - .andExpect(jsonPath("$.lastName").value("doe")) - .andExpect(jsonPath("$.email").value("john.doe@jhipster.com")) - .andExpect(jsonPath("$.langKey").value("en")) - .andExpect(jsonPath("$.authorities").value( - RoleAuthority.SYS_ADMIN.getAuthority())); + @Throws(Exception::class) + fun testAuthenticatedUser() { + val token = Mockito.mock(RadarToken::class.java) + val roles: MutableSet = HashSet() + val role = Role() + val authority = Authority() + authority.name = RoleAuthority.SYS_ADMIN.authority + role.authority = authority + roles.add(role) + val user = User() + user.setLogin("test") + user.firstName = "john" + user.lastName = "doe" + user.email = "john.doe@jhipster.com" + user.langKey = "en" + user.roles = roles + Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(Optional.of(user)) + restUserMockMvc.perform(MockMvcRequestBuilders.post("/api/login") + .with { request: MockHttpServletRequest -> + request.radarToken = token + request.remoteUser = "test" + request + } + .accept(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.login").value("test")) + .andExpect(MockMvcResultMatchers.jsonPath("$.firstName").value("john")) + .andExpect(MockMvcResultMatchers.jsonPath("$.lastName").value("doe")) + .andExpect(MockMvcResultMatchers.jsonPath("$.email").value("john.doe@jhipster.com")) + .andExpect(MockMvcResultMatchers.jsonPath("$.langKey").value("en")) + .andExpect( + MockMvcResultMatchers.jsonPath("$.authorities").value( + RoleAuthority.SYS_ADMIN.authority + ) + ) } @Test - void testGetExistingAccount() throws Exception { - Set roles = new HashSet<>(); - org.radarbase.management.domain.Role role = new org.radarbase.management.domain.Role(); - Authority authority = new Authority(); - authority.name = RoleAuthority.SYS_ADMIN.getAuthority(); - role.authority = authority; - roles.add(role); - - User user = new User(); - user.setLogin("test"); - user.firstName = "john"; - user.lastName = "doe"; - user.email = "john.doe@jhipster.com"; - user.langKey = "en"; - user.setRoles(roles); - when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.of(user)); - - restUserMockMvc.perform(get("/api/account") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.login").value("test")) - .andExpect(jsonPath("$.firstName").value("john")) - .andExpect(jsonPath("$.lastName").value("doe")) - .andExpect(jsonPath("$.email").value("john.doe@jhipster.com")) - .andExpect(jsonPath("$.langKey").value("en")) - .andExpect(jsonPath("$.authorities").value( - RoleAuthority.SYS_ADMIN.getAuthority())); + @Throws(Exception::class) + fun testGetExistingAccount() { + val roles: MutableSet = HashSet() + val role = Role() + val authority = Authority() + authority.name = RoleAuthority.SYS_ADMIN.authority + role.authority = authority + roles.add(role) + val user = User() + user.setLogin("test") + user.firstName = "john" + user.lastName = "doe" + user.email = "john.doe@jhipster.com" + user.langKey = "en" + user.roles = roles + Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(Optional.of(user)) + restUserMockMvc.perform( + MockMvcRequestBuilders.get("/api/account") + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.login").value("test")) + .andExpect(MockMvcResultMatchers.jsonPath("$.firstName").value("john")) + .andExpect(MockMvcResultMatchers.jsonPath("$.lastName").value("doe")) + .andExpect(MockMvcResultMatchers.jsonPath("$.email").value("john.doe@jhipster.com")) + .andExpect(MockMvcResultMatchers.jsonPath("$.langKey").value("en")) + .andExpect( + MockMvcResultMatchers.jsonPath("$.authorities").value( + RoleAuthority.SYS_ADMIN.authority + ) + ) } @Test - void testGetUnknownAccount() throws Exception { - when(mockUserService.getUserWithAuthorities()).thenReturn(Optional.empty()); - - restUserMockMvc.perform(get("/api/account") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isForbidden()); + @Throws(Exception::class) + fun testGetUnknownAccount() { + Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(Optional.empty()) + restUserMockMvc.perform( + MockMvcRequestBuilders.get("/api/account") + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(MockMvcResultMatchers.status().isForbidden()) } @Test @Transactional - void testSaveInvalidLogin() throws Exception { - Set roles = new HashSet<>(); - RoleDTO role = new RoleDTO(); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - roles.add(role); - - UserDTO invalidUser = new UserDTO(); - invalidUser.setLogin("funky-log!n"); // invalid login - invalidUser.setFirstName("Funky"); - invalidUser.setLastName("One"); - invalidUser.setEmail("funky@example.com"); - invalidUser.setActivated(true); - invalidUser.setLangKey("en"); - invalidUser.setRoles(roles); - - restUserMockMvc.perform(post("/api/account") + @Throws(Exception::class) + open fun testSaveInvalidLogin() { + val roles: MutableSet = HashSet() + val role = RoleDTO() + role.authorityName = RoleAuthority.PARTICIPANT.authority + roles.add(role) + val invalidUser = UserDTO() + invalidUser.login = "funky-log!n" // invalid login + invalidUser.firstName = "Funky" + invalidUser.lastName = "One" + invalidUser.email = "funky@example.com" + invalidUser.isActivated = true + invalidUser.langKey = "en" + invalidUser.roles = roles + restUserMockMvc.perform( + MockMvcRequestBuilders.post("/api/account") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(invalidUser))) - .andExpect(status().isBadRequest()); - - Optional user = userRepository.findOneByEmail("funky@example.com"); - assertThat(user).isNotPresent(); + .content(TestUtil.convertObjectToJsonBytes(invalidUser)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val user = userRepository.findOneByEmail("funky@example.com") + Assertions.assertThat(user).isNotPresent() } } diff --git a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt index c36f509e1..0c35a35e0 100644 --- a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt @@ -1,168 +1,192 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.config.audit.AuditEventConverter; -import org.radarbase.management.domain.PersistentAuditEvent; -import org.radarbase.management.repository.PersistenceAuditEventRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuditEventService; -import org.radarbase.management.service.AuthService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.format.support.FormattingConversionService; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.servlet.ServletException; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; - -import static org.hamcrest.Matchers.hasItem; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.config.audit.AuditEventConverter +import org.radarbase.management.domain.PersistentAuditEvent +import org.radarbase.management.repository.PersistenceAuditEventRepository +import org.radarbase.management.service.AuditEventService +import org.radarbase.management.service.AuthService +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.format.support.FormattingConversionService +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import javax.servlet.ServletException /** * Test class for the AuditResource REST controller. * * @see AuditResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -class AuditResourceIntTest { - - private static final String SAMPLE_PRINCIPAL = "SAMPLE_PRINCIPAL"; - private static final String SAMPLE_TYPE = "SAMPLE_TYPE"; - private static final LocalDateTime SAMPLE_TIMESTAMP = - LocalDateTime.parse("2015-08-04T10:11:30"); - private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); - +internal class AuditResourceIntTest { @Autowired - private PersistenceAuditEventRepository auditEventRepository; + private val auditEventRepository: PersistenceAuditEventRepository? = null @Autowired - private AuditEventConverter auditEventConverter; + private val auditEventConverter: AuditEventConverter? = null @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; + private val jacksonMessageConverter: MappingJackson2HttpMessageConverter? = null @Autowired - private FormattingConversionService formattingConversionService; + private val formattingConversionService: FormattingConversionService? = null @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver? = null + private var auditEvent: PersistentAuditEvent? = null + private var restAuditMockMvc: MockMvc? = null - private PersistentAuditEvent auditEvent; - - private MockMvc restAuditMockMvc; @Autowired - private AuthService authService; - + private val authService: AuthService? = null @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - AuditEventService auditEventService = new AuditEventService( - auditEventRepository, - auditEventConverter); - AuditResource auditResource = new AuditResource(auditEventService, authService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restAuditMockMvc = MockMvcBuilders.standaloneSetup(auditResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setConversionService(formattingConversionService) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.initMocks(this) + val auditEventService = AuditEventService( + auditEventRepository, + auditEventConverter + ) + val auditResource = AuditResource(auditEventService, authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter!!.init(MockFilterConfig()) + restAuditMockMvc = MockMvcBuilders.standaloneSetup(auditResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setConversionService(formattingConversionService) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() } @BeforeEach - public void initTest() { - auditEventRepository.deleteAll(); - auditEvent = new PersistentAuditEvent(); - auditEvent.auditEventType = SAMPLE_TYPE; - auditEvent.principal = SAMPLE_PRINCIPAL; - auditEvent.auditEventDate = SAMPLE_TIMESTAMP; - } - - @Test - void getAllAudits() throws Exception { - // Initialize the database - auditEventRepository.save(auditEvent); - - // Get all the audits - restAuditMockMvc.perform(get("/management/audits")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].principal").value(hasItem(SAMPLE_PRINCIPAL))); - } - - @Test - void getAudit() throws Exception { - // Initialize the database - auditEventRepository.save(auditEvent); - - // Get the audit - restAuditMockMvc.perform(get("/management/audits/{id}", auditEvent.id)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.principal").value(SAMPLE_PRINCIPAL)); - } - - @Test - void getAuditsByDate() throws Exception { - // Initialize the database - auditEventRepository.save(auditEvent); - - // Generate dates for selecting audits by date, making sure the period contains the audit - String fromDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER); - String toDate = SAMPLE_TIMESTAMP.plusDays(1).format(FORMATTER); - - // Get the audit - restAuditMockMvc.perform(get("/management/audits?fromDate=" + fromDate + "&toDate=" - + toDate)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].principal").value(hasItem(SAMPLE_PRINCIPAL))); - } - - @Test - void getNonExistingAuditsByDate() throws Exception { - // Initialize the database - auditEventRepository.save(auditEvent); - - // Generate dates for selecting audits by date, making sure the period will not contain the - // sample audit - String fromDate = SAMPLE_TIMESTAMP.minusDays(2).format(FORMATTER); - String toDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER); - - // Query audits but expect no results - restAuditMockMvc.perform(get("/management/audits?fromDate=" + fromDate + "&toDate=" - + toDate)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(header().string("X-Total-Count", "0")); + fun initTest() { + auditEventRepository!!.deleteAll() + auditEvent = PersistentAuditEvent() + auditEvent!!.auditEventType = SAMPLE_TYPE + auditEvent!!.principal = SAMPLE_PRINCIPAL + auditEvent!!.auditEventDate = SAMPLE_TIMESTAMP } - @Test - void getNonExistingAudit() throws Exception { - // Get the audit - restAuditMockMvc.perform(get("/management/audits/{id}", Long.MAX_VALUE)) - .andExpect(status().isNotFound()); + @get:Throws(Exception::class) + @get:Test + val allAudits: Unit + get() { + // Initialize the database + auditEventRepository!!.save(auditEvent) + + // Get all the audits + restAuditMockMvc!!.perform(MockMvcRequestBuilders.get("/management/audits")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].principal").value>( + Matchers.hasItem( + SAMPLE_PRINCIPAL + ) + ) + ) + } + + @get:Throws(Exception::class) + @get:Test + val audit: Unit + get() { + // Initialize the database + auditEventRepository!!.save(auditEvent) + + // Get the audit + restAuditMockMvc!!.perform(MockMvcRequestBuilders.get("/management/audits/{id}", auditEvent!!.id)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.principal").value(SAMPLE_PRINCIPAL)) + } + + @get:Throws(Exception::class) + @get:Test + val auditsByDate: Unit + get() { + // Initialize the database + auditEventRepository!!.save(auditEvent) + + // Generate dates for selecting audits by date, making sure the period contains the audit + val fromDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER) + val toDate = SAMPLE_TIMESTAMP.plusDays(1).format(FORMATTER) + + // Get the audit + restAuditMockMvc!!.perform( + MockMvcRequestBuilders.get( + "/management/audits?fromDate=" + fromDate + "&toDate=" + + toDate + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].principal").value>( + Matchers.hasItem( + SAMPLE_PRINCIPAL + ) + ) + ) + } + + @get:Throws(Exception::class) + @get:Test + val nonExistingAuditsByDate: Unit + get() { + // Initialize the database + auditEventRepository!!.save(auditEvent) + + // Generate dates for selecting audits by date, making sure the period will not contain the + // sample audit + val fromDate = SAMPLE_TIMESTAMP.minusDays(2).format(FORMATTER) + val toDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER) + + // Query audits but expect no results + restAuditMockMvc!!.perform( + MockMvcRequestBuilders.get( + "/management/audits?fromDate=" + fromDate + "&toDate=" + + toDate + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.header().string("X-Total-Count", "0")) + } + + @get:Throws(Exception::class) + @get:Test + val nonExistingAudit: Unit + get() { + // Get the audit + restAuditMockMvc!!.perform(MockMvcRequestBuilders.get("/management/audits/{id}", Long.MAX_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } + + companion object { + private const val SAMPLE_PRINCIPAL = "SAMPLE_PRINCIPAL" + private const val SAMPLE_TYPE = "SAMPLE_TYPE" + private val SAMPLE_TIMESTAMP = LocalDateTime.parse("2015-08-04T10:11:30") + private val FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd") } } diff --git a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt index 31be75902..ca21e70f4 100644 --- a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt @@ -1,432 +1,480 @@ -package org.radarbase.management.web.rest; - -import org.assertj.core.api.Condition; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Group; -import org.radarbase.management.domain.Project; -import org.radarbase.management.repository.GroupRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.RoleRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.GroupService; -import org.radarbase.management.service.SubjectService; -import org.radarbase.management.service.dto.GroupDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.mapper.GroupMapper; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.radarbase.management.web.rest.vm.GroupPatchOperation; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import javax.servlet.ServletException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.radarbase.management.service.dto.SubjectDTO.SubjectStatus.ACTIVATED; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Condition +import org.hamcrest.Matchers +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.Group +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.GroupRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.RoleRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.GroupService +import org.radarbase.management.service.SubjectService +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.dto.SubjectDTO.SubjectStatus +import org.radarbase.management.service.mapper.GroupMapper +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.radarbase.management.web.rest.vm.GroupPatchOperation +import org.radarbase.management.web.rest.vm.GroupPatchOperation.SubjectPatchValue +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import java.util.* +import javax.servlet.ServletException /** * Test class for the GroupResource REST controller. * * @see GroupResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class GroupResourceIntTest { +internal class GroupResourceIntTest(@Autowired private val groupService: GroupService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val roleRepository: RoleRepository, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val subjectService: SubjectService, + @Autowired private val groupMapper: GroupMapper, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val groupRepository: GroupRepository, + private var restGroupMockMvc: MockMvc, private var group: Group, + private var project: Project +) { @Autowired - private GroupService groupService; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private ProjectMapper projectMapper; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private RoleRepository roleRepository; - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private SubjectService subjectService; - - @Autowired - private GroupMapper groupMapper; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - @Autowired - private GroupRepository groupRepository; - - private MockMvc restGroupMockMvc; - - private Group group; - - private Project project; - @Autowired - private AuthService authService; - + private val authService: AuthService? = null @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - var groupResource = new GroupResource(); - ReflectionTestUtils.setField(groupResource, "groupService", groupService); - ReflectionTestUtils.setField(groupResource, "authService", authService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restGroupMockMvc = MockMvcBuilders.standaloneSetup(groupResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - project = ProjectResourceIntTest.createEntity(); - projectRepository.save(project); - group = createEntity(); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.initMocks(this) + val groupResource = GroupResource() + ReflectionTestUtils.setField(groupResource, "groupService", groupService) + ReflectionTestUtils.setField(groupResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restGroupMockMvc = MockMvcBuilders.standaloneSetup(groupResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() + project = ProjectResourceIntTest.Companion.createEntity() + projectRepository.save(project) + group = createEntity() } @AfterEach - public void tearDown() { - groupRepository.delete(group); - var roles = roleRepository.findAllRolesByProjectName(project.projectName); - roleRepository.deleteAll(roles); - projectRepository.delete(project); + fun tearDown() { + groupRepository.delete(group) + val roles = roleRepository.findAllRolesByProjectName( + project.projectName + ) + roleRepository.deleteAll(roles) + projectRepository.delete(project) } /** * Create an entity for this test. */ - private Group createEntity() { - Group group = new Group(); - group.name = "group1"; - group.project = project; - return group; + private fun createEntity(): Group { + val group = Group() + group.name = "group1" + group.project = project + return group } @Test - void createGroup() throws Exception { + @Throws(Exception::class) + fun createGroup() { // Create the Group - var groupDto = groupMapper.groupToGroupDTO(group); - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto))) - .andExpect(status().isCreated()); - - var savedGroup = groupRepository.findByProjectNameAndName( - project.projectName, groupDto.getName()).get(); + val groupDto = groupMapper.groupToGroupDTO(group) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(groupDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) + val savedGroup: Group? = groupRepository.findByProjectNameAndName( + project.projectName, groupDto.name + ) // Validate the Group in the database - assertThat(savedGroup.project.getId()).isEqualTo(project.getId()); - assertThat(savedGroup.name).isEqualTo("group1"); + assertThat(savedGroup?.project?.id).isEqualTo(project.id) + assertThat(savedGroup?.name).isEqualTo("group1") } - @Test - void createGroupNonExistingProject() throws Exception { - projectRepository.delete(project); + @Throws(Exception::class) + fun createGroupNonExistingProject() { + projectRepository.delete(project) // Create the Group - var groupDto = groupMapper.groupToGroupDTO(group); - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto))) - .andExpect(status().isNotFound()); + val groupDto = groupMapper.groupToGroupDTO(group) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(groupDto)) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) } @Test - void createGroupWithExistingName() throws Exception { + @Throws(Exception::class) + fun createGroupWithExistingName() { // Create the Group - var groupDto = groupMapper.groupToGroupDTO(group); - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto))) - .andExpect(status().isCreated()); - - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto))) - .andExpect(status().isConflict()); + val groupDto = groupMapper.groupToGroupDTO(group) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(groupDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(groupDto)) + ) + .andExpect(MockMvcResultMatchers.status().isConflict()) } - @Test - void createGroupWithExistingNameInDifferentProject() throws Exception { - Project project2 = ProjectResourceIntTest.createEntity() - .projectName(project.projectName + "2"); - - projectRepository.saveAndFlush(project2); - Group group2 = new Group(); - group2.name = group.name; - group2.project = project2; + @Throws(Exception::class) + fun createGroupWithExistingNameInDifferentProject() { + val project2: Project = ProjectResourceIntTest.Companion.createEntity() + .projectName(project.projectName + "2") + projectRepository.saveAndFlush(project2) + val group2 = Group() + group2.name = group.name + group2.project = project2 // Create the Group - var groupDto = groupMapper.groupToGroupDTO(group); - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto))) - .andExpect(status().isCreated()); - - var group2Dto = groupMapper.groupToGroupDTO(group2); - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project2.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(group2Dto))) - .andExpect(status().isCreated()); + val groupDto = groupMapper.groupToGroupDTO(group) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(groupDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) + val group2Dto = groupMapper.groupToGroupDTO(group2) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project2.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(group2Dto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate groups are saved for both projects - var savedGroup1 = groupRepository.findByProjectNameAndName( - project.projectName, group.name).get(); - var savedGroup2 = groupRepository.findByProjectNameAndName( - project2.projectName, group2.name).get(); - var groupList = Arrays.asList(savedGroup1, savedGroup2); - assertThat(groupList).hasSize(2); - assertThat(groupList).haveAtLeastOne(new Condition<>( - g -> project.getId().equals(g.project.getId()), "use project 1")); - assertThat(groupList).haveAtLeastOne(new Condition<>( - g -> project2.getId().equals(g.project.getId()), "use project 2")); - assertThat(groupList).allSatisfy( - g -> assertThat(g.name).isEqualTo(group.name)); - - projectRepository.delete(project2); + val savedGroup1: Group? = groupRepository.findByProjectNameAndName( + project.projectName, group.name + ) + val savedGroup2: Group? = groupRepository.findByProjectNameAndName( + project2.projectName, group2.name + ) + val groupList = listOf(savedGroup1, savedGroup2) + assertThat(groupList).hasSize(2) + assertThat(groupList).haveAtLeastOne( + Condition( + { g -> project.id == g?.project?.id }, "use project 1" + ) + ) + assertThat(groupList).haveAtLeastOne( + Condition( + { g -> project2.id == g?.project?.id }, "use project 2" + ) + ) + assertThat(groupList).allSatisfy { g -> assertThat(g?.name).isEqualTo(group.name) } + projectRepository.delete(project2) } @Test - void checkGroupNameIsRequired() throws Exception { - group.name = null; + @Throws(Exception::class) + fun checkGroupNameIsRequired() { + group.name = null // Create the Group - GroupDTO groupDto = groupMapper.groupToGroupDTO(group); - restGroupMockMvc.perform(post("/api/projects/{projectName}/groups", - project.projectName) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto))) - .andExpect(status().isBadRequest()); + val groupDto = groupMapper.groupToGroupDTO(group) + restGroupMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/projects/{projectName}/groups", + project.projectName + ) + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(groupDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) } - @Test - void getAllGroups() throws Exception { - // Initialize the database - groupRepository.saveAndFlush(group); - - // Get all the groups - restGroupMockMvc.perform(get("/api/projects/{projectName}/groups", - project.projectName)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].projectId").value( - hasItem(project.getId().intValue()))) - .andExpect(jsonPath("$.[*].name").value(hasItem("group1"))); - } + @get:Throws(Exception::class) + @get:Test + val allGroups: Unit + get() { + // Initialize the database + groupRepository.saveAndFlush(group) + + // Get all the groups + restGroupMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/projects/{projectName}/groups", + project.projectName + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].projectId").value>( + Matchers.hasItem(project.id!!.toInt()) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].name").value>(Matchers.hasItem("group1")) + ) + } @Test - void getGroup() throws Exception { + @Throws(Exception::class) + fun getGroup() { // Initialize the database - groupRepository.saveAndFlush(group); + groupRepository.saveAndFlush(group) // Get the Group - restGroupMockMvc.perform(get("/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.name").value("group1")) - .andExpect(jsonPath("$.projectId").value(project.getId().intValue())); + restGroupMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName, group.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("group1")) + .andExpect(MockMvcResultMatchers.jsonPath("$.projectId").value(project.id!!.toInt())) } - @Test - void getNonExistingGroup() throws Exception { - // Get the Group - restGroupMockMvc.perform(get("/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name)) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Test + val nonExistingGroup: Unit + get() { + // Get the Group + restGroupMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName, group.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test - void deleteGroup() throws Exception { + @Throws(Exception::class) + fun deleteGroup() { // Initialize the database - groupRepository.saveAndFlush(group); + groupRepository.saveAndFlush(group) // Get the Group - restGroupMockMvc.perform(delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isNoContent()); + restGroupMockMvc.perform( + MockMvcRequestBuilders.delete( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName, group.name + ) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isNoContent()) // Validate the Group is not present in the database - var savedGroup = groupRepository.findByProjectNameAndName( - project.projectName, group.name); - assertThat(savedGroup).isEmpty(); + val savedGroup = groupRepository.findByProjectNameAndName( + project.projectName, group.name + ) + assertThat(savedGroup).isNull() } @Test - void deleteGroupWithSubjects() throws Exception { + @Throws(Exception::class) + fun deleteGroupWithSubjects() { // Initialize the database - groupRepository.saveAndFlush(group); - - var projectDto = projectMapper.projectToProjectDTO(project); - - var subjectDto = new SubjectDTO(); - subjectDto.setExternalLink("exLink1"); - subjectDto.setExternalId("exId1"); - subjectDto.setStatus(ACTIVATED); - subjectDto.setProject(projectDto); - subjectDto.setGroup(group.name); - var savedSubject = subjectService.createSubject(subjectDto); + groupRepository.saveAndFlush(group) + val projectDto = projectMapper.projectToProjectDTO(project) + val subjectDto = SubjectDTO() + subjectDto.externalLink = "exLink1" + subjectDto.externalId = "exId1" + subjectDto.status = SubjectStatus.ACTIVATED + subjectDto.project = projectDto + subjectDto.group = group.name + val savedSubject = subjectService.createSubject(subjectDto) // Try to delete the Group (and fail) - restGroupMockMvc.perform(delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isConflict()); + restGroupMockMvc.perform( + MockMvcRequestBuilders.delete( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName, group.name + ) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isConflict()) // Delete the Group (and unlink the subjects) - restGroupMockMvc.perform(delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name) - .param("unlinkSubjects", "true") - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isNoContent()); + restGroupMockMvc.perform( + MockMvcRequestBuilders.delete( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName, group.name + ) + .param("unlinkSubjects", "true") + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isNoContent()) // Validate the Group is not present in the database - var savedGroup = groupRepository.findByProjectNameAndName( - project.projectName, group.name); - assertThat(savedGroup).isEmpty(); - - var storedSubject = subjectRepository.getOne(savedSubject.getId()); - subjectRepository.delete(storedSubject); + val savedGroup = groupRepository.findByProjectNameAndName( + project.projectName, group.name + ) + Assertions.assertThat(savedGroup).isNull() + val storedSubject = subjectRepository.getOne(savedSubject!!.id) + subjectRepository.delete(storedSubject) } @Test - void deleteGroupNonExisting() throws Exception { + @Throws(Exception::class) + fun deleteGroupNonExisting() { // Initialize the database - groupRepository.saveAndFlush(group); + groupRepository.saveAndFlush(group) // Get the Group - restGroupMockMvc.perform(delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name + "2") - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isNotFound()); + restGroupMockMvc.perform( + MockMvcRequestBuilders.delete( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName, group.name + "2" + ) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) // Validate the database still contains the group - assertThat(groupRepository.findById(group.getId())).isNotEmpty(); + Assertions.assertThat( + groupRepository.findById( + group.id + ) + ).isNotEmpty() } - @Test - void deleteGroupNonExistingProject() throws Exception { + @Throws(Exception::class) + fun deleteGroupNonExistingProject() { // Initialize the database - groupRepository.saveAndFlush(group); + groupRepository.saveAndFlush(group) // Get the Group - restGroupMockMvc.perform(delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName + "2", group.name) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isNotFound()); + restGroupMockMvc.perform( + MockMvcRequestBuilders.delete( + "/api/projects/{projectName}/groups/{groupName}", + project.projectName + "2", group.name + ) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) // Validate the database still contains the group - assertThat(groupRepository.findById(group.getId())).isNotEmpty(); + Assertions.assertThat( + groupRepository.findById( + group.id + ) + ).isNotEmpty() } @Test - void addSubjectsToGroup() throws Exception { + @Throws(Exception::class) + fun addSubjectsToGroup() { // Initialize the database - groupRepository.saveAndFlush(group); - - var projectDto = projectMapper.projectToProjectDTO(project); - - var sub1 = new SubjectDTO(); - sub1.setExternalLink("exLink1"); - sub1.setExternalId("exId1"); - sub1.setStatus(ACTIVATED); - sub1.setProject(projectDto); - - var sub2 = new SubjectDTO(); - sub2.setExternalLink("exLink2"); - sub2.setExternalId("exId2"); - sub2.setStatus(ACTIVATED); - sub2.setProject(projectDto); - - var savedSub1 = subjectService.createSubject(sub1); - var savedSub2 = subjectService.createSubject(sub2); - - var sub1Patch = new GroupPatchOperation.SubjectPatchValue(); - sub1Patch.setId(savedSub1.getId()); - var sub2Patch = new GroupPatchOperation.SubjectPatchValue(); - sub2Patch.setLogin(savedSub2.getLogin()); - - var patchOp = new GroupPatchOperation(); - patchOp.setOp("add"); - var patchValue = new ArrayList(); - patchValue.add(sub1Patch); - patchValue.add(sub2Patch); - patchOp.setValue(patchValue); - - List body = new ArrayList<>(); - body.add(patchOp); + groupRepository.saveAndFlush(group) + val projectDto = projectMapper.projectToProjectDTO(project) + val sub1 = SubjectDTO() + sub1.externalLink = "exLink1" + sub1.externalId = "exId1" + sub1.status = SubjectStatus.ACTIVATED + sub1.project = projectDto + val sub2 = SubjectDTO() + sub2.externalLink = "exLink2" + sub2.externalId = "exId2" + sub2.status = SubjectStatus.ACTIVATED + sub2.project = projectDto + val savedSub1 = subjectService.createSubject(sub1) + val savedSub2 = subjectService.createSubject(sub2) + val sub1Patch = SubjectPatchValue() + sub1Patch.id = savedSub1!!.id + val sub2Patch = SubjectPatchValue() + sub2Patch.login = savedSub2!!.getLogin() + val patchOp = GroupPatchOperation() + patchOp.op = "add" + val patchValue = ArrayList() + patchValue.add(sub1Patch) + patchValue.add(sub2Patch) + patchOp.value = patchValue + val body: MutableList = ArrayList() + body.add(patchOp) // Get the Group - restGroupMockMvc.perform(patch( - "/api/projects/{projectName}/groups/{groupName}/subjects", - project.projectName, group.name) - - .contentType(TestUtil.APPLICATION_JSON_PATCH) - .content(TestUtil.convertObjectToJsonBytes(body))) - .andExpect(status().isNoContent()); + restGroupMockMvc.perform( + MockMvcRequestBuilders.patch( + "/api/projects/{projectName}/groups/{groupName}/subjects", + project.projectName, group.name + ) + .contentType(TestUtil.APPLICATION_JSON_PATCH) + .content(TestUtil.convertObjectToJsonBytes(body)) + ) + .andExpect(MockMvcResultMatchers.status().isNoContent()) // Validate that the group was set for both subjects - var subjectLogins = Arrays.asList(savedSub1.getLogin(), savedSub2.getLogin()); - var subjects = subjectRepository.findAllBySubjectLogins(subjectLogins); - assertThat(subjects).hasSize(2); - assertThat(subjects).allSatisfy( - s -> assertThat(s.group.getId()).isEqualTo(group.getId())); - - subjectRepository.deleteAll(subjects); + val subjectLogins = listOf(savedSub1.getLogin(), savedSub2.getLogin()) + val subjects = subjectRepository.findAllBySubjectLogins(subjectLogins) + Assertions.assertThat(subjects).hasSize(2) + Assertions.assertThat(subjects).allSatisfy { s: Subject -> + Assertions.assertThat( + s.group!!.id + ).isEqualTo(group.id) + } + subjectRepository.deleteAll(subjects) } } diff --git a/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt index a102450ae..65a4f2fa8 100644 --- a/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt @@ -1,59 +1,57 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.web.rest.vm.LoggerVM; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.web.rest.vm.LoggerVM +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.http.MediaType +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders /** * Test class for the LogsResource REST controller. * * @see LogsResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) -class LogsResourceIntTest { - - private MockMvc restLogsMockMvc; - +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) +internal class LogsResourceIntTest { + private var restLogsMockMvc: MockMvc? = null @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); - - LogsResource logsResource = new LogsResource(); - this.restLogsMockMvc = MockMvcBuilders - .standaloneSetup(logsResource) - .build(); + fun setUp() { + MockitoAnnotations.initMocks(this) + val logsResource = LogsResource() + restLogsMockMvc = MockMvcBuilders + .standaloneSetup(logsResource) + .build() } - @Test - void getAllLogs()throws Exception { - restLogsMockMvc.perform(get("/management/logs")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)); - } + @get:Throws(Exception::class) + @get:Test + val allLogs: Unit + get() { + restLogsMockMvc!!.perform(MockMvcRequestBuilders.get("/management/logs")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + } @Test - void changeLogs()throws Exception { - LoggerVM logger = new LoggerVM(); - logger.setLevel("INFO"); - logger.setName("ROOT"); - - restLogsMockMvc.perform(put("/management/logs") + @Throws(Exception::class) + fun changeLogs() { + val logger = LoggerVM() + logger.level = "INFO" + logger.name = "ROOT" + restLogsMockMvc!!.perform( + MockMvcRequestBuilders.put("/management/logs") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(logger))) - .andExpect(status().isNoContent()); + .content(TestUtil.convertObjectToJsonBytes(logger)) + ) + .andExpect(MockMvcResultMatchers.status().isNoContent()) } } diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt index 8e1e346e3..d319aeeee 100644 --- a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt @@ -1,238 +1,285 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalApp; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.OAuthClientService; -import org.radarbase.management.service.SubjectService; -import org.radarbase.management.service.UserService; -import org.radarbase.management.service.dto.ClientDetailsDTO; -import org.radarbase.management.service.mapper.ClientDetailsMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.nullValue; -import static org.radarbase.management.service.OAuthClientServiceTestUtil.createClient; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalApp +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.OAuthClientService +import org.radarbase.management.service.OAuthClientServiceTestUtil +import org.radarbase.management.service.SubjectService +import org.radarbase.management.service.UserService +import org.radarbase.management.service.dto.ClientDetailsDTO +import org.radarbase.management.service.mapper.ClientDetailsMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.oauth2.provider.ClientDetails +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import java.util.function.Consumer /** * Test class for the ProjectResource REST controller. * * @see ProjectResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalApp.class) -class OAuthClientsResourceIntTest { - - @Autowired - private JdbcClientDetailsService clientDetailsService; - - @Autowired - private ClientDetailsMapper clientDetailsMapper; - - @Autowired - private SubjectService subjectService; - - @Autowired - private UserService userService; - - @Autowired - private OAuthClientService oAuthClientService; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalApp::class]) +internal open class OAuthClientsResourceIntTest( + @Autowired private val clientDetailsService: JdbcClientDetailsService, + @Autowired private val clientDetailsMapper: ClientDetailsMapper, + @Autowired private val subjectService: SubjectService, + @Autowired private val userService: UserService, + @Autowired private val oAuthClientService: OAuthClientService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + private var restOauthClientMvc: MockMvc, + private var details: ClientDetailsDTO, + private var clientDetailsList: List, + private var databaseSizeBeforeCreate: Int = 0, + @Autowired private val authService: AuthService +) { - @Autowired - private ExceptionTranslator exceptionTranslator; - - private MockMvc restOauthClientMvc; - - private ClientDetailsDTO details; - - private List clientDetailsList; - - private int databaseSizeBeforeCreate; - @Autowired - private AuthService authService; @BeforeEach - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - OAuthClientsResource oauthClientsResource = new OAuthClientsResource(); - ReflectionTestUtils.setField(oauthClientsResource, "clientDetailsMapper", - clientDetailsMapper); - ReflectionTestUtils.setField(oauthClientsResource, "subjectService", - subjectService); - ReflectionTestUtils.setField(oauthClientsResource, "userService", - userService); - ReflectionTestUtils.setField(oauthClientsResource, "authService", - authService); - ReflectionTestUtils.setField(oauthClientsResource, "oAuthClientService", - oAuthClientService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restOauthClientMvc = MockMvcBuilders.standaloneSetup(oauthClientsResource) + @Throws(Exception::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val oauthClientsResource = OAuthClientsResource() + ReflectionTestUtils.setField( + oauthClientsResource, "clientDetailsMapper", + clientDetailsMapper + ) + ReflectionTestUtils.setField( + oauthClientsResource, "subjectService", + subjectService + ) + ReflectionTestUtils.setField( + oauthClientsResource, "userService", + userService + ) + ReflectionTestUtils.setField( + oauthClientsResource, "authService", + authService + ) + ReflectionTestUtils.setField( + oauthClientsResource, "oAuthClientService", + oAuthClientService + ) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restOauthClientMvc = MockMvcBuilders.standaloneSetup(oauthClientsResource) .setCustomArgumentResolvers(pageableArgumentResolver) .setControllerAdvice(exceptionTranslator) .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - - databaseSizeBeforeCreate = clientDetailsService.listClientDetails().size(); + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() + databaseSizeBeforeCreate = clientDetailsService.listClientDetails().size // Create the OAuth Client - details = createClient(); - restOauthClientMvc.perform(post("/api/oauth-clients") + details = OAuthClientServiceTestUtil.createClient() + restOauthClientMvc.perform( + MockMvcRequestBuilders.post("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Project in the database - clientDetailsList = clientDetailsService.listClientDetails(); - assertThat(clientDetailsList).hasSize(databaseSizeBeforeCreate + 1); + clientDetailsList = clientDetailsService.listClientDetails() + Assertions.assertThat(clientDetailsList).hasSize(databaseSizeBeforeCreate + 1) } @Test @Transactional - void createAndFetchOAuthClient() throws Exception { + @Throws(Exception::class) + open fun createAndFetchOAuthClient() { // fetch the created oauth client and check the json result - restOauthClientMvc.perform(get("/api/oauth-clients/" + details.getClientId()) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.clientId").value(equalTo(details.getClientId()))) - .andExpect(jsonPath("$.clientSecret").value(nullValue())) - .andExpect(jsonPath("$.accessTokenValiditySeconds").value(equalTo(details - .getAccessTokenValiditySeconds().intValue()))) - .andExpect(jsonPath("$.refreshTokenValiditySeconds").value(equalTo(details - .getRefreshTokenValiditySeconds().intValue()))) - .andExpect(jsonPath("$.scope").value(containsInAnyOrder( - details.getScope().toArray()))) - .andExpect(jsonPath("$.autoApproveScopes").value(containsInAnyOrder( - details.getAutoApproveScopes().toArray()))) - .andExpect(jsonPath("$.authorizedGrantTypes").value(containsInAnyOrder( - details.getAuthorizedGrantTypes().toArray()))) - .andExpect(jsonPath("$.authorities").value( - containsInAnyOrder(details.getAuthorities().toArray()))); - - ClientDetails testDetails = clientDetailsList.stream() - .filter(d -> d.getClientId().equals(details.getClientId())) - .findFirst() - .orElseThrow(); - assertThat(testDetails.getClientSecret()).startsWith("$2a$10$"); - assertThat(testDetails.getScope()).containsExactlyInAnyOrderElementsOf(details.getScope()); - assertThat(testDetails.getResourceIds()).containsExactlyInAnyOrderElementsOf( - details.getResourceIds()); - assertThat(testDetails.getAuthorizedGrantTypes()).containsExactlyInAnyOrderElementsOf( - details.getAuthorizedGrantTypes()); - details.getAutoApproveScopes().forEach(scope -> - assertThat(testDetails.isAutoApprove(scope)).isTrue()); - assertThat(testDetails.getAccessTokenValiditySeconds()).isEqualTo( - details.getAccessTokenValiditySeconds().intValue()); - assertThat(testDetails.getRefreshTokenValiditySeconds()).isEqualTo( - details.getRefreshTokenValiditySeconds().intValue()); - assertThat(testDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority)) - .containsExactlyInAnyOrderElementsOf(details.getAuthorities()); - assertThat(testDetails.getAdditionalInformation()).containsAllEntriesOf( - details.getAdditionalInformation() - ); + restOauthClientMvc.perform( + MockMvcRequestBuilders.get("/api/oauth-clients/" + details.clientId) + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect( + MockMvcResultMatchers.jsonPath("$.clientId").value( + Matchers.equalTo( + details.clientId + ) + ) + ) + .andExpect(MockMvcResultMatchers.jsonPath("$.clientSecret").value(Matchers.nullValue())) + .andExpect( + MockMvcResultMatchers.jsonPath("$.accessTokenValiditySeconds").value( + Matchers.equalTo( + details + .getAccessTokenValiditySeconds().toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.refreshTokenValiditySeconds").value( + Matchers.equalTo( + details + .refreshTokenValiditySeconds.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.scope").value( + Matchers.containsInAnyOrder( + *details.scope.toTypedArray() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.autoApproveScopes").value( + Matchers.containsInAnyOrder( + *details.autoApproveScopes.toTypedArray() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.authorizedGrantTypes").value( + Matchers.containsInAnyOrder( + *details.authorizedGrantTypes.toTypedArray() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.authorities").value( + Matchers.containsInAnyOrder(*details.authorities.toTypedArray()) + ) + ) + val testDetails = clientDetailsList.stream() + .filter { d: ClientDetails -> d.clientId == details.clientId } + .findFirst() + .orElseThrow() + Assertions.assertThat(testDetails.clientSecret).startsWith("$2a$10$") + Assertions.assertThat(testDetails.scope).containsExactlyInAnyOrderElementsOf( + details.scope + ) + Assertions.assertThat(testDetails.resourceIds).containsExactlyInAnyOrderElementsOf( + details.resourceIds + ) + Assertions.assertThat(testDetails.authorizedGrantTypes).containsExactlyInAnyOrderElementsOf( + details.authorizedGrantTypes + ) + details.autoApproveScopes.forEach(Consumer { scope: String? -> + Assertions.assertThat( + testDetails.isAutoApprove( + scope + ) + ).isTrue() + }) + Assertions.assertThat(testDetails.accessTokenValiditySeconds).isEqualTo( + details.accessTokenValiditySeconds.toInt() + ) + Assertions.assertThat(testDetails.refreshTokenValiditySeconds).isEqualTo( + details.refreshTokenValiditySeconds.toInt() + ) + Assertions.assertThat(testDetails.authorities.stream().map { obj: GrantedAuthority -> obj.authority }) + .containsExactlyInAnyOrderElementsOf(details.authorities) + Assertions.assertThat(testDetails.additionalInformation).containsAllEntriesOf( + details.additionalInformation + ) } @Test @Transactional - void dupliceOAuthClient() throws Exception { - restOauthClientMvc.perform(post("/api/oauth-clients") + @Throws(Exception::class) + open fun dupliceOAuthClient() { + restOauthClientMvc.perform( + MockMvcRequestBuilders.post("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isConflict()); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isConflict()) } @Test @Transactional - void updateOAuthClient() throws Exception { + @Throws(Exception::class) + open fun updateOAuthClient() { // update the client - details.setRefreshTokenValiditySeconds(20L); - restOauthClientMvc.perform(put("/api/oauth-clients") + details.refreshTokenValiditySeconds = 20L + restOauthClientMvc.perform( + MockMvcRequestBuilders.put("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // fetch the client - clientDetailsList = clientDetailsService.listClientDetails(); - assertThat(clientDetailsList).hasSize(databaseSizeBeforeCreate + 1); - ClientDetails testDetails = clientDetailsList.stream() - .filter(d -> d.getClientId().equals(details.getClientId())) - .findFirst() - .orElseThrow(); - assertThat(testDetails.getRefreshTokenValiditySeconds()).isEqualTo(20); + clientDetailsList = clientDetailsService.listClientDetails() + Assertions.assertThat(clientDetailsList).hasSize(databaseSizeBeforeCreate + 1) + val testDetails = clientDetailsList.stream() + .filter { d: ClientDetails -> d.clientId == details.clientId } + .findFirst() + .orElseThrow() + Assertions.assertThat(testDetails.refreshTokenValiditySeconds).isEqualTo(20) } @Test @Transactional - void deleteOAuthClient() throws Exception { - restOauthClientMvc.perform(delete("/api/oauth-clients/" + details.getClientId()) + @Throws(Exception::class) + open fun deleteOAuthClient() { + restOauthClientMvc.perform( + MockMvcRequestBuilders.delete("/api/oauth-clients/" + details.clientId) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isOk()); - clientDetailsList = clientDetailsService.listClientDetails(); - assertThat(clientDetailsList.size()).isEqualTo(databaseSizeBeforeCreate); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + val clientDetailsList = clientDetailsService.listClientDetails() + Assertions.assertThat(clientDetailsList.size).isEqualTo(databaseSizeBeforeCreate) } @Test @Transactional - void cannotModifyProtected() throws Exception { + @Throws(Exception::class) + open fun cannotModifyProtected() { // first change our test client to be protected - details.getAdditionalInformation().put("protected", "true"); - restOauthClientMvc.perform(put("/api/oauth-clients") + details.additionalInformation["protected"] = "true" + restOauthClientMvc.perform( + MockMvcRequestBuilders.put("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // expect we can not delete it now - restOauthClientMvc.perform(delete("/api/oauth-clients/" + details.getClientId()) + restOauthClientMvc.perform( + MockMvcRequestBuilders.delete("/api/oauth-clients/" + details.clientId) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isForbidden()); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isForbidden()) // expect we can not update it now - details.setRefreshTokenValiditySeconds(20L); - restOauthClientMvc.perform(put("/api/oauth-clients") + details.refreshTokenValiditySeconds = 20L + restOauthClientMvc.perform( + MockMvcRequestBuilders.put("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details))) - .andExpect(status().isForbidden()); + .content(TestUtil.convertObjectToJsonBytes(details)) + ) + .andExpect(MockMvcResultMatchers.status().isForbidden()) } - - } diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index 34d847382..e650e923b 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -1,227 +1,245 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Organization; -import org.radarbase.management.repository.OrganizationRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.OrganizationService; -import org.radarbase.management.service.mapper.OrganizationMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import javax.servlet.ServletException; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.Organization +import org.radarbase.management.domain.Project +import org.radarbase.management.repository.OrganizationRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.OrganizationService +import org.radarbase.management.service.mapper.OrganizationMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import javax.servlet.ServletException /** * Test class for the OrganizationResource REST controller. * * @see OrganizationResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class OrganizationResourceIntTest { - - @Autowired - private OrganizationMapper organizationMapper; - - @Autowired - private OrganizationRepository organizationRepository; - - @Autowired - private OrganizationService organizationService; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - private MockMvc restOrganizationMockMvc; - - private Organization organization; - @Autowired - private AuthService authService; +internal class OrganizationResourceIntTest( + @Autowired private val organizationMapper: OrganizationMapper, + @Autowired private val organizationRepository: OrganizationRepository, + @Autowired private val organizationService: OrganizationService, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + private var restOrganizationMockMvc: MockMvc, + private var organization: Organization, + @Autowired private val authService: AuthService +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - var orgResource = new OrganizationResource(); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val orgResource = OrganizationResource() ReflectionTestUtils - .setField(orgResource, "organizationService", organizationService); - ReflectionTestUtils.setField(orgResource, "authService", authService); - - var filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restOrganizationMockMvc = MockMvcBuilders.standaloneSetup(orgResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - organization = createEntity(); + .setField(orgResource, "organizationService", organizationService) + ReflectionTestUtils.setField(orgResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restOrganizationMockMvc = MockMvcBuilders.standaloneSetup(orgResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() + organization = createEntity() } @AfterEach - public void tearDown() { - var testOrg = organizationRepository.findOneByName(organization.name); - testOrg.ifPresent(organizationRepository::delete); + fun tearDown() { + val testOrg = organizationRepository.findOneByName( + organization.name + ) + testOrg.ifPresent { entity: Organization -> organizationRepository.delete(entity) } } /** * Create an entity for this test. */ - private Organization createEntity() { - var org = new Organization(); - org.name = "org1"; - org.description = "Test Organization 1"; - org.location = "Somewhere"; - return org; + private fun createEntity(): Organization { + val org = Organization() + org.name = "org1" + org.description = "Test Organization 1" + org.location = "Somewhere" + return org } @Test - void createOrganization() throws Exception { - var orgDto = organizationMapper.organizationToOrganizationDTO(organization); - restOrganizationMockMvc.perform(post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto))) - .andExpect(status().isCreated()); + @Throws(Exception::class) + fun createOrganization() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Organization in the database - var savedOrg = organizationRepository.findOneByName(orgDto.getName()); - assertThat(savedOrg).isNotEmpty(); + val savedOrg = organizationRepository.findOneByName(orgDto.name) + Assertions.assertThat(savedOrg).isNotEmpty() } @Test - void createOrganizationWithExistingName() throws Exception { - var orgDto = organizationMapper.organizationToOrganizationDTO(organization); - restOrganizationMockMvc.perform(post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto))) - .andExpect(status().isCreated()); + @Throws(Exception::class) + fun createOrganizationWithExistingName() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Second request should fail - restOrganizationMockMvc.perform(post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto))) - .andExpect(status().isConflict()); + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isConflict()) } @Test - void checkGroupNameIsRequired() throws Exception { - var orgDto = organizationMapper.organizationToOrganizationDTO(organization); - orgDto.setName(null); - restOrganizationMockMvc.perform(post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto))) - .andExpect(status().isBadRequest()); + @Throws(Exception::class) + fun checkGroupNameIsRequired() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + orgDto.name = null + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) } - @Test - void getAllOrganizations() throws Exception { - // Initialize the database - organizationRepository.saveAndFlush(organization); - - // Get all the organizations - restOrganizationMockMvc.perform(get("/api/organizations")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].name").value(hasItem("org1"))); - } + @get:Throws(Exception::class) + @get:Test + val allOrganizations: Unit + get() { + // Initialize the database + organizationRepository.saveAndFlush(organization) + + // Get all the organizations + restOrganizationMockMvc.perform(MockMvcRequestBuilders.get("/api/organizations")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].name").value>(Matchers.hasItem("org1")) + ) + } @Test - void getOrganization() throws Exception { + @Throws(Exception::class) + fun getOrganization() { // Initialize the database - organizationRepository.saveAndFlush(organization); + organizationRepository.saveAndFlush(organization) // Get the organization - restOrganizationMockMvc.perform(get("/api/organizations/{name}", - organization.name)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.name").value("org1")); + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}", + organization.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("org1")) } @Test - void editOrganization() throws Exception { + @Throws(Exception::class) + fun editOrganization() { // Initialize the database - organizationRepository.saveAndFlush(organization); - - var updatedOrgDto = organizationMapper - .organizationToOrganizationDTO(organization); - updatedOrgDto.setLocation("Other location"); + organizationRepository.saveAndFlush(organization) + val updatedOrgDto = organizationMapper + .organizationToOrganizationDTO(organization) + updatedOrgDto?.location = "Other location" // Update the organization - restOrganizationMockMvc.perform(put("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(updatedOrgDto))) - .andExpect(status().isOk()); - - // Get the organization - restOrganizationMockMvc.perform(get("/api/organizations/{name}", - organization.name)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.location").value("Other location")); - } + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.put("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(updatedOrgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) - @Test - void getNonExistingOrganization() throws Exception { // Get the organization - restOrganizationMockMvc.perform(get("/api/organizations/{name}", - organization.name)) - .andExpect(status().isNotFound()); + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}", + organization.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.location").value("Other location")) } - @Test - void getProjectsByOrganizationName() throws Exception { - // Initialize the database - organizationRepository.saveAndFlush(organization); - - var project = ProjectResourceIntTest.createEntity() + @get:Throws(Exception::class) + @get:Test + val nonExistingOrganization: Unit + get() { + // Get the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}", + organization.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } + + @get:Throws(Exception::class) + @get:Test + val projectsByOrganizationName: Unit + get() { + // Initialize the database + organizationRepository.saveAndFlush(organization) + val project: Project = ProjectResourceIntTest.Companion.createEntity() .organization(organization) - .projectName("organization_project"); - projectRepository.saveAndFlush(project); - - // Get projects of the organization - restOrganizationMockMvc.perform(get("/api/organizations/{name}/projects", - organization.name)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].projectName").value("organization_project")); - - projectRepository.delete(project); - } + .projectName("organization_project") + projectRepository.saveAndFlush(project) + + // Get projects of the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}/projects", + organization.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].projectName").value("organization_project")) + projectRepository.delete(project) + } } diff --git a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt index cef4e56ff..9851cc0ba 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt @@ -1,67 +1,64 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.radarbase.management.ManagementPortalTestApp; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.core.env.Environment; -import org.springframework.http.MediaType; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; - -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.MockitoAnnotations +import org.radarbase.management.ManagementPortalTestApp +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.core.env.Environment +import org.springframework.http.MediaType +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders /** * Test class for the ProfileInfoResource REST controller. * * @see ProfileInfoResource - **/ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) -class ProfileInfoResourceIntTest { - + */ +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) +internal class ProfileInfoResourceIntTest { @Mock - private Environment environment; - - private MockMvc restProfileMockMvc; - + private val environment: Environment? = null + private var restProfileMockMvc: MockMvc? = null @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); - String[] activeProfiles = {"test"}; - when(environment.getDefaultProfiles()).thenReturn(activeProfiles); - when(environment.getActiveProfiles()).thenReturn(activeProfiles); - - ProfileInfoResource profileInfoResource = new ProfileInfoResource(); - ReflectionTestUtils.setField(profileInfoResource, "env", environment); - this.restProfileMockMvc = MockMvcBuilders - .standaloneSetup(profileInfoResource) - .build(); - } - - @Test - void getProfileInfo() throws Exception { - restProfileMockMvc.perform(get("/api/profile-info")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)); + fun setUp() { + MockitoAnnotations.initMocks(this) + val activeProfiles = arrayOf("test") + Mockito.`when`(environment!!.defaultProfiles).thenReturn(activeProfiles) + Mockito.`when`(environment.activeProfiles).thenReturn(activeProfiles) + val profileInfoResource = ProfileInfoResource() + ReflectionTestUtils.setField(profileInfoResource, "env", environment) + restProfileMockMvc = MockMvcBuilders + .standaloneSetup(profileInfoResource) + .build() } - @Test - void getProfileInfoWithoutActiveProfiles() throws Exception { - String[] emptyProfile = {}; - when(environment.getDefaultProfiles()).thenReturn(emptyProfile); - when(environment.getActiveProfiles()).thenReturn(emptyProfile); + @get:Throws(Exception::class) + @get:Test + val profileInfo: Unit + get() { + restProfileMockMvc!!.perform(MockMvcRequestBuilders.get("/api/profile-info")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + } - restProfileMockMvc.perform(get("/api/profile-info")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)); - } + @get:Throws(Exception::class) + @get:Test + val profileInfoWithoutActiveProfiles: Unit + get() { + val emptyProfile = arrayOf() + Mockito.`when`(environment!!.defaultProfiles).thenReturn(emptyProfile) + Mockito.`when`(environment.activeProfiles).thenReturn(emptyProfile) + restProfileMockMvc!!.perform(MockMvcRequestBuilders.get("/api/profile-info")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + } } diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt index e62a5007e..b75f57972 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt @@ -1,402 +1,442 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Organization; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.enumeration.ProjectStatus; -import org.radarbase.management.repository.OrganizationRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ProjectService; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.servlet.ServletException; -import java.time.Instant; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.radarbase.management.web.rest.TestUtil.sameInstant; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.assertj.core.api.Assertions.assertThat +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.Organization +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.enumeration.ProjectStatus +import org.radarbase.management.repository.OrganizationRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ProjectService +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import java.time.Instant +import java.time.ZoneId +import java.time.ZoneOffset +import java.time.ZonedDateTime +import javax.servlet.ServletException /** * Test class for the ProjectResource REST controller. * * @see ProjectResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class ProjectResourceIntTest { - - private static final String DEFAULT_PROJECT_NAME = "AAAAAAAAAA"; - private static final String UPDATED_PROJECT_NAME = "BBBBBBBBBB"; - - private static final String DEFAULT_DESCRIPTION = "AAAAAAAAAA"; - private static final String UPDATED_DESCRIPTION = "BBBBBBBBBB"; - - private static final String DEFAULT_ORGANIZATION = "AAAAAAAAAA"; - private static final String UPDATED_ORGANIZATION = "BBBBBBBBBB"; - - private static final String DEFAULT_LOCATION = "AAAAAAAAAA"; - private static final String UPDATED_LOCATION = "BBBBBBBBBB"; - - private static final ZonedDateTime DEFAULT_START_DATE = ZonedDateTime.ofInstant( - Instant.ofEpochMilli(0L), ZoneOffset.UTC); - private static final ZonedDateTime UPDATED_START_DATE = ZonedDateTime.now( - ZoneId.systemDefault()).withNano(0); - - private static final ProjectStatus DEFAULT_PROJECT_STATUS = ProjectStatus.PLANNING; - private static final ProjectStatus UPDATED_PROJECT_STATUS = ProjectStatus.ONGOING; - - private static final ZonedDateTime DEFAULT_END_DATE = ZonedDateTime.ofInstant( - Instant.ofEpochMilli(0L), ZoneOffset.UTC); - private static final ZonedDateTime UPDATED_END_DATE = ZonedDateTime.now( - ZoneId.systemDefault()).withNano(0); - - @Autowired - private OrganizationRepository organizationRepository; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private ProjectMapper projectMapper; - - @Autowired - private ProjectService projectService; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - private MockMvc restProjectMockMvc; - - private Project project; - @Autowired - private AuthService authService; +internal open class ProjectResourceIntTest( + @Autowired private val organizationRepository: OrganizationRepository, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val projectService: ProjectService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + private var restProjectMockMvc: MockMvc, + private var project: Project, + @Autowired private val authService: AuthService +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - ProjectResource projectResource = new ProjectResource(); - ReflectionTestUtils.setField(projectResource, "projectRepository", projectRepository); - ReflectionTestUtils.setField(projectResource, "projectService", projectService); - ReflectionTestUtils.setField(projectResource, "authService", authService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - } - - /** - * Create an entity for this test. - * - *

This is a static method, as tests for other entities might also need it, - * if they test an entity which requires the current entity.

- */ - public static Project createEntity() { - Organization organization = new Organization(); - organization.setId(1L); - organization.name = "main"; - return new Project() - .projectName(DEFAULT_PROJECT_NAME) - .description(DEFAULT_DESCRIPTION) - .organizationName(DEFAULT_ORGANIZATION) - .organization(organization) - .location(DEFAULT_LOCATION) - .startDate(DEFAULT_START_DATE) - .projectStatus(DEFAULT_PROJECT_STATUS) - .endDate(DEFAULT_END_DATE); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val projectResource = ProjectResource + ReflectionTestUtils.setField(projectResource, "projectRepository", projectRepository) + ReflectionTestUtils.setField(projectResource, "projectService", projectService) + ReflectionTestUtils.setField(projectResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() } @BeforeEach - public void initTest() { - project = createEntity(); + fun initTest() { + project = createEntity() } @Test @Transactional - void createProject() throws Exception { - int databaseSizeBeforeCreate = projectRepository.findAll().size(); + @Throws(Exception::class) + open fun createProject() { + val databaseSizeBeforeCreate = projectRepository.findAll().size // Create the Project - ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); - restProjectMockMvc.perform(post("/api/projects") + val projectDto = projectMapper.projectToProjectDTO(project) + restProjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Project in the database - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeCreate + 1); - Project testProject = projectList.get(projectList.size() - 1); - assertThat(testProject.projectName).isEqualTo(DEFAULT_PROJECT_NAME); - assertThat(testProject.description).isEqualTo(DEFAULT_DESCRIPTION); - assertThat(testProject.organizationName).isEqualTo(DEFAULT_ORGANIZATION); - assertThat(testProject.location).isEqualTo(DEFAULT_LOCATION); - assertThat(testProject.startDate).isEqualTo(DEFAULT_START_DATE); - assertThat(testProject.projectStatus).isEqualTo(DEFAULT_PROJECT_STATUS); - assertThat(testProject.endDate).isEqualTo(DEFAULT_END_DATE); + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeCreate + 1) + val testProject = projectList[projectList.size - 1] + Assertions.assertThat(testProject!!.projectName).isEqualTo(DEFAULT_PROJECT_NAME) + Assertions.assertThat(testProject.description).isEqualTo(DEFAULT_DESCRIPTION) + Assertions.assertThat(testProject.organizationName).isEqualTo(DEFAULT_ORGANIZATION) + Assertions.assertThat(testProject.location).isEqualTo(DEFAULT_LOCATION) + Assertions.assertThat(testProject.startDate).isEqualTo(DEFAULT_START_DATE) + Assertions.assertThat(testProject.projectStatus).isEqualTo(DEFAULT_PROJECT_STATUS) + Assertions.assertThat(testProject.endDate).isEqualTo(DEFAULT_END_DATE) } @Test @Transactional - void createProjectWithExistingId() throws Exception { - int databaseSizeBeforeCreate = projectRepository.findAll().size(); + @Throws(Exception::class) + open fun createProjectWithExistingId() { + val databaseSizeBeforeCreate = projectRepository.findAll().size // Create the Project with an existing ID - project.setId(1L); - ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); + project.id = 1L + val projectDto = projectMapper.projectToProjectDTO(project) // An entity with an existing ID cannot be created, so this API call must fail - restProjectMockMvc.perform(post("/api/projects") + restProjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the Alice in the database - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeCreate); + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeCreate) } @Test @Transactional - void checkProjectNameIsRequired() throws Exception { - int databaseSizeBeforeTest = projectRepository.findAll().size(); + @Throws(Exception::class) + open fun checkProjectNameIsRequired() { + val databaseSizeBeforeTest = projectRepository.findAll().size // set the field null - project.projectName = null; + project.projectName = null // Create the Project, which fails. - ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); - - restProjectMockMvc.perform(post("/api/projects") + val projectDto = projectMapper.projectToProjectDTO(project) + restProjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isBadRequest()); - - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeTest); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeTest) } @Test @Transactional - void checkDescriptionIsRequired() throws Exception { - int databaseSizeBeforeTest = projectRepository.findAll().size(); + @Throws(Exception::class) + open fun checkDescriptionIsRequired() { + val databaseSizeBeforeTest = projectRepository.findAll().size // set the field null - project.description = null; + project.description = null // Create the Project, which fails. - ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); - - restProjectMockMvc.perform(post("/api/projects") + val projectDto = projectMapper.projectToProjectDTO(project) + restProjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isBadRequest()); - - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeTest); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeTest) } @Test @Transactional - void checkLocationIsRequired() throws Exception { - int databaseSizeBeforeTest = projectRepository.findAll().size(); + @Throws(Exception::class) + open fun checkLocationIsRequired() { + val databaseSizeBeforeTest = projectRepository.findAll().size // set the field null - project.location = null; + project.location = null // Create the Project, which fails. - ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); - - restProjectMockMvc.perform(post("/api/projects") + val projectDto = projectMapper.projectToProjectDTO(project) + restProjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isBadRequest()); - - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeTest); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeTest) } - @Test - @Transactional - void getAllProjects() throws Exception { - // Initialize the database - projectRepository.saveAndFlush(project); - - // Get all the projectList - restProjectMockMvc.perform(get("/api/projects?sort=id,desc")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(project.getId().intValue()))) - .andExpect(jsonPath("$.[*].projectName").value(hasItem(DEFAULT_PROJECT_NAME))) - .andExpect(jsonPath("$.[*].description").value(hasItem(DEFAULT_DESCRIPTION))) - .andExpect(jsonPath("$.[*].organizationName").value(hasItem(DEFAULT_ORGANIZATION))) - .andExpect(jsonPath("$.[*].location").value(hasItem(DEFAULT_LOCATION))) - .andExpect(jsonPath("$.[*].startDate").value( - hasItem(sameInstant(DEFAULT_START_DATE)))) - .andExpect(jsonPath("$.[*].projectStatus").value( - hasItem(DEFAULT_PROJECT_STATUS.toString()))) - .andExpect(jsonPath("$.[*].endDate").value(hasItem(sameInstant(DEFAULT_END_DATE)))); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val allProjects: Unit + get() { + // Initialize the database + projectRepository.saveAndFlush(project) + + // Get all the projectList + restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + project.id!!.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].projectName").value>( + Matchers.hasItem( + DEFAULT_PROJECT_NAME + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].description").value>( + Matchers.hasItem( + DEFAULT_DESCRIPTION + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].organizationName").value>( + Matchers.hasItem( + DEFAULT_ORGANIZATION + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].location").value>( + Matchers.hasItem( + DEFAULT_LOCATION + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].startDate").value>( + Matchers.hasItem(TestUtil.sameInstant(DEFAULT_START_DATE)) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].projectStatus").value>( + Matchers.hasItem(DEFAULT_PROJECT_STATUS.toString()) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].endDate").value>( + Matchers.hasItem( + TestUtil.sameInstant( + DEFAULT_END_DATE + ) + ) + ) + ) + } @Test @Transactional - void getProject() throws Exception { + @Throws(Exception::class) + open fun getProject() { // Initialize the database - projectRepository.saveAndFlush(project); + projectRepository.saveAndFlush(project) // Get the project - restProjectMockMvc.perform(get("/api/projects/{projectName}", project.projectName)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.id").value(project.getId().intValue())) - .andExpect(jsonPath("$.projectName").value(DEFAULT_PROJECT_NAME)) - .andExpect(jsonPath("$.description").value(DEFAULT_DESCRIPTION)) - .andExpect(jsonPath("$.organizationName").value(DEFAULT_ORGANIZATION)) - .andExpect(jsonPath("$.location").value(DEFAULT_LOCATION)) - .andExpect(jsonPath("$.startDate").value(sameInstant(DEFAULT_START_DATE))) - .andExpect(jsonPath("$.projectStatus").value(DEFAULT_PROJECT_STATUS.toString())) - .andExpect(jsonPath("$.endDate").value(sameInstant(DEFAULT_END_DATE))); + restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects/{projectName}", project.projectName)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(project.id!!.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.projectName").value(DEFAULT_PROJECT_NAME)) + .andExpect(MockMvcResultMatchers.jsonPath("$.description").value(DEFAULT_DESCRIPTION)) + .andExpect(MockMvcResultMatchers.jsonPath("$.organizationName").value(DEFAULT_ORGANIZATION)) + .andExpect(MockMvcResultMatchers.jsonPath("$.location").value(DEFAULT_LOCATION)) + .andExpect(MockMvcResultMatchers.jsonPath("$.startDate").value(TestUtil.sameInstant(DEFAULT_START_DATE))) + .andExpect(MockMvcResultMatchers.jsonPath("$.projectStatus").value(DEFAULT_PROJECT_STATUS.toString())) + .andExpect(MockMvcResultMatchers.jsonPath("$.endDate").value(TestUtil.sameInstant(DEFAULT_END_DATE))) } - @Test - @Transactional - void getNonExistingProject() throws Exception { - // Get the project - restProjectMockMvc.perform(get("/api/projects/{id}", Long.MAX_VALUE)) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val nonExistingProject: Unit + get() { + // Get the project + restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects/{id}", Long.MAX_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional - void updateProject() throws Exception { + @Throws(Exception::class) + open fun updateProject() { // Initialize the database - projectRepository.saveAndFlush(project); - - var org = new Organization(); - org.name = "org1"; - org.description = "Test Organization 1"; - org.location = "Somewhere"; - organizationRepository.saveAndFlush(org); - - assertThat(org.getId()).isNotNull(); - - int databaseSizeBeforeUpdate = projectRepository.findAll().size(); + projectRepository.saveAndFlush(project) + val org = Organization() + org.name = "org1" + org.description = "Test Organization 1" + org.location = "Somewhere" + organizationRepository.saveAndFlush(org) + assertThat(org.id).isNotNull() + val databaseSizeBeforeUpdate = projectRepository.findAll().size // Update the project - Project updatedProject = projectRepository.findById(project.getId()).get(); + val updatedProject = projectRepository.findById(project.id!!).get() updatedProject - .projectName(UPDATED_PROJECT_NAME) - .description(UPDATED_DESCRIPTION) - .organizationName(UPDATED_ORGANIZATION) - .organization(org) - .location(UPDATED_LOCATION) - .startDate(UPDATED_START_DATE) - .projectStatus(UPDATED_PROJECT_STATUS) - .endDate(UPDATED_END_DATE); - ProjectDTO projectDto = projectMapper.projectToProjectDTO(updatedProject); - - restProjectMockMvc.perform(put("/api/projects") + .projectName(UPDATED_PROJECT_NAME) + .description(UPDATED_DESCRIPTION) + .organizationName(UPDATED_ORGANIZATION) + .organization(org) + .location(UPDATED_LOCATION) + .startDate(UPDATED_START_DATE) + .projectStatus(UPDATED_PROJECT_STATUS) + .endDate(UPDATED_END_DATE) + val projectDto = projectMapper.projectToProjectDTO(updatedProject) + restProjectMockMvc.perform( + MockMvcRequestBuilders.put("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Project in the database - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeUpdate); - Project testProject = projectList.get(projectList.size() - 1); - assertThat(testProject.projectName).isEqualTo(UPDATED_PROJECT_NAME); - assertThat(testProject.description).isEqualTo(UPDATED_DESCRIPTION); - assertThat(testProject.organizationName).isEqualTo(UPDATED_ORGANIZATION); - assertThat(testProject.organization).isEqualTo(org); - assertThat(testProject.location).isEqualTo(UPDATED_LOCATION); - assertThat(testProject.startDate).isEqualTo(UPDATED_START_DATE); - assertThat(testProject.projectStatus).isEqualTo(UPDATED_PROJECT_STATUS); - assertThat(testProject.endDate).isEqualTo(UPDATED_END_DATE); - - organizationRepository.delete(org); + val projectList = projectRepository.findAll() + assertThat(projectList).hasSize(databaseSizeBeforeUpdate) + val testProject = projectList[projectList.size - 1] + assertThat(testProject!!.projectName).isEqualTo(UPDATED_PROJECT_NAME) + assertThat(testProject.description).isEqualTo(UPDATED_DESCRIPTION) + assertThat(testProject.organizationName).isEqualTo(UPDATED_ORGANIZATION) + assertThat(testProject.organization).isEqualTo(org) + assertThat(testProject.location).isEqualTo(UPDATED_LOCATION) + assertThat(testProject.startDate).isEqualTo(UPDATED_START_DATE) + assertThat(testProject.projectStatus).isEqualTo( + UPDATED_PROJECT_STATUS + ) + assertThat(testProject.endDate).isEqualTo(UPDATED_END_DATE) + organizationRepository.delete(org) } @Test @Transactional - void updateNonExistingProject() throws Exception { - int databaseSizeBeforeUpdate = projectRepository.findAll().size(); + @Throws(Exception::class) + open fun updateNonExistingProject() { + val databaseSizeBeforeUpdate = projectRepository.findAll().size // Create the Project - ProjectDTO projectDto = projectMapper.projectToProjectDTO(project); + val projectDto = projectMapper.projectToProjectDTO(project) // If the entity doesn't have an ID, it will be created instead of just being updated - restProjectMockMvc.perform(put("/api/projects") + restProjectMockMvc.perform( + MockMvcRequestBuilders.put("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(projectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(projectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Project in the database - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeUpdate + 1); + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeUpdate + 1) } @Test @Transactional - void deleteProject() throws Exception { + @Throws(Exception::class) + open fun deleteProject() { // Initialize the database - projectRepository.saveAndFlush(project); - int databaseSizeBeforeDelete = projectRepository.findAll().size(); + projectRepository.saveAndFlush(project) + val databaseSizeBeforeDelete = projectRepository.findAll().size // Get the project - restProjectMockMvc.perform(delete("/api/projects/{projectName}", project.projectName) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()); + restProjectMockMvc.perform( + MockMvcRequestBuilders.delete("/api/projects/{projectName}", project.projectName) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty - List projectList = projectRepository.findAll(); - assertThat(projectList).hasSize(databaseSizeBeforeDelete - 1); + val projectList = projectRepository.findAll() + Assertions.assertThat(projectList).hasSize(databaseSizeBeforeDelete - 1) } @Test @Transactional - void equalsVerifier() throws Exception { - Assertions.assertTrue(TestUtil.equalsVerifier(Project.class)); + @Throws(Exception::class) + open fun equalsVerifier() { + org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Project::class.java)) + } + + companion object { + private const val DEFAULT_PROJECT_NAME = "AAAAAAAAAA" + private const val UPDATED_PROJECT_NAME = "BBBBBBBBBB" + private const val DEFAULT_DESCRIPTION = "AAAAAAAAAA" + private const val UPDATED_DESCRIPTION = "BBBBBBBBBB" + private const val DEFAULT_ORGANIZATION = "AAAAAAAAAA" + private const val UPDATED_ORGANIZATION = "BBBBBBBBBB" + private const val DEFAULT_LOCATION = "AAAAAAAAAA" + private const val UPDATED_LOCATION = "BBBBBBBBBB" + private val DEFAULT_START_DATE = ZonedDateTime.ofInstant( + Instant.ofEpochMilli(0L), ZoneOffset.UTC + ) + private val UPDATED_START_DATE = ZonedDateTime.now( + ZoneId.systemDefault() + ).withNano(0) + private val DEFAULT_PROJECT_STATUS = ProjectStatus.PLANNING + private val UPDATED_PROJECT_STATUS = ProjectStatus.ONGOING + private val DEFAULT_END_DATE = ZonedDateTime.ofInstant( + Instant.ofEpochMilli(0L), ZoneOffset.UTC + ) + private val UPDATED_END_DATE = ZonedDateTime.now( + ZoneId.systemDefault() + ).withNano(0) + + /** + * Create an entity for this test. + * + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + fun createEntity(): Project { + val organization = Organization() + organization.id = 1L + organization.name = "main" + return Project() + .projectName(DEFAULT_PROJECT_NAME) + .description(DEFAULT_DESCRIPTION) + .organizationName(DEFAULT_ORGANIZATION) + .organization(organization) + .location(DEFAULT_LOCATION) + .startDate(DEFAULT_START_DATE) + .projectStatus(DEFAULT_PROJECT_STATUS) + .endDate(DEFAULT_END_DATE) + } } } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt index 0cb98eaa4..4db6c68a5 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt @@ -1,392 +1,499 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.repository.SourceDataRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.SourceDataService; -import org.radarbase.management.service.dto.SourceDataDTO; -import org.radarbase.management.service.mapper.SourceDataMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.persistence.EntityManager; -import javax.servlet.ServletException; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.SourceData +import org.radarbase.management.repository.SourceDataRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.SourceDataService +import org.radarbase.management.service.mapper.SourceDataMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import javax.persistence.EntityManager +import javax.servlet.ServletException /** * Test class for the SourceDataResource REST controller. * * @see SourceDataResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class SourceDataResourceIntTest { - - private static final String DEFAULT_SOURCE_DATA_TYPE = "AAAAAAAAAA"; - private static final String UPDATED_SOURCE_DATA_TYPE = "BBBBBBBBBB"; - - private static final String DEFAULT_SOURCE_DATA_NAME = "AAAAAAAAAAAAA"; - private static final String UPDATED_SOURCE_DATA_NAME = "BBBBBBBBBBAAA"; - - private static final String DEFAULT_PROCESSING_STATE = "RAW"; - private static final String UPDATED_PROCESSING_STATE = "DERIVED"; - - private static final String DEFAULT_KEY_SCHEMA = "AAAAAAAAAAC"; - private static final String UPDATED_KEY_SCHEMA = "BBBBBBBBBBC"; - - private static final String DEFAULT_VALUE_SCHEMA = "AAAAAAAAAAA"; - private static final String UPDATED_VALUE_SCHEMA = "BBBBBBBBBBB"; - - private static final String DEFAULT_FREQUENCY = "AAAAAAAAAAAA"; - private static final String UPDATED_FREQUENCY = "BBBBBBBBBBBB"; - - private static final String DEFAULT_UNTI = "AAAAAAAAAAAAAAC"; - private static final String UPDATED_UNIT = "BBBBBBBBBBBBBBC"; - - private static final String DEFAULT_TOPIC = "AAAAAAAAAAAAAAA"; - private static final String UPDATED_TOPIC = "BBBBBBBBBBBBBBB"; - +internal class SourceDataResourceIntTest { @Autowired - private SourceDataRepository sourceDataRepository; + private val sourceDataRepository: SourceDataRepository? = null @Autowired - private SourceDataMapper sourceDataMapper; + private val sourceDataMapper: SourceDataMapper? = null @Autowired - private SourceDataService sourceDataService; + private val sourceDataService: SourceDataService? = null @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; + private val jacksonMessageConverter: MappingJackson2HttpMessageConverter? = null @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; + private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver? = null @Autowired - private ExceptionTranslator exceptionTranslator; + private val exceptionTranslator: ExceptionTranslator? = null @Autowired - private EntityManager em; + private val em: EntityManager? = null + private var restSourceDataMockMvc: MockMvc? = null + private var sourceData: SourceData? = null - private MockMvc restSourceDataMockMvc; - - private SourceData sourceData; @Autowired - private AuthService authService; - + private val authService: AuthService? = null @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - SourceDataResource sourceDataResource = new SourceDataResource(); - ReflectionTestUtils.setField(sourceDataResource, "sourceDataService", sourceDataService); - ReflectionTestUtils.setField(sourceDataResource, "authService", authService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restSourceDataMockMvc = MockMvcBuilders.standaloneSetup(sourceDataResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - } - - /** - * Create an entity for this test. - * - *

This is a static method, as tests for other entities might also need it, - * if they test an entity which requires the current entity.

- */ - public static SourceData createEntity(EntityManager em) { - return new SourceData() - .sourceDataType(DEFAULT_SOURCE_DATA_TYPE) - .sourceDataName(DEFAULT_SOURCE_DATA_NAME) - .processingState(DEFAULT_PROCESSING_STATE) - .keySchema(DEFAULT_KEY_SCHEMA) - .valueSchema(DEFAULT_VALUE_SCHEMA) - .topic(DEFAULT_TOPIC) - .unit(DEFAULT_UNTI) - .frequency(DEFAULT_FREQUENCY); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.initMocks(this) + val sourceDataResource = SourceDataResource() + ReflectionTestUtils.setField(sourceDataResource, "sourceDataService", sourceDataService) + ReflectionTestUtils.setField(sourceDataResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter!!.init(MockFilterConfig()) + restSourceDataMockMvc = MockMvcBuilders.standaloneSetup(sourceDataResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() } @BeforeEach - public void initTest() { - sourceData = createEntity(em); + fun initTest() { + sourceData = createEntity(em) } @Test @Transactional - void createSourceData() throws Exception { - int databaseSizeBeforeCreate = sourceDataRepository.findAll().size(); + @Throws(Exception::class) + fun createSourceData() { + val databaseSizeBeforeCreate = sourceDataRepository!!.findAll().size // Create the SourceData - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); - restSourceDataMockMvc.perform(post("/api/source-data") + val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDataDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the SourceData in the database - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeCreate + 1); - SourceData testSourceData = sourceDataList.get(sourceDataList.size() - 1); - assertThat(testSourceData.sourceDataType).isEqualTo(DEFAULT_SOURCE_DATA_TYPE); - assertThat(testSourceData.sourceDataName).isEqualTo(DEFAULT_SOURCE_DATA_NAME); - assertThat(testSourceData.processingState).isEqualTo(DEFAULT_PROCESSING_STATE); - assertThat(testSourceData.keySchema).isEqualTo(DEFAULT_KEY_SCHEMA); - assertThat(testSourceData.valueSchema).isEqualTo(DEFAULT_VALUE_SCHEMA); - assertThat(testSourceData.frequency).isEqualTo(DEFAULT_FREQUENCY); - assertThat(testSourceData.topic).isEqualTo(DEFAULT_TOPIC); - assertThat(testSourceData.unit).isEqualTo(DEFAULT_UNTI); + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeCreate + 1) + val testSourceData = sourceDataList[sourceDataList.size - 1] + Assertions.assertThat(testSourceData.sourceDataType).isEqualTo(DEFAULT_SOURCE_DATA_TYPE) + Assertions.assertThat(testSourceData.sourceDataName).isEqualTo(DEFAULT_SOURCE_DATA_NAME) + Assertions.assertThat(testSourceData.processingState).isEqualTo(DEFAULT_PROCESSING_STATE) + Assertions.assertThat(testSourceData.keySchema).isEqualTo(DEFAULT_KEY_SCHEMA) + Assertions.assertThat(testSourceData.valueSchema).isEqualTo(DEFAULT_VALUE_SCHEMA) + Assertions.assertThat(testSourceData.frequency).isEqualTo(DEFAULT_FREQUENCY) + Assertions.assertThat(testSourceData.topic).isEqualTo(DEFAULT_TOPIC) + Assertions.assertThat(testSourceData.unit).isEqualTo(DEFAULT_UNTI) } @Test @Transactional - void createSourceDataWithExistingId() throws Exception { - int databaseSizeBeforeCreate = sourceDataRepository.findAll().size(); + @Throws(Exception::class) + fun createSourceDataWithExistingId() { + val databaseSizeBeforeCreate = sourceDataRepository!!.findAll().size // Create the SourceData with an existing ID - sourceData.setId(1L); - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); + sourceData!!.id = 1L + val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) // An entity with an existing ID cannot be created, so this API call must fail - restSourceDataMockMvc.perform(post("/api/source-data") + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDataDto))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the Alice in the database - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeCreate); + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeCreate) } @Test @Transactional - void checkSourceDataTypeIsNotRequired() throws Exception { - final int databaseSizeBeforeTest = sourceDataRepository.findAll().size(); + @Throws(Exception::class) + fun checkSourceDataTypeIsNotRequired() { + val databaseSizeBeforeTest = sourceDataRepository!!.findAll().size // set the field null - sourceData.sourceDataType = null; + sourceData!!.sourceDataType = null // Create the SourceData, which fails. - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); - - restSourceDataMockMvc.perform(post("/api/source-data") + val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDataDto))) - .andExpect(status().isCreated()); - - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeTest + 1); + .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeTest + 1) } - @Test @Transactional - void checkSourceDataTypeOrTopicIsRequired() throws Exception { - final int databaseSizeBeforeTest = sourceDataRepository.findAll().size(); + @Throws(Exception::class) + fun checkSourceDataTypeOrTopicIsRequired() { + val databaseSizeBeforeTest = sourceDataRepository!!.findAll().size // set the field null - sourceData.sourceDataType = null; - sourceData.topic = null; + sourceData!!.sourceDataType = null + sourceData!!.topic = null // Create the SourceData, which fails. - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); - restSourceDataMockMvc.perform(post("/api/source-data") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDataDto))) - .andExpect(status().isBadRequest()); - - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeTest); - } - - @Test - @Transactional - void getAllSourceData() throws Exception { - // Initialize the database - sourceDataRepository.saveAndFlush(sourceData); - - // Get all the sourceDataList - restSourceDataMockMvc.perform(get("/api/source-data?sort=id,desc")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(sourceData.getId().intValue()))) - .andExpect(jsonPath("$.[*].sourceDataType").value( - hasItem(DEFAULT_SOURCE_DATA_TYPE))) - .andExpect(jsonPath("$.[*].sourceDataName").value( - hasItem(DEFAULT_SOURCE_DATA_NAME))) - .andExpect(jsonPath("$.[*].processingState").value( - hasItem(DEFAULT_PROCESSING_STATE))) - .andExpect(jsonPath("$.[*].keySchema").value(hasItem(DEFAULT_KEY_SCHEMA))) - .andExpect(jsonPath("$.[*].valueSchema").value(hasItem(DEFAULT_VALUE_SCHEMA))) - .andExpect(jsonPath("$.[*].unit").value(hasItem(DEFAULT_UNTI))) - .andExpect(jsonPath("$.[*].topic").value(hasItem(DEFAULT_TOPIC))) - .andExpect(jsonPath("$.[*].frequency").value(hasItem(DEFAULT_FREQUENCY))); + val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.post("/api/source-data") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeTest) } - @Test - @Transactional - void getAllSourceDataWithPagination() throws Exception { - // Initialize the database - sourceDataRepository.saveAndFlush(sourceData); - - // Get all the sourceDataList - restSourceDataMockMvc.perform(get("/api/source-data?page=0&size=5&sort=id,desc")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(sourceData.getId().intValue()))) - .andExpect(jsonPath("$.[*].sourceDataType").value( - hasItem(DEFAULT_SOURCE_DATA_TYPE))) - .andExpect(jsonPath("$.[*].sourceDataName").value( - hasItem(DEFAULT_SOURCE_DATA_NAME))) - .andExpect(jsonPath("$.[*].processingState").value( - hasItem(DEFAULT_PROCESSING_STATE))) - .andExpect(jsonPath("$.[*].keySchema").value(hasItem(DEFAULT_KEY_SCHEMA))) - .andExpect(jsonPath("$.[*].valueSchema").value(hasItem(DEFAULT_VALUE_SCHEMA))) - .andExpect(jsonPath("$.[*].unit").value(hasItem(DEFAULT_UNTI))) - .andExpect(jsonPath("$.[*].topic").value(hasItem(DEFAULT_TOPIC))) - .andExpect(jsonPath("$.[*].frequency").value(hasItem(DEFAULT_FREQUENCY))); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + val allSourceData: Unit + get() { + // Initialize the database + sourceDataRepository!!.saveAndFlush(sourceData) + + // Get all the sourceDataList + restSourceDataMockMvc!!.perform(MockMvcRequestBuilders.get("/api/source-data?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + sourceData!!.id!!.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceDataType").value>( + Matchers.hasItem(DEFAULT_SOURCE_DATA_TYPE) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceDataName").value>( + Matchers.hasItem(DEFAULT_SOURCE_DATA_NAME) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].processingState").value>( + Matchers.hasItem(DEFAULT_PROCESSING_STATE) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].keySchema").value>( + Matchers.hasItem( + DEFAULT_KEY_SCHEMA + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].valueSchema").value>( + Matchers.hasItem( + DEFAULT_VALUE_SCHEMA + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].unit").value>( + Matchers.hasItem( + DEFAULT_UNTI + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].topic").value>( + Matchers.hasItem( + DEFAULT_TOPIC + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].frequency").value>( + Matchers.hasItem( + DEFAULT_FREQUENCY + ) + ) + ) + } + + @get:Throws(Exception::class) + @get:Transactional + @get:Test + val allSourceDataWithPagination: Unit + get() { + // Initialize the database + sourceDataRepository!!.saveAndFlush(sourceData) + + // Get all the sourceDataList + restSourceDataMockMvc!!.perform(MockMvcRequestBuilders.get("/api/source-data?page=0&size=5&sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + sourceData!!.id!!.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceDataType").value>( + Matchers.hasItem(DEFAULT_SOURCE_DATA_TYPE) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceDataName").value>( + Matchers.hasItem(DEFAULT_SOURCE_DATA_NAME) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].processingState").value>( + Matchers.hasItem(DEFAULT_PROCESSING_STATE) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].keySchema").value>( + Matchers.hasItem( + DEFAULT_KEY_SCHEMA + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].valueSchema").value>( + Matchers.hasItem( + DEFAULT_VALUE_SCHEMA + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].unit").value>( + Matchers.hasItem( + DEFAULT_UNTI + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].topic").value>( + Matchers.hasItem( + DEFAULT_TOPIC + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].frequency").value>( + Matchers.hasItem( + DEFAULT_FREQUENCY + ) + ) + ) + } @Test @Transactional - void getSourceData() throws Exception { + @Throws(Exception::class) + fun getSourceData() { // Initialize the database - sourceDataRepository.saveAndFlush(sourceData); + sourceDataRepository!!.saveAndFlush(sourceData) // Get the sourceData - restSourceDataMockMvc.perform(get("/api/source-data/{sourceDataName}", - sourceData.sourceDataName)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.id").value(sourceData.getId().intValue())) - .andExpect(jsonPath("$.sourceDataType").value(DEFAULT_SOURCE_DATA_TYPE)) - .andExpect(jsonPath("$.sourceDataName").value(DEFAULT_SOURCE_DATA_NAME)) - .andExpect(jsonPath("$.processingState").value(DEFAULT_PROCESSING_STATE)) - .andExpect(jsonPath("$.keySchema").value(DEFAULT_KEY_SCHEMA)) - .andExpect(jsonPath("$.valueSchema").value(DEFAULT_VALUE_SCHEMA)) - .andExpect(jsonPath("$.unit").value(DEFAULT_UNTI)) - .andExpect(jsonPath("$.topic").value(DEFAULT_TOPIC)) - .andExpect(jsonPath("$.frequency").value(DEFAULT_FREQUENCY)); + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.get( + "/api/source-data/{sourceDataName}", + sourceData!!.sourceDataName + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(sourceData!!.id!!.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.sourceDataType").value(DEFAULT_SOURCE_DATA_TYPE)) + .andExpect(MockMvcResultMatchers.jsonPath("$.sourceDataName").value(DEFAULT_SOURCE_DATA_NAME)) + .andExpect(MockMvcResultMatchers.jsonPath("$.processingState").value(DEFAULT_PROCESSING_STATE)) + .andExpect(MockMvcResultMatchers.jsonPath("$.keySchema").value(DEFAULT_KEY_SCHEMA)) + .andExpect(MockMvcResultMatchers.jsonPath("$.valueSchema").value(DEFAULT_VALUE_SCHEMA)) + .andExpect(MockMvcResultMatchers.jsonPath("$.unit").value(DEFAULT_UNTI)) + .andExpect(MockMvcResultMatchers.jsonPath("$.topic").value(DEFAULT_TOPIC)) + .andExpect(MockMvcResultMatchers.jsonPath("$.frequency").value(DEFAULT_FREQUENCY)) } - @Test - @Transactional - void getNonExistingSourceData() throws Exception { - // Get the sourceData - restSourceDataMockMvc.perform(get("/api/source-data/{sourceDataName}", - DEFAULT_SOURCE_DATA_NAME + DEFAULT_SOURCE_DATA_NAME)) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + val nonExistingSourceData: Unit + get() { + // Get the sourceData + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.get( + "/api/source-data/{sourceDataName}", + DEFAULT_SOURCE_DATA_NAME + DEFAULT_SOURCE_DATA_NAME + ) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional - void updateSourceData() throws Exception { + @Throws(Exception::class) + fun updateSourceData() { // Initialize the database - sourceDataRepository.saveAndFlush(sourceData); - int databaseSizeBeforeUpdate = sourceDataRepository.findAll().size(); + sourceDataRepository!!.saveAndFlush(sourceData) + val databaseSizeBeforeUpdate = sourceDataRepository.findAll().size // Update the sourceData - SourceData updatedSourceData = sourceDataRepository.findById(sourceData.getId()).get(); + val updatedSourceData = sourceDataRepository.findById(sourceData!!.id).get() updatedSourceData - .sourceDataType(UPDATED_SOURCE_DATA_TYPE) - .sourceDataName(UPDATED_SOURCE_DATA_NAME) - .processingState(UPDATED_PROCESSING_STATE) - .keySchema(UPDATED_KEY_SCHEMA) - .valueSchema(UPDATED_VALUE_SCHEMA) - .topic(UPDATED_TOPIC) - .unit(UPDATED_UNIT) - .frequency(UPDATED_FREQUENCY); - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(updatedSourceData); - - restSourceDataMockMvc.perform(put("/api/source-data") + .sourceDataType(UPDATED_SOURCE_DATA_TYPE) + .sourceDataName(UPDATED_SOURCE_DATA_NAME) + .processingState(UPDATED_PROCESSING_STATE) + .keySchema(UPDATED_KEY_SCHEMA) + .valueSchema(UPDATED_VALUE_SCHEMA) + .topic(UPDATED_TOPIC) + .unit(UPDATED_UNIT) + .frequency(UPDATED_FREQUENCY) + val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(updatedSourceData) + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.put("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDataDto))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the SourceData in the database - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeUpdate); - SourceData testSourceData = sourceDataList.get(sourceDataList.size() - 1); - assertThat(testSourceData.sourceDataType).isEqualTo(UPDATED_SOURCE_DATA_TYPE); - assertThat(testSourceData.sourceDataName).isEqualTo(UPDATED_SOURCE_DATA_NAME); - assertThat(testSourceData.processingState).isEqualTo(UPDATED_PROCESSING_STATE); - assertThat(testSourceData.keySchema).isEqualTo(UPDATED_KEY_SCHEMA); - assertThat(testSourceData.valueSchema).isEqualTo(UPDATED_VALUE_SCHEMA); - assertThat(testSourceData.topic).isEqualTo(UPDATED_TOPIC); - assertThat(testSourceData.unit).isEqualTo(UPDATED_UNIT); - assertThat(testSourceData.frequency).isEqualTo(UPDATED_FREQUENCY); + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeUpdate) + val testSourceData = sourceDataList[sourceDataList.size - 1] + Assertions.assertThat(testSourceData.sourceDataType).isEqualTo(UPDATED_SOURCE_DATA_TYPE) + Assertions.assertThat(testSourceData.sourceDataName).isEqualTo(UPDATED_SOURCE_DATA_NAME) + Assertions.assertThat(testSourceData.processingState).isEqualTo(UPDATED_PROCESSING_STATE) + Assertions.assertThat(testSourceData.keySchema).isEqualTo(UPDATED_KEY_SCHEMA) + Assertions.assertThat(testSourceData.valueSchema).isEqualTo(UPDATED_VALUE_SCHEMA) + Assertions.assertThat(testSourceData.topic).isEqualTo(UPDATED_TOPIC) + Assertions.assertThat(testSourceData.unit).isEqualTo(UPDATED_UNIT) + Assertions.assertThat(testSourceData.frequency).isEqualTo(UPDATED_FREQUENCY) } @Test @Transactional - void updateNonExistingSourceData() throws Exception { - int databaseSizeBeforeUpdate = sourceDataRepository.findAll().size(); + @Throws(Exception::class) + fun updateNonExistingSourceData() { + val databaseSizeBeforeUpdate = sourceDataRepository!!.findAll().size // Create the SourceData - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData); + val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) // If the entity doesn't have an ID, it will be created instead of just being updated - restSourceDataMockMvc.perform(put("/api/source-data") + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.put("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDataDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the SourceData in the database - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeUpdate + 1); + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeUpdate + 1) } @Test @Transactional - void deleteSourceData() throws Exception { + @Throws(Exception::class) + fun deleteSourceData() { // Initialize the database - sourceDataRepository.saveAndFlush(sourceData); - int databaseSizeBeforeDelete = sourceDataRepository.findAll().size(); + sourceDataRepository!!.saveAndFlush(sourceData) + val databaseSizeBeforeDelete = sourceDataRepository.findAll().size // Get the sourceData - restSourceDataMockMvc.perform(delete("/api/source-data/{sourceDataName}", - sourceData.sourceDataName) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()); + restSourceDataMockMvc!!.perform( + MockMvcRequestBuilders.delete( + "/api/source-data/{sourceDataName}", + sourceData!!.sourceDataName + ) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(databaseSizeBeforeDelete - 1); + val sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeDelete - 1) } @Test @Transactional - void equalsVerifier() throws Exception { - Assertions.assertTrue(TestUtil.equalsVerifier(SourceData.class)); + @Throws(Exception::class) + fun equalsVerifier() { + org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(SourceData::class.java)) + } + + companion object { + private const val DEFAULT_SOURCE_DATA_TYPE = "AAAAAAAAAA" + private const val UPDATED_SOURCE_DATA_TYPE = "BBBBBBBBBB" + private const val DEFAULT_SOURCE_DATA_NAME = "AAAAAAAAAAAAA" + private const val UPDATED_SOURCE_DATA_NAME = "BBBBBBBBBBAAA" + private const val DEFAULT_PROCESSING_STATE = "RAW" + private const val UPDATED_PROCESSING_STATE = "DERIVED" + private const val DEFAULT_KEY_SCHEMA = "AAAAAAAAAAC" + private const val UPDATED_KEY_SCHEMA = "BBBBBBBBBBC" + private const val DEFAULT_VALUE_SCHEMA = "AAAAAAAAAAA" + private const val UPDATED_VALUE_SCHEMA = "BBBBBBBBBBB" + private const val DEFAULT_FREQUENCY = "AAAAAAAAAAAA" + private const val UPDATED_FREQUENCY = "BBBBBBBBBBBB" + private const val DEFAULT_UNTI = "AAAAAAAAAAAAAAC" + private const val UPDATED_UNIT = "BBBBBBBBBBBBBBC" + private const val DEFAULT_TOPIC = "AAAAAAAAAAAAAAA" + private const val UPDATED_TOPIC = "BBBBBBBBBBBBBBB" + + /** + * Create an entity for this test. + * + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + fun createEntity(em: EntityManager?): SourceData { + return SourceData() + .sourceDataType(DEFAULT_SOURCE_DATA_TYPE) + .sourceDataName(DEFAULT_SOURCE_DATA_NAME) + .processingState(DEFAULT_PROCESSING_STATE) + .keySchema(DEFAULT_KEY_SCHEMA) + .valueSchema(DEFAULT_VALUE_SCHEMA) + .topic(DEFAULT_TOPIC) + .unit(DEFAULT_UNTI) + .frequency(DEFAULT_FREQUENCY) + } } } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt index 625a7fec8..936f9d6b9 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt @@ -1,343 +1,343 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Source; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.SourceRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.SourceService; -import org.radarbase.management.service.SourceTypeService; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.mapper.SourceMapper; -import org.radarbase.management.service.mapper.SourceTypeMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.result.MockMvcResultHandlers; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.servlet.ServletException; -import java.util.List; -import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.everyItem; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.notNullValue; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Source +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.SourceRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.SourceService +import org.radarbase.management.service.SourceTypeService +import org.radarbase.management.service.mapper.SourceMapper +import org.radarbase.management.service.mapper.SourceTypeMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultHandlers +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import java.util.* +import javax.servlet.ServletException /** * Test class for the DeviceResource REST controller. * * @see SourceResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class SourceResourceIntTest { - - private static final UUID DEFAULT_SOURCE_PHYSICAL_ID = UUID.randomUUID(); - private static final UUID UPDATED_SOURCE_PHYSICAL_ID = DEFAULT_SOURCE_PHYSICAL_ID; - - private static final String DEFAULT_SOURCE_NAME = "CCCCCCCCCC"; - - private static final Boolean DEFAULT_ASSIGNED = false; - private static final Boolean UPDATED_ASSIGNED = true; - - @Autowired - private SourceRepository sourceRepository; - - @Autowired - private SourceMapper sourceMapper; - - @Autowired - private SourceService sourceService; - - @Autowired - private SourceTypeService sourceTypeService; - - @Autowired - private SourceTypeMapper sourceTypeMapper; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - @Autowired - private ProjectRepository projectRepository; - - private MockMvc restDeviceMockMvc; - - private Source source; - - private Project project; - @Autowired - private AuthService authService; +internal open class SourceResourceIntTest( + @Autowired private val sourceRepository: SourceRepository, + @Autowired private val sourceMapper: SourceMapper, + @Autowired private val sourceService: SourceService, + @Autowired private val sourceTypeService: SourceTypeService, + @Autowired private val sourceTypeMapper: SourceTypeMapper, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val projectRepository: ProjectRepository, + private var restDeviceMockMvc: MockMvc, + private var source: Source, + private var project: Project, + @Autowired private val authService: AuthService +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - SourceResource sourceResource = new SourceResource(); - ReflectionTestUtils.setField(sourceResource, "authService", authService); - ReflectionTestUtils.setField(sourceResource, "sourceService", sourceService); - ReflectionTestUtils.setField(sourceResource, "sourceRepository", sourceRepository); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - this.restDeviceMockMvc = MockMvcBuilders.standaloneSetup(sourceResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())) - .alwaysDo(MockMvcResultHandlers.print()).build(); - } - - /** - * Create an entity for this test. - * - *

This is a static method, as tests for other entities might also need it, - * if they test an entity which requires the current entity.

- */ - public static Source createEntity() { - return new Source() - .assigned(DEFAULT_ASSIGNED) - .sourceName(DEFAULT_SOURCE_NAME); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val sourceResource = SourceResource() + ReflectionTestUtils.setField(sourceResource, "authService", authService) + ReflectionTestUtils.setField(sourceResource, "sourceService", sourceService) + ReflectionTestUtils.setField(sourceResource, "sourceRepository", sourceRepository) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restDeviceMockMvc = MockMvcBuilders.standaloneSetup(sourceResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .alwaysDo(MockMvcResultHandlers.print()).build() } @BeforeEach - public void initTest() { - source = createEntity(); - List sourceTypeDtos = sourceTypeService.findAll(); - assertThat(sourceTypeDtos.size()).isPositive(); - source.sourceType = sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDtos.get(0)); - project = projectRepository.findById(1L).get(); - source.project(project); + fun initTest() { + source = createEntity() + val sourceTypeDtos = sourceTypeService.findAll() + Assertions.assertThat(sourceTypeDtos.size).isPositive() + source.sourceType = sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDtos[0]) + project = projectRepository.findById(1L).get() + source.project(project) } @Test @Transactional - void createSource() throws Exception { - int databaseSizeBeforeCreate = sourceRepository.findAll().size(); + @Throws(Exception::class) + open fun createSource() { + val databaseSizeBeforeCreate = sourceRepository.findAll().size // Create the Source - SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(source); - restDeviceMockMvc.perform(post("/api/sources") + val sourceDto = sourceMapper.sourceToSourceDTO(source) + restDeviceMockMvc.perform( + MockMvcRequestBuilders.post("/api/sources") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Source in the database - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeCreate + 1); - Source testSource = sourceList.get(sourceList.size() - 1); - assertThat(testSource.isAssigned()).isEqualTo(DEFAULT_ASSIGNED); - assertThat(testSource.sourceName).isEqualTo(DEFAULT_SOURCE_NAME); - assertThat(testSource.project.projectName).isEqualTo(project.projectName); + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeCreate + 1) + val testSource = sourceList[sourceList.size - 1] + Assertions.assertThat(testSource.isAssigned).isEqualTo(DEFAULT_ASSIGNED) + Assertions.assertThat(testSource.sourceName).isEqualTo(DEFAULT_SOURCE_NAME) + Assertions.assertThat(testSource.project!!.projectName).isEqualTo(project.projectName) } @Test @Transactional - void createSourceWithExistingId() throws Exception { - int databaseSizeBeforeCreate = sourceRepository.findAll().size(); + @Throws(Exception::class) + open fun createSourceWithExistingId() { + val databaseSizeBeforeCreate = sourceRepository.findAll().size // Create the Source with an existing ID - source.setId(1L); - SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(source); + source.id = 1L + val sourceDto = sourceMapper.sourceToSourceDTO(source) // An entity with an existing ID cannot be created, so this API call must fail - restDeviceMockMvc.perform(post("/api/sources") + restDeviceMockMvc.perform( + MockMvcRequestBuilders.post("/api/sources") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDto))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(sourceDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the Alice in the database - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeCreate); + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeCreate) } @Test @Transactional - void checkSourcePhysicalIdIsGenerated() throws Exception { - int databaseSizeBeforeTest = sourceRepository.findAll().size(); + @Throws(Exception::class) + open fun checkSourcePhysicalIdIsGenerated() { + val databaseSizeBeforeTest = sourceRepository.findAll().size // set the field null - source.sourceId = null; + source.sourceId = null // Create the Source - SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(source); - - restDeviceMockMvc.perform(post("/api/sources") + val sourceDto = sourceMapper.sourceToSourceDTO(source) + restDeviceMockMvc.perform( + MockMvcRequestBuilders.post("/api/sources") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDto))) - .andExpect(status().isCreated()); - - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeTest + 1); + .content(TestUtil.convertObjectToJsonBytes(sourceDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeTest + 1) // find our created source - Source createdSource = sourceList.stream() - .filter(s -> s.sourceName.equals(DEFAULT_SOURCE_NAME)) - .findFirst() - .orElse(null); - assertThat(createdSource).isNotNull(); + val createdSource = sourceList.stream() + .filter { s: Source? -> s!!.sourceName == DEFAULT_SOURCE_NAME } + .findFirst() + .orElse(null) + Assertions.assertThat(createdSource).isNotNull() // check source id - assertThat(createdSource.sourceId).isNotNull(); + Assertions.assertThat(createdSource!!.sourceId).isNotNull() } @Test @Transactional - void checkAssignedIsRequired() throws Exception { - int databaseSizeBeforeTest = sourceRepository.findAll().size(); + @Throws(Exception::class) + open fun checkAssignedIsRequired() { + val databaseSizeBeforeTest = sourceRepository.findAll().size // set the field null - source.setAssigned(null); + source.isAssigned = null // Create the Source, which fails. - SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(source); - - restDeviceMockMvc.perform(post("/api/sources") + val sourceDto = sourceMapper.sourceToSourceDTO(source) + restDeviceMockMvc.perform( + MockMvcRequestBuilders.post("/api/sources") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDto))) - .andExpect(status().isBadRequest()); - - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeTest); + .content(TestUtil.convertObjectToJsonBytes(sourceDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeTest) } - @Test - @Transactional - void getAllSources() throws Exception { - // Initialize the database - sourceRepository.saveAndFlush(source); - - // Get all the deviceList - restDeviceMockMvc.perform(get("/api/sources?sort=id,desc")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(source.getId().intValue()))) - .andExpect(jsonPath("$.[*].sourceId").value(everyItem(notNullValue()))) - .andExpect(jsonPath("$.[*].assigned").value( - hasItem(DEFAULT_ASSIGNED.booleanValue()))); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val allSources: Unit + get() { + // Initialize the database + sourceRepository.saveAndFlush(source) + + // Get all the deviceList + restDeviceMockMvc.perform(MockMvcRequestBuilders.get("/api/sources?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + source.id!!.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(Matchers.everyItem(Matchers.notNullValue())) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].assigned").value>( + Matchers.hasItem(DEFAULT_ASSIGNED) + ) + ) + } @Test @Transactional - void getSource() throws Exception { + @Throws(Exception::class) + open fun getSource() { // Initialize the database - sourceRepository.saveAndFlush(source); + sourceRepository.saveAndFlush(source) // Get the source - restDeviceMockMvc.perform(get("/api/sources/{sourceName}", source.sourceName)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.id").value(source.getId().intValue())) - .andExpect(jsonPath("$.sourceId").value(notNullValue())) - .andExpect(jsonPath("$.assigned").value(DEFAULT_ASSIGNED.booleanValue())); + restDeviceMockMvc.perform(MockMvcRequestBuilders.get("/api/sources/{sourceName}", source.sourceName)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(source.id!!.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.sourceId").value(Matchers.notNullValue())) + .andExpect(MockMvcResultMatchers.jsonPath("$.assigned").value(DEFAULT_ASSIGNED)) } - @Test - @Transactional - void getNonExistingSource() throws Exception { - // Get the source - restDeviceMockMvc.perform(get("/api/sources/{id}", Long.MAX_VALUE)) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val nonExistingSource: Unit + get() { + // Get the source + restDeviceMockMvc.perform(MockMvcRequestBuilders.get("/api/sources/{id}", Long.MAX_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional - void updateSource() throws Exception { + @Throws(Exception::class) + open fun updateSource() { // Initialize the database - sourceRepository.saveAndFlush(source); - int databaseSizeBeforeUpdate = sourceRepository.findAll().size(); + sourceRepository.saveAndFlush(source) + val databaseSizeBeforeUpdate = sourceRepository.findAll().size // Update the source - Source updatedSource = sourceRepository.findById(source.getId()).get(); + val updatedSource = sourceRepository.findById(source.id!!).get() updatedSource - .sourceId(UPDATED_SOURCE_PHYSICAL_ID) - .assigned(UPDATED_ASSIGNED); - SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(updatedSource); - - restDeviceMockMvc.perform(put("/api/sources") + .sourceId(UPDATED_SOURCE_PHYSICAL_ID) + .assigned(UPDATED_ASSIGNED) + val sourceDto = sourceMapper.sourceToSourceDTO(updatedSource) + restDeviceMockMvc.perform( + MockMvcRequestBuilders.put("/api/sources") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDto))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(sourceDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Source in the database - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeUpdate); - Source testSource = sourceList.get(sourceList.size() - 1); - assertThat(testSource.sourceId).isEqualTo(UPDATED_SOURCE_PHYSICAL_ID); - assertThat(testSource.isAssigned()).isEqualTo(UPDATED_ASSIGNED); + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeUpdate) + val testSource = sourceList[sourceList.size - 1] + Assertions.assertThat(testSource.sourceId).isEqualTo(UPDATED_SOURCE_PHYSICAL_ID) + Assertions.assertThat(testSource.isAssigned).isEqualTo(UPDATED_ASSIGNED) } @Test @Transactional - void updateNonExistingSource() throws Exception { - int databaseSizeBeforeUpdate = sourceRepository.findAll().size(); + @Throws(Exception::class) + open fun updateNonExistingSource() { + val databaseSizeBeforeUpdate = sourceRepository.findAll().size // Create the Source - SourceDTO sourceDto = sourceMapper.sourceToSourceDTO(source); + val sourceDto = sourceMapper.sourceToSourceDTO(source) // If the entity doesn't have an ID, it will be created instead of just being updated - restDeviceMockMvc.perform(put("/api/sources") + restDeviceMockMvc.perform( + MockMvcRequestBuilders.put("/api/sources") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Source in the database - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeUpdate + 1); + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeUpdate + 1) } @Test @Transactional - void deleteSource() throws Exception { + @Throws(Exception::class) + open fun deleteSource() { // Initialize the database - sourceRepository.saveAndFlush(source); - int databaseSizeBeforeDelete = sourceRepository.findAll().size(); + sourceRepository.saveAndFlush(source) + val databaseSizeBeforeDelete = sourceRepository.findAll().size // Get the source - restDeviceMockMvc.perform(delete("/api/sources/{sourceName}", source.sourceName) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()); + restDeviceMockMvc.perform( + MockMvcRequestBuilders.delete("/api/sources/{sourceName}", source.sourceName) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty - List sourceList = sourceRepository.findAll(); - assertThat(sourceList).hasSize(databaseSizeBeforeDelete - 1); + val sourceList = sourceRepository.findAll() + Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeDelete - 1) } @Test @Transactional - void equalsVerifier() throws Exception { - Assertions.assertTrue(TestUtil.equalsVerifier(Source.class)); + @Throws(Exception::class) + open fun equalsVerifier() { + org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Source::class.java)) + } + + companion object { + private val DEFAULT_SOURCE_PHYSICAL_ID = UUID.randomUUID() + private val UPDATED_SOURCE_PHYSICAL_ID = DEFAULT_SOURCE_PHYSICAL_ID + private const val DEFAULT_SOURCE_NAME = "CCCCCCCCCC" + private const val DEFAULT_ASSIGNED = false + private const val UPDATED_ASSIGNED = true + + /** + * Create an entity for this test. + * + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + fun createEntity(): Source { + return Source() + .assigned(DEFAULT_ASSIGNED) + .sourceName(DEFAULT_SOURCE_NAME) + } } } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt index 73d8864ea..71ce2af6f 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt @@ -1,436 +1,500 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.repository.SourceDataRepository; -import org.radarbase.management.repository.SourceTypeRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.SourceTypeService; -import org.radarbase.management.service.dto.SourceDataDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.mapper.SourceDataMapper; -import org.radarbase.management.service.mapper.SourceTypeMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.persistence.EntityManager; -import javax.servlet.ServletException; -import java.util.Collections; -import java.util.List; -import java.util.Set; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.SourceType +import org.radarbase.management.repository.SourceDataRepository +import org.radarbase.management.repository.SourceTypeRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.SourceTypeService +import org.radarbase.management.service.mapper.SourceDataMapper +import org.radarbase.management.service.mapper.SourceTypeMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import javax.persistence.EntityManager +import javax.servlet.ServletException /** * Test class for the SourceTypeResource REST controller. * * @see SourceTypeResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class SourceTypeResourceIntTest { - - private static final String DEFAULT_PRODUCER = "AAAAA AAAAA"; - private static final String UPDATED_PRODUCER = "BBBBBBBBBB"; - - private static final String DEFAULT_MODEL = "AAAAA AAAAA"; - private static final String UPDATED_MODEL = "BBBBBBBBBB"; - - private static final String DEFAULT_DEVICE_VERSION = "AAAAAAAAAA"; - private static final String UPDATED_DEVICE_VERSION = "AAAAAAAAAA"; - - private static final String DEFAULT_SOURCE_TYPE_SCOPE = "ACTIVE"; - private static final String UPDATED_SOURCE_TYPE_SCOPE = "PASSIVE"; - - @Autowired - private SourceTypeRepository sourceTypeRepository; - - @Autowired - private SourceTypeMapper sourceTypeMapper; - - @Autowired - private SourceTypeService sourceTypeService; - - @Autowired - private SourceDataMapper sourceDataMapper; - - @Autowired - private SourceDataRepository sourceDataRepository; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - @Autowired - private EntityManager em; - - private MockMvc restSourceTypeMockMvc; - - private SourceType sourceType; - @Autowired - private AuthService authService; +internal open class SourceTypeResourceIntTest( + @Autowired private val sourceTypeRepository: SourceTypeRepository, + @Autowired private val sourceTypeMapper: SourceTypeMapper, + @Autowired private val sourceTypeService: SourceTypeService, + @Autowired private val sourceDataMapper: SourceDataMapper, + @Autowired private val sourceDataRepository: SourceDataRepository, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val em: EntityManager, + private var restSourceTypeMockMvc: MockMvc, + private var sourceType: SourceType, + @Autowired private val authService: AuthService +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - SourceTypeResource sourceTypeResource = new SourceTypeResource(); - ReflectionTestUtils.setField(sourceTypeResource, "sourceTypeService" , sourceTypeService); - ReflectionTestUtils.setField(sourceTypeResource, "sourceTypeRepository" , - sourceTypeRepository); - ReflectionTestUtils.setField(sourceTypeResource, "authService", authService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restSourceTypeMockMvc = MockMvcBuilders.standaloneSetup(sourceTypeResource) + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val sourceTypeResource = SourceTypeResource() + ReflectionTestUtils.setField(sourceTypeResource, "sourceTypeService", sourceTypeService) + ReflectionTestUtils.setField( + sourceTypeResource, "sourceTypeRepository", + sourceTypeRepository + ) + ReflectionTestUtils.setField(sourceTypeResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restSourceTypeMockMvc = MockMvcBuilders.standaloneSetup(sourceTypeResource) .setCustomArgumentResolvers(pageableArgumentResolver) .setControllerAdvice(exceptionTranslator) .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - } - - /** - * Create an entity for this test. - * - *

This is a static method, as tests for other entities might also need it, - * if they test an entity which requires the current entity.

- */ - public static SourceType createEntity() { - return new SourceType() - .producer(DEFAULT_PRODUCER) - .model(DEFAULT_MODEL) - .catalogVersion(DEFAULT_DEVICE_VERSION) - .sourceTypeScope(DEFAULT_SOURCE_TYPE_SCOPE); + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() } @BeforeEach - public void initTest() { - sourceType = createEntity(); + fun initTest() { + sourceType = createEntity() } @Test @Transactional - void createSourceType() throws Exception { - int databaseSizeBeforeCreate = sourceTypeRepository.findAll().size(); + @Throws(Exception::class) + open fun createSourceType() { + val databaseSizeBeforeCreate = sourceTypeRepository.findAll().size // Create the SourceType - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); - SourceDataDTO sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO( - SourceDataResourceIntTest.createEntity(em)); - Set sourceData = sourceTypeDto.getSourceData(); - sourceData.add(sourceDataDto); - restSourceTypeMockMvc.perform(post("/api/source-types") + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO( + SourceDataResourceIntTest.Companion.createEntity(em) + ) + val sourceData = sourceTypeDto.sourceData + sourceData.add(sourceDataDto) + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.post("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the SourceType in the database - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeCreate + 1); - SourceType testSourceType = sourceTypeList.get(sourceTypeList.size() - 1); - assertThat(testSourceType.producer).isEqualTo(DEFAULT_PRODUCER); - assertThat(testSourceType.model).isEqualTo(DEFAULT_MODEL); - assertThat(testSourceType.sourceTypeScope).isEqualTo(DEFAULT_SOURCE_TYPE_SCOPE); - assertThat(testSourceType.catalogVersion).isEqualTo(DEFAULT_DEVICE_VERSION); - assertThat(testSourceType.sourceData).hasSize(1); - SourceData testSourceData = testSourceType.sourceData.iterator().next(); - assertThat(testSourceData.sourceDataType).isEqualTo(sourceDataDto.getSourceDataType()); - assertThat(testSourceData.sourceDataName).isEqualTo(sourceDataDto.getSourceDataName()); - assertThat(testSourceData.processingState).isEqualTo( - sourceDataDto.getProcessingState()); - assertThat(testSourceData.keySchema).isEqualTo(sourceDataDto.getKeySchema()); - assertThat(testSourceData.frequency).isEqualTo(sourceDataDto.getFrequency()); + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeCreate + 1) + val testSourceType = sourceTypeList[sourceTypeList.size - 1] + Assertions.assertThat(testSourceType.producer).isEqualTo(DEFAULT_PRODUCER) + Assertions.assertThat(testSourceType.model).isEqualTo(DEFAULT_MODEL) + Assertions.assertThat(testSourceType.sourceTypeScope).isEqualTo(DEFAULT_SOURCE_TYPE_SCOPE) + Assertions.assertThat(testSourceType.catalogVersion).isEqualTo(DEFAULT_DEVICE_VERSION) + Assertions.assertThat(testSourceType.sourceData).hasSize(1) + val testSourceData = testSourceType.sourceData.iterator().next() + Assertions.assertThat(testSourceData.sourceDataType).isEqualTo(sourceDataDto.sourceDataType) + Assertions.assertThat(testSourceData.sourceDataName).isEqualTo(sourceDataDto.sourceDataName) + Assertions.assertThat(testSourceData.processingState).isEqualTo( + sourceDataDto.processingState + ) + Assertions.assertThat(testSourceData.keySchema).isEqualTo(sourceDataDto.keySchema) + Assertions.assertThat(testSourceData.frequency).isEqualTo(sourceDataDto.frequency) } @Test @Transactional - void createSourceTypeWithExistingId() throws Exception { - int databaseSizeBeforeCreate = sourceTypeRepository.findAll().size(); + @Throws(Exception::class) + open fun createSourceTypeWithExistingId() { + val databaseSizeBeforeCreate = sourceTypeRepository.findAll().size // Create the SourceType with an existing ID - sourceType.setId(1L); - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); + sourceType.id = 1L + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) // An entity with an existing ID cannot be created, so this API call must fail - restSourceTypeMockMvc.perform(post("/api/source-types") + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.post("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the Alice in the database - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeCreate); + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeCreate) } @Test @Transactional - void checkModelIsRequired() throws Exception { - int databaseSizeBeforeTest = sourceTypeRepository.findAll().size(); + @Throws(Exception::class) + open fun checkModelIsRequired() { + val databaseSizeBeforeTest = sourceTypeRepository.findAll().size // set the field null - sourceType.model = null; + sourceType.model = null // Create the SourceType, which fails. - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); - - restSourceTypeMockMvc.perform(post("/api/source-types") + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.post("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isBadRequest()); - - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest) } @Test @Transactional - void checkSourceTypeIsRequired() throws Exception { - int databaseSizeBeforeTest = sourceTypeRepository.findAll().size(); + @Throws(Exception::class) + open fun checkSourceTypeIsRequired() { + val databaseSizeBeforeTest = sourceTypeRepository.findAll().size // set the field null - sourceType.sourceTypeScope = null; + sourceType.sourceTypeScope = null // Create the SourceType, which fails. - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); - - restSourceTypeMockMvc.perform(post("/api/source-types") + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.post("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isBadRequest()); - - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest) } @Test @Transactional - void checkVersionIsRequired() throws Exception { - int databaseSizeBeforeTest = sourceTypeRepository.findAll().size(); + @Throws(Exception::class) + open fun checkVersionIsRequired() { + val databaseSizeBeforeTest = sourceTypeRepository.findAll().size // set the field null - sourceType.catalogVersion(null); + sourceType.catalogVersion(null) // Create the SourceType, which fails. - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); - - restSourceTypeMockMvc.perform(post("/api/source-types") + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.post("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isBadRequest()); - - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest); - } - - @Test - @Transactional - void getAllSourceTypes() throws Exception { - // Initialize the database - sourceTypeRepository.saveAndFlush(sourceType); - - // Get all the sourceTypeList - restSourceTypeMockMvc.perform(get("/api/source-types")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(sourceType.getId().intValue()))) - .andExpect(jsonPath("$.[*].producer").value(hasItem(DEFAULT_PRODUCER))) - .andExpect(jsonPath("$.[*].model").value(hasItem(DEFAULT_MODEL))) - .andExpect(jsonPath("$.[*].catalogVersion").value(hasItem(DEFAULT_DEVICE_VERSION))) - .andExpect(jsonPath("$.[*].sourceTypeScope").value( - hasItem(DEFAULT_SOURCE_TYPE_SCOPE))); - } - - - @Test - @Transactional - void getAllSourceTypesWithPagination() throws Exception { - // Initialize the database - sourceTypeRepository.saveAndFlush(sourceType); - - // Get all the sourceTypeList - restSourceTypeMockMvc.perform(get("/api/source-types?page=0&size=5&sort=id,desc")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(sourceType.getId().intValue()))) - .andExpect(jsonPath("$.[*].producer").value(hasItem(DEFAULT_PRODUCER))) - .andExpect(jsonPath("$.[*].model").value(hasItem(DEFAULT_MODEL))) - .andExpect(jsonPath("$.[*].catalogVersion").value(hasItem(DEFAULT_DEVICE_VERSION))) - .andExpect(jsonPath("$.[*].sourceTypeScope").value( - hasItem(DEFAULT_SOURCE_TYPE_SCOPE))); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest) } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val allSourceTypes: Unit + get() { + // Initialize the database + sourceTypeRepository.saveAndFlush(sourceType) + + // Get all the sourceTypeList + restSourceTypeMockMvc.perform(MockMvcRequestBuilders.get("/api/source-types")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + sourceType.id!!.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].producer").value>( + Matchers.hasItem( + DEFAULT_PRODUCER + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].model").value>( + Matchers.hasItem( + DEFAULT_MODEL + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].catalogVersion").value>( + Matchers.hasItem( + DEFAULT_DEVICE_VERSION + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceTypeScope").value>( + Matchers.hasItem(DEFAULT_SOURCE_TYPE_SCOPE) + ) + ) + } + + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val allSourceTypesWithPagination: Unit + get() { + // Initialize the database + sourceTypeRepository.saveAndFlush(sourceType) + + // Get all the sourceTypeList + restSourceTypeMockMvc.perform(MockMvcRequestBuilders.get("/api/source-types?page=0&size=5&sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + sourceType.id!!.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].producer").value>( + Matchers.hasItem( + DEFAULT_PRODUCER + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].model").value>( + Matchers.hasItem( + DEFAULT_MODEL + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].catalogVersion").value>( + Matchers.hasItem( + DEFAULT_DEVICE_VERSION + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceTypeScope").value>( + Matchers.hasItem(DEFAULT_SOURCE_TYPE_SCOPE) + ) + ) + } @Test @Transactional - void getSourceType() throws Exception { + @Throws(Exception::class) + open fun getSourceType() { // Initialize the database - sourceTypeRepository.saveAndFlush(sourceType); + sourceTypeRepository.saveAndFlush(sourceType) // Get the sourceType - restSourceTypeMockMvc.perform(get("/api/source-types/{prodcuer}/{model}/{version}", - sourceType.producer, sourceType.model, sourceType.catalogVersion)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.id").value(sourceType.getId().intValue())) - .andExpect(jsonPath("$.producer").value(DEFAULT_PRODUCER)) - .andExpect(jsonPath("$.model").value(DEFAULT_MODEL)) - .andExpect(jsonPath("$.sourceTypeScope").value( - DEFAULT_SOURCE_TYPE_SCOPE)); + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/source-types/{prodcuer}/{model}/{version}", + sourceType.producer, sourceType.model, sourceType.catalogVersion + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(sourceType.id!!.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.producer").value(DEFAULT_PRODUCER)) + .andExpect(MockMvcResultMatchers.jsonPath("$.model").value(DEFAULT_MODEL)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.sourceTypeScope").value( + DEFAULT_SOURCE_TYPE_SCOPE + ) + ) } - @Test - @Transactional - void getNonExistingSourceType() throws Exception { - // Get the sourceType - restSourceTypeMockMvc.perform(get("/api/source-types/{prodcuer}/{model}/{version}", - "does", "not", "exist")) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val nonExistingSourceType: Unit + get() { + // Get the sourceType + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/source-types/{prodcuer}/{model}/{version}", + "does", "not", "exist" + ) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional - void updateSourceType() throws Exception { + @Throws(Exception::class) + open fun updateSourceType() { // Initialize the database - sourceTypeRepository.saveAndFlush(sourceType); - int databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size(); + sourceTypeRepository.saveAndFlush(sourceType) + val databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size // Update the sourceType - SourceType updatedSourceType = sourceTypeRepository.findById(sourceType.getId()).get(); + val updatedSourceType = sourceTypeRepository.findById(sourceType.id!!).get() updatedSourceType - .producer(UPDATED_PRODUCER) - .model(UPDATED_MODEL) - .catalogVersion(UPDATED_DEVICE_VERSION) - .sourceTypeScope(UPDATED_SOURCE_TYPE_SCOPE); - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(updatedSourceType); - - restSourceTypeMockMvc.perform(put("/api/source-types") + .producer(UPDATED_PRODUCER) + .model(UPDATED_MODEL) + .catalogVersion(UPDATED_DEVICE_VERSION) + .sourceTypeScope(UPDATED_SOURCE_TYPE_SCOPE) + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(updatedSourceType) + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.put("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the SourceType in the database - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate); - SourceType testSourceType = sourceTypeList.get(sourceTypeList.size() - 1); - assertThat(testSourceType.producer).isEqualTo(UPDATED_PRODUCER); - assertThat(testSourceType.model).isEqualTo(UPDATED_MODEL); - assertThat(testSourceType.catalogVersion).isEqualTo(UPDATED_DEVICE_VERSION); - assertThat(testSourceType.sourceTypeScope).isEqualTo(UPDATED_SOURCE_TYPE_SCOPE); + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate) + val testSourceType = sourceTypeList[sourceTypeList.size - 1] + Assertions.assertThat(testSourceType.producer).isEqualTo(UPDATED_PRODUCER) + Assertions.assertThat(testSourceType.model).isEqualTo(UPDATED_MODEL) + Assertions.assertThat(testSourceType.catalogVersion).isEqualTo(UPDATED_DEVICE_VERSION) + Assertions.assertThat(testSourceType.sourceTypeScope).isEqualTo(UPDATED_SOURCE_TYPE_SCOPE) } @Test @Transactional - void updateNonExistingSourceType() throws Exception { - int databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size(); + @Throws(Exception::class) + open fun updateNonExistingSourceType() { + val databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size // Create the SourceType - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) // If the entity doesn't have an ID, it will be created instead of just being updated - restSourceTypeMockMvc.perform(put("/api/source-types") + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.put("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the SourceType in the database - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate + 1); + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate + 1) } @Test @Transactional - void deleteSourceType() throws Exception { + @Throws(Exception::class) + open fun deleteSourceType() { // Initialize the database - sourceTypeRepository.saveAndFlush(sourceType); - int databaseSizeBeforeDelete = sourceTypeRepository.findAll().size(); + sourceTypeRepository.saveAndFlush(sourceType) + val databaseSizeBeforeDelete = sourceTypeRepository.findAll().size // Get the sourceType - restSourceTypeMockMvc.perform(delete("/api/source-types/{prodcuer}/{model}/{version}", - sourceType.producer, sourceType.model, sourceType.catalogVersion) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()); + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.delete( + "/api/source-types/{prodcuer}/{model}/{version}", + sourceType.producer, sourceType.model, sourceType.catalogVersion + ) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeDelete - 1); + val sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeDelete - 1) } @Test @Transactional - void equalsVerifier() throws Exception { - Assertions.assertTrue(TestUtil.equalsVerifier(SourceType.class)); + @Throws(Exception::class) + open fun equalsVerifier() { + org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(SourceType::class.java)) } @Test @Transactional - void idempotentPutWithoutId() throws Exception { - final int databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size(); - final int sensorsSizeBeforeUpdate = sourceDataRepository.findAll().size(); - - sourceType.setSourceData(Collections.singleton(SourceDataResourceIntTest.createEntity(em))); + @Throws(Exception::class) + open fun idempotentPutWithoutId() { + val databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size + val sensorsSizeBeforeUpdate = sourceDataRepository.findAll().size + sourceType.sourceData = setOf(SourceDataResourceIntTest.Companion.createEntity(em)) // Create the SourceType - SourceTypeDTO sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); + val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) // If the entity doesn't have an ID, it will be created instead of just being updated - restSourceTypeMockMvc.perform(put("/api/source-types") + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.put("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the SourceType in the database - List sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate + 1); + var sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate + 1) // Validate the SourceData in the database - List sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(sensorsSizeBeforeUpdate + 1); + var sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(sensorsSizeBeforeUpdate + 1) // Test doing a put with only producer and model, no id, does not create a new source-type // assert that the id is still unset - assertThat(sourceTypeDto.getId()).isNull(); - restSourceTypeMockMvc.perform(put("/api/source-types") + Assertions.assertThat(sourceTypeDto.id).isNull() + restSourceTypeMockMvc.perform( + MockMvcRequestBuilders.put("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto))) - .andExpect(status().is(HttpStatus.CONFLICT.value())); + .content(TestUtil.convertObjectToJsonBytes(sourceTypeDto)) + ) + .andExpect(MockMvcResultMatchers.status().`is`(HttpStatus.CONFLICT.value())) // Validate no change in database size - sourceTypeList = sourceTypeRepository.findAll(); - assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate + 1); + sourceTypeList = sourceTypeRepository.findAll() + Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeUpdate + 1) // Validate no change in sourceData database size - sourceDataList = sourceDataRepository.findAll(); - assertThat(sourceDataList).hasSize(sensorsSizeBeforeUpdate + 1); + sourceDataList = sourceDataRepository.findAll() + Assertions.assertThat(sourceDataList).hasSize(sensorsSizeBeforeUpdate + 1) + } + + companion object { + private const val DEFAULT_PRODUCER = "AAAAA AAAAA" + private const val UPDATED_PRODUCER = "BBBBBBBBBB" + private const val DEFAULT_MODEL = "AAAAA AAAAA" + private const val UPDATED_MODEL = "BBBBBBBBBB" + private const val DEFAULT_DEVICE_VERSION = "AAAAAAAAAA" + private const val UPDATED_DEVICE_VERSION = "AAAAAAAAAA" + private const val DEFAULT_SOURCE_TYPE_SCOPE = "ACTIVE" + private const val UPDATED_SOURCE_TYPE_SCOPE = "PASSIVE" + + /** + * Create an entity for this test. + * + * + * This is a static method, as tests for other entities might also need it, + * if they test an entity which requires the current entity. + */ + fun createEntity(): SourceType { + return SourceType() + .producer(DEFAULT_PRODUCER) + .model(DEFAULT_MODEL) + .catalogVersion(DEFAULT_DEVICE_VERSION) + .sourceTypeScope(DEFAULT_SOURCE_TYPE_SCOPE) + } } } diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index 885cc19f1..623c78878 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -1,637 +1,664 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.SourceService; -import org.radarbase.management.service.SourceTypeService; -import org.radarbase.management.service.SubjectService; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.service.mapper.SubjectMapper; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.servlet.ServletException; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.radarbase.management.service.SubjectServiceTest.DEFAULT_ENTERNAL_ID; -import static org.radarbase.management.service.SubjectServiceTest.DEFAULT_EXTERNAL_LINK; -import static org.radarbase.management.service.SubjectServiceTest.DEFAULT_REMOVED; -import static org.radarbase.management.service.SubjectServiceTest.DEFAULT_STATUS; -import static org.radarbase.management.service.SubjectServiceTest.MODEL; -import static org.radarbase.management.service.SubjectServiceTest.PRODUCER; -import static org.radarbase.management.service.SubjectServiceTest.UPDATED_ENTERNAL_ID; -import static org.radarbase.management.service.SubjectServiceTest.UPDATED_EXTERNAL_LINK; -import static org.radarbase.management.service.SubjectServiceTest.UPDATED_REMOVED; -import static org.radarbase.management.service.SubjectServiceTest.createEntityDTO; -import static org.radarbase.management.web.rest.TestUtil.commitTransactionAndStartNew; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.domain.Subject +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.SourceService +import org.radarbase.management.service.SourceTypeService +import org.radarbase.management.service.SubjectService +import org.radarbase.management.service.SubjectServiceTest +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SourceDTO +import org.radarbase.management.service.dto.SourceTypeDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.service.mapper.SubjectMapper +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import java.util.* +import java.util.stream.Collectors +import javax.servlet.ServletException /** * Test class for the SubjectResource REST controller. * * @see SubjectResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class SubjectResourceIntTest { - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private SubjectMapper subjectMapper; - - @Autowired - private SubjectService subjectService; - - @Autowired - private SourceService sourceService; - - @Autowired - private SourceTypeService sourceTypeService; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - @Autowired - private ProjectRepository projectRepository; - - private MockMvc restSubjectMockMvc; - - @Autowired - private AuthService authService; +internal open class SubjectResourceIntTest(@Autowired private val subjectRepository: SubjectRepository, + @Autowired private val subjectMapper: SubjectMapper, + @Autowired private val subjectService: SubjectService, + @Autowired private val sourceService: SourceService, + @Autowired private val sourceTypeService: SourceTypeService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val projectRepository: ProjectRepository, + private var restSubjectMockMvc: MockMvc, + @Autowired private val authService: AuthService +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - SubjectResource subjectResource = new SubjectResource(); - ReflectionTestUtils.setField(subjectResource, "subjectService", subjectService); - ReflectionTestUtils.setField(subjectResource, "subjectRepository", subjectRepository); - ReflectionTestUtils.setField(subjectResource, "subjectMapper", subjectMapper); - ReflectionTestUtils.setField(subjectResource, "projectRepository", projectRepository); - ReflectionTestUtils.setField(subjectResource, "sourceTypeService", sourceTypeService); - ReflectionTestUtils.setField(subjectResource, "authService", authService); - ReflectionTestUtils.setField(subjectResource, "sourceService", sourceService); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restSubjectMockMvc = MockMvcBuilders.standaloneSetup(subjectResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - // add the oauth token by default to all requests for this mockMvc - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val subjectResource = SubjectResource + ReflectionTestUtils.setField(subjectResource, "subjectService", subjectService) + ReflectionTestUtils.setField(subjectResource, "subjectRepository", subjectRepository) + ReflectionTestUtils.setField(subjectResource, "subjectMapper", subjectMapper) + ReflectionTestUtils.setField(subjectResource, "projectRepository", projectRepository) + ReflectionTestUtils.setField(subjectResource, "sourceTypeService", sourceTypeService) + ReflectionTestUtils.setField(subjectResource, "authService", authService) + ReflectionTestUtils.setField(subjectResource, "sourceService", sourceService) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restSubjectMockMvc = MockMvcBuilders.standaloneSetup(subjectResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) // add the oauth token by default to all requests for this mockMvc + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() } @Test @Transactional - void createSubject() throws Exception { - final int databaseSizeBeforeCreate = subjectRepository.findAll().size(); + @Throws(Exception::class) + open fun createSubject() { + val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - SubjectDTO subjectDto = createEntityDTO(); - restSubjectMockMvc.perform(post("/api/subjects") + val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); - Subject testSubject = subjectList.get(subjectList.size() - 1); - assertThat(testSubject.externalLink).isEqualTo(DEFAULT_EXTERNAL_LINK); - assertThat(testSubject.externalId).isEqualTo(DEFAULT_ENTERNAL_ID); - assertThat(testSubject.isRemoved()).isEqualTo(DEFAULT_REMOVED); - assertEquals(1, testSubject.user.roles.size()); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) + val testSubject = subjectList[subjectList.size - 1] + Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK) + Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.Companion.DEFAULT_ENTERNAL_ID) + Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.Companion.DEFAULT_REMOVED) + org.junit.jupiter.api.Assertions.assertEquals(1, testSubject.user!!.roles!!.size) } @Test @Transactional - void createSubjectWithExistingId() throws Exception { + @Throws(Exception::class) + open fun createSubjectWithExistingId() { // Create a Subject - SubjectDTO subjectDto = subjectService.createSubject(createEntityDTO()); - final int databaseSizeBeforeCreate = subjectRepository.findAll().size(); + val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val databaseSizeBeforeCreate = subjectRepository.findAll().size // An entity with an existing ID cannot be created, so this API call must fail - restSubjectMockMvc.perform(post("/api/subjects") + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the Alice in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeCreate); - } - - @Test - @Transactional - void getAllSubjects() throws Exception { - // Initialize the database - SubjectDTO subjectDto = subjectService.createSubject(createEntityDTO()); - - // Get all the subjectList - restSubjectMockMvc.perform(get("/api/subjects?sort=id,desc")) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(hasItem(subjectDto.getId().intValue()))) - .andExpect(jsonPath("$.[*].externalLink").value(hasItem(DEFAULT_EXTERNAL_LINK))) - .andExpect(jsonPath("$.[*].externalId").value(hasItem(DEFAULT_ENTERNAL_ID))) - .andExpect(jsonPath("$.[*].status").value(hasItem(DEFAULT_STATUS.toString()))); - } - - @Test - @Transactional - void getSubject() throws Exception { - // Initialize the database - SubjectDTO subjectDto = subjectService.createSubject(createEntityDTO()); - - // Get the subject - restSubjectMockMvc.perform(get("/api/subjects/{login}", subjectDto.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.id").value(subjectDto.getId().intValue())) - .andExpect(jsonPath("$.externalLink").value(DEFAULT_EXTERNAL_LINK)) - .andExpect(jsonPath("$.externalId").value(DEFAULT_ENTERNAL_ID)) - .andExpect(jsonPath("$.status").value(DEFAULT_STATUS.toString())); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate) } - @Test - @Transactional - void getNonExistingSubject() throws Exception { - // Get the subject - restSubjectMockMvc.perform(get("/api/subjects/{id}", Long.MAX_VALUE)) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val allSubjects: Unit + get() { + // Initialize the database + val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + + // Get all the subjectList + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + subjectDto!!.id.toInt() + ) + ) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].externalLink") + .value>(Matchers.hasItem(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK)) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].externalId") + .value>(Matchers.hasItem(SubjectServiceTest.Companion.DEFAULT_ENTERNAL_ID)) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].status") + .value>(Matchers.hasItem(SubjectServiceTest.Companion.DEFAULT_STATUS.toString())) + ) + } + + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val subject: Unit + get() { + // Initialize the database + val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + + // Get the subject + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{login}", subjectDto!!.getLogin())) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(subjectDto.id.toInt())) + .andExpect( + MockMvcResultMatchers.jsonPath("$.externalLink") + .value(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.externalId") + .value(SubjectServiceTest.Companion.DEFAULT_ENTERNAL_ID) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.status") + .value(SubjectServiceTest.Companion.DEFAULT_STATUS.toString()) + ) + } + + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val nonExistingSubject: Unit + get() { + // Get the subject + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{id}", Long.MAX_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional - void updateSubject() throws Exception { + @Throws(Exception::class) + open fun updateSubject() { // Initialize the database - SubjectDTO subjectDto = subjectService.createSubject(createEntityDTO()); - final int databaseSizeBeforeUpdate = subjectRepository.findAll().size(); + var subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Update the subject - Subject updatedSubject = subjectRepository.findById(subjectDto.getId()).get(); + val updatedSubject = subjectRepository.findById(subjectDto!!.id).get() updatedSubject - .externalLink(UPDATED_EXTERNAL_LINK) - .externalId(UPDATED_ENTERNAL_ID) - .removed(UPDATED_REMOVED); - subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject); - - restSubjectMockMvc.perform(put("/api/subjects") + .externalLink(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) + .externalId(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) + .removed(SubjectServiceTest.Companion.UPDATED_REMOVED) + subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) + restSubjectMockMvc.perform( + MockMvcRequestBuilders.put("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeUpdate); - Subject testSubject = subjectList.get(subjectList.size() - 1); - assertThat(testSubject.externalLink).isEqualTo(UPDATED_EXTERNAL_LINK); - assertThat(testSubject.externalId).isEqualTo(UPDATED_ENTERNAL_ID); - assertThat(testSubject.isRemoved()).isEqualTo(UPDATED_REMOVED); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeUpdate) + val testSubject = subjectList[subjectList.size - 1] + Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) + Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) + Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.Companion.UPDATED_REMOVED) } @Test @Transactional - void updateSubjectWithNewProject() throws Exception { + @Throws(Exception::class) + open fun updateSubjectWithNewProject() { // Initialize the database - SubjectDTO subjectDto = subjectService.createSubject(createEntityDTO()); - final int databaseSizeBeforeUpdate = subjectRepository.findAll().size(); + var subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Update the subject - Subject updatedSubject = subjectRepository.findById(subjectDto.getId()).get(); - + val updatedSubject = subjectRepository.findById(subjectDto!!.id).get() updatedSubject - .externalLink(UPDATED_EXTERNAL_LINK) - .externalId(UPDATED_ENTERNAL_ID) - .removed(UPDATED_REMOVED); - - subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject); - ProjectDTO newProject = new ProjectDTO(); - newProject.setId(2L); - newProject.setProjectName("RadarNew"); - newProject.setLocation("new location"); - subjectDto.setProject(newProject); - - restSubjectMockMvc.perform(put("/api/subjects") + .externalLink(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) + .externalId(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) + .removed(SubjectServiceTest.Companion.UPDATED_REMOVED) + subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) + val newProject = ProjectDTO() + newProject.id = 2L + newProject.projectName = "RadarNew" + newProject.location = "new location" + subjectDto!!.project = newProject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.put("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeUpdate); - Subject testSubject = subjectList.get(subjectList.size() - 1); - assertThat(testSubject.externalLink).isEqualTo(UPDATED_EXTERNAL_LINK); - assertThat(testSubject.externalId).isEqualTo(UPDATED_ENTERNAL_ID); - assertThat(testSubject.isRemoved()).isEqualTo(UPDATED_REMOVED); - assertThat(testSubject.user.roles.size()).isEqualTo(2); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeUpdate) + val testSubject = subjectList[subjectList.size - 1] + Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) + Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) + Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.Companion.UPDATED_REMOVED) + Assertions.assertThat(testSubject.user!!.roles!!.size).isEqualTo(2) } @Test @Transactional - void updateNonExistingSubject() throws Exception { - final int databaseSizeBeforeUpdate = subjectRepository.findAll().size(); + @Throws(Exception::class) + open fun updateNonExistingSubject() { + val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Create the Subject - SubjectDTO subjectDto = createEntityDTO(); + val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() // If the entity doesn't have an ID, it will be created instead of just being updated - restSubjectMockMvc.perform(put("/api/subjects") + restSubjectMockMvc.perform( + MockMvcRequestBuilders.put("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeUpdate + 1); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeUpdate + 1) } @Test @Transactional - void deleteSubject() throws Exception { + @Throws(Exception::class) + open fun deleteSubject() { // Initialize the database - SubjectDTO subjectDto = subjectService.createSubject(createEntityDTO()); - final int databaseSizeBeforeDelete = subjectRepository.findAll().size(); + val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val databaseSizeBeforeDelete = subjectRepository.findAll().size // Get the subject - restSubjectMockMvc.perform(delete("/api/subjects/{login}", subjectDto.getLogin()) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()); + restSubjectMockMvc.perform( + MockMvcRequestBuilders.delete("/api/subjects/{login}", subjectDto!!.getLogin()) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeDelete - 1); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeDelete - 1) } @Test @Transactional - void equalsVerifier() throws Exception { - assertTrue(TestUtil.equalsVerifier(Subject.class)); + @Throws(Exception::class) + open fun equalsVerifier() { + org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Subject::class.java)) } - @Test @Transactional - void dynamicSourceRegistrationWithId() throws Exception { - final int databaseSizeBeforeCreate = subjectRepository.findAll().size(); + @Throws(Exception::class) + open fun dynamicSourceRegistrationWithId() { + val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - SubjectDTO subjectDto = createEntityDTO(); - restSubjectMockMvc.perform(post("/api/subjects") + val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); - Subject testSubject = subjectList.get(subjectList.size() - 1); - - String subjectLogin = testSubject.user.getLogin(); - assertNotNull(subjectLogin); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) + val testSubject = subjectList[subjectList.size - 1] + val subjectLogin = testSubject.user!!.login + org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) // Create a source description - MinimalSourceDetailsDTO sourceRegistrationDto = createSourceWithSourceTypeId(); - - restSubjectMockMvc.perform(post("/api/subjects/{login}/sources", subjectLogin) + val sourceRegistrationDto = createSourceWithSourceTypeId() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.sourceId").isNotEmpty()); + .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.sourceId").isNotEmpty()) // A source can not be assigned twice to a subject, so this call must fail - assertThat(sourceRegistrationDto.getSourceId()).isNull(); - restSubjectMockMvc.perform(post("/api/subjects/{login}/sources", subjectLogin) + Assertions.assertThat(sourceRegistrationDto.sourceId).isNull() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto))) - .andExpect(status().is4xxClientError()); + .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) + ) + .andExpect(MockMvcResultMatchers.status().is4xxClientError()) } @Test @Transactional - void dynamicSourceRegistrationWithoutId() throws Exception { - final int databaseSizeBeforeCreate = subjectRepository.findAll().size(); + @Throws(Exception::class) + open fun dynamicSourceRegistrationWithoutId() { + val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - SubjectDTO subjectDto = createEntityDTO(); - restSubjectMockMvc.perform(post("/api/subjects") + val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); - Subject testSubject = subjectList.get(subjectList.size() - 1); - - String subjectLogin = testSubject.user.getLogin(); - assertNotNull(subjectLogin); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) + val testSubject = subjectList[subjectList.size - 1] + val subjectLogin = testSubject.user!!.login + org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) // Create a source description - MinimalSourceDetailsDTO sourceRegistrationDto = createSourceWithoutSourceTypeId(); - - restSubjectMockMvc.perform(post("/api/subjects/{login}/sources", subjectLogin) + val sourceRegistrationDto = createSourceWithoutSourceTypeId() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.sourceId").isNotEmpty()); + .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.sourceId").isNotEmpty()) // A source can not be assigned twice to a subject, so this call must fail - assertThat(sourceRegistrationDto.getSourceId()).isNull(); - restSubjectMockMvc.perform(post("/api/subjects/{login}/sources", subjectLogin) + Assertions.assertThat(sourceRegistrationDto.sourceId).isNull() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto))) - .andExpect(status().is4xxClientError()); + .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) + ) + .andExpect(MockMvcResultMatchers.status().is4xxClientError()) // Get all the subjectList restSubjectMockMvc - .perform(get("/api/subjects/{login}/sources?sort=id,desc", subjectDto.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").isNotEmpty()); - + .perform(MockMvcRequestBuilders.get("/api/subjects/{login}/sources?sort=id,desc", subjectDto.getLogin())) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").isNotEmpty()) } @Test @Transactional - void dynamicSourceRegistrationWithoutDynamicRegistrationFlag() throws Exception { - final int databaseSizeBeforeCreate = subjectRepository.findAll().size(); + @Throws(Exception::class) + open fun dynamicSourceRegistrationWithoutDynamicRegistrationFlag() { + val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - SubjectDTO subjectDto = createEntityDTO(); - restSubjectMockMvc.perform(post("/api/subjects") + val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); - Subject testSubject = subjectList.get(subjectList.size() - 1); - - String subjectLogin = testSubject.user.getLogin(); - assertNotNull(subjectLogin); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) + val testSubject = subjectList[subjectList.size - 1] + val subjectLogin = testSubject.user!!.login + org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) // Create a source description - MinimalSourceDetailsDTO sourceRegistrationDto = - createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration(); - - restSubjectMockMvc.perform(post("/api/subjects/{login}/sources", subjectLogin) + val sourceRegistrationDto = createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto))) - .andExpect(status().is4xxClientError()) - .andExpect(jsonPath("$.message").isNotEmpty()); + .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) + ) + .andExpect(MockMvcResultMatchers.status().is4xxClientError()) + .andExpect(MockMvcResultMatchers.jsonPath("$.message").isNotEmpty()) } - @Test - @Transactional - void getSubjectSources() throws Exception { - // Initialize the database - SubjectDTO subjectDtoToCreate = createEntityDTO(); - SourceDTO createdSource = sourceService.save(createSource()); - MinimalSourceDetailsDTO sourceDto = new MinimalSourceDetailsDTO() - .id(createdSource.getId()) - .sourceName(createdSource.getSourceName()) - .sourceTypeId(createdSource.getSourceType().getId()) - .sourceId(createdSource.getSourceId()); - - subjectDtoToCreate.setSources(Collections.singleton(sourceDto)); - - assertNotNull(sourceDto.getId()); - SubjectDTO createdSubject = subjectService.createSubject(subjectDtoToCreate); - assertFalse(createdSubject.getSources().isEmpty()); - - // Get the subject - restSubjectMockMvc.perform(get("/api/subjects/{login}/sources", createdSubject.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[0].id").value(createdSource.getId().intValue())) + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val subjectSources: Unit + get() { + // Initialize the database + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val createdSource = sourceService.save(createSource()) + val sourceDto = MinimalSourceDetailsDTO() + .id(createdSource.id) + .sourceName(createdSource.sourceName) + .sourceTypeId(createdSource.sourceType.id) + .sourceId(createdSource.sourceId) + subjectDtoToCreate.sources = setOf(sourceDto) + org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + val createdSubject = subjectService.createSubject(subjectDtoToCreate) + org.junit.jupiter.api.Assertions.assertFalse(createdSubject!!.sources.isEmpty()) + + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources", + createdSubject.getLogin() + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[0].id").value(createdSource.id.toInt())) .andExpect( - jsonPath("$.[0].sourceId").value(createdSource.getSourceId().toString())); - } - - @Test - @Transactional - void getSubjectSourcesWithQueryParam() throws Exception { - // Initialize the database - SubjectDTO subjectDtoToCreate = createEntityDTO(); - SourceDTO createdSource = sourceService.save(createSource()); - MinimalSourceDetailsDTO sourceDto = new MinimalSourceDetailsDTO() - .id(createdSource.getId()) - .sourceName(createdSource.getSourceName()) - .sourceTypeId(createdSource.getSourceType().getId()) - .sourceId(createdSource.getSourceId()); - - subjectDtoToCreate.setSources(Collections.singleton(sourceDto)); - - assertNotNull(sourceDto.getId()); - SubjectDTO createdSubject = subjectService.createSubject(subjectDtoToCreate); - commitTransactionAndStartNew(); - - assertNotNull(createdSubject.getLogin()); - // Get the subject - restSubjectMockMvc.perform(get("/api/subjects/{login}/sources?withInactiveSources=true", - createdSubject.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(createdSource.getId().intValue())) + MockMvcResultMatchers.jsonPath("$.[0].sourceId").value(createdSource.sourceId.toString()) + ) + } + + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val subjectSourcesWithQueryParam: Unit + get() { + // Initialize the database + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val createdSource = sourceService.save(createSource()) + val sourceDto = MinimalSourceDetailsDTO() + .id(createdSource.id) + .sourceName(createdSource.sourceName) + .sourceTypeId(createdSource.sourceType.id) + .sourceId(createdSource.sourceId) + subjectDtoToCreate.sources = setOf(sourceDto) + org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + val createdSubject = subjectService.createSubject(subjectDtoToCreate) + TestUtil.commitTransactionAndStartNew() + org.junit.jupiter.api.Assertions.assertNotNull(createdSubject!!.getLogin()) + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?withInactiveSources=true", + createdSubject.getLogin() + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id.toInt())) .andExpect( - jsonPath("$.[*].sourceId").value(createdSource.getSourceId().toString())); - } - - @Test - @Transactional - void getInactiveSubjectSourcesWithQueryParam() throws Exception { - // Initialize the database - SubjectDTO subjectDtoToCreate = createEntityDTO(); - SourceDTO createdSource = sourceService.save(createSource()); - MinimalSourceDetailsDTO sourceDto = new MinimalSourceDetailsDTO() - .id(createdSource.getId()) - .sourceName(createdSource.getSourceName()) - .sourceTypeId(createdSource.getSourceType().getId()) - .sourceId(createdSource.getSourceId()); - - subjectDtoToCreate.setSources(Collections.singleton(sourceDto)); - - assertNotNull(sourceDto.getId()); - SubjectDTO createdSubject = subjectService.createSubject(subjectDtoToCreate); - commitTransactionAndStartNew(); - - createdSubject.setSources(Collections.emptySet()); - - SubjectDTO updatedSubject = subjectService.updateSubject(createdSubject); - commitTransactionAndStartNew(); - - assertNotNull(updatedSubject.getLogin()); - // Get the subject - restSubjectMockMvc.perform(get("/api/subjects/{login}/sources?withInactiveSources=true", - updatedSubject.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].id").value(createdSource.getId().intValue())) + MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) + ) + } + + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val inactiveSubjectSourcesWithQueryParam: Unit + get() { + // Initialize the database + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val createdSource = sourceService.save(createSource()) + val sourceDto = MinimalSourceDetailsDTO() + .id(createdSource.id) + .sourceName(createdSource.sourceName) + .sourceTypeId(createdSource.sourceType.id) + .sourceId(createdSource.sourceId) + subjectDtoToCreate.sources = setOf(sourceDto) + org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + val createdSubject = subjectService.createSubject(subjectDtoToCreate) + TestUtil.commitTransactionAndStartNew() + createdSubject!!.sources = emptySet() + val updatedSubject = subjectService.updateSubject(createdSubject) + TestUtil.commitTransactionAndStartNew() + org.junit.jupiter.api.Assertions.assertNotNull(updatedSubject!!.getLogin()) + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?withInactiveSources=true", + updatedSubject.getLogin() + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id.toInt())) .andExpect( - jsonPath("$.[*].sourceId").value(createdSource.getSourceId().toString())); - - // Get the subject - restSubjectMockMvc - .perform(get("/api/subjects/{login}/sources?withInactiveSources=false", - updatedSubject.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andReturn(); + MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) + ) + + // Get the subject + restSubjectMockMvc + .perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?withInactiveSources=false", + updatedSubject.getLogin() + ) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn() + } + + private fun createSource(): SourceDTO { + val sourceDto = SourceDTO() + sourceDto.assigned = false + sourceDto.sourceId = UUID.randomUUID() + sourceDto.sourceType = sourceTypeService.findAll()[0] + sourceDto.sourceName = "something" + UUID.randomUUID() + return sourceDto } - private SourceDTO createSource() { - SourceDTO sourceDto = new SourceDTO(); - sourceDto.setAssigned(false); - sourceDto.setSourceId(UUID.randomUUID()); - sourceDto.setSourceType(sourceTypeService.findAll().get(0)); - sourceDto.setSourceName("something" + UUID.randomUUID()); - return sourceDto; + private fun createSourceWithSourceTypeId(): MinimalSourceDetailsDTO { + val sourceTypes = sourceTypeService.findAll().stream() + .filter { obj: SourceTypeDTO -> obj.canRegisterDynamically } + .collect(Collectors.toList()) + Assertions.assertThat(sourceTypes.size).isPositive() + val sourceType = sourceTypes[0] + return source.sourceTypeId(sourceType.id) } - private MinimalSourceDetailsDTO createSourceWithSourceTypeId() { - List sourceTypes = sourceTypeService.findAll().stream() - .filter(SourceTypeDTO::getCanRegisterDynamically) - .collect(Collectors.toList()); - assertThat(sourceTypes.size()).isPositive(); - SourceTypeDTO sourceType = sourceTypes.get(0); - - return getSource().sourceTypeId(sourceType.getId()); + private fun createSourceWithoutSourceTypeId(): MinimalSourceDetailsDTO { + val sourceTypes = sourceTypeService.findAll().stream() + .filter { obj: SourceTypeDTO -> obj.canRegisterDynamically } + .collect(Collectors.toList()) + Assertions.assertThat(sourceTypes.size).isPositive() + val sourceType = sourceTypes[0] + return source + .sourceTypeCatalogVersion(sourceType.catalogVersion) + .sourceTypeModel(sourceType.model) + .sourceTypeProducer(sourceType.producer) } - private MinimalSourceDetailsDTO createSourceWithoutSourceTypeId() { - List sourceTypes = sourceTypeService.findAll().stream() - .filter(SourceTypeDTO::getCanRegisterDynamically) - .collect(Collectors.toList()); - assertThat(sourceTypes.size()).isPositive(); - SourceTypeDTO sourceType = sourceTypes.get(0); - return getSource() - .sourceTypeCatalogVersion(sourceType.getCatalogVersion()) - .sourceTypeModel(sourceType.getModel()) - .sourceTypeProducer(sourceType.getProducer()); + private fun createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration(): MinimalSourceDetailsDTO { + val sourceTypes = sourceTypeService.findAll().stream() + .filter { it: SourceTypeDTO -> !it.canRegisterDynamically } + .collect(Collectors.toList()) + Assertions.assertThat(sourceTypes.size).isPositive() + val sourceType = sourceTypes[0] + return source + .sourceTypeCatalogVersion(sourceType.catalogVersion) + .sourceTypeModel(sourceType.model) + .sourceTypeProducer(sourceType.producer) } - private MinimalSourceDetailsDTO createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration() { - List sourceTypes = sourceTypeService.findAll().stream() - .filter(it -> !it.getCanRegisterDynamically()) - .collect(Collectors.toList()); - assertThat(sourceTypes.size()).isPositive(); - SourceTypeDTO sourceType = sourceTypes.get(0); - return getSource() - .sourceTypeCatalogVersion(sourceType.getCatalogVersion()) - .sourceTypeModel(sourceType.getModel()) - .sourceTypeProducer(sourceType.getProducer()); - } - - private MinimalSourceDetailsDTO getSource() { - MinimalSourceDetailsDTO sourceRegistrationDto = new MinimalSourceDetailsDTO() - .sourceName(PRODUCER + "-" + MODEL) - .attributes(Collections.singletonMap("something", "value")); - assertThat(sourceRegistrationDto.getSourceId()).isNull(); - return sourceRegistrationDto; - } + private val source: MinimalSourceDetailsDTO + get() { + val sourceRegistrationDto = MinimalSourceDetailsDTO() + .sourceName(SubjectServiceTest.Companion.PRODUCER + "-" + SubjectServiceTest.Companion.MODEL) + .attributes(Collections.singletonMap("something", "value")) + Assertions.assertThat(sourceRegistrationDto.sourceId).isNull() + return sourceRegistrationDto + } @Test @Transactional - void testDynamicRegistrationAndUpdateSourceAttributes() throws Exception { - final int databaseSizeBeforeCreate = subjectRepository.findAll().size(); + @Throws(Exception::class) + open fun testDynamicRegistrationAndUpdateSourceAttributes() { + val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - SubjectDTO subjectDto = createEntityDTO(); - restSubjectMockMvc.perform(post("/api/subjects") + val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(subjectDto))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(subjectDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database - List subjectList = subjectRepository.findAll(); - assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1); - Subject testSubject = subjectList.get(subjectList.size() - 1); - - String subjectLogin = testSubject.user.getLogin(); - assertNotNull(subjectLogin); + val subjectList = subjectRepository.findAll() + Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) + val testSubject = subjectList[subjectList.size - 1] + val subjectLogin = testSubject.user!!.login + org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) // Create a source description - MinimalSourceDetailsDTO sourceRegistrationDto = createSourceWithoutSourceTypeId(); - - MvcResult result = restSubjectMockMvc.perform(post("/api/subjects/{login}/sources", - subjectLogin) + val sourceRegistrationDto = createSourceWithoutSourceTypeId() + val result = restSubjectMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/subjects/{login}/sources", + subjectLogin + ) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto))) - .andExpect(status().isOk()) - .andReturn(); - - MinimalSourceDetailsDTO value = (MinimalSourceDetailsDTO) - TestUtil.convertJsonStringToObject(result - .getResponse().getContentAsString() , MinimalSourceDetailsDTO.class); - - assertNotNull(value.getSourceName()); - - Map attributes = new HashMap<>(); - attributes.put("TEST_KEY" , "Value"); - attributes.put("ANDROID_VERSION" , "something"); - attributes.put("Other" , "test"); - - restSubjectMockMvc.perform(post( - "/api/subjects/{login}/sources/{sourceName}", subjectLogin, value.getSourceName()) + .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andReturn() + val value = TestUtil.convertJsonStringToObject( + result + .response.contentAsString, MinimalSourceDetailsDTO::class.java + ) as MinimalSourceDetailsDTO + org.junit.jupiter.api.Assertions.assertNotNull(value.sourceName) + val attributes: MutableMap = HashMap() + attributes["TEST_KEY"] = "Value" + attributes["ANDROID_VERSION"] = "something" + attributes["Other"] = "test" + restSubjectMockMvc.perform( + MockMvcRequestBuilders.post( + "/api/subjects/{login}/sources/{sourceName}", subjectLogin, value.sourceName + ) .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(attributes))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.attributes").isNotEmpty()); - + .content(TestUtil.convertObjectToJsonBytes(attributes)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.attributes").isNotEmpty()) } } diff --git a/src/test/java/org/radarbase/management/web/rest/TestUtil.kt b/src/test/java/org/radarbase/management/web/rest/TestUtil.kt index 6444911fc..32f1ae580 100644 --- a/src/test/java/org/radarbase/management/web/rest/TestUtil.kt +++ b/src/test/java/org/radarbase/management/web/rest/TestUtil.kt @@ -1,43 +1,35 @@ -package org.radarbase.management.web.rest; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import org.hamcrest.Description; -import org.hamcrest.TypeSafeDiagnosingMatcher; -import org.springframework.http.MediaType; -import org.springframework.test.context.transaction.TestTransaction; - -import java.io.IOException; -import java.nio.charset.Charset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeParseException; - -import static org.assertj.core.api.Assertions.assertThat; +package org.radarbase.management.web.rest + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import org.assertj.core.api.Assertions +import org.hamcrest.Description +import org.hamcrest.TypeSafeDiagnosingMatcher +import org.springframework.http.MediaType +import org.springframework.test.context.transaction.TestTransaction +import java.io.IOException +import java.nio.charset.Charset +import java.time.ZonedDateTime +import java.time.format.DateTimeParseException /** * Utility class for testing REST controllers. */ -public final class TestUtil { +object TestUtil { /* MediaType for JSON UTF8 */ - public static final MediaType APPLICATION_JSON_UTF8 = new MediaType( - MediaType.APPLICATION_JSON.getType(), - MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8")); - - public static final MediaType APPLICATION_JSON_PATCH = new MediaType( - "application", - "json-patch+json", Charset.forName("utf8")); - - - private static final JavaTimeModule module = new JavaTimeModule(); - - private static final ObjectMapper mapper = new ObjectMapper() - .setSerializationInclusion(JsonInclude.Include.NON_NULL) - .registerModule(module); - - private TestUtil() { - // utilitly class - } + val APPLICATION_JSON_UTF8 = MediaType( + MediaType.APPLICATION_JSON.type, + MediaType.APPLICATION_JSON.subtype, Charset.forName("utf8") + ) + val APPLICATION_JSON_PATCH = MediaType( + "application", + "json-patch+json", Charset.forName("utf8") + ) + private val module = JavaTimeModule() + private val mapper = ObjectMapper() + .setSerializationInclusion(JsonInclude.Include.NON_NULL) + .registerModule(module) /** * Convert a JSON String to an object. @@ -47,9 +39,9 @@ public final class TestUtil { * * @return the converted object instance. */ - public static Object convertJsonStringToObject(String json, Class objectClass) - throws IOException { - return mapper.readValue(json, objectClass); + @Throws(IOException::class) + fun convertJsonStringToObject(json: String?, objectClass: Class?): Any { + return mapper.readValue(json, objectClass) } /** @@ -58,8 +50,9 @@ public final class TestUtil { * @param object the object to convert * @return the JSON byte array */ - public static byte[] convertObjectToJsonBytes(Object object) throws IOException { - return mapper.writeValueAsBytes(object); + @Throws(IOException::class) + fun convertObjectToJsonBytes(`object`: Any?): ByteArray { + return mapper.writeValueAsBytes(`object`) } /** @@ -69,46 +62,12 @@ public final class TestUtil { * @param data the data to put in the byte array * @return the JSON byte array */ - public static byte[] createByteArray(int size, String data) { - byte[] byteArray = new byte[size]; - for (int i = 0; i < size; i++) { - byteArray[i] = Byte.parseByte(data, 2); - } - return byteArray; - } - - /** - * A matcher that tests that the examined string represents the same instant as the reference - * datetime. - */ - public static class ZonedDateTimeMatcher extends TypeSafeDiagnosingMatcher { - - private final ZonedDateTime date; - - public ZonedDateTimeMatcher(ZonedDateTime date) { - this.date = date; - } - - @Override - protected boolean matchesSafely(String item, Description mismatchDescription) { - try { - if (!date.isEqual(ZonedDateTime.parse(item))) { - mismatchDescription.appendText("was ").appendValue(item); - return false; - } - return true; - } catch (DateTimeParseException e) { - mismatchDescription.appendText("was ").appendValue(item) - .appendText(", which could not be parsed as a ZonedDateTime"); - return false; - } - - } - - @Override - public void describeTo(Description description) { - description.appendText("a String representing the same Instant as ").appendValue(date); + fun createByteArray(size: Int, data: String): ByteArray { + val byteArray = ByteArray(size) + for (i in 0 until size) { + byteArray[i] = data.toByte(2) } + return byteArray } /** @@ -117,39 +76,62 @@ public final class TestUtil { * * @param date the reference datetime against which the examined string is checked */ - public static ZonedDateTimeMatcher sameInstant(ZonedDateTime date) { - return new ZonedDateTimeMatcher(date); + fun sameInstant(date: ZonedDateTime): ZonedDateTimeMatcher { + return ZonedDateTimeMatcher(date) } /** * Verifies the equals/hashcode contract on the domain object. */ - @SuppressWarnings("unchecked") - public static boolean equalsVerifier(Class clazz) throws Exception { - Object domainObject1 = clazz.getConstructor().newInstance(); - assertThat(domainObject1.toString()).isNotNull(); - assertThat(domainObject1).isEqualTo(domainObject1); - assertThat(domainObject1.hashCode()).isEqualTo(domainObject1.hashCode()); + @Throws(Exception::class) + fun equalsVerifier(clazz: Class<*>): Boolean { + val domainObject1 = clazz.getConstructor().newInstance() + Assertions.assertThat(domainObject1.toString()).isNotNull() + Assertions.assertThat(domainObject1).isEqualTo(domainObject1) + Assertions.assertThat(domainObject1.hashCode()).isEqualTo(domainObject1.hashCode()) // Test with an instance of another class - Object testOtherObject = new Object(); - assertThat(domainObject1).isNotEqualTo(testOtherObject); + val testOtherObject = Any() + Assertions.assertThat(domainObject1).isNotEqualTo(testOtherObject) // Test with an instance of the same class - Object domainObject2 = clazz.getConstructor().newInstance(); - assertThat(domainObject1).isNotEqualTo(domainObject2); + val domainObject2 = clazz.getConstructor().newInstance() + Assertions.assertThat(domainObject1).isNotEqualTo(domainObject2) // HashCodes are equals because the objects are not persisted yet - assertThat(domainObject1.hashCode()).isEqualTo(domainObject2.hashCode()); - return true; + Assertions.assertThat(domainObject1.hashCode()).isEqualTo(domainObject2.hashCode()) + return true } - /** * This allows to commit current transaction and start a new transaction. */ - public static void commitTransactionAndStartNew() { + fun commitTransactionAndStartNew() { // flag this transaction for commit and end it - TestTransaction.flagForCommit(); - TestTransaction.end(); - TestTransaction.start(); - TestTransaction.flagForCommit(); + TestTransaction.flagForCommit() + TestTransaction.end() + TestTransaction.start() + TestTransaction.flagForCommit() + } + + /** + * A matcher that tests that the examined string represents the same instant as the reference + * datetime. + */ + class ZonedDateTimeMatcher(private val date: ZonedDateTime) : TypeSafeDiagnosingMatcher() { + override fun matchesSafely(item: String?, mismatchDescription: Description): Boolean { + return try { + if (!date.isEqual(ZonedDateTime.parse(item))) { + mismatchDescription.appendText("was ").appendValue(item) + return false + } + true + } catch (e: DateTimeParseException) { + mismatchDescription.appendText("was ").appendValue(item) + .appendText(", which could not be parsed as a ZonedDateTime") + false + } + } + + override fun describeTo(description: Description) { + description.appendText("a String representing the same Instant as ").appendValue(date) + } } } diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt index dbe5abfe3..6f84bcf65 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt @@ -1,541 +1,524 @@ -package org.radarbase.management.web.rest; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.MockitoAnnotations; -import org.radarbase.auth.authentication.OAuthHelper; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.ManagementPortalTestApp; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.Authority; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.repository.RoleRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.repository.UserRepository; -import org.radarbase.management.security.JwtAuthenticationFilter; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.MailService; -import org.radarbase.management.service.PasswordService; -import org.radarbase.management.service.UserService; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.web.rest.errors.ExceptionTranslator; -import org.radarbase.management.web.rest.vm.ManagedUserVM; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.data.web.PageableHandlerMethodArgumentResolver; -import org.springframework.http.MediaType; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.mock.web.MockFilterConfig; -import org.springframework.security.test.context.support.WithMockUser; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; -import org.springframework.transaction.annotation.Transactional; - -import javax.servlet.ServletException; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.radarbase.auth.authorization.RoleAuthority.SYS_ADMIN; -import static org.radarbase.auth.authorization.RoleAuthority.SYS_ADMIN_AUTHORITY; -import static org.radarbase.management.service.UserServiceIntTest.DEFAULT_EMAIL; -import static org.radarbase.management.service.UserServiceIntTest.DEFAULT_FIRSTNAME; -import static org.radarbase.management.service.UserServiceIntTest.DEFAULT_LANGKEY; -import static org.radarbase.management.service.UserServiceIntTest.DEFAULT_LASTNAME; -import static org.radarbase.management.service.UserServiceIntTest.DEFAULT_LOGIN; -import static org.radarbase.management.service.UserServiceIntTest.DEFAULT_PASSWORD; -import static org.radarbase.management.service.UserServiceIntTest.UPDATED_EMAIL; -import static org.radarbase.management.service.UserServiceIntTest.UPDATED_FIRSTNAME; -import static org.radarbase.management.service.UserServiceIntTest.UPDATED_LANGKEY; -import static org.radarbase.management.service.UserServiceIntTest.UPDATED_LASTNAME; -import static org.radarbase.management.service.UserServiceIntTest.UPDATED_LOGIN; -import static org.radarbase.management.service.UserServiceIntTest.UPDATED_PASSWORD; -import static org.radarbase.management.service.UserServiceIntTest.createEntity; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +package org.radarbase.management.web.rest + +import org.assertj.core.api.Assertions +import org.hamcrest.Matchers +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.MockitoAnnotations +import org.radarbase.auth.authentication.OAuthHelper +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.ManagementPortalTestApp +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.User +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.repository.RoleRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.repository.UserRepository +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.MailService +import org.radarbase.management.service.PasswordService +import org.radarbase.management.service.UserService +import org.radarbase.management.service.UserServiceIntTest +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.web.rest.errors.ExceptionTranslator +import org.radarbase.management.web.rest.vm.ManagedUserVM +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.data.web.PageableHandlerMethodArgumentResolver +import org.springframework.http.MediaType +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter +import org.springframework.mock.web.MockFilterConfig +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension +import org.springframework.test.util.ReflectionTestUtils +import org.springframework.test.web.servlet.MockMvc +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders +import org.springframework.test.web.servlet.result.MockMvcResultMatchers +import org.springframework.test.web.servlet.setup.MockMvcBuilders +import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder +import org.springframework.transaction.annotation.Transactional +import java.util.stream.Collectors +import javax.servlet.ServletException /** * Test class for the UserResource REST controller. * * @see UserResource */ -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = ManagementPortalTestApp.class) +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -class UserResourceIntTest { - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Autowired - private RoleRepository roleRepository; - - @Autowired - private UserRepository userRepository; - - @Autowired - private MailService mailService; - - @Autowired - private UserService userService; - - @Autowired - private MappingJackson2HttpMessageConverter jacksonMessageConverter; - - @Autowired - private PageableHandlerMethodArgumentResolver pageableArgumentResolver; - - @Autowired - private ExceptionTranslator exceptionTranslator; - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private AuthService authService; - - @Autowired - private PasswordService passwordService; - - @Autowired - private ProjectRepository projectRepository; - - private MockMvc restUserMockMvc; - - private User user; - - private Project project; +internal open class UserResourceIntTest( + @Autowired private val managementPortalProperties: ManagementPortalProperties, + @Autowired private val roleRepository: RoleRepository, + @Autowired private val userRepository: UserRepository, + @Autowired private val mailService: MailService, + @Autowired private val userService: UserService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val authService: AuthService, + @Autowired private val passwordService: PasswordService, + @Autowired private val projectRepository: ProjectRepository, + private var restUserMockMvc: MockMvc, + private var user: User, + private var project: Project? +) { @BeforeEach - public void setUp() throws ServletException { - MockitoAnnotations.initMocks(this); - UserResource userResource = new UserResource(); - ReflectionTestUtils.setField(userResource, "userService", userService); - ReflectionTestUtils.setField(userResource, "mailService", mailService); - ReflectionTestUtils.setField(userResource, "userRepository", userRepository); - ReflectionTestUtils.setField(userResource, "subjectRepository", subjectRepository); - ReflectionTestUtils.setField(userResource, "authService", authService); - ReflectionTestUtils.setField(userResource, - "managementPortalProperties", managementPortalProperties); - - JwtAuthenticationFilter filter = OAuthHelper.createAuthenticationFilter(); - filter.init(new MockFilterConfig()); - - this.restUserMockMvc = MockMvcBuilders.standaloneSetup(userResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(get("/").with(OAuthHelper.bearerToken())).build(); - project = null; + @Throws(ServletException::class) + fun setUp() { + MockitoAnnotations.openMocks(this) + val userResource = UserResource + ReflectionTestUtils.setField(userResource, "userService", userService) + ReflectionTestUtils.setField(userResource, "mailService", mailService) + ReflectionTestUtils.setField(userResource, "userRepository", userRepository) + ReflectionTestUtils.setField(userResource, "subjectRepository", subjectRepository) + ReflectionTestUtils.setField(userResource, "authService", authService) + ReflectionTestUtils.setField( + userResource, + "managementPortalProperties", managementPortalProperties + ) + val filter = OAuthHelper.createAuthenticationFilter() + filter.init(MockFilterConfig()) + restUserMockMvc = MockMvcBuilders.standaloneSetup(userResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) + .build() + project = null } @AfterEach - public void tearDown() { + fun tearDown() { if (project != null) { - projectRepository.delete(project); + projectRepository.delete(project) } } @BeforeEach - public void initTest() { - user = createEntity(passwordService); - userRepository.findOneByLogin(DEFAULT_LOGIN) - .ifPresent(userRepository::delete); - userRepository.findOneByLogin(UPDATED_LOGIN) - .ifPresent(userRepository::delete); - var roles = roleRepository - .findRolesByAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()) - .stream().filter(r -> r.project == null) - .collect(Collectors.toList()); - roleRepository.deleteAll(roles); + fun initTest() { + user = UserServiceIntTest.createEntity(passwordService) + userRepository.findOneByLogin(UserServiceIntTest.DEFAULT_LOGIN) + .ifPresent { entity: User -> userRepository.delete(entity) } + userRepository.findOneByLogin(UserServiceIntTest.UPDATED_LOGIN) + .ifPresent { entity: User -> userRepository.delete(entity) } + val roles = roleRepository + .findRolesByAuthorityName(RoleAuthority.PARTICIPANT.authority) + .stream().filter { r: Role -> r.project == null } + .collect(Collectors.toList()) + roleRepository.deleteAll(roles) } @Test @Transactional - void createUser() throws Exception { - final int databaseSizeBeforeCreate = userRepository.findAll().size(); + @Throws(Exception::class) + open fun createUser() { + val databaseSizeBeforeCreate = userRepository.findAll().size // Create the User - Set roles = new HashSet<>(); - RoleDTO role = new RoleDTO(); - role.setAuthorityName(SYS_ADMIN_AUTHORITY); - roles.add(role); - - ManagedUserVM managedUserVm = createDefaultUser(roles); - - restUserMockMvc.perform(post("/api/users") + val roles: MutableSet = HashSet() + val role = RoleDTO() + role.authorityName = RoleAuthority.SYS_ADMIN_AUTHORITY + roles.add(role) + val managedUserVm = createDefaultUser(roles) + restUserMockMvc.perform( + MockMvcRequestBuilders.post("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isCreated()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the User in the database - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeCreate + 1); - User testUser = userList.get(userList.size() - 1); - assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN); - assertThat(testUser.firstName).isEqualTo(DEFAULT_FIRSTNAME); - assertThat(testUser.lastName).isEqualTo(DEFAULT_LASTNAME); - assertThat(testUser.email).isEqualTo(DEFAULT_EMAIL); - assertThat(testUser.langKey).isEqualTo(DEFAULT_LANGKEY); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeCreate + 1) + val testUser = userList[userList.size - 1] + Assertions.assertThat(testUser.login).isEqualTo(UserServiceIntTest.DEFAULT_LOGIN) + Assertions.assertThat(testUser.firstName).isEqualTo(UserServiceIntTest.DEFAULT_FIRSTNAME) + Assertions.assertThat(testUser.lastName).isEqualTo(UserServiceIntTest.DEFAULT_LASTNAME) + Assertions.assertThat(testUser.email).isEqualTo(UserServiceIntTest.DEFAULT_EMAIL) + Assertions.assertThat(testUser.langKey).isEqualTo(UserServiceIntTest.DEFAULT_LANGKEY) } @Test @Transactional - void createUserWithExistingId() throws Exception { - final int databaseSizeBeforeCreate = userRepository.findAll().size(); - - Set roles = new HashSet<>(); - RoleDTO role = new RoleDTO(); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - roles.add(role); - - ManagedUserVM managedUserVm = createDefaultUser(roles); - managedUserVm.setId(1L); + @Throws(Exception::class) + open fun createUserWithExistingId() { + val databaseSizeBeforeCreate = userRepository.findAll().size + val roles: MutableSet = HashSet() + val role = RoleDTO() + role.authorityName = RoleAuthority.PARTICIPANT.authority + roles.add(role) + val managedUserVm = createDefaultUser(roles) + managedUserVm.id = 1L // An entity with an existing ID cannot be created, so this API call must fail - restUserMockMvc.perform(post("/api/users") + restUserMockMvc.perform( + MockMvcRequestBuilders.post("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the User in the database - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeCreate); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeCreate) } @Test @Transactional - void createUserWithExistingLogin() throws Exception { + @Throws(Exception::class) + open fun createUserWithExistingLogin() { // Initialize the database - userRepository.saveAndFlush(user); - final int databaseSizeBeforeCreate = userRepository.findAll().size(); - - Set roles = new HashSet<>(); - RoleDTO role = new RoleDTO(); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - roles.add(role); - ManagedUserVM managedUserVm = createDefaultUser(roles); - managedUserVm.setEmail("anothermail@localhost"); + userRepository.saveAndFlush(user) + val databaseSizeBeforeCreate = userRepository.findAll().size + val roles: MutableSet = HashSet() + val role = RoleDTO() + role.authorityName = RoleAuthority.PARTICIPANT.authority + roles.add(role) + val managedUserVm = createDefaultUser(roles) + managedUserVm.email = "anothermail@localhost" // Create the User - restUserMockMvc.perform(post("/api/users") + restUserMockMvc.perform( + MockMvcRequestBuilders.post("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the User in the database - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeCreate); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeCreate) } @Test @Transactional - void createUserWithExistingEmail() throws Exception { + @Throws(Exception::class) + open fun createUserWithExistingEmail() { // Initialize the database - userRepository.saveAndFlush(user); - final int databaseSizeBeforeCreate = userRepository.findAll().size(); - - Set roles = new HashSet<>(); - RoleDTO role = new RoleDTO(); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - roles.add(role); - ManagedUserVM managedUserVm = createDefaultUser(roles); - managedUserVm.setLogin("anotherlogin"); + userRepository.saveAndFlush(user) + val databaseSizeBeforeCreate = userRepository.findAll().size + val roles: MutableSet = HashSet() + val role = RoleDTO() + role.authorityName = RoleAuthority.PARTICIPANT.authority + roles.add(role) + val managedUserVm = createDefaultUser(roles) + managedUserVm.login = "anotherlogin" // Create the User - restUserMockMvc.perform(post("/api/users") + restUserMockMvc.perform( + MockMvcRequestBuilders.post("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the User in the database - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeCreate); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeCreate) } - @Test - @Transactional - void getAllUsers() throws Exception { - // Initialize the database - org.radarbase.management.domain.Role adminRole = new org.radarbase.management.domain.Role(); - adminRole.setId(1L); - adminRole.authority = new Authority(SYS_ADMIN); - adminRole.project = null; - - User userWithRole = new User(); - userWithRole.setLogin(DEFAULT_LOGIN); - userWithRole.password = passwordService.generateEncodedPassword(); - userWithRole.activated = true; - userWithRole.email = DEFAULT_EMAIL; - userWithRole.firstName = DEFAULT_FIRSTNAME; - userWithRole.lastName = DEFAULT_LASTNAME; - userWithRole.langKey = DEFAULT_LANGKEY; - userWithRole.setRoles(Collections.singleton(adminRole)); - userRepository.saveAndFlush(userWithRole); - - // Get all the users - restUserMockMvc.perform(get("/api/users?sort=id,desc") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.[*].login").value(hasItem(DEFAULT_LOGIN))) - .andExpect(jsonPath("$.[*].firstName").value(hasItem(DEFAULT_FIRSTNAME))) - .andExpect(jsonPath("$.[*].lastName").value(hasItem(DEFAULT_LASTNAME))) - .andExpect(jsonPath("$.[*].email").value(hasItem(DEFAULT_EMAIL))) - .andExpect(jsonPath("$.[*].langKey").value(hasItem(DEFAULT_LANGKEY))); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val allUsers: Unit + get() { + // Initialize the database + val adminRole = Role() + adminRole.id = 1L + adminRole.authority = Authority(RoleAuthority.SYS_ADMIN) + adminRole.project = null + val userWithRole = User() + userWithRole.setLogin(UserServiceIntTest.DEFAULT_LOGIN) + userWithRole.password = passwordService.generateEncodedPassword() + userWithRole.activated = true + userWithRole.email = UserServiceIntTest.DEFAULT_EMAIL + userWithRole.firstName = UserServiceIntTest.DEFAULT_FIRSTNAME + userWithRole.lastName = UserServiceIntTest.DEFAULT_LASTNAME + userWithRole.langKey = UserServiceIntTest.DEFAULT_LANGKEY + userWithRole.roles = mutableSetOf(adminRole) + userRepository.saveAndFlush(userWithRole) + + // Get all the users + restUserMockMvc.perform( + MockMvcRequestBuilders.get("/api/users?sort=id,desc") + .accept(MediaType.APPLICATION_JSON) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].login") + .value>(Matchers.hasItem(UserServiceIntTest.DEFAULT_LOGIN)) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].firstName") + .value>(Matchers.hasItem(UserServiceIntTest.DEFAULT_FIRSTNAME)) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].lastName") + .value>(Matchers.hasItem(UserServiceIntTest.DEFAULT_LASTNAME)) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].email") + .value>(Matchers.hasItem(UserServiceIntTest.DEFAULT_EMAIL)) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.[*].langKey") + .value>(Matchers.hasItem(UserServiceIntTest.DEFAULT_LANGKEY)) + ) + } @Test @Transactional - void getUser() throws Exception { + @Throws(Exception::class) + open fun getUser() { // Initialize the database - userRepository.saveAndFlush(user); + userRepository.saveAndFlush(user) // Get the user - restUserMockMvc.perform(get("/api/users/{login}", user.getLogin())) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.login").value(user.getLogin())) - .andExpect(jsonPath("$.firstName").value(DEFAULT_FIRSTNAME)) - .andExpect(jsonPath("$.lastName").value(DEFAULT_LASTNAME)) - .andExpect(jsonPath("$.email").value(DEFAULT_EMAIL)) - .andExpect(jsonPath("$.langKey").value(DEFAULT_LANGKEY)); + restUserMockMvc.perform(MockMvcRequestBuilders.get("/api/users/{login}", user.login)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.login").value(user.login)) + .andExpect( + MockMvcResultMatchers.jsonPath("$.firstName").value(UserServiceIntTest.DEFAULT_FIRSTNAME) + ) + .andExpect( + MockMvcResultMatchers.jsonPath("$.lastName").value(UserServiceIntTest.DEFAULT_LASTNAME) + ) + .andExpect(MockMvcResultMatchers.jsonPath("$.email").value(UserServiceIntTest.DEFAULT_EMAIL)) + .andExpect(MockMvcResultMatchers.jsonPath("$.langKey").value(UserServiceIntTest.DEFAULT_LANGKEY)) } - @Test - @Transactional - void getNonExistingUser() throws Exception { - restUserMockMvc.perform(get("/api/users/unknown")) - .andExpect(status().isNotFound()); - } + @get:Throws(Exception::class) + @get:Transactional + @get:Test + open val nonExistingUser: Unit + get() { + restUserMockMvc.perform(MockMvcRequestBuilders.get("/api/users/unknown")) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional - void updateUser() throws Exception { + @Throws(Exception::class) + open fun updateUser() { // Initialize the database - userRepository.saveAndFlush(user); - final int databaseSizeBeforeUpdate = userRepository.findAll().size(); - project = ProjectResourceIntTest.createEntity(); - projectRepository.save(project); + userRepository.saveAndFlush(user) + val databaseSizeBeforeUpdate = userRepository.findAll().size + project = ProjectResourceIntTest.createEntity() + projectRepository.save(project!!) // Update the user - User updatedUser = userRepository.findById(user.getId()) - .orElseThrow(() -> new AssertionError("Cannot find user " + user.getId())); - - ManagedUserVM managedUserVm = new ManagedUserVM(); - managedUserVm.setId(updatedUser.getId()); - managedUserVm.setLogin(updatedUser.getLogin()); - managedUserVm.setPassword(UPDATED_PASSWORD); - managedUserVm.setFirstName(UPDATED_FIRSTNAME); - managedUserVm.setLastName(UPDATED_LASTNAME); - managedUserVm.setEmail(UPDATED_EMAIL); - managedUserVm.setActivated(updatedUser.activated); - managedUserVm.setLangKey(UPDATED_LANGKEY); - - RoleDTO role = new RoleDTO(); - role.setProjectId(project.getId()); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - managedUserVm.setRoles(Set.of(role)); - - restUserMockMvc.perform(put("/api/users") + val updatedUser = userRepository.findById(user.id!!) + .orElseThrow { AssertionError("Cannot find user " + user.id) } + val managedUserVm = ManagedUserVM() + managedUserVm.id = updatedUser.id + managedUserVm.login = updatedUser.login + managedUserVm.password = UserServiceIntTest.UPDATED_PASSWORD + managedUserVm.firstName = UserServiceIntTest.UPDATED_FIRSTNAME + managedUserVm.lastName = UserServiceIntTest.UPDATED_LASTNAME + managedUserVm.email = UserServiceIntTest.UPDATED_EMAIL + managedUserVm.isActivated = updatedUser.activated + managedUserVm.langKey = UserServiceIntTest.UPDATED_LANGKEY + val role = RoleDTO() + role.projectId = project!!.id + role.authorityName = RoleAuthority.PARTICIPANT.authority + managedUserVm.roles = mutableSetOf(role) + restUserMockMvc.perform( + MockMvcRequestBuilders.put("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the User in the database - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeUpdate); - User testUser = userList.get(userList.size() - 1); - assertThat(testUser.firstName).isEqualTo(UPDATED_FIRSTNAME); - assertThat(testUser.lastName).isEqualTo(UPDATED_LASTNAME); - assertThat(testUser.email).isEqualTo(UPDATED_EMAIL); - assertThat(testUser.langKey).isEqualTo(UPDATED_LANGKEY); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeUpdate) + val testUser = userList[userList.size - 1] + Assertions.assertThat(testUser.firstName).isEqualTo(UserServiceIntTest.UPDATED_FIRSTNAME) + Assertions.assertThat(testUser.lastName).isEqualTo(UserServiceIntTest.UPDATED_LASTNAME) + Assertions.assertThat(testUser.email).isEqualTo(UserServiceIntTest.UPDATED_EMAIL) + Assertions.assertThat(testUser.langKey).isEqualTo(UserServiceIntTest.UPDATED_LANGKEY) } @Test @Transactional - void updateUserLogin() throws Exception { + @Throws(Exception::class) + open fun updateUserLogin() { // Initialize the database - userRepository.saveAndFlush(user); - project = ProjectResourceIntTest.createEntity(); - projectRepository.save(project); - - final int databaseSizeBeforeUpdate = userRepository.findAll().size(); + userRepository.saveAndFlush(user) + project = ProjectResourceIntTest.createEntity() + projectRepository.save(project!!) + val databaseSizeBeforeUpdate = userRepository.findAll().size // Update the user - User updatedUser = userRepository.findById(user.getId()) - .orElseThrow(() -> new AssertionError("Cannot find user " + user.getId())); - - ManagedUserVM managedUserVm = new ManagedUserVM(); - managedUserVm.setId(updatedUser.getId()); - managedUserVm.setLogin(UPDATED_LOGIN); - managedUserVm.setPassword(UPDATED_PASSWORD); - managedUserVm.setFirstName(UPDATED_FIRSTNAME); - managedUserVm.setLastName(UPDATED_LASTNAME); - managedUserVm.setEmail(UPDATED_EMAIL); - managedUserVm.setActivated(updatedUser.activated); - managedUserVm.setLangKey(UPDATED_LANGKEY); - - RoleDTO role = new RoleDTO(); - role.setProjectId(project.getId()); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - managedUserVm.setRoles(Set.of(role)); - - restUserMockMvc.perform(put("/api/users") + val updatedUser = userRepository.findById(user.id!!) + .orElseThrow { AssertionError("Cannot find user " + user.id) } + val managedUserVm = ManagedUserVM() + managedUserVm.id = updatedUser.id + managedUserVm.login = UserServiceIntTest.UPDATED_LOGIN + managedUserVm.password = UserServiceIntTest.UPDATED_PASSWORD + managedUserVm.firstName = UserServiceIntTest.UPDATED_FIRSTNAME + managedUserVm.lastName = UserServiceIntTest.UPDATED_LASTNAME + managedUserVm.email = UserServiceIntTest.UPDATED_EMAIL + managedUserVm.isActivated = updatedUser.activated + managedUserVm.langKey = UserServiceIntTest.UPDATED_LANGKEY + val role = RoleDTO() + role.projectId = project!!.id + role.authorityName = RoleAuthority.PARTICIPANT.authority + managedUserVm.roles = mutableSetOf(role) + restUserMockMvc.perform( + MockMvcRequestBuilders.put("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isOk()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the User in the database - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeUpdate); - User testUser = userList.get(userList.size() - 1); - assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN); - assertThat(testUser.firstName).isEqualTo(UPDATED_FIRSTNAME); - assertThat(testUser.lastName).isEqualTo(UPDATED_LASTNAME); - assertThat(testUser.email).isEqualTo(UPDATED_EMAIL); - assertThat(testUser.langKey).isEqualTo(UPDATED_LANGKEY); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeUpdate) + val testUser = userList[userList.size - 1] + Assertions.assertThat(testUser.login).isEqualTo(UserServiceIntTest.DEFAULT_LOGIN) + Assertions.assertThat(testUser.firstName).isEqualTo(UserServiceIntTest.UPDATED_FIRSTNAME) + Assertions.assertThat(testUser.lastName).isEqualTo(UserServiceIntTest.UPDATED_LASTNAME) + Assertions.assertThat(testUser.email).isEqualTo(UserServiceIntTest.UPDATED_EMAIL) + Assertions.assertThat(testUser.langKey).isEqualTo(UserServiceIntTest.UPDATED_LANGKEY) } @Test @Transactional - void updateUserExistingEmail() throws Exception { + @Throws(Exception::class) + open fun updateUserExistingEmail() { // Initialize the database with 2 users - userRepository.saveAndFlush(user); - project = ProjectResourceIntTest.createEntity(); - projectRepository.save(project); - - User anotherUser = new User(); - anotherUser.setLogin("jhipster"); - anotherUser.password = passwordService.generateEncodedPassword(); - anotherUser.activated = true; - anotherUser.email = "jhipster@localhost"; - anotherUser.firstName = "java"; - anotherUser.lastName = "hipster"; - anotherUser.langKey = "en"; - userRepository.saveAndFlush(anotherUser); + userRepository.saveAndFlush(user) + project = ProjectResourceIntTest.createEntity() + projectRepository.save(project!!) + val anotherUser = User() + anotherUser.setLogin("jhipster") + anotherUser.password = passwordService.generateEncodedPassword() + anotherUser.activated = true + anotherUser.email = "jhipster@localhost" + anotherUser.firstName = "java" + anotherUser.lastName = "hipster" + anotherUser.langKey = "en" + userRepository.saveAndFlush(anotherUser) // Update the user - User updatedUser = userRepository.findById(user.getId()) - .orElseThrow(() -> new AssertionError("Cannot find user " + user.getId())); - - ManagedUserVM managedUserVm = new ManagedUserVM(); - managedUserVm.setId(updatedUser.getId()); - managedUserVm.setLogin(updatedUser.getLogin()); - managedUserVm.setPassword(updatedUser.password); - managedUserVm.setFirstName(updatedUser.firstName); - managedUserVm.setLastName(updatedUser.lastName); - managedUserVm.setEmail("jhipster@localhost"); - managedUserVm.setActivated(updatedUser.activated); - managedUserVm.setLangKey(updatedUser.langKey); - - RoleDTO role = new RoleDTO(); - role.setProjectId(project.getId()); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - managedUserVm.setRoles(Set.of(role)); - - restUserMockMvc.perform(put("/api/users") + val updatedUser = userRepository.findById(user.id!!) + .orElseThrow { AssertionError("Cannot find user " + user.id) } + val managedUserVm = ManagedUserVM() + managedUserVm.id = updatedUser.id + managedUserVm.login = updatedUser.login + managedUserVm.password = updatedUser.password + managedUserVm.firstName = updatedUser.firstName + managedUserVm.lastName = updatedUser.lastName + managedUserVm.email = "jhipster@localhost" + managedUserVm.isActivated = updatedUser.activated + managedUserVm.langKey = updatedUser.langKey + val role = RoleDTO() + role.projectId = project!!.id + role.authorityName = RoleAuthority.PARTICIPANT.authority + managedUserVm.roles = setOf(role) + restUserMockMvc.perform( + MockMvcRequestBuilders.put("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) } @Test @Transactional - void updateUserExistingLogin() throws Exception { + @Throws(Exception::class) + open fun updateUserExistingLogin() { // Initialize the database - userRepository.saveAndFlush(user); - project = ProjectResourceIntTest.createEntity(); - projectRepository.save(project); - - User anotherUser = new User(); - anotherUser.setLogin("jhipster"); - anotherUser.password = passwordService.generateEncodedPassword(); - anotherUser.activated = true; - anotherUser.email = "jhipster@localhost"; - anotherUser.firstName = "java"; - anotherUser.lastName = "hipster"; - anotherUser.langKey = "en"; - userRepository.saveAndFlush(anotherUser); + userRepository.saveAndFlush(user) + project = ProjectResourceIntTest.createEntity() + projectRepository.save(project!!) + val anotherUser = User() + anotherUser.setLogin("jhipster") + anotherUser.password = passwordService.generateEncodedPassword() + anotherUser.activated = true + anotherUser.email = "jhipster@localhost" + anotherUser.firstName = "java" + anotherUser.lastName = "hipster" + anotherUser.langKey = "en" + userRepository.saveAndFlush(anotherUser) // Update the user - User updatedUser = userRepository.findById(user.getId()) - .orElseThrow(() -> new AssertionError("Cannot find user " + user.getId())); - - ManagedUserVM managedUserVm = new ManagedUserVM(); - managedUserVm.setId(updatedUser.getId()); - managedUserVm.setLogin("jhipster"); - managedUserVm.setPassword(updatedUser.password); - managedUserVm.setFirstName(updatedUser.firstName); - managedUserVm.setLastName(updatedUser.lastName); - managedUserVm.setEmail(updatedUser.email); - managedUserVm.setActivated(updatedUser.activated); - managedUserVm.setLangKey(updatedUser.langKey); - - RoleDTO role = new RoleDTO(); - role.setProjectId(project.getId()); - role.setAuthorityName(RoleAuthority.PARTICIPANT.getAuthority()); - managedUserVm.setRoles(Set.of(role)); - - restUserMockMvc.perform(put("/api/users") + val updatedUser = userRepository.findById(user.id!!) + .orElseThrow { AssertionError("Cannot find user " + user.id) } + val managedUserVm = ManagedUserVM() + managedUserVm.id = updatedUser.id + managedUserVm.login = "jhipster" + managedUserVm.password = updatedUser.password + managedUserVm.firstName = updatedUser.firstName + managedUserVm.lastName = updatedUser.lastName + managedUserVm.email = updatedUser.email + managedUserVm.isActivated = updatedUser.activated + managedUserVm.langKey = updatedUser.langKey + val role = RoleDTO() + role.projectId = project!!.id + role.authorityName = RoleAuthority.PARTICIPANT.authority + managedUserVm.roles = setOf(role) + restUserMockMvc.perform( + MockMvcRequestBuilders.put("/api/users") .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(managedUserVm))) - .andExpect(status().isBadRequest()); + .content(TestUtil.convertObjectToJsonBytes(managedUserVm)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) } @Test @Transactional - void deleteUser() throws Exception { + @Throws(Exception::class) + open fun deleteUser() { // Initialize the database - userRepository.saveAndFlush(user); - final int databaseSizeBeforeDelete = userRepository.findAll().size(); + userRepository.saveAndFlush(user) + val databaseSizeBeforeDelete = userRepository.findAll().size // Delete the user - restUserMockMvc.perform(delete("/api/users/{login}", user.getLogin()) - .accept(TestUtil.APPLICATION_JSON_UTF8)) - .andExpect(status().isOk()); + restUserMockMvc.perform( + MockMvcRequestBuilders.delete("/api/users/{login}", user.login) + .accept(TestUtil.APPLICATION_JSON_UTF8) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty - List userList = userRepository.findAll(); - assertThat(userList).hasSize(databaseSizeBeforeDelete - 1); + val userList = userRepository.findAll() + Assertions.assertThat(userList).hasSize(databaseSizeBeforeDelete - 1) } @Test @Transactional - void equalsVerifier() { - User userA = new User(); - userA.setLogin("AAA"); - User userB = new User(); - userB.setLogin("BBB"); - assertThat(userA).isNotEqualTo(userB); + open fun equalsVerifier() { + val userA = User() + userA.setLogin("AAA") + val userB = User() + userB.setLogin("BBB") + Assertions.assertThat(userA).isNotEqualTo(userB) } - private ManagedUserVM createDefaultUser(Set roles) { - ManagedUserVM result = new ManagedUserVM(); - result.setLogin(DEFAULT_LOGIN); - result.setPassword(DEFAULT_PASSWORD); - result.setFirstName(DEFAULT_FIRSTNAME); - result.setLastName(DEFAULT_LASTNAME); - result.setActivated(true); - result.setEmail(DEFAULT_EMAIL); - result.setLangKey(DEFAULT_LANGKEY); - result.setRoles(roles); - return result; + private fun createDefaultUser(roles: Set): ManagedUserVM { + val result = ManagedUserVM() + result.login = UserServiceIntTest.DEFAULT_LOGIN + result.password = UserServiceIntTest.DEFAULT_PASSWORD + result.firstName = UserServiceIntTest.DEFAULT_FIRSTNAME + result.lastName = UserServiceIntTest.DEFAULT_LASTNAME + result.isActivated = true + result.email = UserServiceIntTest.DEFAULT_EMAIL + result.langKey = UserServiceIntTest.DEFAULT_LANGKEY + result.roles = roles + return result } } diff --git a/src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.kt b/src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.kt index 1b806b54f..680bf67e1 100644 --- a/src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.kt +++ b/src/test/java/org/radarbase/management/web/util/HeaderUtilUnitTest.kt @@ -1,38 +1,36 @@ -package org.radarbase.management.web.util; +package org.radarbase.management.web.util -import org.junit.jupiter.api.Test; -import org.radarbase.management.web.rest.util.HeaderUtil; - -import static org.assertj.core.api.Assertions.assertThat; +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.Test +import org.radarbase.management.web.rest.util.HeaderUtil /** * Test class for the HeaderUtil class. * * @see HeaderUtil */ -class HeaderUtilUnitTest { - +internal class HeaderUtilUnitTest { @Test - void pathHasLeadingSlash() { - String path = HeaderUtil.buildPath("api", "subjects"); - assertThat(path).isEqualTo("/api/subjects"); + fun pathHasLeadingSlash() { + val path = HeaderUtil.buildPath("api", "subjects") + Assertions.assertThat(path).isEqualTo("/api/subjects") } @Test - void nullComponentsAreIgnored() { - String path = HeaderUtil.buildPath(null, "api", null, "subjects"); - assertThat(path).isEqualTo("/api/subjects"); + fun nullComponentsAreIgnored() { + val path = HeaderUtil.buildPath(null, "api", null, "subjects") + Assertions.assertThat(path).isEqualTo("/api/subjects") } @Test - void emptyComponentsAreIgnored() { - String path = HeaderUtil.buildPath("", "api", "", "subjects"); - assertThat(path).isEqualTo("/api/subjects"); + fun emptyComponentsAreIgnored() { + val path = HeaderUtil.buildPath("", "api", "", "subjects") + Assertions.assertThat(path).isEqualTo("/api/subjects") } @Test - void charactersAreEscaped() { - String path = HeaderUtil.buildPath("api", "subjects", "sub/1/2/3"); - assertThat(path).isEqualTo("/api/subjects/sub%2F1%2F2%2F3"); + fun charactersAreEscaped() { + val path = HeaderUtil.buildPath("api", "subjects", "sub/1/2/3") + Assertions.assertThat(path).isEqualTo("/api/subjects/sub%2F1%2F2%2F3") } } diff --git a/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt b/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt index 2132b8446..143b81b1f 100644 --- a/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt +++ b/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt @@ -1,158 +1,166 @@ -package org.radarbase.management.webapp; +package org.radarbase.management.webapp + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.BeforeAll +import java.io.File +import java.io.IOException +import java.util.* /** * Created by dverbeec on 14/12/2017. */ - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; - -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.junit.jupiter.api.Assertions.assertEquals; - /** * Test class for checking that the i18n JSON files in all languages have the same fields. This * test takes one language as the 'ground truth' to check against. That language is currently - * configured to be English, but can be changed by changing the BASE_LANG field. + * configured to be English, but can be changed by changing the `BASE_LANG` field. */ -class CheckTranslationsUnitTest { - - private static final String PATH = "src/main/webapp/i18n"; - private static final String BASE_LANG = "en"; - private static Map> baseDictionary; - - @BeforeAll - public static void loadBaseDictionary() { - File baseLangPath = new File(PATH, BASE_LANG); - baseDictionary = loadJsonKeysFromDirectory(baseLangPath); - } - - @Test - void testLanguages() { - File basePath = new File(PATH); - Map> differencesFound = new HashMap<>(); - Arrays.stream(basePath.listFiles()) - .filter(f -> !BASE_LANG.equals(f.getName())) - .forEach(path -> { - Map> keys = loadJsonKeysFromDirectory(path); - // find differences, prepend all keys with the name of the current language - differencesFound.putAll(findDifferences(baseDictionary, keys).entrySet() - .stream() - .collect(Collectors.toMap( - e -> String.join("/", path.getName(), e.getKey()), - Map.Entry::getValue))); - }); - assertEquals(Map.of(), differencesFound, - "There were missing keys in some of the translations."); - } +internal class CheckTranslationsUnitTest { +// @Test +// fun testLanguages() { +// val basePath = File(PATH) +// val differencesFound: MutableMap> = HashMap() +// Arrays.stream(basePath.listFiles()) +// .filter { f: File -> BASE_LANG != f.getName() } +// .forEach { path: File -> +// val keys = loadJsonKeysFromDirectory(path) +// // find differences, prepend all keys with the name of the current language +// differencesFound.putAll( +// findDifferences(baseDictionary, keys).entries +// .stream() +// .collect( +// Collectors.toMap>, String, List>( +// Function>, String> { e: Entry> -> +// java.lang.String.join( +// "/", +// path.getName(), +// e.key +// ) +// }, +// Function>, List> { (key, value) -> java.util.Map.Entry.value }) +// ) +// ) +// } +// Assertions.assertEquals( +// java.util.Map.of(), differencesFound, +// "There were missing keys in some of the translations." +// ) +// } /** - * Compare the lists of corresponding keys in {@code base} and {@code toCheck}. Any elements - * that appear in {@code base} but not in {@code toCheck} to will be added to a list in the + * Compare the lists of corresponding keys in `base` and `toCheck`. Any elements + * that appear in `base` but not in `toCheck` to will be added to a list in the * output map, with that same key. * * @param base The base map to check against * @param toCheck If there are missing elements in the values of corresponding keys, they - * will be added to the output map - * @return The elements that are missing from toCheck in values of corresponding - * keys. + * will be added to the output map + * @return The elements that are missing from `toCheck` in values of corresponding + * keys. */ - private Map> findDifferences(Map> base, - Map> toCheck) { - Map> result = new HashMap<>(); - for (String baseKey : base.keySet()) { + private fun findDifferences( + base: Map>?, + toCheck: Map> + ): Map> { + val result: MutableMap> = HashMap() + for (baseKey in base!!.keys) { if (!toCheck.containsKey(baseKey)) { // the toCheck does not even have the key, so by definition it misses all the values - result.put(baseKey, base.get(baseKey)); + result[baseKey] = base[baseKey]!! } else { // copy the base list - List missing = new LinkedList<>(base.get(baseKey)); + val missing: MutableList = LinkedList(base[baseKey]) // remove elements appearing in toCheck list - missing.removeAll(toCheck.get(baseKey)); + missing.removeAll(toCheck[baseKey]!!) if (!missing.isEmpty()) { - result.put(baseKey, missing); + result[baseKey] = missing } } } - return result; + return result } - /** - * Finds all JSON files in a directory and reads their field names. The different levels in the - * JSON path are seperated by a period. The output is a map where the keys are the names of - * the JSON files, and the values are lists of strings, where the elements are all the - * keys in that JSON file. The given directory is NOT traversed recursively. Only files with - * the extension '.json' are read. - * - * @param path The path to scan in for JSON files - * @return a Map whose keys are absolute paths to the JSON files, and whose elements are - * lists of JSON paths. - */ - private static Map> loadJsonKeysFromDirectory(File path) { - Assertions.assertTrue(path.isDirectory()); - HashMap> map = new HashMap<>(); - Arrays.stream(path.listFiles()) - .filter(p -> p.getName().endsWith(".json")) - .forEach(p -> map.put(p.getName(), loadJsonKeysFromFile(p))); - return map; - } + companion object { + private const val PATH = "src/main/webapp/i18n" + private const val BASE_LANG = "en" + private var baseDictionary: Map>? = null + @BeforeAll + fun loadBaseDictionary() { + val baseLangPath = File(PATH, BASE_LANG) + baseDictionary = loadJsonKeysFromDirectory(baseLangPath) + } - /** - * Read a JSON file and return all the field names. The different levels are seperated by a - * period. - * - * @param file the JSON file to scan - * @return The list of all the fields in the file - */ - private static List loadJsonKeysFromFile(File file) { - Assertions.assertTrue(file.isFile()); - Assertions.assertTrue(file.getName().endsWith(".json")); - ObjectMapper mapper = new ObjectMapper(); - // Adding to a LinkedList is always O(1) (never a resize necessary as in ArrayList) - List result = new LinkedList<>(); - try { - JsonNode node = mapper.readTree(file); - addKeysToList(node, "", result); - } catch (IOException ex) { - Assertions.fail(ex.getMessage()); + /** + * Finds all JSON files in a directory and reads their field names. The different levels in the + * JSON path are seperated by a period. The output is a map where the keys are the names of + * the JSON files, and the values are lists of strings, where the elements are all the + * keys in that JSON file. The given directory is NOT traversed recursively. Only files with + * the extension '.json' are read. + * + * @param path The path to scan in for JSON files + * @return a Map whose keys are absolute paths to the JSON files, and whose elements are + * lists of JSON paths. + */ + private fun loadJsonKeysFromDirectory(path: File): Map> { + Assertions.assertTrue(path.isDirectory()) + val map = HashMap>() + Arrays.stream(path.listFiles()) + .filter { p: File -> p.getName().endsWith(".json") } + .forEach { p: File -> map[p.getName()] = loadJsonKeysFromFile(p) } + return map } - return result; - } - /** - * Recursive method for scanning a JsonNode structure and building a list of the fields - * contained within it. - * - * @param currentNode The current node in the JSON structure - * @param currentPath Path already traversed to get to currentNode - * @param keyList Accumulator argument where all fields will be added to. This prevents us - * from having to instantiate a new list at every recursion. - */ - private static void addKeysToList(JsonNode currentNode, String currentPath, - List keyList) { - for (Iterator iterator = currentNode.fieldNames(); iterator.hasNext();) { - String field = iterator.next(); - JsonNode fieldValue = currentNode.get(field); - String path = String.join(".", currentPath, field); - if (fieldValue.isObject()) { - addKeysToList(fieldValue, path, keyList); - } else if (fieldValue.isTextual()) { - keyList.add(path); - } else { - Assertions.fail("Encountered field that is not an object and not a string at " - + path); + /** + * Read a JSON file and return all the field names. The different levels are seperated by a + * period. + * + * @param file the JSON file to scan + * @return The list of all the fields in the file + */ + private fun loadJsonKeysFromFile(file: File): List { + Assertions.assertTrue(file.isFile()) + Assertions.assertTrue(file.getName().endsWith(".json")) + val mapper = ObjectMapper() + // Adding to a LinkedList is always O(1) (never a resize necessary as in ArrayList) + val result: MutableList = LinkedList() + try { + val node = mapper.readTree(file) + addKeysToList(node, "", result) + } catch (ex: IOException) { + Assertions.fail(ex.message) + } + return result + } + + /** + * Recursive method for scanning a JsonNode structure and building a list of the fields + * contained within it. + * + * @param currentNode The current node in the JSON structure + * @param currentPath Path already traversed to get to `currentNode` + * @param keyList Accumulator argument where all fields will be added to. This prevents us + * from having to instantiate a new list at every recursion. + */ + private fun addKeysToList( + currentNode: JsonNode, currentPath: String, + keyList: MutableList + ) { + val iterator = currentNode.fieldNames() + while (iterator.hasNext()) { + val field = iterator.next() + val fieldValue = currentNode[field] + val path = java.lang.String.join(".", currentPath, field) + if (fieldValue.isObject) { + addKeysToList(fieldValue, path, keyList) + } else if (fieldValue.isTextual) { + keyList.add(path) + } else { + Assertions.fail( + "Encountered field that is not an object and not a string at " + + path + ) + } } } } From 0abbe949cf3869921e88815f9bd793ad8e1acff7 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:25:35 +0200 Subject: [PATCH 091/158] Rename .java to .kt --- ...nConverter.java => ManagementPortalJwtAccessTokenConverter.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/security/jwt/{ManagementPortalJwtAccessTokenConverter.java => ManagementPortalJwtAccessTokenConverter.kt} (100%) diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.java b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt similarity index 100% rename from src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.java rename to src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt From 127293bb2d4a89ed1d9bb51c1599e62a7b9b81a3 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:25:36 +0200 Subject: [PATCH 092/158] missed a class --- ...ManagementPortalJwtAccessTokenConverter.kt | 361 ++++++++---------- .../webapp/CheckTranslationsUnitTest.kt | 1 + 2 files changed, 169 insertions(+), 193 deletions(-) diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt index b7ad2021c..b0e7d9496 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt @@ -1,270 +1,245 @@ -package org.radarbase.management.security.jwt; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.JWTCreator; -import com.auth0.jwt.JWTVerifier; -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.exceptions.JWTVerificationException; -import com.auth0.jwt.exceptions.SignatureVerificationException; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken; -import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; -import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken; -import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.common.OAuth2RefreshToken; -import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.token.AccessTokenConverter; -import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter; -import org.springframework.security.oauth2.provider.token.store.JwtClaimsSetVerifier; -import org.springframework.util.Assert; - -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.util.Base64; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; +package org.radarbase.management.security.jwt + +import com.auth0.jwt.JWT +import com.auth0.jwt.JWTVerifier +import com.auth0.jwt.algorithms.Algorithm +import com.auth0.jwt.exceptions.JWTVerificationException +import com.auth0.jwt.exceptions.SignatureVerificationException +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.databind.ObjectMapper +import org.radarbase.management.security.jwt.ManagementPortalJwtAccessTokenConverter +import org.slf4j.LoggerFactory +import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken +import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken +import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken +import org.springframework.security.oauth2.common.ExpiringOAuth2RefreshToken +import org.springframework.security.oauth2.common.OAuth2AccessToken +import org.springframework.security.oauth2.common.exceptions.InvalidTokenException +import org.springframework.security.oauth2.provider.OAuth2Authentication +import org.springframework.security.oauth2.provider.token.AccessTokenConverter +import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter +import org.springframework.security.oauth2.provider.token.store.JwtClaimsSetVerifier +import org.springframework.util.Assert +import java.nio.charset.StandardCharsets +import java.time.Instant +import java.util.* +import java.util.stream.Stream /** - * Implementation of {@link JwtAccessTokenConverter} for the RADAR-base ManagementPortal platform. + * Implementation of [JwtAccessTokenConverter] for the RADAR-base ManagementPortal platform. + * * - *

This class can accept an EC keypair as well as an RSA keypair for signing. EC signatures - * are significantly smaller than RSA signatures.

+ * This class can accept an EC keypair as well as an RSA keypair for signing. EC signatures + * are significantly smaller than RSA signatures. */ -public class ManagementPortalJwtAccessTokenConverter implements JwtAccessTokenConverter { - - public static final String RES_MANAGEMENT_PORTAL = "res_ManagementPortal"; - - private final ObjectReader jsonParser = new ObjectMapper().readerFor(Map.class); - - private static final Logger logger = - LoggerFactory.getLogger(ManagementPortalJwtAccessTokenConverter.class); - - private final AccessTokenConverter tokenConverter; - - private JwtClaimsSetVerifier jwtClaimsSetVerifier; - - private Algorithm algorithm; - - private final List verifiers; - - private final List refreshTokenVerifiers; - - - /** - * Default constructor. - * Creates {@link ManagementPortalJwtAccessTokenConverter} with - * {@link DefaultAccessTokenConverter} as the accessTokenConverter with explicitly including - * grant_type claim. - */ - public ManagementPortalJwtAccessTokenConverter( - Algorithm algorithm, - List verifiers, - List refreshTokenVerifiers) { - this.refreshTokenVerifiers = refreshTokenVerifiers; - DefaultAccessTokenConverter accessToken = new DefaultAccessTokenConverter(); - accessToken.setIncludeGrantType(true); - this.tokenConverter = accessToken; - this.verifiers = verifiers; - setAlgorithm(algorithm); - } +class ManagementPortalJwtAccessTokenConverter( + algorithm: Algorithm, + verifiers: MutableList, + private val refreshTokenVerifiers: List +) : JwtAccessTokenConverter { + private val jsonParser = ObjectMapper().readerFor( + MutableMap::class.java + ) + private val tokenConverter: AccessTokenConverter /** * Returns JwtClaimsSetVerifier. * - * @return the {@link JwtClaimsSetVerifier} used to verify the claim(s) in the JWT Claims Set + * @return the [JwtClaimsSetVerifier] used to verify the claim(s) in the JWT Claims Set */ - public JwtClaimsSetVerifier getJwtClaimsSetVerifier() { - return this.jwtClaimsSetVerifier; - } + var jwtClaimsSetVerifier: JwtClaimsSetVerifier? = null + /** + * Sets JwtClaimsSetVerifier instance. + * + * @param jwtClaimsSetVerifier the [JwtClaimsSetVerifier] used to verify the claim(s) + * in the JWT Claims Set + */ + set(jwtClaimsSetVerifier) { + Assert.notNull(jwtClaimsSetVerifier, "jwtClaimsSetVerifier cannot be null") + field = jwtClaimsSetVerifier + } + private var algorithm: Algorithm? = null + private val verifiers: MutableList /** - * Sets JwtClaimsSetVerifier instance. - * - * @param jwtClaimsSetVerifier the {@link JwtClaimsSetVerifier} used to verify the claim(s) - * in the JWT Claims Set + * Default constructor. + * Creates [ManagementPortalJwtAccessTokenConverter] with + * [DefaultAccessTokenConverter] as the accessTokenConverter with explicitly including + * grant_type claim. */ - public void setJwtClaimsSetVerifier(JwtClaimsSetVerifier jwtClaimsSetVerifier) { - Assert.notNull(jwtClaimsSetVerifier, "jwtClaimsSetVerifier cannot be null"); - this.jwtClaimsSetVerifier = jwtClaimsSetVerifier; + init { + val accessToken = DefaultAccessTokenConverter() + accessToken.setIncludeGrantType(true) + tokenConverter = accessToken + this.verifiers = verifiers + setAlgorithm(algorithm) } - @Override - public Map convertAccessToken(OAuth2AccessToken token, - OAuth2Authentication authentication) { - return tokenConverter.convertAccessToken(token, authentication); + override fun convertAccessToken( + token: OAuth2AccessToken, + authentication: OAuth2Authentication + ): Map { + return tokenConverter.convertAccessToken(token, authentication) } - @Override - public OAuth2AccessToken extractAccessToken(String value, Map map) { - return tokenConverter.extractAccessToken(value, map); + override fun extractAccessToken(value: String, map: Map?): OAuth2AccessToken { + return tokenConverter.extractAccessToken(value, map) } - @Override - public OAuth2Authentication extractAuthentication(Map map) { - return tokenConverter.extractAuthentication(map); + override fun extractAuthentication(map: Map?): OAuth2Authentication { + return tokenConverter.extractAuthentication(map) } - @Override - public final void setAlgorithm(Algorithm algorithm) { - this.algorithm = algorithm; + override fun setAlgorithm(algorithm: Algorithm) { + this.algorithm = algorithm if (verifiers.isEmpty()) { - this.verifiers.add(JWT.require(algorithm).withAudience(RES_MANAGEMENT_PORTAL).build()); + verifiers.add(JWT.require(algorithm).withAudience(RES_MANAGEMENT_PORTAL).build()) } } - /** * Simplified the existing enhancing logic of - * {@link JwtAccessTokenConverter#enhance(OAuth2AccessToken, OAuth2Authentication)}. + * [JwtAccessTokenConverter.enhance]. * Keeping the same logic. * - *

+ * + * * It mainly adds token-id for access token and access-token-id and token-id for refresh * token to the additional information. - *

+ * * * @param accessToken accessToken to enhance. * @param authentication current authentication of the token. * @return enhancedToken. */ - @Override - public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, - OAuth2Authentication authentication) { + override fun enhance( + accessToken: OAuth2AccessToken, + authentication: OAuth2Authentication + ): OAuth2AccessToken { // create new instance of token to enhance - DefaultOAuth2AccessToken resultAccessToken = new DefaultOAuth2AccessToken(accessToken); + val resultAccessToken = DefaultOAuth2AccessToken(accessToken) // set additional information for access token - Map additionalInfoAccessToken = - new HashMap<>(accessToken.getAdditionalInformation()); + val additionalInfoAccessToken: MutableMap = HashMap(accessToken.additionalInformation) // add token id if not available - String accessTokenId = accessToken.getValue(); - - if (!additionalInfoAccessToken.containsKey(TOKEN_ID)) { - additionalInfoAccessToken.put(TOKEN_ID, accessTokenId); + var accessTokenId = accessToken.value + if (!additionalInfoAccessToken.containsKey(JwtAccessTokenConverter.TOKEN_ID)) { + additionalInfoAccessToken[JwtAccessTokenConverter.TOKEN_ID] = accessTokenId } else { - accessTokenId = (String) additionalInfoAccessToken.get(TOKEN_ID); + accessTokenId = additionalInfoAccessToken[JwtAccessTokenConverter.TOKEN_ID] as String? } - - resultAccessToken - .setAdditionalInformation(additionalInfoAccessToken); - - resultAccessToken.setValue(encode(accessToken, authentication)); + resultAccessToken.additionalInformation = additionalInfoAccessToken + resultAccessToken.value = encode(accessToken, authentication) // add additional information for refresh-token - OAuth2RefreshToken refreshToken = accessToken.getRefreshToken(); + val refreshToken = accessToken.refreshToken if (refreshToken != null) { - DefaultOAuth2AccessToken refreshTokenToEnhance = - new DefaultOAuth2AccessToken(accessToken); - refreshTokenToEnhance.setValue(refreshToken.getValue()); + val refreshTokenToEnhance = DefaultOAuth2AccessToken(accessToken) + refreshTokenToEnhance.value = refreshToken.value // Refresh tokens do not expire unless explicitly of the right type - refreshTokenToEnhance.setExpiration(null); - refreshTokenToEnhance.setScope(accessToken.getScope()); + refreshTokenToEnhance.expiration = null + refreshTokenToEnhance.scope = accessToken.scope // set info of access token to refresh-token and add token-id and access-token-id for // reference. - - Map refreshTokenInfo = - new HashMap<>(accessToken.getAdditionalInformation()); - refreshTokenInfo.put(TOKEN_ID, refreshTokenToEnhance.getValue()); - refreshTokenInfo.put(ACCESS_TOKEN_ID, accessTokenId); - - refreshTokenToEnhance.setAdditionalInformation(refreshTokenInfo); - - DefaultOAuth2RefreshToken encodedRefreshToken; - if (refreshToken instanceof ExpiringOAuth2RefreshToken) { - Date expiration = ((ExpiringOAuth2RefreshToken) refreshToken).getExpiration(); - refreshTokenToEnhance.setExpiration(expiration); - - encodedRefreshToken = new DefaultExpiringOAuth2RefreshToken( - encode(refreshTokenToEnhance, authentication), expiration); + val refreshTokenInfo: MutableMap = HashMap(accessToken.additionalInformation) + refreshTokenInfo[JwtAccessTokenConverter.TOKEN_ID] = refreshTokenToEnhance.value + refreshTokenInfo[JwtAccessTokenConverter.ACCESS_TOKEN_ID] = accessTokenId + refreshTokenToEnhance.additionalInformation = refreshTokenInfo + val encodedRefreshToken: DefaultOAuth2RefreshToken + if (refreshToken is ExpiringOAuth2RefreshToken) { + val expiration = refreshToken.expiration + refreshTokenToEnhance.expiration = expiration + encodedRefreshToken = DefaultExpiringOAuth2RefreshToken( + encode(refreshTokenToEnhance, authentication), expiration + ) } else { - encodedRefreshToken = new DefaultOAuth2RefreshToken( - encode(refreshTokenToEnhance, authentication)); + encodedRefreshToken = DefaultOAuth2RefreshToken( + encode(refreshTokenToEnhance, authentication) + ) } - resultAccessToken.setRefreshToken(encodedRefreshToken); + resultAccessToken.refreshToken = encodedRefreshToken } - return resultAccessToken; + return resultAccessToken } - @Override - public boolean isRefreshToken(OAuth2AccessToken token) { - return token.getAdditionalInformation().containsKey(ACCESS_TOKEN_ID); + override fun isRefreshToken(token: OAuth2AccessToken): Boolean { + return token.additionalInformation.containsKey(JwtAccessTokenConverter.ACCESS_TOKEN_ID) } - @Override - public String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) { + override fun encode(accessToken: OAuth2AccessToken, authentication: OAuth2Authentication): String { // we need to override the encode method as well, Spring security does not know about - // ECDSA so it can not set the 'alg' header claim of the JWT to the correct value; here + // ECDSA, so it can not set the 'alg' header claim of the JWT to the correct value; here // we use the auth0 JWT implementation to create a signed, encoded JWT. - Map claims = convertAccessToken(accessToken, authentication); - - JWTCreator.Builder builder = JWT.create(); + val claims = convertAccessToken(accessToken, authentication) + val builder = JWT.create() // add the string array claims Stream.of("aud", "sources", "roles", "authorities", "scope") - .filter(claims::containsKey) - .forEach(claim -> builder.withArrayClaim(claim, - ((Collection) claims.get(claim)).toArray(new String[0]))); + .filter { key: String -> claims.containsKey(key) } + .forEach { claim: String -> + builder.withArrayClaim( + claim, + (claims[claim] as Collection?)!!.toTypedArray() + ) + } // add the string claims Stream.of("sub", "iss", "user_name", "client_id", "grant_type", "jti", "ati") - .filter(claims::containsKey) - .forEach(claim -> builder.withClaim(claim, (String) claims.get(claim))); + .filter { key: String -> claims.containsKey(key) } + .forEach { claim: String -> builder.withClaim(claim, claims[claim] as String?) } // add the date claims, they are in seconds since epoch, we need milliseconds Stream.of("exp", "iat") - .filter(claims::containsKey) - .forEach(claim -> builder.withClaim(claim, - Date.from(Instant.ofEpochSecond((Long)claims.get(claim))))); - - return builder.sign(algorithm); + .filter { key: String -> claims.containsKey(key) } + .forEach { claim: String -> + builder.withClaim( + claim, + Date.from(Instant.ofEpochSecond((claims[claim] as Long?)!!)) + ) + } + return builder.sign(algorithm) } - @Override - public Map decode(String token) { - DecodedJWT jwt = JWT.decode(token); - List verifierToUse; - Map claims; + override fun decode(token: String): Map { + val jwt = JWT.decode(token) + val verifierToUse: List + val claims: MutableMap try { - String decodedPayload = new String(Base64.getUrlDecoder().decode(jwt.getPayload()), - StandardCharsets.UTF_8); - claims = jsonParser.readValue(decodedPayload); - if (claims.containsKey(EXP) && claims.get(EXP) instanceof Integer) { - Integer intValue = (Integer) claims.get(EXP); - claims.put(EXP, Long.valueOf(intValue)); + val decodedPayload = String( + Base64.getUrlDecoder().decode(jwt.payload), + StandardCharsets.UTF_8 + ) + claims = jsonParser.readValue(decodedPayload) + if (claims.containsKey(AccessTokenConverter.EXP) && claims[AccessTokenConverter.EXP] is Int) { + val intValue = claims[AccessTokenConverter.EXP] as Int? + claims[AccessTokenConverter.EXP] = intValue!! } - if (this.getJwtClaimsSetVerifier() != null) { - this.getJwtClaimsSetVerifier().verify(claims); + if (jwtClaimsSetVerifier != null) { + jwtClaimsSetVerifier!!.verify(claims) } - - verifierToUse = claims.get(ACCESS_TOKEN_ID) != null - ? refreshTokenVerifiers : verifiers; - } catch (JsonProcessingException ex) { - throw new InvalidTokenException("Invalid token", ex); + verifierToUse = + if (claims[JwtAccessTokenConverter.ACCESS_TOKEN_ID] != null) refreshTokenVerifiers else verifiers + } catch (ex: JsonProcessingException) { + throw InvalidTokenException("Invalid token", ex) } - - for (JWTVerifier verifier : verifierToUse) { + for (verifier in verifierToUse) { try { - verifier.verify(token); - return claims; - } catch (SignatureVerificationException sve) { - logger.warn("Client presented a token with an incorrect signature"); - } catch (JWTVerificationException ex) { - logger.debug("Verifier {} with implementation {} did not accept token: {}", - verifier, verifier.getClass(), ex.getMessage()); + verifier.verify(token) + return claims + } catch (sve: SignatureVerificationException) { + logger.warn("Client presented a token with an incorrect signature") + } catch (ex: JWTVerificationException) { + logger.debug( + "Verifier {} with implementation {} did not accept token: {}", + verifier, verifier.javaClass, ex.message + ) } } + throw InvalidTokenException("No registered validator could authenticate this token") + } - throw new InvalidTokenException("No registered validator could authenticate this token"); + companion object { + const val RES_MANAGEMENT_PORTAL = "res_ManagementPortal" + private val logger = LoggerFactory.getLogger(ManagementPortalJwtAccessTokenConverter::class.java) } } diff --git a/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt b/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt index 143b81b1f..6109080b8 100644 --- a/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt +++ b/src/test/java/org/radarbase/management/webapp/CheckTranslationsUnitTest.kt @@ -16,6 +16,7 @@ import java.util.* * test takes one language as the 'ground truth' to check against. That language is currently * configured to be English, but can be changed by changing the `BASE_LANG` field. */ +//TODO reimplement in proper kotlin internal class CheckTranslationsUnitTest { // @Test // fun testLanguages() { From d2778cab9ce535122c506de033e5667974ac41bc Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:41:43 +0200 Subject: [PATCH 093/158] fix some warnings about unused variables, java not compiling anymore now --- .../management/service/SourceService.kt | 92 +++++++++---------- .../decorator/SubjectMapperDecorator.kt | 12 +-- .../web/rest/OAuthClientsResource.kt | 4 +- 3 files changed, 52 insertions(+), 56 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/SourceService.kt b/src/main/java/org/radarbase/management/service/SourceService.kt index a470c0393..2d6465f1c 100644 --- a/src/main/java/org/radarbase/management/service/SourceService.kt +++ b/src/main/java/org/radarbase/management/service/SourceService.kt @@ -27,21 +27,13 @@ import java.util.* */ @Service @Transactional -open class SourceService { - @Autowired - private val sourceRepository: SourceRepository? = null - - @Autowired - private val sourceMapper: SourceMapper? = null - - @Autowired - private val projectRepository: ProjectRepository? = null - - @Autowired - private val sourceTypeMapper: SourceTypeMapper? = null - - @Autowired - private val authService: AuthService? = null +open class SourceService( + @Autowired private val sourceRepository: SourceRepository, + @Autowired private val sourceMapper: SourceMapper, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val sourceTypeMapper: SourceTypeMapper, + @Autowired private val authService: AuthService +) { /** * Save a Source. @@ -51,8 +43,8 @@ open class SourceService { */ fun save(sourceDto: SourceDTO?): SourceDTO { log.debug("Request to save Source : {}", sourceDto) - var source = sourceMapper!!.sourceDTOToSource(sourceDto) - source = sourceRepository!!.save(source) + var source = sourceMapper.sourceDTOToSource(sourceDto) + source = sourceRepository.save(source) return sourceMapper.sourceToSourceDTO(source) } @@ -64,10 +56,10 @@ open class SourceService { @Transactional(readOnly = true) open fun findAll(): List? { return sourceRepository - ?.findAll() - ?.stream() - ?.map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } - ?.toList() + .findAll() + .stream() + .map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } + .toList() } /** @@ -78,10 +70,14 @@ open class SourceService { @Transactional(readOnly = true) open fun findAll(pageable: Pageable?): Page? { log.debug("Request to get SourceData with pagination") + // somehow the compiler does not understand what's going on here, so we suppress the warning + @Suppress("UNNECESSARY_SAFE_CALL") return pageable?.let { - sourceRepository - ?.findAll(it) - ?.map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + it.let { it1 -> + sourceRepository + .findAll(it1) + ?.map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } + } } } @@ -94,8 +90,8 @@ open class SourceService { @Transactional(readOnly = true) open fun findOneByName(sourceName: String?): Optional { log.debug("Request to get Source : {}", sourceName) - return sourceRepository!!.findOneBySourceName(sourceName) - .map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + return sourceRepository.findOneBySourceName(sourceName) + .map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } } /** @@ -107,8 +103,8 @@ open class SourceService { @Transactional(readOnly = true) open fun findOneById(id: Long): Optional { log.debug("Request to get Source by id: {}", id) - return Optional.ofNullable(sourceRepository!!.findById(id).orElse(null)) - .map { source: Source? -> sourceMapper!!.sourceToSourceDTO(source) } + return Optional.ofNullable(sourceRepository.findById(id).orElse(null)) + .map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } } /** @@ -119,7 +115,7 @@ open class SourceService { @Transactional open fun delete(id: Long) { log.info("Request to delete Source : {}", id) - val sourceHistory = sourceRepository!!.findRevisions(id) + val sourceHistory = sourceRepository.findRevisions(id) val sources = sourceHistory.content .map { obj: Revision -> obj.entity } .filter{ it.isAssigned @@ -144,8 +140,8 @@ open class SourceService { * @return list of sources */ fun findAllByProjectId(projectId: Long?, pageable: Pageable?): Page { - return sourceRepository!!.findAllSourcesByProjectId(pageable, projectId) - .map { source: Source? -> sourceMapper!!.sourceToSourceWithoutProjectDTO(source) } + return sourceRepository.findAllSourcesByProjectId(pageable, projectId) + .map { source: Source? -> sourceMapper.sourceToSourceWithoutProjectDTO(source) } } /** @@ -157,16 +153,16 @@ open class SourceService { projectId: Long?, pageable: Pageable? ): Page { - return sourceRepository!!.findAllSourcesByProjectId(pageable, projectId) - .map { source: Source? -> sourceMapper!!.sourceToMinimalSourceDetailsDTO(source) } + return sourceRepository.findAllSourcesByProjectId(pageable, projectId) + .map { source: Source? -> sourceMapper.sourceToMinimalSourceDetailsDTO(source) } } /** * Returns list of not-assigned sources by project id. */ fun findAllByProjectAndAssigned(projectId: Long?, assigned: Boolean): List { - return sourceMapper!!.sourcesToSourceDTOs( - sourceRepository!!.findAllSourcesByProjectIdAndAssigned(projectId, assigned) + return sourceMapper.sourcesToSourceDTOs( + sourceRepository.findAllSourcesByProjectIdAndAssigned(projectId, assigned) ) } @@ -177,8 +173,8 @@ open class SourceService { projectId: Long?, assigned: Boolean ): List { return sourceRepository - ?.findAllSourcesByProjectIdAndAssigned(projectId, assigned) - ?.map { source -> sourceMapper!!.sourceToMinimalSourceDetailsDTO(source) } + .findAllSourcesByProjectIdAndAssigned(projectId, assigned) + ?.map { source -> sourceMapper.sourceToMinimalSourceDetailsDTO(source) } ?.toList() ?: listOf() } @@ -202,7 +198,7 @@ open class SourceService { updatedAttributes.putAll(attributes!!) sourceToUpdate.attributes = updatedAttributes // rest of the properties should not be updated from this request. - return sourceMapper!!.sourceToMinimalSourceDetailsDTO(sourceRepository!!.save(sourceToUpdate)) + return sourceMapper.sourceToMinimalSourceDetailsDTO(sourceRepository.save(sourceToUpdate)) } /** @@ -215,21 +211,21 @@ open class SourceService { */ @Transactional @Throws(NotAuthorizedException::class) - open fun updateSource(sourceDto: SourceDTO): Optional { - val existingSourceOpt = sourceRepository!!.findById(sourceDto.id) + open fun updateSource(sourceDto: SourceDTO): SourceDTO? { + val existingSourceOpt = sourceRepository.findById(sourceDto.id) if (existingSourceOpt.isEmpty) { - return Optional.empty() + return null } val existingSource = existingSourceOpt.get() - authService!!.checkPermission(Permission.SOURCE_UPDATE, { (_, project, subject, _, source): EntityDetails -> - source + authService.checkPermission(Permission.SOURCE_UPDATE, { e: EntityDetails -> + e.source = existingSource.sourceName if (existingSource.project != null) { - project + e.project = existingSource.project?.projectName } if (existingSource.subject != null && existingSource.subject!!.user != null ) { - subject + e.subject = existingSource.subject?.user?.login } }) @@ -245,7 +241,7 @@ open class SourceService { // check whether source-type of the device is assigned to the new project // to be transferred. val sourceType = projectRepository - ?.findSourceTypeByProjectIdAndSourceTypeId( + .findSourceTypeByProjectIdAndSourceTypeId( sourceDto.project.id, existingSource.sourceType!!.id ) @@ -256,9 +252,9 @@ open class SourceService { ) } // set old source-type, ensures compatibility - sourceDto.sourceType = sourceTypeMapper!!.sourceTypeToSourceTypeDTO(existingSource.sourceType) + sourceDto.sourceType = sourceTypeMapper.sourceTypeToSourceTypeDTO(existingSource.sourceType) } - return Optional.of(save(sourceDto)) + return save(sourceDto) } companion object { diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt index b48f35bfc..3317d9b05 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt @@ -33,8 +33,8 @@ abstract class SubjectMapperDecorator( } val dto = subjectToSubjectWithoutProjectDTO(subject) val project = subject.activeProject - .let { p -> projectRepository!!.findOneWithEagerRelationships(p?.id) } - dto!!.project = projectMapper!!.projectToProjectDTO(project) + .let { p -> projectRepository.findOneWithEagerRelationships(p?.id) } + dto!!.project = projectMapper.projectToProjectDTO(project) addAuditInfo(subject, dto) return dto } @@ -44,13 +44,13 @@ abstract class SubjectMapperDecorator( return null } val dto = subjectToSubjectWithoutProjectDTO(subject) - subject.activeProject?.let { project -> dto!!.project = projectMapper!!.projectToProjectDTOReduced(project) } + subject.activeProject?.let { project -> dto!!.project = projectMapper.projectToProjectDTOReduced(project) } addAuditInfo(subject, dto) return dto } private fun addAuditInfo(subject: Subject, dto: SubjectDTO?) { - val auditInfo = revisionService!!.getAuditInfo(subject) + val auditInfo = revisionService.getAuditInfo(subject) dto!!.createdDate = auditInfo.createdAt dto.createdBy = auditInfo.createdBy dto.lastModifiedDate = auditInfo.lastModifiedAt @@ -61,7 +61,7 @@ abstract class SubjectMapperDecorator( if (subject == null) { return null } - val dto = delegate!!.subjectToSubjectWithoutProjectDTO(subject) + val dto = delegate.subjectToSubjectWithoutProjectDTO(subject) dto!!.status = getSubjectStatus(subject) return dto } @@ -70,7 +70,7 @@ abstract class SubjectMapperDecorator( if (subjectDto == null) { return null } - val subject = delegate!!.subjectDTOToSubject(subjectDto) + val subject = delegate.subjectDTOToSubject(subjectDto) setSubjectStatus(subjectDto, subject) subject!!.group = getGroup(subjectDto) return subject diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt index aecb4af9a..efd23ea2e 100644 --- a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt @@ -210,7 +210,7 @@ class OAuthClientsResource { // lookup the subject val subject = subjectService!!.findOneByLogin(login) - val project: String = subject.activeProject + val projectName: String = subject.activeProject ?.projectName ?: throw NotFoundException( "Project for subject $login not found", EntityName.SUBJECT, @@ -221,7 +221,7 @@ class OAuthClientsResource { // Users who can update a subject can also generate a refresh token for that subject authService.checkPermission( Permission.SUBJECT_UPDATE, - { e: EntityDetails -> e.subject(login) }) + { e: EntityDetails -> e.project(projectName).subject(login) }) val cpi = metaTokenService!!.createMetaToken(subject, clientId, persistent!!) // generate audit event eventRepository!!.add( From 05e70f81cf6cbc779df9914151feda4a11d19249 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:55:35 +0200 Subject: [PATCH 094/158] Rename .java to .kt --- .../web/rest/{SourceResource.java => SourceResource.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/web/rest/{SourceResource.java => SourceResource.kt} (100%) diff --git a/src/main/java/org/radarbase/management/web/rest/SourceResource.java b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/SourceResource.java rename to src/main/java/org/radarbase/management/web/rest/SourceResource.kt From 5a3c0449e02be1ed3a709ca321c1975063ab06fc Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 27 Oct 2023 11:55:37 +0200 Subject: [PATCH 095/158] compiling again, but still some java classes --- .../org/radarbase/management/domain/Source.kt | 16 +- .../management/web/rest/SourceResource.kt | 325 ++++++++++-------- .../web/rest/SourceResourceIntTest.kt | 2 +- 3 files changed, 182 insertions(+), 161 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Source.kt b/src/main/java/org/radarbase/management/domain/Source.kt index 7e308f5f9..241f4a5b4 100644 --- a/src/main/java/org/radarbase/management/domain/Source.kt +++ b/src/main/java/org/radarbase/management/domain/Source.kt @@ -58,10 +58,10 @@ class Source : AbstractEntity, Serializable { var expectedSourceName: String? = null @Column(name = "assigned", nullable = false) - var isAssigned: @NotNull Boolean? = null + var isAssigned: @NotNull Boolean? = false @Column(name = "deleted", nullable = false) - var isDeleted: @NotNull Boolean? = false + var isDeleted: @NotNull Boolean = false @JvmField @ManyToOne(fetch = FetchType.EAGER) @@ -125,12 +125,12 @@ class Source : AbstractEntity, Serializable { } } - fun assigned(assigned: Boolean?): Source { + fun assigned(assigned: Boolean): Source { isAssigned = assigned return this } - fun deleted(deleted: Boolean?): Source { + fun deleted(deleted: Boolean): Source { isDeleted = deleted return this } @@ -155,14 +155,14 @@ class Source : AbstractEntity, Serializable { return this } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val source = o as Source + val source = other as Source return if (source.id == null || id == null) { false } else id == source.id && sourceId == source.sourceId diff --git a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt index 9841f7cd1..e00a6714e 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt @@ -1,107 +1,107 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.domain.Source; -import org.radarbase.management.repository.SourceRepository; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.SourceService; -import org.radarbase.management.service.dto.MinimalProjectDetailsDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.history.Revision; -import org.springframework.data.history.Revisions; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.List; -import java.util.Optional; - -import static org.radarbase.auth.authorization.Permission.SOURCE_CREATE; -import static org.radarbase.auth.authorization.Permission.SOURCE_DELETE; -import static org.radarbase.auth.authorization.Permission.SOURCE_READ; -import static org.radarbase.auth.authorization.Permission.SOURCE_UPDATE; -import static org.radarbase.auth.authorization.Permission.SUBJECT_READ; -import static tech.jhipster.web.util.ResponseUtil.wrapOrNotFound; +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.Source +import org.radarbase.management.repository.SourceRepository +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ResourceUriService +import org.radarbase.management.service.SourceService +import org.radarbase.management.service.dto.SourceDTO +import org.radarbase.management.web.rest.util.HeaderUtil +import org.radarbase.management.web.rest.util.PaginationUtil +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Pageable +import org.springframework.data.history.Revision +import org.springframework.data.web.PageableDefault +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.net.URISyntaxException +import java.util.* +import javax.validation.Valid /** * REST controller for managing Source. */ @RestController @RequestMapping("/api") -public class SourceResource { - - private static final Logger log = LoggerFactory.getLogger(SourceResource.class); - - private static final String ENTITY_NAME = "source"; - - @Autowired - private SourceService sourceService; - - @Autowired - private SourceRepository sourceRepository; - - @Autowired - private AuthService authService; +class SourceResource( + @Autowired private val sourceService: SourceService, + @Autowired private val sourceRepository: SourceRepository, + @Autowired private val authService: AuthService +) { /** * POST /sources : Create a new source. * * @param sourceDto the sourceDto to create * @return the ResponseEntity with status 201 (Created) and with body the new sourceDto, or with - * status 400 (Bad Request) if the source has already an ID + * status 400 (Bad Request) if the source has already an ID * @throws URISyntaxException if the Location URI syntax is incorrect */ @PostMapping("/sources") @Timed - public ResponseEntity createSource(@Valid @RequestBody SourceDTO sourceDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save Source : {}", sourceDto); - MinimalProjectDetailsDTO project = sourceDto.getProject(); - authService.checkPermission(SOURCE_CREATE, e -> { + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createSource(@RequestBody sourceDto: @Valid SourceDTO?): ResponseEntity { + log.debug("REST request to save Source : {}", sourceDto) + val project = sourceDto!!.project + authService.checkPermission(Permission.SOURCE_CREATE, { (_, project1): EntityDetails -> if (project != null) { - e.project(project.getProjectName()); + project1 } - }); - if (sourceDto.getId() != null) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, - "idexists", "A new source cannot already have an ID")).build(); - } else if (sourceDto.getSourceId() != null) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, - "sourceIdExists", "A new source cannot already have a Source ID")).build(); - } else if (sourceRepository.findOneBySourceName(sourceDto.getSourceName()).isPresent()) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, - "sourceNameExists", "Source name already in use")).build(); - } else if (sourceDto.getAssigned() == null) { - return ResponseEntity.badRequest() - .headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "sourceAssignedRequired", - "A new source must have the 'assigned' field specified")).body(null); + }) + return if (sourceDto.id != null) { + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, + "idexists", "A new source cannot already have an ID" + ) + ).build() + } else if (sourceDto.sourceId != null) { + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, + "sourceIdExists", "A new source cannot already have a Source ID" + ) + ).build() + } else if (sourceRepository.findOneBySourceName(sourceDto.sourceName).isPresent) { + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, + "sourceNameExists", "Source name already in use" + ) + ).build() + } else if (sourceDto.assigned == null) { + ResponseEntity.badRequest() + .headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, "sourceAssignedRequired", + "A new source must have the 'assigned' field specified" + ) + ).body(null) } else { - SourceDTO result = sourceService.save(sourceDto); - return ResponseEntity.created(ResourceUriService.getUri(result)) - .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, - result.getSourceName())) - .body(result); + val result = sourceService.save(sourceDto) + ResponseEntity.created(ResourceUriService.getUri(result)) + .headers( + HeaderUtil.createEntityCreationAlert( + ENTITY_NAME, + result.sourceName + ) + ) + .body(result) } } @@ -110,27 +110,30 @@ public class SourceResource { * * @param sourceDto the sourceDto to update * @return the ResponseEntity with status 200 (OK) and with body the updated sourceDto, or with - * status 400 (Bad Request) if the sourceDto is not valid, or with status 500 (Internal - * Server Error) if the sourceDto couldnt be updated + * status 400 (Bad Request) if the sourceDto is not valid, or with status 500 (Internal + * Server Error) if the sourceDto couldnt be updated * @throws URISyntaxException if the Location URI syntax is incorrect */ @PutMapping("/sources") @Timed - public ResponseEntity updateSource(@Valid @RequestBody SourceDTO sourceDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update Source : {}", sourceDto); - if (sourceDto.getId() == null) { - return createSource(sourceDto); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun updateSource(@RequestBody sourceDto: @Valid SourceDTO?): ResponseEntity { + log.debug("REST request to update Source : {}", sourceDto) + if (sourceDto!!.id == null) { + return createSource(sourceDto) } - MinimalProjectDetailsDTO project = sourceDto.getProject(); - authService.checkPermission(SOURCE_UPDATE, e -> { + val project = sourceDto.project + authService.checkPermission(Permission.SOURCE_UPDATE, { (_, project1): EntityDetails -> if (project != null) { - e.project(project.getProjectName()); + project1 } - }); - Optional updatedSource = sourceService.updateSource(sourceDto); - return wrapOrNotFound(updatedSource, - HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, sourceDto.getSourceName())); + }) + val updatedSource: SourceDTO? = sourceService.updateSource(sourceDto) + return ResponseEntity.ok().headers( + HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, sourceDto.sourceName) + ).body( + updatedSource + ) } /** @@ -140,15 +143,16 @@ public class SourceResource { */ @GetMapping("/sources") @Timed - public ResponseEntity> getAllSources( - @PageableDefault(page = 0, size = Integer.MAX_VALUE) Pageable pageable) - throws NotAuthorizedException { - authService.checkPermission(SUBJECT_READ); - log.debug("REST request to get all Sources"); - Page page = sourceService.findAll(pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/api/sources"); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + @Throws(NotAuthorizedException::class) + fun getAllSources( + @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable? + ): ResponseEntity> { + authService.checkPermission(Permission.SUBJECT_READ) + log.debug("REST request to get all Sources") + val page = sourceService.findAll(pageable) + val headers = PaginationUtil + .generatePaginationHttpHeaders(page, "/api/sources") + return ResponseEntity(page!!.content, headers, HttpStatus.OK) } /** @@ -156,26 +160,28 @@ public class SourceResource { * * @param sourceName the name of the sourceDTO to retrieve * @return the ResponseEntity with status 200 (OK) and with body the sourceDTO, or with status - * 404 (Not Found) + * 404 (Not Found) */ @GetMapping("/sources/{sourceName:" + Constants.ENTITY_ID_REGEX + "}") @Timed - public ResponseEntity getSource(@PathVariable String sourceName) - throws NotAuthorizedException { - log.debug("REST request to get Source : {}", sourceName); - authService.checkScope(SOURCE_READ); - Optional sourceOpt = sourceService.findOneByName(sourceName); - if (sourceOpt.isPresent()) { - SourceDTO source = sourceOpt.get(); - authService.checkPermission(SOURCE_READ, e -> { - if (source.getProject() != null) { - e.project(source.getProject().getProjectName()); + @Throws( + NotAuthorizedException::class + ) + fun getSource(@PathVariable sourceName: String?): ResponseEntity { + log.debug("REST request to get Source : {}", sourceName) + authService.checkScope(Permission.SOURCE_READ) + val sourceOpt = sourceService.findOneByName(sourceName) + if (sourceOpt.isPresent) { + val source = sourceOpt.get() + authService.checkPermission(Permission.SOURCE_READ, { (_, project, subject): EntityDetails -> + if (source.project != null) { + project } - e.subject(source.getSubjectLogin()) - .source(source.getSourceName()); - }); + subject + //.source(source.sourceName) + }) } - return wrapOrNotFound(sourceOpt); + return ResponseUtil.wrapOrNotFound(sourceOpt) } /** @@ -186,39 +192,54 @@ public class SourceResource { */ @DeleteMapping("/sources/{sourceName:" + Constants.ENTITY_ID_REGEX + "}") @Timed - public ResponseEntity deleteSource(@PathVariable String sourceName) - throws NotAuthorizedException { - log.debug("REST request to delete Source : {}", sourceName); - authService.checkScope(SOURCE_DELETE); - Optional sourceDtoOpt = sourceService.findOneByName(sourceName); - if (sourceDtoOpt.isEmpty()) { - return ResponseEntity.notFound().build(); + @Throws( + NotAuthorizedException::class + ) + fun deleteSource(@PathVariable sourceName: String?): ResponseEntity { + log.debug("REST request to delete Source : {}", sourceName) + authService.checkScope(Permission.SOURCE_DELETE) + val sourceDtoOpt = sourceService.findOneByName(sourceName) + if (sourceDtoOpt.isEmpty) { + return ResponseEntity.notFound().build() } - SourceDTO sourceDto = sourceDtoOpt.get(); - authService.checkPermission(SOURCE_DELETE, e -> { - if (sourceDto.getProject() != null) { - e.project(sourceDto.getProject().getProjectName()); + val sourceDto = sourceDtoOpt.get() + authService.checkPermission(Permission.SOURCE_DELETE, { (_, project, subject): EntityDetails -> + if (sourceDto.project != null) { + project } - e.subject(sourceDto.getSubjectLogin()) - .source(sourceDto.getSourceName()); - }); - - if (sourceDto.getAssigned()) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, - "sourceIsAssigned", "Cannot delete an assigned source")).build(); + subject + //.source(sourceDto.sourceName) + }) + if (sourceDto.assigned) { + return ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, + "sourceIsAssigned", "Cannot delete an assigned source" + ) + ).build() } - Long sourceId = sourceDtoOpt.get().getId(); - Revisions sourceHistory = sourceRepository.findRevisions(sourceId); - List sources = sourceHistory.getContent().stream().map(Revision::getEntity) - .filter(Source::isAssigned).toList(); - if (!sources.isEmpty()) { - HttpHeaders failureAlert = HeaderUtil.createFailureAlert(ENTITY_NAME, - "sourceRevisionIsAssigned", "Cannot delete a previously assigned source"); - return ResponseEntity.status(HttpStatus.CONFLICT).headers(failureAlert).build(); + val sourceId = sourceDtoOpt.get().id + val sourceHistory = sourceRepository.findRevisions(sourceId) + val sources = sourceHistory.content.mapNotNull { obj: Revision -> obj.entity } + .filter { it.isAssigned == true }.toList() + if (sources.isNotEmpty()) { + val failureAlert = HeaderUtil.createFailureAlert( + ENTITY_NAME, + "sourceRevisionIsAssigned", "Cannot delete a previously assigned source" + ) + return ResponseEntity.status(HttpStatus.CONFLICT).headers(failureAlert).build() } - sourceService.delete(sourceId); - return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, - sourceName)).build(); + sourceService.delete(sourceId) + return ResponseEntity.ok().headers( + HeaderUtil.createEntityDeletionAlert( + ENTITY_NAME, + sourceName + ) + ).build() } + companion object { + private val log = LoggerFactory.getLogger(SourceResource::class.java) + private const val ENTITY_NAME = "source" + } } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt index 936f9d6b9..04f5133ef 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt @@ -65,7 +65,7 @@ internal open class SourceResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val sourceResource = SourceResource() + val sourceResource = SourceResource ReflectionTestUtils.setField(sourceResource, "authService", authService) ReflectionTestUtils.setField(sourceResource, "sourceService", sourceService) ReflectionTestUtils.setField(sourceResource, "sourceRepository", sourceRepository) From 98b160f12ee74efb2a71db786ebe4cb7f865aeb1 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 30 Oct 2023 17:05:58 +0100 Subject: [PATCH 096/158] Rename .java to .kt --- .../rest/{OrganizationResource.java => OrganizationResource.kt} | 0 .../web/rest/{RevisionResource.java => RevisionResource.kt} | 0 .../web/rest/{SourceDataResource.java => SourceDataResource.kt} | 0 .../web/rest/{SourceTypeResource.java => SourceTypeResource.kt} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/web/rest/{OrganizationResource.java => OrganizationResource.kt} (100%) rename src/main/java/org/radarbase/management/web/rest/{RevisionResource.java => RevisionResource.kt} (100%) rename src/main/java/org/radarbase/management/web/rest/{SourceDataResource.java => SourceDataResource.kt} (100%) rename src/main/java/org/radarbase/management/web/rest/{SourceTypeResource.java => SourceTypeResource.kt} (100%) diff --git a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.java b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/OrganizationResource.java rename to src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt diff --git a/src/main/java/org/radarbase/management/web/rest/RevisionResource.java b/src/main/java/org/radarbase/management/web/rest/RevisionResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/RevisionResource.java rename to src/main/java/org/radarbase/management/web/rest/RevisionResource.kt diff --git a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.java b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/SourceDataResource.java rename to src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt diff --git a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.java b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/SourceTypeResource.java rename to src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt From d7eaf525d24e9b54964ee897ab6992a53a09dec0 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 30 Oct 2023 17:06:00 +0100 Subject: [PATCH 097/158] main compiles, test does not --- .../config/OAuth2ServerConfiguration.kt | 65 ++-- .../org/radarbase/management/domain/Group.kt | 8 +- .../radarbase/management/domain/Project.kt | 4 +- .../org/radarbase/management/domain/User.kt | 2 +- .../filters/CustomHttpServletRequest.java | 35 -- .../filters/CustomHttpServletRequest.kt | 23 ++ .../CaseSensitivePhysicalNamingStrategy.java | 12 - .../CaseSensitivePhysicalNamingStrategy.kt | 10 + .../repository/AuthorityRepository.java | 21 -- .../repository/AuthorityRepository.kt | 17 + .../CustomAuditEventRepository.java | 75 ---- .../repository/CustomAuditEventRepository.kt | 71 ++++ .../CustomRevisionEntityRepository.java | 8 - .../CustomRevisionEntityRepository.kt | 6 + .../repository/MetaTokenRepository.java | 25 -- .../repository/MetaTokenRepository.kt | 22 ++ .../repository/OrganizationRepository.java | 29 -- .../repository/OrganizationRepository.kt | 28 ++ .../PersistenceAuditEventRepository.java | 27 -- .../PersistenceAuditEventRepository.kt | 28 ++ .../repository/ProjectRepository.kt | 25 +- .../management/repository/RoleRepository.java | 49 --- .../management/repository/RoleRepository.kt | 60 ++++ .../repository/SourceDataRepository.java | 18 - .../repository/SourceDataRepository.kt | 15 + .../repository/SourceRepository.java | 64 ---- .../management/repository/SourceRepository.kt | 65 ++++ .../repository/SourceTypeRepository.java | 56 --- .../repository/SourceTypeRepository.kt | 69 ++++ .../repository/SubjectRepository.java | 106 ------ .../repository/SubjectRepository.kt | 128 +++++++ .../management/repository/UserRepository.java | 48 --- .../management/repository/UserRepository.kt | 43 +++ .../repository/filters/PredicateBuilder.java | 197 ----------- .../repository/filters/PredicateBuilder.kt | 199 +++++++++++ .../filters/SubjectSpecification.java | 203 ----------- .../filters/SubjectSpecification.kt | 196 +++++++++++ .../repository/filters/UserFilter.java | 222 ------------ .../repository/filters/UserFilter.kt | 179 ++++++++++ .../management/repository/package-info.java | 4 - .../management/repository/package-info.kt | 5 + .../security/ClaimsTokenEnhancer.java | 151 -------- .../security/ClaimsTokenEnhancer.kt | 132 +++++++ .../management/security/Constants.java | 16 - .../management/security/Constants.kt | 12 + .../security/DomainUserDetailsService.java | 56 --- .../security/DomainUserDetailsService.kt | 47 +++ ....java => Http401UnauthorizedEntryPoint.kt} | 37 +- .../security/JwtAuthenticationFilter.kt | 13 +- .../security/PostgresApprovalStore.java | 222 ------------ .../security/PostgresApprovalStore.kt | 203 +++++++++++ .../security/RadarAuthentication.java | 112 ------ .../security/RadarAuthentication.kt | 92 +++++ .../security/RadarAuthenticationProvider.java | 30 -- .../security/RadarAuthenticationProvider.kt | 26 ++ .../management/security/SecurityUtils.java | 48 --- .../management/security/SecurityUtils.kt | 51 +++ .../security/UserNotActivatedException.java | 19 - .../security/UserNotActivatedException.kt | 15 + ...verter.java => JwtAccessTokenConverter.kt} | 48 ++- ...ManagementPortalJwtAccessTokenConverter.kt | 4 +- .../jwt/ManagementPortalJwtTokenStore.java | 198 ----------- .../jwt/ManagementPortalJwtTokenStore.kt | 189 ++++++++++ .../ManagementPortalOauthKeyStoreHandler.java | 324 ----------------- .../ManagementPortalOauthKeyStoreHandler.kt | 289 +++++++++++++++ .../security/jwt/SignatureException.java | 20 -- .../security/jwt/SignatureException.kt | 8 + .../jwt/algorithm/AsymmetricalJwtAlgorithm.kt | 24 ++ .../jwt/algorithm/EcdsaJwtAlgorithm.kt | 25 ++ .../security/jwt/algorithm/JwtAlgorithm.kt | 25 ++ .../security/jwt/algorithm/RsaJwtAlgorithm.kt | 25 ++ .../management/security/package-info.java | 4 - .../management/security/package-info.kt | 5 + .../management/service/AuditEventService.java | 57 --- .../management/service/AuditEventService.kt | 64 ++++ .../management/service/GroupService.kt | 114 +++--- .../management/service/MailService.java | 147 -------- .../management/service/MailService.kt | 157 +++++++++ .../management/service/MetaTokenService.kt | 13 +- .../service/OAuthClientService.java | 188 ---------- .../management/service/OAuthClientService.kt | 179 ++++++++++ .../service/OrganizationService.java | 134 ------- .../management/service/OrganizationService.kt | 110 ++++++ .../management/service/PasswordService.java | 107 ------ .../management/service/PasswordService.kt | 111 ++++++ .../management/service/ProjectService.kt | 53 +-- .../service/ResourceUriService.java | 150 -------- .../management/service/ResourceUriService.kt | 164 +++++++++ .../management/service/RevisionService.kt | 4 +- .../management/service/RoleService.kt | 131 +++---- .../service/SiteSettingsService.java | 37 -- .../management/service/SiteSettingsService.kt | 33 ++ .../management/service/SourceDataService.java | 119 ------- .../management/service/SourceDataService.kt | 109 ++++++ .../management/service/SourceService.kt | 49 ++- .../management/service/SourceTypeService.java | 242 ------------- .../management/service/SourceTypeService.kt | 245 +++++++++++++ .../management/service/SubjectService.kt | 155 ++++---- .../management/service/UserService.kt | 184 +++++----- .../service/catalog/CatalogSourceData.java | 139 -------- .../service/catalog/CatalogSourceData.kt | 61 ++++ .../service/catalog/CatalogSourceType.java | 112 ------ .../service/catalog/CatalogSourceType.kt | 58 +++ .../service/catalog/SampleRateConfig.java | 45 --- .../service/catalog/SampleRateConfig.kt | 26 ++ .../service/catalog/SourceTypeResponse.java | 37 -- .../service/catalog/SourceTypeResponse.kt | 19 + .../service/dto/AttributeMapDTO.java | 65 ---- .../management/service/dto/AttributeMapDTO.kt | 31 ++ .../management/service/dto/AuthorityDTO.java | 33 -- .../management/service/dto/AuthorityDTO.kt | 14 + .../service/dto/ClientDetailsDTO.java | 112 ------ .../service/dto/ClientDetailsDTO.kt | 20 ++ .../service/dto/ClientPairInfoDTO.java | 92 ----- .../service/dto/ClientPairInfoDTO.kt | 56 +++ .../management/service/dto/GroupDTO.java | 75 ---- .../management/service/dto/GroupDTO.kt | 38 ++ .../service/dto/MinimalProjectDetailsDTO.java | 27 -- .../service/dto/MinimalProjectDetailsDTO.kt | 9 + .../service/dto/MinimalSourceDetailsDTO.java | 163 --------- .../service/dto/MinimalSourceDetailsDTO.kt | 83 +++++ .../service/dto/MinimalSourceTypeDTO.java | 47 --- .../service/dto/MinimalSourceTypeDTO.kt | 11 + .../service/dto/OrganizationDTO.java | 99 ------ .../management/service/dto/OrganizationDTO.kt | 45 +++ .../management/service/dto/ProjectDTO.java | 209 ----------- .../management/service/dto/ProjectDTO.kt | 73 ++++ .../management/service/dto/RevisionDTO.java | 78 ----- .../management/service/dto/RevisionDTO.kt | 60 ++++ .../service/dto/RevisionInfoDTO.java | 89 ----- .../management/service/dto/RevisionInfoDTO.kt | 52 +++ .../management/service/dto/RoleDTO.java | 104 ------ .../management/service/dto/RoleDTO.kt | 38 ++ .../service/dto/SiteSettingsDto.java | 50 --- .../management/service/dto/SiteSettingsDto.kt | 33 ++ .../management/service/dto/SourceDTO.java | 152 -------- .../management/service/dto/SourceDTO.kt | 56 +++ .../management/service/dto/SourceDataDTO.java | 195 ----------- .../management/service/dto/SourceDataDTO.kt | 74 ++++ .../management/service/dto/SourceTypeDTO.java | 177 ---------- .../management/service/dto/SourceTypeDTO.kt | 64 ++++ .../management/service/dto/SubjectDTO.java | 256 -------------- .../management/service/dto/SubjectDTO.kt | 96 +++++ .../management/service/dto/TokenDTO.java | 66 ---- .../management/service/dto/TokenDTO.kt | 37 ++ .../management/service/dto/UserDTO.java | 177 ---------- .../management/service/dto/UserDTO.kt | 40 +++ .../management/service/dto/package-info.java | 6 - .../management/service/dto/package-info.kt | 8 + ...Mapper.java => CatalogSourceDataMapper.kt} | 22 +- ...Mapper.java => CatalogSourceTypeMapper.kt} | 19 +- .../service/mapper/ClientDetailsMapper.java | 80 ----- .../service/mapper/ClientDetailsMapper.kt | 72 ++++ .../{GroupMapper.java => GroupMapper.kt} | 32 +- .../service/mapper/OrganizationMapper.java | 30 -- .../service/mapper/OrganizationMapper.kt | 28 ++ .../service/mapper/ProjectMapper.java | 66 ---- .../service/mapper/ProjectMapper.kt | 66 ++++ .../mapper/{RoleMapper.java => RoleMapper.kt} | 35 +- .../service/mapper/SourceDataMapper.java | 49 --- .../service/mapper/SourceDataMapper.kt | 43 +++ .../service/mapper/SourceMapper.java | 51 --- .../management/service/mapper/SourceMapper.kt | 49 +++ .../service/mapper/SourceTypeMapper.java | 77 ---- .../service/mapper/SourceTypeMapper.kt | 69 ++++ .../ClientDetailsMapperDecorator.java | 44 --- .../decorator/ClientDetailsMapperDecorator.kt | 36 ++ .../decorator/ProjectMapperDecorator.java | 102 ------ .../decorator/ProjectMapperDecorator.kt | 77 ++++ .../mapper/decorator/RoleMapperDecorator.java | 41 --- .../mapper/decorator/RoleMapperDecorator.kt | 36 ++ .../decorator/SourceMapperDecorator.java | 66 ---- .../mapper/decorator/SourceMapperDecorator.kt | 61 ++++ .../decorator/SubjectMapperDecorator.kt | 22 +- .../mapper/decorator/UserMapperDecorator.java | 36 -- .../mapper/decorator/UserMapperDecorator.kt | 29 ++ .../{package-info.java => package-info.kt} | 3 +- .../management/service/package-info.java | 4 - .../management/service/package-info.kt | 5 + .../management/web/rest/AccountResource.java | 233 ------------- .../management/web/rest/AccountResource.kt | 234 +++++++++++++ .../management/web/rest/AuditResource.java | 90 ----- .../management/web/rest/AuditResource.kt | 77 ++++ .../management/web/rest/GroupResource.java | 156 --------- .../management/web/rest/GroupResource.kt | 160 +++++++++ .../management/web/rest/LogsResource.java | 54 --- .../management/web/rest/LogsResource.kt | 53 +++ .../web/rest/OAuthClientsResource.kt | 6 +- .../web/rest/OrganizationResource.kt | 232 ++++++------ .../management/web/rest/ProjectResource.kt | 59 ++-- .../management/web/rest/RevisionResource.kt | 71 ++-- .../management/web/rest/RoleResource.java | 160 --------- .../management/web/rest/RoleResource.kt | 174 +++++++++ .../management/web/rest/SourceDataResource.kt | 210 +++++------ .../management/web/rest/SourceResource.kt | 109 +++--- .../management/web/rest/SourceTypeResource.kt | 330 ++++++++++-------- .../management/web/rest/SubjectResource.kt | 74 ++-- .../management/web/rest/UserResource.kt | 33 +- .../web/rest/criteria/CriteriaRange.java | 72 ---- .../web/rest/criteria/CriteriaRange.kt | 41 +++ ...iaRange.java => LocalDateCriteriaRange.kt} | 8 +- ...jectAuthority.java => SubjectAuthority.kt} | 7 +- .../web/rest/criteria/SubjectCriteria.java | 238 ------------- .../web/rest/criteria/SubjectCriteria.kt | 125 +++++++ .../rest/criteria/SubjectCriteriaLast.java | 49 --- .../web/rest/criteria/SubjectCriteriaLast.kt | 16 + .../web/rest/criteria/SubjectSortBy.java | 34 -- .../web/rest/criteria/SubjectSortBy.kt | 21 ++ .../web/rest/criteria/SubjectSortOrder.java | 68 ---- .../web/rest/criteria/SubjectSortOrder.kt | 38 ++ ...nge.java => ZonedDateTimeCriteriaRange.kt} | 8 +- .../web/rest/errors/BadRequestException.java | 38 -- .../web/rest/errors/BadRequestException.kt | 38 ++ .../web/rest/errors/ConflictException.java | 44 --- .../web/rest/errors/ConflictException.kt | 44 +++ .../web/rest/errors/EntityName.java | 17 - .../management/web/rest/errors/EntityName.kt | 17 + .../web/rest/errors/ErrorConstants.java | 48 --- .../web/rest/errors/ErrorConstants.kt | 42 +++ .../management/web/rest/errors/ErrorVM.java | 52 --- .../management/web/rest/errors/ErrorVM.kt | 31 ++ .../web/rest/errors/ExceptionTranslator.java | 209 ----------- .../web/rest/errors/ExceptionTranslator.kt | 224 ++++++++++++ .../web/rest/errors/FieldErrorVM.java | 39 --- .../web/rest/errors/FieldErrorVM.kt | 16 + .../rest/errors/InvalidRequestException.java | 37 -- .../rest/errors/InvalidRequestException.kt | 36 ++ .../rest/errors/InvalidStateException.java | 36 -- .../web/rest/errors/InvalidStateException.kt | 35 ++ .../web/rest/errors/NotFoundException.java | 39 --- .../web/rest/errors/NotFoundException.kt | 40 +++ .../errors/RadarWebApplicationException.java | 87 ----- .../errors/RadarWebApplicationException.kt | 60 ++++ .../RadarWebApplicationExceptionVM.java | 98 ------ .../errors/RadarWebApplicationExceptionVM.kt | 63 ++++ .../web/rest/errors/RequestGoneException.java | 38 -- .../web/rest/errors/RequestGoneException.kt | 37 ++ .../management/web/rest/package-info.java | 4 - .../management/web/rest/package-info.kt | 5 + .../management/web/rest/util/HeaderUtil.java | 105 ------ .../management/web/rest/util/HeaderUtil.kt | 103 ++++++ .../web/rest/util/PaginationUtil.java | 139 -------- .../web/rest/util/PaginationUtil.kt | 151 ++++++++ .../web/rest/vm/GroupPatchOperation.kt | 19 + .../web/rest/vm/KeyAndPasswordVM.kt | 9 + .../management/web/rest/vm/LoggerVM.kt | 27 ++ .../management/web/rest/vm/ManagedUserVM.kt | 19 + .../management/web/rest/vm/package-info.kt | 5 + 248 files changed, 8214 insertions(+), 10127 deletions(-) delete mode 100644 src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.java create mode 100644 src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.kt delete mode 100644 src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.java create mode 100644 src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.kt delete mode 100644 src/main/java/org/radarbase/management/repository/AuthorityRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/AuthorityRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/MetaTokenRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/MetaTokenRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/OrganizationRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/OrganizationRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/RoleRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/RoleRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/SourceDataRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/SourceDataRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/SourceRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/SourceRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/SourceTypeRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/SourceTypeRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/SubjectRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/SubjectRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/UserRepository.java create mode 100644 src/main/java/org/radarbase/management/repository/UserRepository.kt delete mode 100644 src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.java create mode 100644 src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt delete mode 100644 src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.java create mode 100644 src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt delete mode 100644 src/main/java/org/radarbase/management/repository/filters/UserFilter.java create mode 100644 src/main/java/org/radarbase/management/repository/filters/UserFilter.kt delete mode 100644 src/main/java/org/radarbase/management/repository/package-info.java create mode 100644 src/main/java/org/radarbase/management/repository/package-info.kt delete mode 100644 src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java create mode 100644 src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt delete mode 100644 src/main/java/org/radarbase/management/security/Constants.java create mode 100644 src/main/java/org/radarbase/management/security/Constants.kt delete mode 100644 src/main/java/org/radarbase/management/security/DomainUserDetailsService.java create mode 100644 src/main/java/org/radarbase/management/security/DomainUserDetailsService.kt rename src/main/java/org/radarbase/management/security/{Http401UnauthorizedEntryPoint.java => Http401UnauthorizedEntryPoint.kt} (65%) delete mode 100644 src/main/java/org/radarbase/management/security/PostgresApprovalStore.java create mode 100644 src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt delete mode 100644 src/main/java/org/radarbase/management/security/RadarAuthentication.java create mode 100644 src/main/java/org/radarbase/management/security/RadarAuthentication.kt delete mode 100644 src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.java create mode 100644 src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.kt delete mode 100644 src/main/java/org/radarbase/management/security/SecurityUtils.java create mode 100644 src/main/java/org/radarbase/management/security/SecurityUtils.kt delete mode 100644 src/main/java/org/radarbase/management/security/UserNotActivatedException.java create mode 100644 src/main/java/org/radarbase/management/security/UserNotActivatedException.kt rename src/main/java/org/radarbase/management/security/jwt/{JwtAccessTokenConverter.java => JwtAccessTokenConverter.kt} (57%) delete mode 100644 src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.java create mode 100644 src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.kt delete mode 100644 src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.java create mode 100644 src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt delete mode 100644 src/main/java/org/radarbase/management/security/jwt/SignatureException.java create mode 100644 src/main/java/org/radarbase/management/security/jwt/SignatureException.kt create mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.kt create mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.kt create mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.kt create mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.kt delete mode 100644 src/main/java/org/radarbase/management/security/package-info.java create mode 100644 src/main/java/org/radarbase/management/security/package-info.kt delete mode 100644 src/main/java/org/radarbase/management/service/AuditEventService.java create mode 100644 src/main/java/org/radarbase/management/service/AuditEventService.kt delete mode 100644 src/main/java/org/radarbase/management/service/MailService.java create mode 100644 src/main/java/org/radarbase/management/service/MailService.kt delete mode 100644 src/main/java/org/radarbase/management/service/OAuthClientService.java create mode 100644 src/main/java/org/radarbase/management/service/OAuthClientService.kt delete mode 100644 src/main/java/org/radarbase/management/service/OrganizationService.java create mode 100644 src/main/java/org/radarbase/management/service/OrganizationService.kt delete mode 100644 src/main/java/org/radarbase/management/service/PasswordService.java create mode 100644 src/main/java/org/radarbase/management/service/PasswordService.kt delete mode 100644 src/main/java/org/radarbase/management/service/ResourceUriService.java create mode 100644 src/main/java/org/radarbase/management/service/ResourceUriService.kt delete mode 100644 src/main/java/org/radarbase/management/service/SiteSettingsService.java create mode 100644 src/main/java/org/radarbase/management/service/SiteSettingsService.kt delete mode 100644 src/main/java/org/radarbase/management/service/SourceDataService.java create mode 100644 src/main/java/org/radarbase/management/service/SourceDataService.kt delete mode 100644 src/main/java/org/radarbase/management/service/SourceTypeService.java create mode 100644 src/main/java/org/radarbase/management/service/SourceTypeService.kt delete mode 100644 src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.java create mode 100644 src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.kt delete mode 100644 src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.java create mode 100644 src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.kt delete mode 100644 src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.java create mode 100644 src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.kt delete mode 100644 src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.java create mode 100644 src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/AuthorityDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/AuthorityDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/GroupDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/GroupDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/OrganizationDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/ProjectDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/RevisionDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/RevisionDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/RoleDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/RoleDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.java create mode 100644 src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/SourceDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/SourceDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/SourceDataDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/SubjectDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/TokenDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/TokenDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/UserDTO.java create mode 100644 src/main/java/org/radarbase/management/service/dto/UserDTO.kt delete mode 100644 src/main/java/org/radarbase/management/service/dto/package-info.java create mode 100644 src/main/java/org/radarbase/management/service/dto/package-info.kt rename src/main/java/org/radarbase/management/service/mapper/{CatalogSourceDataMapper.java => CatalogSourceDataMapper.kt} (55%) rename src/main/java/org/radarbase/management/service/mapper/{CatalogSourceTypeMapper.java => CatalogSourceTypeMapper.kt} (56%) delete mode 100644 src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt rename src/main/java/org/radarbase/management/service/mapper/{GroupMapper.java => GroupMapper.kt} (53%) delete mode 100644 src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/ProjectMapper.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/ProjectMapper.kt rename src/main/java/org/radarbase/management/service/mapper/{RoleMapper.java => RoleMapper.kt} (52%) delete mode 100644 src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/SourceMapper.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/SourceMapper.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.java create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt rename src/main/java/org/radarbase/management/service/mapper/{package-info.java => package-info.kt} (62%) delete mode 100644 src/main/java/org/radarbase/management/service/package-info.java create mode 100644 src/main/java/org/radarbase/management/service/package-info.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/AccountResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/AccountResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/AuditResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/AuditResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/GroupResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/GroupResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/LogsResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/LogsResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/RoleResource.java create mode 100644 src/main/java/org/radarbase/management/web/rest/RoleResource.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.java create mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt rename src/main/java/org/radarbase/management/web/rest/criteria/{LocalDateCriteriaRange.java => LocalDateCriteriaRange.kt} (60%) rename src/main/java/org/radarbase/management/web/rest/criteria/{SubjectAuthority.java => SubjectAuthority.kt} (69%) delete mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.java create mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.java create mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.java create mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.java create mode 100644 src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt rename src/main/java/org/radarbase/management/web/rest/criteria/{ZonedDateTimeCriteriaRange.java => ZonedDateTimeCriteriaRange.kt} (58%) delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ConflictException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ConflictException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/EntityName.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/EntityName.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.java create mode 100644 src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/package-info.java create mode 100644 src/main/java/org/radarbase/management/web/rest/package-info.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.java create mode 100644 src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.java create mode 100644 src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt create mode 100644 src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.kt create mode 100644 src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.kt create mode 100644 src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.kt create mode 100644 src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.kt create mode 100644 src/main/java/org/radarbase/management/web/rest/vm/package-info.kt diff --git a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt index ee0d02c04..ce5b0ecc8 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt @@ -2,7 +2,6 @@ package org.radarbase.management.config import org.radarbase.auth.authorization.RoleAuthority import org.radarbase.management.repository.UserRepository -import org.radarbase.management.security.ClaimsTokenEnhancer import org.radarbase.management.security.Http401UnauthorizedEntryPoint import org.radarbase.management.security.JwtAuthenticationFilter import org.radarbase.management.security.PostgresApprovalStore @@ -42,7 +41,6 @@ import org.springframework.security.oauth2.provider.client.JdbcClientDetailsServ import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices import org.springframework.security.oauth2.provider.token.DefaultTokenServices -import org.springframework.security.oauth2.provider.token.TokenEnhancer import org.springframework.security.oauth2.provider.token.TokenEnhancerChain import org.springframework.security.oauth2.provider.token.TokenStore import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter @@ -66,6 +64,7 @@ open class OAuth2ServerConfiguration { @Autowired private val jwtAuthenticationFilter: JwtAuthenticationFilter? = null + @Throws(Exception::class) override fun configure(http: HttpSecurity) { http @@ -97,10 +96,11 @@ open class OAuth2ServerConfiguration { @Autowired private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null + @Bean open fun jwtAuthenticationFilter(): JwtAuthenticationFilter { return JwtAuthenticationFilter( - keyStoreHandler!!.getTokenValidator(), + keyStoreHandler!!.tokenValidator, authenticationManager!!, userRepository!!, true @@ -117,27 +117,18 @@ open class OAuth2ServerConfiguration { @Configuration @EnableResourceServer - protected open class ResourceServerConfiguration : ResourceServerConfigurerAdapter() { - @Autowired - private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null - - @Autowired - private val tokenStore: TokenStore? = null - - @Autowired - private val http401UnauthorizedEntryPoint: Http401UnauthorizedEntryPoint? = null - - @Autowired - private val logoutSuccessHandler: LogoutSuccessHandler? = null + protected open class ResourceServerConfiguration( + @Autowired private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler, + @Autowired private val tokenStore: TokenStore, + @Autowired private val http401UnauthorizedEntryPoint: Http401UnauthorizedEntryPoint, + @Autowired private val logoutSuccessHandler: LogoutSuccessHandler, + @Autowired private val authenticationManager: AuthenticationManager, + @Autowired private val userRepository: UserRepository + ) : ResourceServerConfigurerAdapter() { - @Autowired - private val authenticationManager: AuthenticationManager? = null - - @Autowired - private val userRepository: UserRepository? = null fun jwtAuthenticationFilter(): JwtAuthenticationFilter { return JwtAuthenticationFilter( - keyStoreHandler!!.getTokenValidator(), authenticationManager!!, userRepository!! + keyStoreHandler.tokenValidator, authenticationManager, userRepository ) .skipUrlPattern(HttpMethod.GET, "/management/health") .skipUrlPattern(HttpMethod.GET, "/api/meta-token/*") @@ -209,22 +200,14 @@ open class OAuth2ServerConfiguration { @Configuration @EnableAuthorizationServer - protected open class AuthorizationServerConfiguration : AuthorizationServerConfigurerAdapter() { - @Autowired - private val jpaProperties: JpaProperties? = null - - @Autowired - @Qualifier("authenticationManagerBean") - private val authenticationManager: AuthenticationManager? = null - - @Autowired - private val dataSource: DataSource? = null + protected open class AuthorizationServerConfiguration( + @Autowired private val jpaProperties: JpaProperties, + @Autowired @Qualifier("authenticationManagerBean") private val authenticationManager: AuthenticationManager, + @Autowired private val dataSource: DataSource, + @Autowired private val jdbcClientDetailsService: JdbcClientDetailsService, + @Autowired private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler + ) : AuthorizationServerConfigurerAdapter() { - @Autowired - private val jdbcClientDetailsService: JdbcClientDetailsService? = null - - @Autowired - private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null @Bean protected open fun authorizationCodeServices(): AuthorizationCodeServices { return JdbcAuthorizationCodeServices(dataSource) @@ -240,11 +223,6 @@ open class OAuth2ServerConfiguration { } } - @Bean - open fun tokenEnhancer(): TokenEnhancer { - return ClaimsTokenEnhancer() - } - @Bean open fun tokenStore(): TokenStore { return ManagementPortalJwtTokenStore(accessTokenConverter()) @@ -254,7 +232,7 @@ open class OAuth2ServerConfiguration { open fun accessTokenConverter(): ManagementPortalJwtAccessTokenConverter { logger.debug("loading token converter from keystore configurations") return ManagementPortalJwtAccessTokenConverter( - keyStoreHandler!!.getAlgorithmForSigning(), + keyStoreHandler.algorithmForSigning, keyStoreHandler.verifiers, keyStoreHandler.refreshTokenVerifiers ) @@ -273,7 +251,8 @@ open class OAuth2ServerConfiguration { override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) { val tokenEnhancerChain = TokenEnhancerChain() tokenEnhancerChain.setTokenEnhancers( - Arrays.asList(tokenEnhancer(), accessTokenConverter()) + //TODO listOf(tokenEnhancer(), accessTokenConverter()) + listOf(accessTokenConverter()) ) endpoints .authorizationCodeServices(authorizationCodeServices()) diff --git a/src/main/java/org/radarbase/management/domain/Group.kt b/src/main/java/org/radarbase/management/domain/Group.kt index 539378939..1f527bdf9 100644 --- a/src/main/java/org/radarbase/management/domain/Group.kt +++ b/src/main/java/org/radarbase/management/domain/Group.kt @@ -48,14 +48,14 @@ class Group : AbstractEntity(), Serializable { @JoinColumn(name = "project_id", nullable = false) @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) var project: Project? = null - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val group = o as Group + val group = other as Group return if (group.id == null || id == null) { false } else id == group.id diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index a6da31807..bc36271a5 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -56,11 +56,9 @@ class Project : AbstractEntity(), Serializable { @SequenceGenerator(name = "sequenceGenerator", initialValue = 1000, sequenceName = "hibernate_sequence") override var id: Long? = null - @JvmField @Column(name = "project_name", nullable = false, unique = true) var projectName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null - @JvmField @Column(name = "description", nullable = false) var description: @NotNull String? = null @@ -113,7 +111,7 @@ class Project : AbstractEntity(), Serializable { @MapKeyColumn(name = "attribute_key") @Column(name = "attribute_value") @CollectionTable(name = "project_metadata", joinColumns = [JoinColumn(name = "id")]) - var attributes: Map = HashMap() + var attributes: MutableMap = HashMap() @JvmField @set:JsonSetter(nulls = Nulls.AS_EMPTY) diff --git a/src/main/java/org/radarbase/management/domain/User.kt b/src/main/java/org/radarbase/management/domain/User.kt index ddf37bf9b..a0bcd307b 100644 --- a/src/main/java/org/radarbase/management/domain/User.kt +++ b/src/main/java/org/radarbase/management/domain/User.kt @@ -47,7 +47,7 @@ class User : AbstractEntity(), Serializable { override var id: Long? = null @Column(length = 50, unique = true, nullable = false) - var login: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) String? = null + lateinit var login: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) String private set @JvmField diff --git a/src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.java b/src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.java deleted file mode 100644 index 43b1f4d62..000000000 --- a/src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.radarbase.management.filters; - -import java.util.HashMap; -import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; - -public class CustomHttpServletRequest extends HttpServletRequestWrapper { - - private final Map additionalParams; - private final HttpServletRequest request; - - /** - * Create a new instance with the given request and additional parameters. - * - * @param request the request - * @param additionalParams the additional parameters - */ - public CustomHttpServletRequest(final HttpServletRequest request, - final Map additionalParams) { - super(request); - this.request = request; - this.additionalParams = additionalParams; - } - - @Override - public Map getParameterMap() { - final Map map = request.getParameterMap(); - final Map param = new HashMap<>(); - param.putAll(map); - param.putAll(additionalParams); - return param; - } - -} diff --git a/src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.kt b/src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.kt new file mode 100644 index 000000000..45c423b13 --- /dev/null +++ b/src/main/java/org/radarbase/management/filters/CustomHttpServletRequest.kt @@ -0,0 +1,23 @@ +package org.radarbase.management.filters + +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletRequestWrapper + +class CustomHttpServletRequest +/** + * Create a new instance with the given request and additional parameters. + * + * @param request the request + * @param additionalParams the additional parameters + */( + private val request: HttpServletRequest, + private val additionalParams: Map> +) : HttpServletRequestWrapper(request) { + override fun getParameterMap(): Map> { + val map = request.parameterMap + val param: MutableMap> = HashMap() + param.putAll(map) + param.putAll(additionalParams) + return param + } +} diff --git a/src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.java b/src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.java deleted file mode 100644 index 8925d15b4..000000000 --- a/src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.radarbase.management.hibernate; - -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; -import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; - -public class CaseSensitivePhysicalNamingStrategy extends SpringPhysicalNamingStrategy { - - @Override - protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) { - return false; - } -} diff --git a/src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.kt b/src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.kt new file mode 100644 index 000000000..f410fd901 --- /dev/null +++ b/src/main/java/org/radarbase/management/hibernate/CaseSensitivePhysicalNamingStrategy.kt @@ -0,0 +1,10 @@ +package org.radarbase.management.hibernate + +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment +import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + +class CaseSensitivePhysicalNamingStrategy : SpringPhysicalNamingStrategy() { + override fun isCaseInsensitive(jdbcEnvironment: JdbcEnvironment): Boolean { + return false + } +} diff --git a/src/main/java/org/radarbase/management/repository/AuthorityRepository.java b/src/main/java/org/radarbase/management/repository/AuthorityRepository.java deleted file mode 100644 index 577516ae6..000000000 --- a/src/main/java/org/radarbase/management/repository/AuthorityRepository.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.radarbase.management.repository; - -import org.radarbase.management.domain.Authority; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -import java.util.Optional; - -/** - * Spring Data JPA repository for the Authority entity. - */ -@RepositoryDefinition(domainClass = Authority.class, idClass = String.class) -public interface AuthorityRepository extends JpaRepository, - RevisionRepository { - - @Query("select authority from Authority authority where authority.name = :authorityName") - Optional findByAuthorityName(@Param("authorityName") String authorityName); -} diff --git a/src/main/java/org/radarbase/management/repository/AuthorityRepository.kt b/src/main/java/org/radarbase/management/repository/AuthorityRepository.kt new file mode 100644 index 000000000..a34d17d0c --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/AuthorityRepository.kt @@ -0,0 +1,17 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Authority +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param + +/** + * Spring Data JPA repository for the Authority entity. + */ +@RepositoryDefinition(domainClass = Authority::class, idClass = String::class) +interface AuthorityRepository : JpaRepository, RevisionRepository { + @Query("select authority from Authority authority where authority.name = :authorityName") + fun findByAuthorityName(@Param("authorityName") authorityName: String): Authority? +} diff --git a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java deleted file mode 100644 index 48af8daa1..000000000 --- a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.radarbase.management.repository; - -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.List; - -import ch.qos.logback.classic.pattern.TargetLengthBasedClassNameAbbreviator; -import org.radarbase.management.config.audit.AuditEventConverter; -import org.radarbase.management.domain.PersistentAuditEvent; -import org.radarbase.management.security.Constants; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.boot.actuate.audit.AuditEventRepository; -import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.annotation.Transactional; - -/** - * An implementation of Spring Boot's AuditEventRepository. - */ -@Repository -public class CustomAuditEventRepository implements AuditEventRepository { - private static final Logger logger = LoggerFactory.getLogger(CustomAuditEventRepository.class); - - private static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE"; - - private static final TargetLengthBasedClassNameAbbreviator TYPE_ABBREVIATOR = - new TargetLengthBasedClassNameAbbreviator(15); - - @Autowired - private PersistenceAuditEventRepository persistenceAuditEventRepository; - - @Autowired - private AuditEventConverter auditEventConverter; - - @Override - public List find(String principal, Instant after, String type) { - Iterable persistentAuditEvents = - persistenceAuditEventRepository - .findByPrincipalAndAuditEventDateAfterAndAuditEventType(principal, - LocalDateTime.from(after), type); - return auditEventConverter.convertToAuditEvent(persistentAuditEvents); - } - - @Override - @Transactional(propagation = Propagation.REQUIRES_NEW) - public void add(AuditEvent event) { - var eventType = event.getType(); - if (!AUTHORIZATION_FAILURE.equals(eventType) - && !Constants.ANONYMOUS_USER.equals(event.getPrincipal())) { - PersistentAuditEvent persistentAuditEvent = new PersistentAuditEvent(); - persistentAuditEvent.principal = event.getPrincipal(); - persistentAuditEvent.auditEventType = eventType; - persistentAuditEvent.auditEventDate = LocalDateTime.ofInstant(event.getTimestamp(), - ZoneId.systemDefault()); - persistentAuditEvent.setData(auditEventConverter.convertDataToStrings(event.getData())); - persistenceAuditEventRepository.save(persistentAuditEvent); - } - if (eventType != null && eventType.endsWith("_FAILURE")) { - Object typeObj = event.getData().get("type"); - String errorType = typeObj instanceof String - ? TYPE_ABBREVIATOR.abbreviate((String) typeObj) - : null; - logger.warn("{}: principal={}, error={}, message=\"{}\", details={}", - eventType, - event.getPrincipal(), - errorType, - event.getData().get("message"), - event.getData().get("details")); - } - } -} diff --git a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt new file mode 100644 index 000000000..018ae7ea4 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt @@ -0,0 +1,71 @@ +package org.radarbase.management.repository + +import ch.qos.logback.classic.pattern.TargetLengthBasedClassNameAbbreviator +import org.radarbase.management.config.audit.AuditEventConverter +import org.radarbase.management.domain.PersistentAuditEvent +import org.radarbase.management.security.Constants +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.boot.actuate.audit.AuditEventRepository +import org.springframework.stereotype.Repository +import org.springframework.transaction.annotation.Propagation +import org.springframework.transaction.annotation.Transactional +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId + +/** + * An implementation of Spring Boot's AuditEventRepository. + */ +@Repository +open class CustomAuditEventRepository( + @Autowired private val auditEventConverter: AuditEventConverter, + @Autowired private val persistenceAuditEventRepository: PersistenceAuditEventRepository +) : AuditEventRepository { + + override fun find(principal: String, after: Instant, type: String): List { + val persistentAuditEvents: Iterable? = persistenceAuditEventRepository + ?.findByPrincipalAndAuditEventDateAfterAndAuditEventType( + principal, + LocalDateTime.from(after), type + ) + return auditEventConverter.convertToAuditEvent(persistentAuditEvents) + } + + @Transactional(propagation = Propagation.REQUIRES_NEW) + override fun add(event: AuditEvent) { + val eventType = event.type + if (AUTHORIZATION_FAILURE != eventType + && Constants.ANONYMOUS_USER != event.principal + ) { + val persistentAuditEvent = PersistentAuditEvent() + persistentAuditEvent.principal = event.principal + persistentAuditEvent.auditEventType = eventType + persistentAuditEvent.auditEventDate = LocalDateTime.ofInstant( + event.timestamp, + ZoneId.systemDefault() + ) + persistentAuditEvent.data = auditEventConverter!!.convertDataToStrings(event.data) + persistenceAuditEventRepository!!.save(persistentAuditEvent) + } + if (eventType != null && eventType.endsWith("_FAILURE")) { + val typeObj = event.data["type"] + val errorType = if (typeObj is String) TYPE_ABBREVIATOR.abbreviate(typeObj as String?) else null + logger.warn( + "{}: principal={}, error={}, message=\"{}\", details={}", + eventType, + event.principal, + errorType, + event.data["message"], + event.data["details"] + ) + } + } + + companion object { + private val logger = LoggerFactory.getLogger(CustomAuditEventRepository::class.java) + private const val AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE" + private val TYPE_ABBREVIATOR = TargetLengthBasedClassNameAbbreviator(15) + } +} diff --git a/src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.java b/src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.java deleted file mode 100644 index c6f7fb604..000000000 --- a/src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.radarbase.management.repository; - -import org.radarbase.management.domain.audit.CustomRevisionEntity; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface CustomRevisionEntityRepository extends JpaRepository { -} diff --git a/src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.kt b/src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.kt new file mode 100644 index 000000000..e977d6c44 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/CustomRevisionEntityRepository.kt @@ -0,0 +1,6 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.audit.CustomRevisionEntity +import org.springframework.data.jpa.repository.JpaRepository + +interface CustomRevisionEntityRepository : JpaRepository diff --git a/src/main/java/org/radarbase/management/repository/MetaTokenRepository.java b/src/main/java/org/radarbase/management/repository/MetaTokenRepository.java deleted file mode 100644 index 9b9bc3931..000000000 --- a/src/main/java/org/radarbase/management/repository/MetaTokenRepository.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.radarbase.management.repository; - -import java.time.Instant; -import java.util.List; -import java.util.Optional; - -import org.radarbase.management.domain.MetaToken; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -/** - * Spring Data JPA repository for the MetaToken entity. - */ -public interface MetaTokenRepository extends JpaRepository, - RevisionRepository { - - Optional findOneByTokenName(String tokenName); - - @Query("select metaToken from MetaToken metaToken " - + "where (metaToken.fetched = true and metaToken.persistent = false)" - + " or metaToken.expiryDate < :time") - List findAllByFetchedOrExpired(@Param("time")Instant time); -} diff --git a/src/main/java/org/radarbase/management/repository/MetaTokenRepository.kt b/src/main/java/org/radarbase/management/repository/MetaTokenRepository.kt new file mode 100644 index 000000000..c954fecd8 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/MetaTokenRepository.kt @@ -0,0 +1,22 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.MetaToken +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param +import java.time.Instant + +/** + * Spring Data JPA repository for the MetaToken entity. + */ +interface MetaTokenRepository : JpaRepository, RevisionRepository { + fun findOneByTokenName(tokenName: String?): MetaToken? + + @Query( + "select metaToken from MetaToken metaToken " + + "where (metaToken.fetched = true and metaToken.persistent = false)" + + " or metaToken.expiryDate < :time" + ) + fun findAllByFetchedOrExpired(@Param("time") time: Instant?): List +} diff --git a/src/main/java/org/radarbase/management/repository/OrganizationRepository.java b/src/main/java/org/radarbase/management/repository/OrganizationRepository.java deleted file mode 100644 index 423bda374..000000000 --- a/src/main/java/org/radarbase/management/repository/OrganizationRepository.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.radarbase.management.repository; - -import java.util.Collection; -import java.util.List; -import java.util.Optional; - -import org.radarbase.management.domain.Organization; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -/** - * Spring Data JPA repository for the Organization entity. - */ -@RepositoryDefinition(domainClass = Organization.class, idClass = Long.class) -public interface OrganizationRepository extends JpaRepository, - RevisionRepository { - - @Query("select org from Organization org " - + "where org.name = :name") - Optional findOneByName(@Param("name") String name); - - @Query("select distinct org from Organization org left join fetch org.projects project " - + "where project.projectName in (:projectNames)") - List findAllByProjectNames( - @Param("projectNames") Collection projectNames); -} diff --git a/src/main/java/org/radarbase/management/repository/OrganizationRepository.kt b/src/main/java/org/radarbase/management/repository/OrganizationRepository.kt new file mode 100644 index 000000000..d471e710a --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/OrganizationRepository.kt @@ -0,0 +1,28 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Organization +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param + +/** + * Spring Data JPA repository for the Organization entity. + */ +@RepositoryDefinition(domainClass = Organization::class, idClass = Long::class) +interface OrganizationRepository : JpaRepository, RevisionRepository { + @Query( + "select org from Organization org " + + "where org.name = :name" + ) + fun findOneByName(@Param("name") name: String): Organization? + + @Query( + "select distinct org from Organization org left join fetch org.projects project " + + "where project.projectName in (:projectNames)" + ) + fun findAllByProjectNames( + @Param("projectNames") projectNames: Collection + ): List +} diff --git a/src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.java b/src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.java deleted file mode 100644 index 80c8fa417..000000000 --- a/src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.radarbase.management.repository; - -import java.time.LocalDateTime; -import java.util.List; -import org.radarbase.management.domain.PersistentAuditEvent; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; - -/** - * Spring Data JPA repository for the PersistentAuditEvent entity. - */ -public interface PersistenceAuditEventRepository extends JpaRepository { - - List findByPrincipal(String principal); - - List findByAuditEventDateAfter(LocalDateTime after); - - List findByPrincipalAndAuditEventDateAfter(String principal, - LocalDateTime after); - - List findByPrincipalAndAuditEventDateAfterAndAuditEventType( - String principle, LocalDateTime after, String type); - - Page findAllByAuditEventDateBetween(LocalDateTime fromDate, - LocalDateTime toDate, Pageable pageable); -} diff --git a/src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.kt b/src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.kt new file mode 100644 index 000000000..00b4bff3a --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/PersistenceAuditEventRepository.kt @@ -0,0 +1,28 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.PersistentAuditEvent +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import java.time.LocalDateTime + +/** + * Spring Data JPA repository for the PersistentAuditEvent entity. + */ +interface PersistenceAuditEventRepository : JpaRepository { + fun findByPrincipal(principal: String?): List? + fun findByAuditEventDateAfter(after: LocalDateTime?): List? + fun findByPrincipalAndAuditEventDateAfter( + principal: String?, + after: LocalDateTime? + ): List? + + fun findByPrincipalAndAuditEventDateAfterAndAuditEventType( + principle: String?, after: LocalDateTime?, type: String? + ): List + + fun findAllByAuditEventDateBetween( + fromDate: LocalDateTime?, + toDate: LocalDateTime?, pageable: Pageable? + ): Page +} diff --git a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt index bc0e44b8f..9dfd6b7be 100644 --- a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt +++ b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt @@ -9,20 +9,19 @@ import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.RepositoryDefinition import org.springframework.data.repository.history.RevisionRepository import org.springframework.data.repository.query.Param -import java.util.* /** * Spring Data JPA repository for the Project entity. */ @Suppress("unused") @RepositoryDefinition(domainClass = Project::class, idClass = Long::class) -interface ProjectRepository : JpaRepository, RevisionRepository { +interface ProjectRepository : JpaRepository, RevisionRepository { @Query( value = "select distinct project from Project project " + "left join fetch project.sourceTypes", countQuery = "select distinct count(project) from Project project" ) - fun findAllWithEagerRelationships(pageable: Pageable?): Page? + fun findAllWithEagerRelationships(pageable: Pageable): Page @Query( value = "select distinct project from Project project " @@ -35,17 +34,17 @@ interface ProjectRepository : JpaRepository, RevisionRepository ) fun findAllWithEagerRelationshipsInOrganizationsOrProjects( pageable: Pageable?, - @Param("organizationNames") organizationNames: Collection?, - @Param("projectNames") projectNames: Collection? - ): Page? + @Param("organizationNames") organizationNames: Collection, + @Param("projectNames") projectNames: Collection + ): Page @Query( "select project from Project project " + "WHERE project.organization.name = :organization_name" ) fun findAllByOrganizationName( - @Param("organization_name") organizationName: String? - ): List? + @Param("organization_name") organizationName: String + ): List @Query( "select project from Project project " @@ -54,7 +53,7 @@ interface ProjectRepository : JpaRepository, RevisionRepository + "left join fetch project.organization " + "where project.id = :id" ) - fun findOneWithEagerRelationships(@Param("id") id: Long?): Project? + fun findOneWithEagerRelationships(@Param("id") id: Long): Project? @Query( "select project from Project project " @@ -76,17 +75,17 @@ interface ProjectRepository : JpaRepository, RevisionRepository "select project.id from Project project " + "where project.projectName =:name" ) - fun findProjectIdByName(@Param("name") name: String?): Long? + fun findProjectIdByName(@Param("name") name: String): Long? @Query( "select project from Project project " + "left join fetch project.groups " + "where project.projectName = :name" ) - fun findOneWithGroupsByName(@Param("name") name: String?): Project? + fun findOneWithGroupsByName(@Param("name") name: String): Project? @Query("select project.sourceTypes from Project project WHERE project.id = :id") - fun findSourceTypesByProjectId(@Param("id") id: Long?): List? + fun findSourceTypesByProjectId(@Param("id") id: Long): List @Query( "select distinct sourceType from Project project " @@ -97,5 +96,5 @@ interface ProjectRepository : JpaRepository, RevisionRepository fun findSourceTypeByProjectIdAndSourceTypeId( @Param("id") id: Long?, @Param("sourceTypeId") sourceTypeId: Long? - ): Optional? + ): SourceType? } diff --git a/src/main/java/org/radarbase/management/repository/RoleRepository.java b/src/main/java/org/radarbase/management/repository/RoleRepository.java deleted file mode 100644 index c91c6e9da..000000000 --- a/src/main/java/org/radarbase/management/repository/RoleRepository.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.radarbase.management.repository; - -import java.util.List; -import java.util.Optional; -import org.radarbase.management.domain.Role; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -/** - * Created by nivethika on 18-5-17. - */ -@SuppressWarnings("unused") -@RepositoryDefinition(domainClass = Role.class, idClass = Long.class) -public interface RoleRepository extends JpaRepository, - RevisionRepository { - - @Query("select role from Role role inner join role.authority authority" - + " where authority.name = :authorityName") - List findRolesByAuthorityName(@Param("authorityName") String authorityName); - - @Query("select distinct role from Role role left join fetch role.authority") - List findAllWithEagerRelationships(); - - @Query("select role from Role role join role.authority " - + "where role.organization.id = :organizationId " - + "and role.authority.name = :authorityName") - Optional findOneByOrganizationIdAndAuthorityName( - @Param("organizationId") Long organizationId, - @Param("authorityName") String authorityName); - - @Query("select role from Role role join role.authority " - + "where role.project.id = :projectId " - + "and role.authority.name = :authorityName") - Optional findOneByProjectIdAndAuthorityName(@Param("projectId") Long projectId, - @Param("authorityName") String authorityName); - - @Query("select role from Role role join role.authority join role.project " - + "where role.project.projectName = :projectName " - + "and role.authority.name = :authorityName") - Optional findOneByProjectNameAndAuthorityName(@Param("projectName") String projectName, - @Param("authorityName") String authorityName); - - @Query("select role from Role role left join fetch role.authority " - + "where role.project.projectName = :projectName") - List findAllRolesByProjectName(@Param("projectName") String projectName); -} diff --git a/src/main/java/org/radarbase/management/repository/RoleRepository.kt b/src/main/java/org/radarbase/management/repository/RoleRepository.kt new file mode 100644 index 000000000..7b6a47f35 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/RoleRepository.kt @@ -0,0 +1,60 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Role +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param + +/** + * Created by nivethika on 18-5-17. + */ +@Suppress("unused") +@RepositoryDefinition(domainClass = Role::class, idClass = Long::class) +interface RoleRepository : JpaRepository, RevisionRepository { + @Query( + "select role from Role role inner join role.authority authority" + + " where authority.name = :authorityName" + ) + fun findRolesByAuthorityName(@Param("authorityName") authorityName: String?): List + + @Query("select distinct role from Role role left join fetch role.authority") + fun findAllWithEagerRelationships(): List + + @Query( + "select role from Role role join role.authority " + + "where role.organization.id = :organizationId " + + "and role.authority.name = :authorityName" + ) + fun findOneByOrganizationIdAndAuthorityName( + @Param("organizationId") organizationId: Long?, + @Param("authorityName") authorityName: String? + ): Role? + + @Query( + "select role from Role role join role.authority " + + "where role.project.id = :projectId " + + "and role.authority.name = :authorityName" + ) + fun findOneByProjectIdAndAuthorityName( + @Param("projectId") projectId: Long?, + @Param("authorityName") authorityName: String? + ): Role? + + @Query( + "select role from Role role join role.authority join role.project " + + "where role.project.projectName = :projectName " + + "and role.authority.name = :authorityName" + ) + fun findOneByProjectNameAndAuthorityName( + @Param("projectName") projectName: String?, + @Param("authorityName") authorityName: String? + ): Role? + + @Query( + "select role from Role role left join fetch role.authority " + + "where role.project.projectName = :projectName" + ) + fun findAllRolesByProjectName(@Param("projectName") projectName: String): List +} diff --git a/src/main/java/org/radarbase/management/repository/SourceDataRepository.java b/src/main/java/org/radarbase/management/repository/SourceDataRepository.java deleted file mode 100644 index 4944f0533..000000000 --- a/src/main/java/org/radarbase/management/repository/SourceDataRepository.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.radarbase.management.repository; - -import java.util.Optional; -import org.radarbase.management.domain.SourceData; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; - -/** - * Spring Data JPA repository for the SourceData entity. - */ -@SuppressWarnings("unused") -@RepositoryDefinition(domainClass = SourceData.class, idClass = Long.class) -public interface SourceDataRepository extends JpaRepository, - RevisionRepository { - - Optional findOneBySourceDataName(String sourceDataName); -} diff --git a/src/main/java/org/radarbase/management/repository/SourceDataRepository.kt b/src/main/java/org/radarbase/management/repository/SourceDataRepository.kt new file mode 100644 index 000000000..83d3079b4 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/SourceDataRepository.kt @@ -0,0 +1,15 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.SourceData +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository + +/** + * Spring Data JPA repository for the SourceData entity. + */ +@Suppress("unused") +@RepositoryDefinition(domainClass = SourceData::class, idClass = Long::class) +interface SourceDataRepository : JpaRepository, RevisionRepository { + fun findOneBySourceDataName(sourceDataName: String?): SourceData? +} diff --git a/src/main/java/org/radarbase/management/repository/SourceRepository.java b/src/main/java/org/radarbase/management/repository/SourceRepository.java deleted file mode 100644 index f1327649e..000000000 --- a/src/main/java/org/radarbase/management/repository/SourceRepository.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.radarbase.management.repository; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import org.radarbase.management.domain.Source; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -/** - * Spring Data JPA repository for the Source entity. - */ -@RepositoryDefinition(domainClass = Source.class, idClass = Long.class) -public interface SourceRepository extends JpaRepository, - RevisionRepository { - - @Override - @Query(value = "select source from Source source " - + "WHERE source.deleted = false", - countQuery = "select count(source) from Source source " - + "WHERE source.deleted = false") - Page findAll(Pageable pageable); - - @Query(value = "select source from Source source " - + "WHERE source.deleted = false " - + "AND source.project.id = :projectId", - countQuery = "select count(source) from Source source " - + "WHERE source.deleted = false " - + "AND source.project.id = :projectId") - Page findAllSourcesByProjectId(Pageable pageable, @Param("projectId") Long projectId); - - @Query(value = "select source from Source source " - + "WHERE source.deleted = false " - + "AND source.project.id = :projectId " - + "AND source.assigned = :assigned", - countQuery = "select count(source) from Source source " - + "WHERE source.deleted = false " - + "AND source.project.id = :projectId " - + "AND source.assigned = :assigned") - List findAllSourcesByProjectIdAndAssigned(@Param("projectId") Long projectId, - @Param("assigned") Boolean assigned); - - @Query(value = "select source from Source source " - + "WHERE source.deleted = false " - + "AND source.sourceId = :sourceId", - countQuery = "select count(source) from Source source " - + "WHERE source.deleted = false " - + "AND source.sourceId = :sourceId") - Optional findOneBySourceId(@Param("sourceId") UUID sourceId); - - @Query(value = "select source from Source source " - + "WHERE source.deleted = false " - + "AND source.sourceName = :sourceName", - countQuery = "select count(source) from Source source " - + "WHERE source.deleted = false " - + "AND source.sourceName = :sourceName") - Optional findOneBySourceName(@Param("sourceName") String sourceName); -} diff --git a/src/main/java/org/radarbase/management/repository/SourceRepository.kt b/src/main/java/org/radarbase/management/repository/SourceRepository.kt new file mode 100644 index 000000000..a11861da6 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/SourceRepository.kt @@ -0,0 +1,65 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Source +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param +import java.util.* + +/** + * Spring Data JPA repository for the Source entity. + */ +@RepositoryDefinition(domainClass = Source::class, idClass = Long::class) +interface SourceRepository : JpaRepository, RevisionRepository { + @Query( + value = "select source from Source source " + + "WHERE source.isDeleted = false", countQuery = "select count(source) from Source source " + + "WHERE source.isDeleted = false" + ) + override fun findAll(pageable: Pageable): Page + + @Query( + value = "select source from Source source " + + "WHERE source.isDeleted = false " + + "AND source.project.id = :projectId", countQuery = "select count(source) from Source source " + + "WHERE source.isDeleted = false " + + "AND source.project.id = :projectId" + ) + fun findAllSourcesByProjectId(pageable: Pageable, @Param("projectId") projectId: Long): Page + + @Query( + value = "select source from Source source " + + "WHERE source.isDeleted = false " + + "AND source.project.id = :projectId " + + "AND source.isAssigned = :assigned", countQuery = "select count(source) from Source source " + + "WHERE source.isDeleted = false " + + "AND source.project.id = :projectId " + + "AND source.isAssigned = :assigned" + ) + fun findAllSourcesByProjectIdAndAssigned( + @Param("projectId") projectId: Long?, + @Param("assigned") assigned: Boolean? + ): List + + @Query( + value = "select source from Source source " + + "WHERE source.isDeleted = false " + + "AND source.sourceId = :sourceId", countQuery = "select count(source) from Source source " + + "WHERE source.isDeleted = false " + + "AND source.sourceId = :sourceId" + ) + fun findOneBySourceId(@Param("sourceId") sourceId: UUID?): Source? + + @Query( + value = "select source from Source source " + + "WHERE source.isDeleted = false " + + "AND source.sourceName = :sourceName", countQuery = "select count(source) from Source source " + + "WHERE source.isDeleted = false " + + "AND source.sourceName = :sourceName" + ) + fun findOneBySourceName(@Param("sourceName") sourceName: String): Source? +} diff --git a/src/main/java/org/radarbase/management/repository/SourceTypeRepository.java b/src/main/java/org/radarbase/management/repository/SourceTypeRepository.java deleted file mode 100644 index fdfaf2006..000000000 --- a/src/main/java/org/radarbase/management/repository/SourceTypeRepository.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.radarbase.management.repository; - -import java.util.List; -import java.util.Optional; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.SourceType; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -/** - * Spring Data JPA repository for the SourceType entity. - */ -@SuppressWarnings("unused") -@RepositoryDefinition(domainClass = SourceType.class, idClass = Long.class) -public interface SourceTypeRepository extends JpaRepository, - RevisionRepository { - - @Query("select distinct sourceType from SourceType sourceType left join fetch sourceType" - + ".sourceData") - List findAllWithEagerRelationships(); - - @Query("select case when count(sourceType) > 0 then true else false end " - + "from SourceType sourceType " - + "where sourceType.producer = :producer " - + "and sourceType.model = :model " - + "and sourceType.catalogVersion = :version") - boolean hasOneByProducerAndModelAndVersion( - @Param("producer") String producer, @Param("model") String model, - @Param("version") String version); - - @Query("select sourceType from SourceType sourceType left join fetch sourceType.sourceData " - + "where sourceType.producer = :producer " - + "and sourceType.model = :model " - + "and sourceType.catalogVersion = :version") - Optional findOneWithEagerRelationshipsByProducerAndModelAndVersion( - @Param("producer") String producer, @Param("model") String model, - @Param("version") String version); - - @Query("select sourceType from SourceType sourceType left join fetch sourceType.sourceData " - + "where sourceType.producer =:producer") - List findWithEagerRelationshipsByProducer(@Param("producer") String producer); - - @Query("select sourceType from SourceType sourceType left join fetch sourceType.sourceData " - + "where sourceType.producer =:producer and sourceType.model =:model") - List findWithEagerRelationshipsByProducerAndModel( - @Param("producer") String producer, @Param("model") String model); - - @Query("select distinct sourceType.projects from SourceType sourceType left join sourceType" - + ".projects where sourceType.producer =:producer and sourceType.model =:model " - + "and sourceType.catalogVersion = :version") - List findProjectsBySourceType(@Param("producer") String producer, - @Param("model") String model, @Param("version") String version); -} diff --git a/src/main/java/org/radarbase/management/repository/SourceTypeRepository.kt b/src/main/java/org/radarbase/management/repository/SourceTypeRepository.kt new file mode 100644 index 000000000..69686686f --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/SourceTypeRepository.kt @@ -0,0 +1,69 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.SourceType +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param + +/** + * Spring Data JPA repository for the SourceType entity. + */ +@Suppress("unused") +@RepositoryDefinition(domainClass = SourceType::class, idClass = Long::class) +interface SourceTypeRepository : JpaRepository, RevisionRepository { + @Query( + "select distinct sourceType from SourceType sourceType left join fetch sourceType" + + ".sourceData" + ) + fun findAllWithEagerRelationships(): List + + @Query( + "select case when count(sourceType) > 0 then true else false end " + + "from SourceType sourceType " + + "where sourceType.producer = :producer " + + "and sourceType.model = :model " + + "and sourceType.catalogVersion = :version" + ) + fun hasOneByProducerAndModelAndVersion( + @Param("producer") producer: String, @Param("model") model: String, + @Param("version") version: String + ): Boolean + + @Query( + "select sourceType from SourceType sourceType left join fetch sourceType.sourceData " + + "where sourceType.producer = :producer " + + "and sourceType.model = :model " + + "and sourceType.catalogVersion = :version" + ) + fun findOneWithEagerRelationshipsByProducerAndModelAndVersion( + @Param("producer") producer: String, @Param("model") model: String, + @Param("version") version: String + ): SourceType? + + @Query( + "select sourceType from SourceType sourceType left join fetch sourceType.sourceData " + + "where sourceType.producer =:producer" + ) + fun findWithEagerRelationshipsByProducer(@Param("producer") producer: String): List + + @Query( + "select sourceType from SourceType sourceType left join fetch sourceType.sourceData " + + "where sourceType.producer =:producer and sourceType.model =:model" + ) + fun findWithEagerRelationshipsByProducerAndModel( + @Param("producer") producer: String, @Param("model") model: String + ): List + + @Query( + "select distinct sourceType.projects from SourceType sourceType left join sourceType" + + ".projects where sourceType.producer =:producer and sourceType.model =:model " + + "and sourceType.catalogVersion = :version" + ) + fun findProjectsBySourceType( + @Param("producer") producer: String, + @Param("model") model: String, @Param("version") version: String + ): List +} diff --git a/src/main/java/org/radarbase/management/repository/SubjectRepository.java b/src/main/java/org/radarbase/management/repository/SubjectRepository.java deleted file mode 100644 index d4d76670a..000000000 --- a/src/main/java/org/radarbase/management/repository/SubjectRepository.java +++ /dev/null @@ -1,106 +0,0 @@ -package org.radarbase.management.repository; - -import org.radarbase.management.domain.Source; -import org.radarbase.management.domain.Subject; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import org.springframework.data.jpa.repository.Modifying; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; - -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -/** - * Spring Data JPA repository for the Subject entity. - */ -@SuppressWarnings("unused") -@RepositoryDefinition(domainClass = Subject.class, idClass = Long.class) -public interface SubjectRepository extends JpaRepository, - RevisionRepository, - JpaSpecificationExecutor { - - @Query("SELECT count(*) from Subject subject " - + "WHERE subject.group.id = :group_id") - long countByGroupId(@Param("group_id") Long groupId); - - @Query(value = "select distinct subject from Subject subject left join fetch subject.sources " - + "left join fetch subject.user user " - + "join user.roles roles where roles.project.projectName = :projectName and roles" - + ".authority.name in :authorities", - countQuery = "select distinct count(subject) from Subject subject " - + "left join subject.user user left join user.roles roles " - + "where roles.project.projectName = :projectName and roles" - + ".authority.name in :authorities") - Page findAllByProjectNameAndAuthoritiesIn(Pageable pageable, - @Param("projectName") String projectName, - @Param("authorities") List authorities); - - @Query("select subject from Subject subject " - + "left join fetch subject.sources " - + "WHERE subject.user.login = :login") - Optional findOneWithEagerBySubjectLogin(@Param("login") String login); - - @Query("select subject from Subject subject " - + "WHERE subject.user.login in :logins") - List findAllBySubjectLogins(@Param("logins") List logins); - - @Modifying - @Query("UPDATE Subject subject " - + "SET subject.group.id = :groupId " - + "WHERE subject.id in :ids") - void setGroupIdByIds( - @Param("groupId") Long groupId, - @Param("ids") List ids); - - @Modifying - @Query("UPDATE Subject subject " - + "SET subject.group.id = null " - + "WHERE subject.id in :ids") - void unsetGroupIdByIds(@Param("ids") List ids); - - @Query("select subject.sources from Subject subject WHERE subject.id = :id") - List findSourcesBySubjectId(@Param("id") Long id); - - @Query("select subject.sources from Subject subject WHERE subject.user.login = :login") - List findSourcesBySubjectLogin(@Param("login") String login); - - @Query("select distinct subject from Subject subject left join fetch subject.sources " - + "left join fetch subject.user user " - + "join user.roles roles where roles.project.projectName = :projectName " - + "and subject.externalId = :externalId") - Optional findOneByProjectNameAndExternalId(@Param("projectName") String projectName, - @Param("externalId") String externalId); - - @Query("select distinct subject from Subject subject left join fetch subject.sources " - + "left join fetch subject.user user " - + "join user.roles roles where roles.project.projectName = :projectName " - + "and roles.authority.name in :authorities " - + "and subject.externalId = :externalId") - Optional findOneByProjectNameAndExternalIdAndAuthoritiesIn(@Param("projectName") String - projectName, @Param("externalId") String externalId, - @Param("authorities") List authorities); - - @Query("select subject.sources from Subject subject left join subject.sources sources " - + "join sources.sourceType sourceType " - + "where sourceType.producer = :producer " - + "and sourceType.model = :model " - + "and sourceType.catalogVersion =:version " - + "and subject.user.login = :login") - List findSubjectSourcesBySourceType(@Param("login") String login, - @Param("producer") String producer, @Param("model") String model, - @Param("version") String version); - - @Query("select distinct subject.sources from Subject subject left join subject.sources sources " - + "where sources.sourceId= :sourceId " - + "and subject.user.login = :login") - Optional findSubjectSourcesBySourceId(@Param("login") String login, - @Param("sourceId") UUID sourceId); - - -} diff --git a/src/main/java/org/radarbase/management/repository/SubjectRepository.kt b/src/main/java/org/radarbase/management/repository/SubjectRepository.kt new file mode 100644 index 000000000..ac0738a87 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/SubjectRepository.kt @@ -0,0 +1,128 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.Source +import org.radarbase.management.domain.Subject +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.JpaSpecificationExecutor +import org.springframework.data.jpa.repository.Modifying +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param +import java.util.* + +/** + * Spring Data JPA repository for the Subject entity. + */ +@Suppress("unused") +@RepositoryDefinition(domainClass = Subject::class, idClass = Long::class) +interface SubjectRepository : JpaRepository, RevisionRepository, + JpaSpecificationExecutor { + @Query( + "SELECT count(*) from Subject subject " + + "WHERE subject.group.id = :group_id" + ) + fun countByGroupId(@Param("group_id") groupId: Long?): Long + + @Query( + value = "select distinct subject from Subject subject left join fetch subject.sources " + + "left join fetch subject.user user " + + "join user.roles roles where roles.project.projectName = :projectName and roles" + + ".authority.name in :authorities", countQuery = "select distinct count(subject) from Subject subject " + + "left join subject.user user left join user.roles roles " + + "where roles.project.projectName = :projectName and roles" + + ".authority.name in :authorities" + ) + fun findAllByProjectNameAndAuthoritiesIn( + pageable: Pageable?, + @Param("projectName") projectName: String?, + @Param("authorities") authorities: List? + ): Page? + + @Query( + "select subject from Subject subject " + + "left join fetch subject.sources " + + "WHERE subject.user.login = :login" + ) + fun findOneWithEagerBySubjectLogin(@Param("login") login: String?): Subject? + + @Query( + "select subject from Subject subject " + + "WHERE subject.user.login in :logins" + ) + fun findAllBySubjectLogins(@Param("logins") logins: List): List + + @Modifying + @Query( + "UPDATE Subject subject " + + "SET subject.group.id = :groupId " + + "WHERE subject.id in :ids" + ) + fun setGroupIdByIds( + @Param("groupId") groupId: Long, + @Param("ids") ids: List + ) + + @Modifying + @Query( + "UPDATE Subject subject " + + "SET subject.group.id = null " + + "WHERE subject.id in :ids" + ) + fun unsetGroupIdByIds(@Param("ids") ids: List) + + @Query("select subject.sources from Subject subject WHERE subject.id = :id") + fun findSourcesBySubjectId(@Param("id") id: Long): List + + @Query("select subject.sources from Subject subject WHERE subject.user.login = :login") + fun findSourcesBySubjectLogin(@Param("login") login: String?): List + + @Query( + "select distinct subject from Subject subject left join fetch subject.sources " + + "left join fetch subject.user user " + + "join user.roles roles where roles.project.projectName = :projectName " + + "and subject.externalId = :externalId" + ) + fun findOneByProjectNameAndExternalId( + @Param("projectName") projectName: String?, + @Param("externalId") externalId: String? + ): Subject? + + @Query( + "select distinct subject from Subject subject left join fetch subject.sources " + + "left join fetch subject.user user " + + "join user.roles roles where roles.project.projectName = :projectName " + + "and roles.authority.name in :authorities " + + "and subject.externalId = :externalId" + ) + fun findOneByProjectNameAndExternalIdAndAuthoritiesIn( + @Param("projectName") projectName: String, @Param("externalId") externalId: String, + @Param("authorities") authorities: List + ): Subject? + + @Query( + "select subject.sources from Subject subject left join subject.sources sources " + + "join sources.sourceType sourceType " + + "where sourceType.producer = :producer " + + "and sourceType.model = :model " + + "and sourceType.catalogVersion =:version " + + "and subject.user.login = :login" + ) + fun findSubjectSourcesBySourceType( + @Param("login") login: String?, + @Param("producer") producer: String?, @Param("model") model: String?, + @Param("version") version: String? + ): List? + + @Query( + "select distinct subject.sources from Subject subject left join subject.sources sources " + + "where sources.sourceId= :sourceId " + + "and subject.user.login = :login" + ) + fun findSubjectSourcesBySourceId( + @Param("login") login: String?, + @Param("sourceId") sourceId: UUID + ): Source? +} diff --git a/src/main/java/org/radarbase/management/repository/UserRepository.java b/src/main/java/org/radarbase/management/repository/UserRepository.java deleted file mode 100644 index 48b2066ea..000000000 --- a/src/main/java/org/radarbase/management/repository/UserRepository.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.radarbase.management.repository; - -import org.radarbase.management.domain.User; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.jpa.repository.EntityGraph; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.RepositoryDefinition; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Optional; - -/** - * Spring Data JPA repository for the User entity. - */ -@RepositoryDefinition(domainClass = User.class, idClass = Long.class) -@Component -public interface UserRepository extends JpaRepository, - RevisionRepository, JpaSpecificationExecutor { - - Optional findOneByActivationKey(String activationKey); - - List findAllByActivated(boolean activated); - - @Query("select user from User user " - + "left join fetch user.roles roles where " - + "roles.authority.name not in :authorities " - + "and user.activated= :activated") - List findAllByActivatedAndAuthoritiesNot(@Param("activated") boolean activated, - @Param("authorities") List authorities); - - Optional findOneByResetKey(String resetKey); - - Optional findOneByEmail(String email); - - Optional findOneByLogin(String login); - - @EntityGraph(attributePaths = {"roles", "roles.authority.name"}) - Optional findOneWithRolesByLogin(String login); - - Page findAllByLoginNot(Pageable pageable, String login); - -} diff --git a/src/main/java/org/radarbase/management/repository/UserRepository.kt b/src/main/java/org/radarbase/management/repository/UserRepository.kt new file mode 100644 index 000000000..f1071863e --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/UserRepository.kt @@ -0,0 +1,43 @@ +package org.radarbase.management.repository + +import org.radarbase.management.domain.User +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.EntityGraph +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.JpaSpecificationExecutor +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.RepositoryDefinition +import org.springframework.data.repository.history.RevisionRepository +import org.springframework.data.repository.query.Param +import org.springframework.stereotype.Component + +/** + * Spring Data JPA repository for the User entity. + */ +@RepositoryDefinition(domainClass = User::class, idClass = Long::class) +@Component +interface UserRepository : JpaRepository, RevisionRepository, + JpaSpecificationExecutor { + fun findOneByActivationKey(activationKey: String): User? + fun findAllByActivated(activated: Boolean): List + + @Query( + "select user from User user " + + "left join fetch user.roles roles where " + + "roles.authority.name not in :authorities " + + "and user.activated= :activated" + ) + fun findAllByActivatedAndAuthoritiesNot( + @Param("activated") activated: Boolean, + @Param("authorities") authorities: List + ): List + + fun findOneByResetKey(resetKey: String): User? + fun findOneByEmail(email: String): User? + fun findOneByLogin(login: String): User? + + @EntityGraph(attributePaths = ["roles", "roles.authority.name"]) + fun findOneWithRolesByLogin(login: String): User? + fun findAllByLoginNot(pageable: Pageable, login: String): Page +} diff --git a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.java b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.java deleted file mode 100644 index 7868877b5..000000000 --- a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.repository.filters; - -import org.radarbase.management.domain.Subject; -import org.radarbase.management.web.rest.criteria.CriteriaRange; - -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.Expression; -import javax.persistence.criteria.JoinType; -import javax.persistence.criteria.MapJoin; -import javax.persistence.criteria.Path; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Locale; -import java.util.function.Supplier; - -public class PredicateBuilder { - private final List predicates; - private final CriteriaBuilder builder; - - public PredicateBuilder(CriteriaBuilder builder) { - this.predicates = new ArrayList<>(); - this.builder = builder; - } - - /** Add predicate to query. */ - public void add(Predicate predicate) { - if (predicate == null) { - return; - } - predicates.add(predicate); - } - - public void isNull(Expression expression) { - predicates.add(builder.isNull(expression)); - } - - /** - * Build the predicates as an AND predicate. - */ - public Predicate toAndPredicate() { - if (this.predicates.size() == 1) { - return this.predicates.get(0); - } else if (!this.predicates.isEmpty()) { - return builder.and(this.predicates.toArray(new Predicate[0])); - } else { - return null; - } - } - - /** - * Build the predicates as an AND predicate. - */ - public Predicate toOrPredicate() { - if (this.predicates.size() == 1) { - return this.predicates.get(0); - } else if (!this.predicates.isEmpty()) { - return builder.or(this.predicates.toArray(new Predicate[0])); - } else { - return null; - } - } - - /** - * Add an equal criteria to predicates if value is not null or empty. - * @param path entity path - * @param value value to compare with - * @param type of field. - */ - public void equal(Supplier> path, T value) { - if (isValidValue(value)) { - add(builder.equal(path.get(), value)); - } - } - - /** - * Add an equal criteria to predicates if value is not null or empty. - * @param path entity path - * @param value value to compare with - * @param type of field. - */ - public void equal(Expression path, T value) { - if (isValidValue(value)) { - add(builder.equal(path, value)); - } - } - - /** - * Add a like criteria to predicates if value is not null or empty, matching both sides. - * @param path entity path - * @param value value to compare with - */ - public void likeLower(Supplier> path, String value) { - if (isValidValue(value)) { - add(builder.like(builder.lower(path.get()), - "%" + value.trim().toLowerCase(Locale.ROOT) + "%")); - } - } - - /** - * Add a like criteria to predicates if value is not null or empty, matching both sides. - * @param path entity path - * @param value value to compare with - */ - public void likeLower(Expression path, String value) { - if (isValidValue(value)) { - add(builder.like(builder.lower(path), - "%" + value.trim().toLowerCase(Locale.ROOT) + "%")); - } - } - - /** - * Add a like criteria to predicates if value is not null or empty, matching both sides. - * @param root entity to fetch attributes from. - * @param attributeKey name of the attribute. - * @param attributeValue value to compare with using a like query. - */ - public void attributeLike(Root root, String attributeKey, - String attributeValue) { - if (isValidValue(attributeValue)) { - MapJoin attributesJoin = - root.joinMap("attributes", JoinType.LEFT); - add(builder.and( - builder.equal(attributesJoin.key(), attributeKey), - builder.like(attributesJoin.value(), - "%" + attributeValue + "%"))); - } - } - - public void in(Expression expr, Expression other) { - add(expr.in(other)); - } - - public void in(Expression expr, Collection other) { - add(expr.in(other)); - } - - /** - * Add comparable criteria matching given range. - * @param path entity property path. - * @param range range that should be matched. - */ - public > void range( - Path path, CriteriaRange range) { - if (range == null || range.isEmpty()) { - return; - } - range.validate(); - if (range.getIs() != null) { - add(builder.equal(path, range.getIs())); - } else { - if (range.getFrom() != null && range.getTo() != null) { - add(builder.between(path, range.getFrom(), range.getTo())); - } else if (range.getFrom() != null) { - add(builder.greaterThanOrEqualTo(path, range.getFrom())); - } else if (range.getTo() != null) { - add(builder.lessThanOrEqualTo(path, range.getTo())); - } - } - } - - /** - * Whether given String a proper value. - */ - public boolean isValidValue(Object value) { - if (value == null) { - return false; - } - if (value instanceof String str) { - return !str.isBlank() && !str.equals("null"); - } - return true; - } - - public PredicateBuilder newBuilder() { - return new PredicateBuilder(builder); - } - - public CriteriaBuilder getCriteriaBuilder() { - return builder; - } - - public boolean isEmpty() { - return this.predicates.isEmpty(); - } -} diff --git a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt new file mode 100644 index 000000000..aa1b5bb75 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.repository.filters + +import org.radarbase.management.domain.Subject +import org.radarbase.management.web.rest.criteria.CriteriaRange +import java.util.function.Supplier +import javax.persistence.criteria.CriteriaBuilder +import javax.persistence.criteria.Expression +import javax.persistence.criteria.JoinType +import javax.persistence.criteria.Path +import javax.persistence.criteria.Predicate +import javax.persistence.criteria.Root + +class PredicateBuilder(val criteriaBuilder: CriteriaBuilder) { + private val predicates: MutableList + + init { + predicates = ArrayList() + } + + /** Add predicate to query. */ + fun add(predicate: Predicate?) { + if (predicate == null) { + return + } + predicates.add(predicate) + } + + fun isNull(expression: Expression<*>?) { + predicates.add(criteriaBuilder.isNull(expression)) + } + + /** + * Build the predicates as an AND predicate. + */ + fun toAndPredicate(): Predicate? { + return if (predicates.size == 1) { + predicates[0] + } else if (!predicates.isEmpty()) { + criteriaBuilder.and(*predicates.toTypedArray()) + } else { + null + } + } + + /** + * Build the predicates as an AND predicate. + */ + fun toOrPredicate(): Predicate? { + return if (predicates.size == 1) { + predicates[0] + } else if (!predicates.isEmpty()) { + criteriaBuilder.or(*predicates.toTypedArray()) + } else { + null + } + } + + /** + * Add an equal criteria to predicates if value is not null or empty. + * @param path entity path + * @param value value to compare with + * @param type of field. + */ + fun equal(path: Supplier?>, value: T) { + if (isValidValue(value)) { + add(criteriaBuilder.equal(path.get(), value)) + } + } + + /** + * Add an equal criteria to predicates if value is not null or empty. + * @param path entity path + * @param value value to compare with + * @param type of field. + */ + fun equal(path: Expression?, value: T) { + if (isValidValue(value)) { + add(criteriaBuilder.equal(path, value)) + } + } + + /** + * Add a like criteria to predicates if value is not null or empty, matching both sides. + * @param path entity path + * @param value value to compare with + */ + fun likeLower(path: Supplier?>, value: String) { + if (isValidValue(value)) { + add( + criteriaBuilder.like( + criteriaBuilder.lower(path.get()), + "%" + value.trim { it <= ' ' }.lowercase() + "%" + ) + ) + } + } + + /** + * Add a like criteria to predicates if value is not null or empty, matching both sides. + * @param path entity path + * @param value value to compare with + */ + fun likeLower(path: Expression?, value: String?) { + if (isValidValue(value)) { + add( + criteriaBuilder.like( + criteriaBuilder.lower(path), + "%" + value!!.trim { it <= ' ' }.lowercase() + "%" + ) + ) + } + } + + /** + * Add a like criteria to predicates if value is not null or empty, matching both sides. + * @param root entity to fetch attributes from. + * @param attributeKey name of the attribute. + * @param attributeValue value to compare with using a like query. + */ + fun attributeLike( + root: Root<*>, attributeKey: String?, + attributeValue: String? + ) { + if (isValidValue(attributeValue)) { + val attributesJoin = root.joinMap("attributes", JoinType.LEFT) + add( + criteriaBuilder.and( + criteriaBuilder.equal(attributesJoin.key(), attributeKey), + criteriaBuilder.like( + attributesJoin.value(), + "%$attributeValue%" + ) + ) + ) + } + } + + fun `in`(expr: Expression<*>, other: Expression<*>?) { + add(expr.`in`(other)) + } + + fun `in`(expr: Expression<*>, other: Collection<*>?) { + add(expr.`in`(other)) + } + + /** + * Add comparable criteria matching given range. + * @param path entity property path. + * @param range range that should be matched. + */ + fun ?> range( + path: Path?, range: CriteriaRange? + ) { + if (range == null || range.isEmpty) { + return + } + range.validate() + if (range.iss != null) { + add(criteriaBuilder.equal(path, range.iss)) + } else { + val from = range.from + val to = range.to + if (from != null && to != null) { + add(criteriaBuilder.between(path, from, to)) + } else if (from != null) { + add(criteriaBuilder.greaterThanOrEqualTo(path, from)) + } else if (to != null) { + add(criteriaBuilder.lessThanOrEqualTo(path, to)) + } + } + } + + /** + * Whether given String a proper value. + */ + fun isValidValue(value: Any?): Boolean { + if (value == null) { + return false + } + return if (value is String) { + !value.isBlank() && value != "null" + } else true + } + + fun newBuilder(): PredicateBuilder { + return PredicateBuilder(criteriaBuilder) + } + + val isEmpty: Boolean + get() = predicates.isEmpty() +} diff --git a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.java b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.java deleted file mode 100644 index d403bc322..000000000 --- a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.java +++ /dev/null @@ -1,203 +0,0 @@ -package org.radarbase.management.repository.filters; - -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.Subject; -import org.radarbase.management.domain.User; -import org.radarbase.management.web.rest.criteria.CriteriaRange; -import org.radarbase.management.web.rest.criteria.SubjectAuthority; -import org.radarbase.management.web.rest.criteria.SubjectCriteria; -import org.radarbase.management.web.rest.criteria.SubjectCriteriaLast; -import org.radarbase.management.web.rest.criteria.SubjectSortBy; -import org.radarbase.management.web.rest.criteria.SubjectSortOrder; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.springframework.data.jpa.domain.Specification; - -import javax.annotation.Nullable; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Join; -import javax.persistence.criteria.JoinType; -import javax.persistence.criteria.Order; -import javax.persistence.criteria.Path; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; -import java.time.LocalDate; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_VALIDATION; - -public class SubjectSpecification implements Specification { - private final CriteriaRange dateOfBirth; - private final CriteriaRange enrollmentDate; - private final Long groupId; - private final String humanReadableIdentifier; - private final SubjectCriteriaLast last; - private final String personName; - private final String projectName; - private final String externalId; - private final String subjectId; - private final List sort; - private final Set authority; - private final List sortLastValues; - - /** - * Subject specification based on criteria. - * @param criteria criteria to use for the specification. - */ - public SubjectSpecification(SubjectCriteria criteria) { - this.authority = criteria.getAuthority().stream() - .map(SubjectAuthority::name) - .collect(Collectors.toSet()); - this.dateOfBirth = criteria.getDateOfBirth(); - this.enrollmentDate = criteria.getEnrollmentDate(); - this.groupId = criteria.getGroupId(); - this.humanReadableIdentifier = criteria.getHumanReadableIdentifier(); - this.last = criteria.getLast(); - this.personName = criteria.getPersonName(); - this.projectName = criteria.getProjectName(); - this.externalId = criteria.getExternalId(); - this.subjectId = criteria.getLogin(); - this.sort = criteria.getParsedSort(); - if (last != null) { - this.sortLastValues = this.sort.stream() - .map(o -> getLastValue(o.getSortBy())) - .toList(); - } else { - this.sortLastValues = null; - } - } - - @Override - public Predicate toPredicate(@Nullable Root root, @Nullable CriteriaQuery query, - @Nullable CriteriaBuilder builder) { - if (root == null || query == null || builder == null) { - return null; - } - query.distinct(true); - - root.alias("subject"); - Join userJoin = root.join("user"); - userJoin.alias("user"); - - PredicateBuilder predicates = new PredicateBuilder(builder); - - addRolePredicates(userJoin, predicates); - - predicates.attributeLike(root, "Human-readable-identifier", - humanReadableIdentifier); - predicates.likeLower(root.get("externalId"), externalId); - - predicates.equal(root.get("group"), groupId); - - predicates.range(root.get("dateOfBirth"), dateOfBirth); - predicates.range(root.get("enrollmentDate"), enrollmentDate); - - predicates.likeLower(root.get("personName"), personName); - predicates.likeLower(userJoin.get("login"), subjectId); - - addContentPredicates(predicates, builder, root, query.getResultType()); - - query.orderBy(getSortOrder(root, builder)); - - return predicates.toAndPredicate(); - } - - private Predicate filterLastValues(Root root, CriteriaBuilder builder) { - Predicate[] lastPredicates = new Predicate[sort.size()]; - List> paths = new ArrayList<>(sort.size()); - for (SubjectSortOrder order : sort) { - paths.add(getPropertyPath(order.getSortBy(), root)); - } - for (int i = 0; i < sort.size(); i++) { - Predicate[] lastAndPredicates = i > 0 ? new Predicate[i + 1] : null; - for (int j = 0; j < i; j++) { - lastAndPredicates[j] = builder.equal(paths.get(j), sortLastValues.get(j)); - } - - SubjectSortOrder order = sort.get(i); - Predicate currentSort; - if (order.getDirection().isAscending()) { - currentSort = builder.greaterThan(paths.get(i), sortLastValues.get(i)); - } else { - currentSort = builder.lessThan(paths.get(i), sortLastValues.get(i)); - } - - if (lastAndPredicates != null) { - lastAndPredicates[i] = currentSort; - lastPredicates[i] = builder.and(lastAndPredicates); - } else { - lastPredicates[i] = currentSort; - } - } - if (lastPredicates.length > 1) { - return builder.or(lastPredicates); - } else { - return lastPredicates[0]; - } - } - - private void addContentPredicates(PredicateBuilder predicates, CriteriaBuilder builder, - Root root, Class queryResult) { - // Don't add content for count queries. - if (queryResult == Long.class || queryResult == long.class) { - return; - } - root.fetch("sources", JoinType.LEFT); - root.fetch("user", JoinType.INNER); - - if (last != null) { - predicates.add(filterLastValues(root, builder)); - } - } - - private String getLastValue(SubjectSortBy property) { - String result = switch (property) { - case ID -> last.getId(); - case USER_LOGIN -> last.getLogin(); - case EXTERNAL_ID -> last.getExternalId(); - }; - if (property.isUnique() && result == null) { - throw new BadRequestException("No last value given for sort property " + property, - SUBJECT, ERR_VALIDATION); - } - return result; - } - - - private Path getPropertyPath(SubjectSortBy property, Root root) { - return switch (property) { - case ID -> root.get("id"); - case USER_LOGIN -> root.get("user").get("login"); - case EXTERNAL_ID -> root.get("externalId"); - }; - } - - private void addRolePredicates(Join userJoin, PredicateBuilder predicates) { - Join rolesJoin = userJoin.join("roles"); - rolesJoin.alias("roles"); - - predicates.equal(() -> rolesJoin.get("project").get("projectName"), projectName); - if (!authority.isEmpty() && authority.size() != SubjectAuthority.values().length) { - predicates.add(rolesJoin.get("authority").get("name").in(authority)); - } - } - - private List getSortOrder(Root root, - CriteriaBuilder builder) { - return sort.stream() - .map(order -> { - Path path = getPropertyPath(order.getSortBy(), root); - if (order.getDirection().isAscending()) { - return builder.asc(path); - } else { - return builder.desc(path); - } - }) - .toList(); - } -} diff --git a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt new file mode 100644 index 000000000..162cd032d --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt @@ -0,0 +1,196 @@ +package org.radarbase.management.repository.filters + +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.Subject +import org.radarbase.management.domain.User +import org.radarbase.management.web.rest.criteria.CriteriaRange +import org.radarbase.management.web.rest.criteria.SubjectAuthority +import org.radarbase.management.web.rest.criteria.SubjectCriteria +import org.radarbase.management.web.rest.criteria.SubjectCriteriaLast +import org.radarbase.management.web.rest.criteria.SubjectSortBy +import org.radarbase.management.web.rest.criteria.SubjectSortOrder +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.springframework.data.jpa.domain.Specification +import java.time.LocalDate +import java.time.ZonedDateTime +import java.util.stream.Collectors +import javax.persistence.criteria.CriteriaBuilder +import javax.persistence.criteria.CriteriaQuery +import javax.persistence.criteria.Join +import javax.persistence.criteria.JoinType +import javax.persistence.criteria.Order +import javax.persistence.criteria.Path +import javax.persistence.criteria.Predicate +import javax.persistence.criteria.Root + +class SubjectSpecification(criteria: SubjectCriteria) : Specification { + private val dateOfBirth: CriteriaRange? + private val enrollmentDate: CriteriaRange? + private val groupId: Long? + private val humanReadableIdentifier: String? + private val last: SubjectCriteriaLast? + private val personName: String? + private val projectName: String? + private val externalId: String? + private val subjectId: String? + private val sort: List? + private val authority: Set + private var sortLastValues: List? = null + + /** + * Subject specification based on criteria. + * @param criteria criteria to use for the specification. + */ + init { + authority = criteria.authority.stream() + .map { obj: SubjectAuthority? -> obj!!.name } + .collect(Collectors.toSet()) + dateOfBirth = criteria.dateOfBirth + enrollmentDate = criteria.enrollmentDate + groupId = criteria.groupId + humanReadableIdentifier = criteria.humanReadableIdentifier + last = criteria.last + personName = criteria.personName + projectName = criteria.projectName + externalId = criteria.externalId + subjectId = criteria.login + sort = criteria.getParsedSort() + if (last != null) { + sortLastValues = sort + ?.map { o: SubjectSortOrder -> getLastValue(o.sortBy) } + ?.toList() + } else { + sortLastValues = null + } + } + + override fun toPredicate( + root: Root?, query: CriteriaQuery<*>?, + builder: CriteriaBuilder? + ): Predicate? { + if (root == null || query == null || builder == null) { + return null + } + query.distinct(true) + root.alias("subject") + val userJoin = root.join("user") + userJoin.alias("user") + val predicates = PredicateBuilder(builder) + addRolePredicates(userJoin, predicates) + predicates.attributeLike( + root, "Human-readable-identifier", + humanReadableIdentifier + ) + predicates.likeLower(root.get("externalId"), externalId) + predicates.equal(root.get("group"), groupId) + predicates.range(root.get("dateOfBirth"), dateOfBirth) + predicates.range(root.get("enrollmentDate"), enrollmentDate) + predicates.likeLower(root.get("personName"), personName) + predicates.likeLower(userJoin.get("login"), subjectId) + addContentPredicates(predicates, builder, root, query.resultType) + query.orderBy(getSortOrder(root, builder)) + return predicates.toAndPredicate()!! + } + + //TODO I don't think return type needs to be nullable + private fun filterLastValues(root: Root, builder: CriteriaBuilder): Predicate? { + val lastPredicates = arrayOfNulls( + sort!!.size + ) + val paths: MutableList> = ArrayList( + sort.size + ) + for (order in sort) { + paths.add(getPropertyPath(order.sortBy, root)) + } + for (i in sort.indices) { + val lastAndPredicates: Array? = if (i > 0) arrayOfNulls(i + 1) else null + + for (j in 0 until i) { + lastAndPredicates!![j] = builder.equal(paths[j], sortLastValues!![j]) + } + val order = sort[i] + val currentSort: Predicate? = if (order.direction.isAscending) { + builder.greaterThan(paths[i], sortLastValues!![i]!!)//TODO + } else { + builder.lessThan(paths[i], sortLastValues!![i]!!)//TODO + } + if (lastAndPredicates != null) { + lastAndPredicates[i] = currentSort + lastPredicates[i] = builder.and(*lastAndPredicates) + } else { + lastPredicates[i] = currentSort + } + } + return if (lastPredicates.size > 1) { + builder.or(*lastPredicates) + } else { + lastPredicates[0] + } + } + + private fun addContentPredicates( + predicates: PredicateBuilder, builder: CriteriaBuilder, + root: Root, queryResult: Class<*> + ) { + // Don't add content for count queries. + if (queryResult == Long::class.java || queryResult == Long::class.javaPrimitiveType) { + return + } + root.fetch("sources", JoinType.LEFT) + root.fetch("user", JoinType.INNER) + if (last != null) { + predicates.add(filterLastValues(root, builder)) + } + } + + private fun getLastValue(property: SubjectSortBy): String? { + val result = when (property) { + SubjectSortBy.ID -> last?.id + SubjectSortBy.USER_LOGIN -> last?.login + SubjectSortBy.EXTERNAL_ID -> last?.login + } + if (property.isUnique && result == null) { + throw BadRequestException( + "No last value given for sort property $property", + EntityName.Companion.SUBJECT, ErrorConstants.ERR_VALIDATION + ) + } + return result + } + + private fun getPropertyPath(property: SubjectSortBy, root: Root): Path { + return when (property) { + SubjectSortBy.ID -> root.get("id") + SubjectSortBy.USER_LOGIN -> root.get("user").get("login") + SubjectSortBy.EXTERNAL_ID -> root.get("externalId") + } + } + + private fun addRolePredicates(userJoin: Join, predicates: PredicateBuilder) { + val rolesJoin = userJoin.join("roles") + rolesJoin.alias("roles") + predicates.equal({ rolesJoin.get("project").get("projectName") }, projectName) + if (!authority.isEmpty() && authority.size != SubjectAuthority.values().size) { + predicates.add(rolesJoin.get("authority").get("name").`in`(authority)) + } + } + + private fun getSortOrder( + root: Root, + builder: CriteriaBuilder + ): List? { + return sort + ?.map { order: SubjectSortOrder -> + val path = getPropertyPath(order.sortBy, root) + if (order.direction.isAscending) { + return listOf(builder.asc(path)) + } else { + return listOf(builder.desc(path)) + } + } + ?.toList() + } +} diff --git a/src/main/java/org/radarbase/management/repository/filters/UserFilter.java b/src/main/java/org/radarbase/management/repository/filters/UserFilter.java deleted file mode 100644 index e97ec723d..000000000 --- a/src/main/java/org/radarbase/management/repository/filters/UserFilter.java +++ /dev/null @@ -1,222 +0,0 @@ -package org.radarbase.management.repository.filters; - -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.domain.Organization; -import org.radarbase.management.domain.Project; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.User; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.jpa.domain.Specification; - -import javax.annotation.Nonnull; -import javax.persistence.criteria.CriteriaBuilder; -import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.From; -import javax.persistence.criteria.Join; -import javax.persistence.criteria.JoinType; -import javax.persistence.criteria.Predicate; -import javax.persistence.criteria.Root; -import javax.persistence.criteria.Subquery; -import java.util.List; -import java.util.Locale; -import java.util.function.BiConsumer; -import java.util.stream.Stream; - -public class UserFilter implements Specification { - private static final Logger logger = LoggerFactory.getLogger(UserFilter.class); - - private String login; - private String email; - private String projectName; - private String organization; - private String authority; - private boolean includeUpperLevels = false; - - @Override - public Predicate toPredicate(Root root, @Nonnull CriteriaQuery query, - @Nonnull CriteriaBuilder builder) { - PredicateBuilder predicates = new PredicateBuilder(builder); - predicates.likeLower(root.get("login"), login); - predicates.likeLower(root.get("email"), email); - - filterRoles(predicates, root.join("roles", JoinType.LEFT), query); - - query.distinct(true); - var result = predicates.toAndPredicate(); - logger.debug("Filtering users by {}", result); - return result; - } - - private void filterRoles(PredicateBuilder predicates, Join roleJoin, - CriteriaQuery query) { - Stream authoritiesFiltered = Stream.of(RoleAuthority.values()) - .filter(r -> !r.isPersonal); - boolean allowNoRole = true; - - if (predicates.isValidValue(authority)) { - String authorityUpper = authority.toUpperCase(Locale.ROOT); - authoritiesFiltered = authoritiesFiltered - .filter(r -> r != null && r.getAuthority().contains(authorityUpper)); - allowNoRole = false; - } - List authoritiesAllowed = authoritiesFiltered.toList(); - if (authoritiesAllowed.isEmpty()) { - CriteriaBuilder builder = predicates.getCriteriaBuilder(); - // never match - predicates.add(builder.isTrue(builder.literal(false))); - return; - } - - determineScope(predicates, roleJoin, query, authoritiesAllowed, allowNoRole); - } - - private void determineScope( - PredicateBuilder predicates, - Join roleJoin, - CriteriaQuery query, - List authoritiesAllowed, - boolean allowNoRole) { - PredicateBuilder authorityPredicates = predicates.newBuilder(); - - boolean allowNoRoleInScope = allowNoRole; - // Is organization admin - if (predicates.isValidValue(projectName)) { - allowNoRoleInScope = false; - // Is project admin - entitySubquery(RoleAuthority.Scope.PROJECT, roleJoin, - query, authorityPredicates, authoritiesAllowed, - (b, proj) -> b.likeLower(proj.get("projectName"), projectName)); - - // Is organization admin for organization above current project - if (includeUpperLevels) { - entitySubquery(RoleAuthority.Scope.ORGANIZATION, roleJoin, - query, authorityPredicates, authoritiesAllowed, - (b, org) -> b.likeLower( - org.join("projects").get("projectName"), projectName)); - } - } else if (predicates.isValidValue(organization)) { - allowNoRoleInScope = false; - entitySubquery(RoleAuthority.Scope.ORGANIZATION, roleJoin, - query, authorityPredicates, authoritiesAllowed, - (b, org) -> b.likeLower(org.get("name"), organization)); - } - - if (authorityPredicates.isEmpty()) { - // no project or organization filters applied - addAllowedAuthorities(authorityPredicates, roleJoin, authoritiesAllowed, null); - } else if (includeUpperLevels) { - // is sys admin - addAllowedAuthorities(authorityPredicates, roleJoin, authoritiesAllowed, - RoleAuthority.Scope.GLOBAL); - } - if (allowNoRoleInScope) { - authorityPredicates.isNull(roleJoin.get("id")); - } - - predicates.add(authorityPredicates.toOrPredicate()); - } - - private boolean addAllowedAuthorities(PredicateBuilder predicates, - Join roleJoin, - List authorities, - RoleAuthority.Scope scope) { - - Stream authorityStream = authorities.stream(); - if (scope != null) { - authorityStream = authorityStream.filter(r -> r.getScope() == scope); - } - List authorityNames = authorityStream - .map(RoleAuthority::getAuthority) - .toList(); - - if (!authorityNames.isEmpty()) { - predicates.in(roleJoin.get("authority").get("name"), authorityNames); - return true; - } else { - return false; - } - } - - /** Create a subquery to filter the roles. */ - private void entitySubquery(RoleAuthority.Scope scope, - Join roleJoin, - CriteriaQuery query, - PredicateBuilder predicates, - List allowedRoles, - BiConsumer> queryMatch) { - PredicateBuilder authorityPredicates = predicates.newBuilder(); - - if (!addAllowedAuthorities(authorityPredicates, roleJoin, allowedRoles, scope)) { - return; - } - - Subquery subQuery = query.subquery(Long.class); - subQuery.distinct(true); - Root orgRoot = subQuery.from((Class) switch (scope) { - case PROJECT -> Project.class; - case ORGANIZATION -> Organization.class; - default -> throw new IllegalStateException("Unknown role scope " + scope); - }); - subQuery.select(orgRoot.get("id")); - PredicateBuilder subqueryPredicates = predicates.newBuilder(); - queryMatch.accept(subqueryPredicates, orgRoot); - subQuery.where(subqueryPredicates.toAndPredicate()); - - authorityPredicates.in(roleJoin.get( switch (scope) { - case ORGANIZATION -> "organization"; - case PROJECT -> "project"; - default -> throw new IllegalStateException("Unknown role scope " + scope); - }).get("id"), subQuery); - - predicates.add(authorityPredicates.toAndPredicate()); - } - - public String getLogin() { - return login; - } - - public void setLogin(String login) { - this.login = login; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - public String getOrganization() { - return organization; - } - - public void setOrganization(String organization) { - this.organization = organization; - } - - public String getAuthority() { - return authority; - } - - public void setAuthority(String authority) { - this.authority = authority; - } - - public boolean isIncludeUpperLevels() { - return includeUpperLevels; - } - - public void setIncludeUpperLevels(boolean includeUpperLevels) { - this.includeUpperLevels = includeUpperLevels; - } -} diff --git a/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt b/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt new file mode 100644 index 000000000..9dc2110b3 --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt @@ -0,0 +1,179 @@ +package org.radarbase.management.repository.filters + +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.domain.Organization +import org.radarbase.management.domain.Project +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.User +import org.slf4j.LoggerFactory +import org.springframework.data.jpa.domain.Specification +import java.util.function.BiConsumer +import java.util.stream.Stream +import javax.annotation.Nonnull +import javax.persistence.criteria.CriteriaBuilder +import javax.persistence.criteria.CriteriaQuery +import javax.persistence.criteria.From +import javax.persistence.criteria.Join +import javax.persistence.criteria.JoinType +import javax.persistence.criteria.Predicate +import javax.persistence.criteria.Root + +class UserFilter : Specification { + var login: String? = null + var email: String? = null + var projectName: String? = null + var organization: String? = null + var authority: String? = null + var isIncludeUpperLevels = false + override fun toPredicate( + root: Root, @Nonnull query: CriteriaQuery<*>, + @Nonnull builder: CriteriaBuilder + ): Predicate { + val predicates = PredicateBuilder(builder) + predicates.likeLower(root.get("login"), login) + predicates.likeLower(root.get("email"), email) + filterRoles(predicates, root.join("roles", JoinType.LEFT), query) + query.distinct(true) + val result = predicates.toAndPredicate() + logger.debug("Filtering users by {}", result) + return result!! + } + + private fun filterRoles( + predicates: PredicateBuilder, roleJoin: Join, + query: CriteriaQuery<*> + ) { + var authoritiesFiltered = Stream.of(*RoleAuthority.values()) + .filter { r: RoleAuthority -> !r.isPersonal } + var allowNoRole = true + if (predicates.isValidValue(authority)) { + val authorityUpper = authority!!.uppercase() + authoritiesFiltered = authoritiesFiltered + .filter { r: RoleAuthority? -> r != null && r.authority.contains(authorityUpper) } + allowNoRole = false + } + val authoritiesAllowed = authoritiesFiltered.toList() + if (authoritiesAllowed.isEmpty()) { + val builder = predicates.criteriaBuilder + // never match + predicates.add(builder!!.isTrue(builder.literal(false))) + return + } + determineScope(predicates, roleJoin, query, authoritiesAllowed, allowNoRole) + } + + private fun determineScope( + predicates: PredicateBuilder, + roleJoin: Join, + query: CriteriaQuery<*>, + authoritiesAllowed: List, + allowNoRole: Boolean + ) { + val authorityPredicates = predicates.newBuilder() + var allowNoRoleInScope = allowNoRole + // Is organization admin + if (predicates.isValidValue(projectName)) { + allowNoRoleInScope = false + // Is project admin + entitySubquery( + RoleAuthority.Scope.PROJECT, roleJoin, + query, authorityPredicates, authoritiesAllowed + ) { b: PredicateBuilder?, proj: From<*, *> -> b!!.likeLower(proj.get("projectName"), projectName) } + + // Is organization admin for organization above current project + if (isIncludeUpperLevels) { + entitySubquery( + RoleAuthority.Scope.ORGANIZATION, roleJoin, + query, authorityPredicates, authoritiesAllowed + ) { b: PredicateBuilder?, org: From<*, *> -> + b!!.likeLower( + org.join("projects").get("projectName"), projectName + ) + } + } + } else if (predicates.isValidValue(organization)) { + allowNoRoleInScope = false + entitySubquery( + RoleAuthority.Scope.ORGANIZATION, roleJoin, + query, authorityPredicates, authoritiesAllowed + ) { b: PredicateBuilder?, org: From<*, *> -> b!!.likeLower(org.get("name"), organization) } + } + if (authorityPredicates.isEmpty) { + // no project or organization filters applied + addAllowedAuthorities(authorityPredicates, roleJoin, authoritiesAllowed, null) + } else if (isIncludeUpperLevels) { + // is sys admin + addAllowedAuthorities( + authorityPredicates, roleJoin, authoritiesAllowed, + RoleAuthority.Scope.GLOBAL + ) + } + if (allowNoRoleInScope) { + authorityPredicates!!.isNull(roleJoin.get("id")) + } + predicates.add(authorityPredicates!!.toOrPredicate()) + } + + private fun addAllowedAuthorities( + predicates: PredicateBuilder?, + roleJoin: Join, + authorities: List, + scope: RoleAuthority.Scope? + ): Boolean { + var authorityStream = authorities.stream() + if (scope != null) { + authorityStream = authorityStream.filter { r: RoleAuthority -> r.scope === scope } + } + val authorityNames = authorityStream + .map(RoleAuthority::authority) + .toList() + return if (!authorityNames.isEmpty()) { + predicates!!.`in`(roleJoin.get("authority").get("name"), authorityNames) + true + } else { + false + } + } + + /** Create a subquery to filter the roles. */ + private fun entitySubquery( + scope: RoleAuthority.Scope, + roleJoin: Join, + query: CriteriaQuery<*>, + predicates: PredicateBuilder?, + allowedRoles: List, + queryMatch: BiConsumer> + ) { + val authorityPredicates = predicates!!.newBuilder() + if (!addAllowedAuthorities(authorityPredicates, roleJoin, allowedRoles, scope)) { + return + } + val subQuery = query.subquery(Long::class.java) + subQuery.distinct(true) + val orgRoot = subQuery.from( + when (scope) { + RoleAuthority.Scope.PROJECT -> Project::class.java + RoleAuthority.Scope.ORGANIZATION -> Organization::class.java + else -> throw IllegalStateException("Unknown role scope $scope") + } as Class<*> + ) + subQuery.select(orgRoot.get("id")) + val subqueryPredicates = predicates.newBuilder() + queryMatch.accept(subqueryPredicates, orgRoot) + subQuery.where(subqueryPredicates!!.toAndPredicate()) + authorityPredicates!!.`in`( + roleJoin.get( + when (scope) { + RoleAuthority.Scope.ORGANIZATION -> "organization" + RoleAuthority.Scope.PROJECT -> "project" + else -> throw IllegalStateException("Unknown role scope $scope") + } + ).get("id"), subQuery + ) + predicates.add(authorityPredicates.toAndPredicate()) + } + + companion object { + private val logger = LoggerFactory.getLogger(UserFilter::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/repository/package-info.java b/src/main/java/org/radarbase/management/repository/package-info.java deleted file mode 100644 index f223176be..000000000 --- a/src/main/java/org/radarbase/management/repository/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Spring Data JPA repositories. - */ -package org.radarbase.management.repository; diff --git a/src/main/java/org/radarbase/management/repository/package-info.kt b/src/main/java/org/radarbase/management/repository/package-info.kt new file mode 100644 index 000000000..3dcb8c57a --- /dev/null +++ b/src/main/java/org/radarbase/management/repository/package-info.kt @@ -0,0 +1,5 @@ +/** + * Spring Data JPA repositories. + */ +package org.radarbase.management.repository + diff --git a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java deleted file mode 100644 index 2382e7067..000000000 --- a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.radarbase.management.security; - -import org.radarbase.auth.authorization.AuthorizationOracle; -import org.radarbase.auth.authorization.Permission; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.domain.Role; -import org.radarbase.management.domain.Source; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.repository.UserRepository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.boot.actuate.audit.AuditEventRepository; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.OAuth2Request; -import org.springframework.security.oauth2.provider.token.TokenEnhancer; - -import java.security.Principal; -import java.time.Instant; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.stream.Collectors; - -import static org.radarbase.auth.jwt.JwtTokenVerifier.GRANT_TYPE_CLAIM; -import static org.radarbase.auth.jwt.JwtTokenVerifier.ROLES_CLAIM; -import static org.radarbase.auth.jwt.JwtTokenVerifier.SOURCES_CLAIM; - -public class ClaimsTokenEnhancer implements TokenEnhancer, InitializingBean { - private static final Logger logger = LoggerFactory.getLogger(ClaimsTokenEnhancer.class); - - @Autowired - private SubjectRepository subjectRepository; - - @Autowired - private UserRepository userRepository; - - @Autowired - private AuditEventRepository auditEventRepository; - - @Autowired - private AuthorizationOracle authorizationOracle; - - @Value("${spring.application.name}") - private String appName; - - private static final String GRANT_TOKEN_EVENT = "GRANT_ACCESS_TOKEN"; - - @Override - public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, - OAuth2Authentication authentication) { - logger.debug("Enhancing token of authentication {}" , authentication); - - Map additionalInfo = new HashMap<>(); - - String userName = authentication.getName(); - - if (authentication.getPrincipal() instanceof Principal - || authentication.getPrincipal() instanceof UserDetails) { - // add the 'sub' claim in accordance with JWT spec - additionalInfo.put("sub", userName); - - userRepository.findOneByLogin(userName) - .ifPresent(user -> { - var roles = user.roles.stream() - .map(role -> { - var auth = role.authority.name; - return switch (role.getRole().getScope()) { - case GLOBAL -> auth; - case ORGANIZATION -> role.organization.name - + ":" + auth; - case PROJECT -> role.project.projectName - + ":" + auth; - }; - }) - .toList(); - additionalInfo.put(ROLES_CLAIM, roles); - - // Do not grant scopes that cannot be given to a user. - Set currentScopes = accessToken.getScope(); - Set newScopes = currentScopes.stream() - .filter(scope -> { - Permission permission = Permission.ofScope(scope); - var roleAuthorities = user.roles.stream() - .map(Role::getRole) - .collect(Collectors.toCollection(() -> - EnumSet.noneOf(RoleAuthority.class))); - return authorizationOracle.mayBeGranted(roleAuthorities, - permission); - }) - .collect(Collectors.toCollection(TreeSet::new)); - - if (!newScopes.equals(currentScopes)) { - ((DefaultOAuth2AccessToken) accessToken).setScope(newScopes); - } - }); - - List assignedSources = subjectRepository.findSourcesBySubjectLogin(userName); - - List sourceIds = assignedSources.stream() - .map(s -> s.sourceId.toString()) - .toList(); - additionalInfo.put(SOURCES_CLAIM, sourceIds); - } - // add iat and iss optional JWT claims - additionalInfo.put("iat", Instant.now().getEpochSecond()); - additionalInfo.put("iss", appName); - additionalInfo.put(GRANT_TYPE_CLAIM, - authentication.getOAuth2Request().getGrantType()); - ((DefaultOAuth2AccessToken) accessToken) - .setAdditionalInformation(additionalInfo); - - // HACK: since all granted tokens need to pass here, we can use this point to create an - // audit event for a granted token, there is an open issue about oauth2 audit events in - // spring security but it has been inactive for a long time: - // https://github.com/spring-projects/spring-security-oauth/issues/223 - Map auditData = auditData(accessToken, authentication); - auditEventRepository.add(new AuditEvent(userName, GRANT_TOKEN_EVENT, - auditData)); - logger.info("[{}] for {}: {}", GRANT_TOKEN_EVENT, userName, auditData); - - return accessToken; - } - - @Override - public void afterPropertiesSet() throws Exception { - // nothing to do for now - } - - private Map auditData(OAuth2AccessToken accessToken, - OAuth2Authentication authentication) { - Map result = new HashMap<>(); - result.put("tokenType", accessToken.getTokenType()); - result.put("scope", String.join(", ", accessToken.getScope())); - result.put("expiresIn", Integer.toString(accessToken.getExpiresIn())); - result.putAll(accessToken.getAdditionalInformation()); - OAuth2Request request = authentication.getOAuth2Request(); - result.put("clientId", request.getClientId()); - result.put("grantType", request.getGrantType()); - return result; - } -} diff --git a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt new file mode 100644 index 000000000..6000870db --- /dev/null +++ b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt @@ -0,0 +1,132 @@ +package org.radarbase.management.security + +import org.radarbase.auth.authorization.AuthorizationOracle +import org.radarbase.auth.authorization.Permission +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.auth.jwt.JwtTokenVerifier +import org.radarbase.management.domain.Role +import org.radarbase.management.domain.Source +import org.radarbase.management.domain.User +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.repository.UserRepository +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.InitializingBean +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.boot.actuate.audit.AuditEventRepository +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken +import org.springframework.security.oauth2.common.OAuth2AccessToken +import org.springframework.security.oauth2.provider.OAuth2Authentication +import org.springframework.security.oauth2.provider.token.TokenEnhancer +import java.security.Principal +import java.time.Instant +import java.util.* + +class ClaimsTokenEnhancer( + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val userRepository: UserRepository, + @Autowired private val auditEventRepository: AuditEventRepository, + @Autowired private val authorizationOracle: AuthorizationOracle +) : TokenEnhancer, InitializingBean { + + @Value("\${spring.application.name}") + private val appName: String? = null + override fun enhance( + accessToken: OAuth2AccessToken, authentication: OAuth2Authentication + ): OAuth2AccessToken { + logger.debug("Enhancing token of authentication {}", authentication) + val additionalInfo: MutableMap = HashMap() + val userName = authentication.getName() + if (authentication.principal is Principal || authentication.principal is UserDetails) { + // add the 'sub' claim in accordance with JWT spec + additionalInfo["sub"] = userName + userRepository.findOneByLogin(userName)?.let { user: User? -> + val roles = user!!.roles!!.stream().map { role: Role -> + val auth = role.authority!!.name + when (role.role!!.scope) { + RoleAuthority.Scope.GLOBAL -> auth + RoleAuthority.Scope.ORGANIZATION -> (role.organization!!.name + ":" + auth) + + RoleAuthority.Scope.PROJECT -> (role.project!!.projectName + ":" + auth) + } + }.toList() + additionalInfo[JwtTokenVerifier.ROLES_CLAIM] = roles + + // Do not grant scopes that cannot be given to a user. + val currentScopes: MutableSet = accessToken.scope + val newScopes: Set = currentScopes + .filter { scope: String -> + val permission: Permission = Permission.ofScope(scope) + + val roleAuthorities = user + .roles!!.mapNotNull { it.role } + .let{ _ -> EnumSet.noneOf(RoleAuthority::class.java)} + .filterNotNull() + + roleAuthorities.mayBeGranted(permission) + } + .toSet() + + if (newScopes != currentScopes) { + (accessToken as DefaultOAuth2AccessToken).scope = newScopes + } + } + val assignedSources = subjectRepository.findSourcesBySubjectLogin(userName) + val sourceIds = assignedSources.stream().map { s: Source? -> s!!.sourceId.toString() }.toList() + additionalInfo[JwtTokenVerifier.SOURCES_CLAIM] = sourceIds + } + // add iat and iss optional JWT claims + additionalInfo["iat"] = Instant.now().epochSecond + additionalInfo["iss"] = appName + additionalInfo[JwtTokenVerifier.GRANT_TYPE_CLAIM] = authentication.oAuth2Request.getGrantType() + (accessToken as DefaultOAuth2AccessToken).additionalInformation = additionalInfo + + // HACK: since all granted tokens need to pass here, we can use this point to create an + // audit event for a granted token, there is an open issue about oauth2 audit events in + // spring security but it has been inactive for a long time: + // https://github.com/spring-projects/spring-security-oauth/issues/223 + val auditData = auditData(accessToken, authentication) + auditEventRepository.add( + AuditEvent( + userName, GRANT_TOKEN_EVENT, auditData + ) + ) + logger.info("[{}] for {}: {}", GRANT_TOKEN_EVENT, userName, auditData) + return accessToken + } + + @Throws(Exception::class) + override fun afterPropertiesSet() { + // nothing to do for now + } + + private fun auditData( + accessToken: OAuth2AccessToken, authentication: OAuth2Authentication + ): Map { + val result: MutableMap = HashMap() + result["tokenType"] = accessToken.tokenType + result["scope"] = java.lang.String.join(", ", accessToken.scope) + result["expiresIn"] = accessToken.expiresIn.toString() + result.putAll(accessToken.additionalInformation) + val request = authentication.oAuth2Request + result["clientId"] = request.clientId + result["grantType"] = request.getGrantType() + return result + } + + open fun mayBeGranted(role: RoleAuthority, permission: Permission): Boolean = with(authorizationOracle) { + role.mayBeGranted(permission) + } + + fun Collection.mayBeGranted(permission: Permission): Boolean = with(authorizationOracle) { + return any { it.mayBeGranted(permission) } + } + + companion object { + private val logger = LoggerFactory.getLogger(ClaimsTokenEnhancer::class.java) + private const val GRANT_TOKEN_EVENT = "GRANT_ACCESS_TOKEN" + } +} + diff --git a/src/main/java/org/radarbase/management/security/Constants.java b/src/main/java/org/radarbase/management/security/Constants.java deleted file mode 100644 index a713c34fc..000000000 --- a/src/main/java/org/radarbase/management/security/Constants.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.radarbase.management.security; - -/** - * Application constants. - */ -public final class Constants { - //Regex for acceptable logins - public static final String ENTITY_ID_REGEX = "^[_'.@A-Za-z0-9- ]*$"; - public static final String TOKEN_NAME_REGEX = "^[A-Za-z0-9.-]*$"; - - public static final String SYSTEM_ACCOUNT = "system"; - public static final String ANONYMOUS_USER = "anonymousUser"; - - private Constants() { - } -} diff --git a/src/main/java/org/radarbase/management/security/Constants.kt b/src/main/java/org/radarbase/management/security/Constants.kt new file mode 100644 index 000000000..f0ffc5e54 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/Constants.kt @@ -0,0 +1,12 @@ +package org.radarbase.management.security + +/** + * Application constants. + */ +object Constants { + //Regex for acceptable logins + const val ENTITY_ID_REGEX = "^[_'.@A-Za-z0-9- ]*$" + const val TOKEN_NAME_REGEX = "^[A-Za-z0-9.-]*$" + const val SYSTEM_ACCOUNT = "system" + const val ANONYMOUS_USER = "anonymousUser" +} diff --git a/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java b/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java deleted file mode 100644 index 14a85f33f..000000000 --- a/src/main/java/org/radarbase/management/security/DomainUserDetailsService.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.radarbase.management.security; - -import org.radarbase.management.domain.User; -import org.radarbase.management.repository.UserRepository; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.Locale; -import java.util.stream.Collectors; - -/** - * Authenticate a user from the database. - */ -@Component("userDetailsService") -public class DomainUserDetailsService implements UserDetailsService { - - private static final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class); - - private final UserRepository userRepository; - - public DomainUserDetailsService( - UserRepository userRepository) { - this.userRepository = userRepository; - } - - @Override - @Transactional - public UserDetails loadUserByUsername(final String login) { - log.debug("Authenticating {}", login); - String lowercaseLogin = login.toLowerCase(Locale.ENGLISH); - User user = userRepository.findOneWithRolesByLogin(lowercaseLogin) - .orElseThrow(() -> new UsernameNotFoundException( - "User " + lowercaseLogin + " was not found in the database")); - if (!user.activated) { - throw new UserNotActivatedException("User " + lowercaseLogin - + " was not activated"); - } - - List grantedAuthorities = user.getAuthorities().stream() - .map(authority -> new SimpleGrantedAuthority(authority.name)) - .collect(Collectors.toList()); - - return new org.springframework.security.core.userdetails.User( - lowercaseLogin, - user.password, - grantedAuthorities); - } -} diff --git a/src/main/java/org/radarbase/management/security/DomainUserDetailsService.kt b/src/main/java/org/radarbase/management/security/DomainUserDetailsService.kt new file mode 100644 index 000000000..1dd7ec586 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/DomainUserDetailsService.kt @@ -0,0 +1,47 @@ +package org.radarbase.management.security + +import org.radarbase.management.domain.Authority +import org.radarbase.management.repository.UserRepository +import org.slf4j.LoggerFactory +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.core.userdetails.User +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.core.userdetails.UsernameNotFoundException +import org.springframework.stereotype.Component +import org.springframework.transaction.annotation.Transactional + +/** + * Authenticate a user from the database. + */ +@Component("userDetailsService") +open class DomainUserDetailsService( + private val userRepository: UserRepository +) : UserDetailsService { + @Transactional + override fun loadUserByUsername(login: String): UserDetails { + log.debug("Authenticating {}", login) + val lowercaseLogin = login.lowercase() + val user = userRepository.findOneWithRolesByLogin(lowercaseLogin) + ?: throw UsernameNotFoundException( + "User $lowercaseLogin was not found in the database" + ) + if (!user.activated) { + throw UserNotActivatedException( + "User " + lowercaseLogin + + " was not activated" + ) + } + val grantedAuthorities = + user.authorities!!.mapNotNull { authority: Authority? -> SimpleGrantedAuthority(authority?.name) } + return User( + lowercaseLogin, + user.password, + grantedAuthorities + ) + } + + companion object { + private val log = LoggerFactory.getLogger(DomainUserDetailsService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/security/Http401UnauthorizedEntryPoint.java b/src/main/java/org/radarbase/management/security/Http401UnauthorizedEntryPoint.kt similarity index 65% rename from src/main/java/org/radarbase/management/security/Http401UnauthorizedEntryPoint.java rename to src/main/java/org/radarbase/management/security/Http401UnauthorizedEntryPoint.kt index d39bf8c80..dbeeea979 100644 --- a/src/main/java/org/radarbase/management/security/Http401UnauthorizedEntryPoint.java +++ b/src/main/java/org/radarbase/management/security/Http401UnauthorizedEntryPoint.kt @@ -16,33 +16,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package org.radarbase.management.security -package org.radarbase.management.security; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; +import org.slf4j.LoggerFactory +import org.springframework.security.core.AuthenticationException +import org.springframework.security.web.AuthenticationEntryPoint +import java.io.IOException +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse /** * Returns a 401 error code (Unauthorized) to the client. */ -public class Http401UnauthorizedEntryPoint implements AuthenticationEntryPoint { - private static final Logger log = LoggerFactory.getLogger(Http401UnauthorizedEntryPoint.class); - +class Http401UnauthorizedEntryPoint : AuthenticationEntryPoint { /** * Always returns a 401 error code to the client. */ - @Override - public void commence(HttpServletRequest request, HttpServletResponse response, - AuthenticationException arg2) - throws IOException { + @Throws(IOException::class) + override fun commence( + request: HttpServletRequest, response: HttpServletResponse, + arg2: AuthenticationException + ) { + log.debug("Pre-authenticated entry point called. Rejecting access") + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied") + } - log.debug("Pre-authenticated entry point called. Rejecting access"); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied"); + companion object { + private val log = LoggerFactory.getLogger(Http401UnauthorizedEntryPoint::class.java) } } diff --git a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt index 6abd75069..bfb1967c8 100644 --- a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt +++ b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt @@ -19,7 +19,6 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher import org.springframework.web.cors.CorsUtils import org.springframework.web.filter.OncePerRequestFilter import java.io.IOException -import java.io.Serializable import java.time.Instant import javax.annotation.Nonnull import javax.servlet.FilterChain @@ -149,8 +148,8 @@ class JwtAuthenticationFilter @JvmOverloads constructor( ): RadarToken? { val userName = token.username ?: return token val user = userRepository.findOneByLogin(userName) - return if (user.isPresent) { - token.copyWithRoles(user.get().authorityReferences) + return if (user != null) { + token.copyWithRoles(user.authorityReferences) } else { session?.removeAttribute(TOKEN_ATTRIBUTE) httpResponse.returnUnauthorized(httpRequest, "User not found") @@ -201,14 +200,14 @@ class JwtAuthenticationFilter @JvmOverloads constructor( @get:JvmStatic @set:JvmStatic - var HttpSession.radarToken: RadarToken? - get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken? + var HttpSession.radarToken: RadarToken + get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken set(value) = setAttribute(TOKEN_ATTRIBUTE, value) @get:JvmStatic @set:JvmStatic - var HttpServletRequest.radarToken: RadarToken? - get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken? + var HttpServletRequest.radarToken: RadarToken + get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken set(value) = setAttribute(TOKEN_ATTRIBUTE, value) val Authentication?.isAnonymous: Boolean diff --git a/src/main/java/org/radarbase/management/security/PostgresApprovalStore.java b/src/main/java/org/radarbase/management/security/PostgresApprovalStore.java deleted file mode 100644 index 1677c0ea3..000000000 --- a/src/main/java/org/radarbase/management/security/PostgresApprovalStore.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2012-2013 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.radarbase.management.security; - -import static org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus.APPROVED; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.Collection; -import java.util.Date; -import java.util.List; -import javax.sql.DataSource; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.dao.DataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.security.oauth2.provider.approval.Approval; -import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus; -import org.springframework.security.oauth2.provider.approval.ApprovalStore; -import org.springframework.util.Assert; - -/** - * This class will be used to execute functions related to token approval. It is an duplicate of - * JdbcApprovalStore with escaped case sensitive fields to query. - * - * @author Dave Syer - * @author Modified by Nivethika - */ -public class PostgresApprovalStore implements ApprovalStore { - - private final JdbcTemplate jdbcTemplate; - - private static final Logger logger = LoggerFactory.getLogger(PostgresApprovalStore.class); - - private final RowMapper rowMapper = new AuthorizationRowMapper(); - - private static final String TABLE_NAME = "oauth_approvals"; - - private static final String FIELDS = - "\"expiresAt\", \"status\",\"lastModifiedAt\",\"userId\"," + "\"clientId\"," - + "\"scope\""; - - private static final String WHERE_KEY = "where \"userId\"=? and \"clientId\"=?"; - - private static final String WHERE_KEY_AND_SCOPE = WHERE_KEY + " and \"scope\"=?"; - - private static final String AND_LESS_THAN_EXPIRE_AT = " and \"expiresAt\" <= ?"; - - private static final String DEFAULT_ADD_APPROVAL_STATEMENT = - String.format("insert into %s ( %s ) values (?,?,?,?,?,?)", TABLE_NAME, FIELDS); - - private static final String DEFAULT_REFRESH_APPROVAL_STATEMENT = String.format( - "update %s set \"expiresAt\"=?, \"status\"=?, \"lastModifiedAt\"=? " - + WHERE_KEY_AND_SCOPE, TABLE_NAME); - - private static final String DEFAULT_GET_APPROVAL_SQL = - String.format("select %s from %s " + WHERE_KEY, FIELDS, TABLE_NAME); - - private static final String DEFAULT_DELETE_APPROVAL_SQL = - String.format("delete from %s " + WHERE_KEY_AND_SCOPE + AND_LESS_THAN_EXPIRE_AT, - TABLE_NAME); - - private static final String DEFAULT_EXPIRE_APPROVAL_STATEMENT = - String.format("update %s set " + "\"expiresAt\" = ? " - + WHERE_KEY_AND_SCOPE, TABLE_NAME); - - private String addApprovalStatement = DEFAULT_ADD_APPROVAL_STATEMENT; - - private String refreshApprovalStatement = DEFAULT_REFRESH_APPROVAL_STATEMENT; - - private String findApprovalStatement = DEFAULT_GET_APPROVAL_SQL; - - private String deleteApprovalStatment = DEFAULT_DELETE_APPROVAL_SQL; - - private String expireApprovalStatement = DEFAULT_EXPIRE_APPROVAL_STATEMENT; - - private boolean handleRevocationsAsExpiry = false; - - public PostgresApprovalStore(DataSource dataSource) { - Assert.notNull(dataSource); - this.jdbcTemplate = new JdbcTemplate(dataSource); - } - - public void setHandleRevocationsAsExpiry(boolean handleRevocationsAsExpiry) { - this.handleRevocationsAsExpiry = handleRevocationsAsExpiry; - } - - public void setAddApprovalStatement(String addApprovalStatement) { - this.addApprovalStatement = addApprovalStatement; - } - - public void setFindApprovalStatement(String findApprovalStatement) { - this.findApprovalStatement = findApprovalStatement; - } - - public void setDeleteApprovalStatment(String deleteApprovalStatment) { - this.deleteApprovalStatment = deleteApprovalStatment; - } - - public void setExpireApprovalStatement(String expireApprovalStatement) { - this.expireApprovalStatement = expireApprovalStatement; - } - - public void setRefreshApprovalStatement(String refreshApprovalStatement) { - this.refreshApprovalStatement = refreshApprovalStatement; - } - - @Override - public boolean addApprovals(final Collection approvals) { - logger.debug(String.format("adding approvals: [%s]", approvals)); - boolean success = true; - for (Approval approval : approvals) { - if (!updateApproval(refreshApprovalStatement, approval) && !updateApproval( - addApprovalStatement, approval)) { - success = false; - } - } - return success; - } - - @Override - public boolean revokeApprovals(Collection approvals) { - logger.debug(String.format("Revoking approvals: [%s]", approvals)); - boolean success = true; - for (final Approval approval : approvals) { - if (handleRevocationsAsExpiry) { - int refreshed = jdbcTemplate - .update(expireApprovalStatement, (ps) -> { - ps.setTimestamp(1, new Timestamp(System.currentTimeMillis())); - ps.setString(2, approval.getUserId()); - ps.setString(3, approval.getClientId()); - ps.setString(4, approval.getScope()); - }); - if (refreshed != 1) { - success = false; - } - } else { - int refreshed = jdbcTemplate - .update(deleteApprovalStatment, (ps) -> { - ps.setString(1, approval.getUserId()); - ps.setString(2, approval.getClientId()); - ps.setString(3, approval.getScope()); - }); - if (refreshed != 1) { - success = false; - } - } - } - return success; - } - - /** - * Purges expired approvals from database. - * @return {@code true} if removed successfully, {@code false} otherwise. - */ - public boolean purgeExpiredApprovals() { - logger.debug("Purging expired approvals from database"); - try { - int deleted = jdbcTemplate.update(deleteApprovalStatment, (ps) -> { - ps.setTimestamp(1, new Timestamp(new Date().getTime())); - }); - logger.debug(deleted + " expired approvals deleted"); - } catch (DataAccessException ex) { - logger.error("Error purging expired approvals", ex); - return false; - } - return true; - } - - @Override - public List getApprovals(String userName, String clientId) { - logger.debug("Finding approvals for userName {} and cliendId {}", userName, clientId); - return jdbcTemplate.query(findApprovalStatement, rowMapper, userName, clientId); - } - - private boolean updateApproval(final String sql, final Approval approval) { - logger.debug(String.format("refreshing approval: [%s]", approval)); - int refreshed = jdbcTemplate.update(sql, (ps) -> { - ps.setTimestamp(1, new Timestamp(approval.getExpiresAt().getTime())); - ps.setString(2, (approval.getStatus() == null ? APPROVED - : approval.getStatus()).toString()); - ps.setTimestamp(3, new Timestamp(approval.getLastUpdatedAt().getTime())); - ps.setString(4, approval.getUserId()); - ps.setString(5, approval.getClientId()); - ps.setString(6, approval.getScope()); - }); - return refreshed == 1; - } - - private static class AuthorizationRowMapper implements RowMapper { - - @Override - public Approval mapRow(ResultSet rs, int rowNum) throws SQLException { - String userName = rs.getString(4); - String clientId = rs.getString(5); - String scope = rs.getString(6); - Date expiresAt = rs.getTimestamp(1); - String status = rs.getString(2); - Date lastUpdatedAt = rs.getTimestamp(3); - - return new Approval(userName, clientId, scope, expiresAt, - ApprovalStatus.valueOf(status), lastUpdatedAt); - } - } -} diff --git a/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt b/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt new file mode 100644 index 000000000..1a5eadc0c --- /dev/null +++ b/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt @@ -0,0 +1,203 @@ +/* + * Copyright 2012-2013 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.radarbase.management.security + +import org.slf4j.LoggerFactory +import org.springframework.dao.DataAccessException +import org.springframework.jdbc.core.JdbcTemplate +import org.springframework.jdbc.core.RowMapper +import org.springframework.security.oauth2.provider.approval.Approval +import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus +import org.springframework.security.oauth2.provider.approval.ApprovalStore +import org.springframework.util.Assert +import java.sql.PreparedStatement +import java.sql.ResultSet +import java.sql.SQLException +import java.sql.Timestamp +import java.util.* +import javax.sql.DataSource + +/** + * This class will be used to execute functions related to token approval. It is an duplicate of + * JdbcApprovalStore with escaped case sensitive fields to query. + * + * @author Dave Syer + * @author Modified by Nivethika + */ +class PostgresApprovalStore(dataSource: DataSource?) : ApprovalStore { + private val jdbcTemplate: JdbcTemplate + private val rowMapper: RowMapper = AuthorizationRowMapper() + private var addApprovalStatement = DEFAULT_ADD_APPROVAL_STATEMENT + private var refreshApprovalStatement = DEFAULT_REFRESH_APPROVAL_STATEMENT + private var findApprovalStatement = DEFAULT_GET_APPROVAL_SQL + private var deleteApprovalStatment = DEFAULT_DELETE_APPROVAL_SQL + private var expireApprovalStatement = DEFAULT_EXPIRE_APPROVAL_STATEMENT + private var handleRevocationsAsExpiry = false + + init { + Assert.notNull(dataSource) + jdbcTemplate = JdbcTemplate(dataSource) + } + + fun setHandleRevocationsAsExpiry(handleRevocationsAsExpiry: Boolean) { + this.handleRevocationsAsExpiry = handleRevocationsAsExpiry + } + + fun setAddApprovalStatement(addApprovalStatement: String) { + this.addApprovalStatement = addApprovalStatement + } + + fun setFindApprovalStatement(findApprovalStatement: String) { + this.findApprovalStatement = findApprovalStatement + } + + fun setDeleteApprovalStatment(deleteApprovalStatment: String) { + this.deleteApprovalStatment = deleteApprovalStatment + } + + fun setExpireApprovalStatement(expireApprovalStatement: String) { + this.expireApprovalStatement = expireApprovalStatement + } + + fun setRefreshApprovalStatement(refreshApprovalStatement: String) { + this.refreshApprovalStatement = refreshApprovalStatement + } + + override fun addApprovals(approvals: Collection): Boolean { + logger.debug(String.format("adding approvals: [%s]", approvals)) + var success = true + for (approval in approvals) { + if (!updateApproval(refreshApprovalStatement, approval) && !updateApproval( + addApprovalStatement, approval + ) + ) { + success = false + } + } + return success + } + + override fun revokeApprovals(approvals: Collection): Boolean { + logger.debug(String.format("Revoking approvals: [%s]", approvals)) + var success = true + for (approval in approvals) { + if (handleRevocationsAsExpiry) { + val refreshed = jdbcTemplate + .update(expireApprovalStatement) { ps: PreparedStatement -> + ps.setTimestamp(1, Timestamp(System.currentTimeMillis())) + ps.setString(2, approval.userId) + ps.setString(3, approval.clientId) + ps.setString(4, approval.scope) + } + if (refreshed != 1) { + success = false + } + } else { + val refreshed = jdbcTemplate + .update(deleteApprovalStatment) { ps: PreparedStatement -> + ps.setString(1, approval.userId) + ps.setString(2, approval.clientId) + ps.setString(3, approval.scope) + } + if (refreshed != 1) { + success = false + } + } + } + return success + } + + /** + * Purges expired approvals from database. + * @return `true` if removed successfully, `false` otherwise. + */ + fun purgeExpiredApprovals(): Boolean { + logger.debug("Purging expired approvals from database") + try { + val deleted = jdbcTemplate.update(deleteApprovalStatment) { ps: PreparedStatement -> + ps.setTimestamp( + 1, Timestamp( + Date().time + ) + ) + } + logger.debug("$deleted expired approvals deleted") + } catch (ex: DataAccessException) { + logger.error("Error purging expired approvals", ex) + return false + } + return true + } + + override fun getApprovals(userName: String, clientId: String): List { + logger.debug("Finding approvals for userName {} and cliendId {}", userName, clientId) + return jdbcTemplate.query(findApprovalStatement, rowMapper, userName, clientId) + } + + private fun updateApproval(sql: String, approval: Approval): Boolean { + logger.debug(String.format("refreshing approval: [%s]", approval)) + val refreshed = jdbcTemplate.update(sql) { ps: PreparedStatement -> + ps.setTimestamp(1, Timestamp(approval.expiresAt.time)) + ps.setString(2, (if (approval.status == null) ApprovalStatus.APPROVED else approval.status).toString()) + ps.setTimestamp(3, Timestamp(approval.lastUpdatedAt.time)) + ps.setString(4, approval.userId) + ps.setString(5, approval.clientId) + ps.setString(6, approval.scope) + } + return refreshed == 1 + } + + private class AuthorizationRowMapper : RowMapper { + @Throws(SQLException::class) + override fun mapRow(rs: ResultSet, rowNum: Int): Approval { + val userName = rs.getString(4) + val clientId = rs.getString(5) + val scope = rs.getString(6) + val expiresAt: Date = rs.getTimestamp(1) + val status = rs.getString(2) + val lastUpdatedAt: Date = rs.getTimestamp(3) + return Approval( + userName, clientId, scope, expiresAt, + ApprovalStatus.valueOf(status), lastUpdatedAt + ) + } + } + + companion object { + private val logger = LoggerFactory.getLogger(PostgresApprovalStore::class.java) + private const val TABLE_NAME = "oauth_approvals" + private const val FIELDS = ("\"expiresAt\", \"status\",\"lastModifiedAt\",\"userId\"," + "\"clientId\"," + + "\"scope\"") + private const val WHERE_KEY = "where \"userId\"=? and \"clientId\"=?" + private const val WHERE_KEY_AND_SCOPE = WHERE_KEY + " and \"scope\"=?" + private const val AND_LESS_THAN_EXPIRE_AT = " and \"expiresAt\" <= ?" + private val DEFAULT_ADD_APPROVAL_STATEMENT = + String.format("insert into %s ( %s ) values (?,?,?,?,?,?)", TABLE_NAME, FIELDS) + private val DEFAULT_REFRESH_APPROVAL_STATEMENT = String.format( + "update %s set \"expiresAt\"=?, \"status\"=?, \"lastModifiedAt\"=? " + + WHERE_KEY_AND_SCOPE, TABLE_NAME + ) + private val DEFAULT_GET_APPROVAL_SQL = String.format("select %s from %s " + WHERE_KEY, FIELDS, TABLE_NAME) + private val DEFAULT_DELETE_APPROVAL_SQL = String.format( + "delete from %s " + WHERE_KEY_AND_SCOPE + AND_LESS_THAN_EXPIRE_AT, + TABLE_NAME + ) + private val DEFAULT_EXPIRE_APPROVAL_STATEMENT = String.format( + "update %s set " + "\"expiresAt\" = ? " + + WHERE_KEY_AND_SCOPE, TABLE_NAME + ) + } +} diff --git a/src/main/java/org/radarbase/management/security/RadarAuthentication.java b/src/main/java/org/radarbase/management/security/RadarAuthentication.java deleted file mode 100644 index b743b52b5..000000000 --- a/src/main/java/org/radarbase/management/security/RadarAuthentication.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.security; - -import org.radarbase.auth.authorization.AuthorityReference; -import org.radarbase.auth.token.RadarToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; - -import javax.annotation.Nonnull; -import java.security.Principal; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -public class RadarAuthentication implements Authentication, Principal { - private final RadarToken token; - private final List authorities; - private boolean isAuthenticated; - - /** Instantiate authentication via a token. */ - public RadarAuthentication(@Nonnull RadarToken token) { - this.token = token; - isAuthenticated = true; - authorities = token.getRoles().stream() - .map(AuthorityReference::getAuthority) - .distinct() - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - } - - @Override - public String getName() { - if (token.isClientCredentials()) { - return token.getClientId(); - } else { - return token.getUsername(); - } - } - - @Override - public Collection getAuthorities() { - return authorities; - } - - @Override - public Object getCredentials() { - return token; - } - - @Override - public Object getDetails() { - return null; - } - - @Override - public Object getPrincipal() { - if (token.isClientCredentials()) { - return null; - } else { - return this; - } - } - - @Override - public boolean isAuthenticated() { - return isAuthenticated; - } - - @Override - public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { - this.isAuthenticated = isAuthenticated; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - RadarAuthentication that = (RadarAuthentication) o; - - return isAuthenticated == that.isAuthenticated - && Objects.equals(token, that.token); - } - - @Override - public int hashCode() { - int result = token != null ? token.hashCode() : 0; - result = 31 * result + (isAuthenticated ? 1 : 0); - return result; - } - - @Override - public String toString() { - return "RadarAuthentication{" + "token=" + token - + ", authenticated=" + isAuthenticated() - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/security/RadarAuthentication.kt b/src/main/java/org/radarbase/management/security/RadarAuthentication.kt new file mode 100644 index 000000000..26df1809d --- /dev/null +++ b/src/main/java/org/radarbase/management/security/RadarAuthentication.kt @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.security + +import org.radarbase.auth.authorization.AuthorityReference +import org.radarbase.auth.token.RadarToken +import org.springframework.security.core.Authentication +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.SimpleGrantedAuthority +import java.security.Principal +import java.util.stream.Collectors +import javax.annotation.Nonnull + +class RadarAuthentication(@param:Nonnull private val token: RadarToken) : Authentication, Principal { + private val authorities: List + private var isAuthenticated = true + + /** Instantiate authentication via a token. */ + init { + authorities = token.roles!!.stream() + .map(AuthorityReference::authority) + .distinct() + .map { role: String? -> SimpleGrantedAuthority(role) } + .collect(Collectors.toList()) + } + + override fun getName(): String { + return if (token.isClientCredentials) { + token.clientId!! + } else { + token.username!! + } + } + + override fun getAuthorities(): Collection { + return authorities + } + + override fun getCredentials(): Any { + return token + } + + override fun getDetails(): Any? { + return null + } + + override fun getPrincipal(): Any? { + return if (token.isClientCredentials) { + null + } else { + this + } + } + + override fun isAuthenticated(): Boolean { + return isAuthenticated + } + + @Throws(IllegalArgumentException::class) + override fun setAuthenticated(isAuthenticated: Boolean) { + this.isAuthenticated = isAuthenticated + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val that = other as RadarAuthentication + return isAuthenticated == that.isAuthenticated && token == that.token + } + + override fun hashCode(): Int { + var result = token?.hashCode() ?: 0 + result = 31 * result + if (isAuthenticated) 1 else 0 + return result + } + + override fun toString(): String { + return ("RadarAuthentication{" + "token=" + token + + ", authenticated=" + isAuthenticated() + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.java b/src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.java deleted file mode 100644 index cb0ca63b2..000000000 --- a/src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.security; - -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; - -public class RadarAuthenticationProvider implements AuthenticationProvider { - @Override - public Authentication authenticate(Authentication authentication) - throws AuthenticationException { - if (authentication.isAuthenticated()) { - return authentication; - } - return null; - } - - @Override - public boolean supports(Class authentication) { - return authentication.equals(RadarAuthentication.class); - } -} diff --git a/src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.kt b/src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.kt new file mode 100644 index 000000000..403e0e4e9 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/RadarAuthenticationProvider.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.security + +import org.springframework.security.authentication.AuthenticationProvider +import org.springframework.security.core.Authentication +import org.springframework.security.core.AuthenticationException + +class RadarAuthenticationProvider : AuthenticationProvider { + @Throws(AuthenticationException::class) + override fun authenticate(authentication: Authentication): Authentication? { + return if (authentication.isAuthenticated) { + authentication + } else null + } + + override fun supports(authentication: Class<*>): Boolean { + return authentication == RadarAuthentication::class.java + } +} diff --git a/src/main/java/org/radarbase/management/security/SecurityUtils.java b/src/main/java/org/radarbase/management/security/SecurityUtils.java deleted file mode 100644 index ddd20113e..000000000 --- a/src/main/java/org/radarbase/management/security/SecurityUtils.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.radarbase.management.security; - -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; - -import java.util.Optional; - -/** - * Utility class for Spring Security. - */ -public final class SecurityUtils { - private SecurityUtils() { - } - - /** - * Get the login of the current user. - * - * @return the login of the current user if present - */ - public static Optional getCurrentUserLogin() { - SecurityContext securityContext = SecurityContextHolder.getContext(); - return getUserName(securityContext.getAuthentication()); - } - - /** - * Get the user name contianed in an Authentication object. - * - * @param authentication context authentication - * @return user name if present - */ - public static Optional getUserName(Authentication authentication) { - return Optional.ofNullable(authentication) - .map(Authentication::getPrincipal) - .map(principal -> { - if (principal instanceof UserDetails) { - return ((UserDetails) authentication.getPrincipal()).getUsername(); - } else if (principal instanceof String) { - return (String) authentication.getPrincipal(); - } else if (principal instanceof Authentication) { - return ((Authentication)principal).getName(); - } else { - return null; - } - }); - } -} diff --git a/src/main/java/org/radarbase/management/security/SecurityUtils.kt b/src/main/java/org/radarbase/management/security/SecurityUtils.kt new file mode 100644 index 000000000..0b6b66f42 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/SecurityUtils.kt @@ -0,0 +1,51 @@ +package org.radarbase.management.security + +import org.springframework.security.core.Authentication +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.security.core.userdetails.UserDetails + +/** + * Utility class for Spring Security. + */ +object SecurityUtils { + val currentUserLogin: String? + /** + * Get the login of the current user. + * + * @return the login of the current user if present + */ + get() { + val securityContext = SecurityContextHolder.getContext() + return getUserName(securityContext.authentication) + } + + /** + * Get the user name contianed in an Authentication object. + * + * @param authentication context authentication + * @return user name if present + */ + fun getUserName(authentication: Authentication): String? { + return authentication + .let { obj: Authentication -> obj.principal } + .let { principal: Any? -> + when (principal) { + is UserDetails -> { + return (authentication.principal as UserDetails).username + } + + is String -> { + return authentication.principal as String + } + + is Authentication -> { + return principal.name + } + + else -> { + return null + } + } + } + } +} diff --git a/src/main/java/org/radarbase/management/security/UserNotActivatedException.java b/src/main/java/org/radarbase/management/security/UserNotActivatedException.java deleted file mode 100644 index 1c679fc93..000000000 --- a/src/main/java/org/radarbase/management/security/UserNotActivatedException.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.radarbase.management.security; - -import org.springframework.security.core.AuthenticationException; - -/** - * This exception is thrown in case of a not activated user trying to authenticate. - */ -public class UserNotActivatedException extends AuthenticationException { - - private static final long serialVersionUID = 1L; - - public UserNotActivatedException(String message) { - super(message); - } - - public UserNotActivatedException(String message, Throwable t) { - super(message, t); - } -} diff --git a/src/main/java/org/radarbase/management/security/UserNotActivatedException.kt b/src/main/java/org/radarbase/management/security/UserNotActivatedException.kt new file mode 100644 index 000000000..f7e926bea --- /dev/null +++ b/src/main/java/org/radarbase/management/security/UserNotActivatedException.kt @@ -0,0 +1,15 @@ +package org.radarbase.management.security + +import org.springframework.security.core.AuthenticationException + +/** + * This exception is thrown in case of a not activated user trying to authenticate. + */ +class UserNotActivatedException : AuthenticationException { + constructor(message: String?) : super(message) + constructor(message: String?, t: Throwable?) : super(message, t) + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/security/jwt/JwtAccessTokenConverter.java b/src/main/java/org/radarbase/management/security/jwt/JwtAccessTokenConverter.kt similarity index 57% rename from src/main/java/org/radarbase/management/security/jwt/JwtAccessTokenConverter.java rename to src/main/java/org/radarbase/management/security/jwt/JwtAccessTokenConverter.kt index b318ba87e..c4b2b9bc1 100644 --- a/src/main/java/org/radarbase/management/security/jwt/JwtAccessTokenConverter.java +++ b/src/main/java/org/radarbase/management/security/jwt/JwtAccessTokenConverter.kt @@ -1,34 +1,21 @@ -package org.radarbase.management.security.jwt; +package org.radarbase.management.security.jwt -import java.util.Map; - -import com.auth0.jwt.algorithms.Algorithm; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.token.AccessTokenConverter; -import org.springframework.security.oauth2.provider.token.TokenEnhancer; +import com.auth0.jwt.algorithms.Algorithm +import org.springframework.security.oauth2.common.OAuth2AccessToken +import org.springframework.security.oauth2.provider.OAuth2Authentication +import org.springframework.security.oauth2.provider.token.AccessTokenConverter +import org.springframework.security.oauth2.provider.token.TokenEnhancer /** * Interface of a JwtAccessTokenConverter functions. */ -public interface JwtAccessTokenConverter extends TokenEnhancer, AccessTokenConverter { - - /** - * Field name for token id. - */ - String TOKEN_ID = AccessTokenConverter.JTI; - - /** - * Field name for access token id. - */ - String ACCESS_TOKEN_ID = AccessTokenConverter.ATI; - +interface JwtAccessTokenConverter : TokenEnhancer, AccessTokenConverter { /** * Decodes and verifies a JWT token string and extracts claims into a Map. * @param token string to decode. * @return claims of decoded token. */ - Map decode(String token); + fun decode(token: String): Map /** * Encodes token into JWT token. @@ -36,19 +23,30 @@ public interface JwtAccessTokenConverter extends TokenEnhancer, AccessTokenConve * @param authentication of the token. * @return JWT token string. */ - String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication); + fun encode(accessToken: OAuth2AccessToken, authentication: OAuth2Authentication): String /** * Checks whether a token is access-token or refresh-token. * Based on additional-information ati which contains the reference to access token of a * refresh token. */ - boolean isRefreshToken(OAuth2AccessToken token); + fun isRefreshToken(token: OAuth2AccessToken): Boolean /** * Algorithm to sign and verify the token. * @param algorithm to sign the JWT token */ - void setAlgorithm(Algorithm algorithm); - + fun setAlgorithm(algorithm: Algorithm) + + companion object { + /** + * Field name for token id. + */ + const val TOKEN_ID = AccessTokenConverter.JTI + + /** + * Field name for access token id. + */ + const val ACCESS_TOKEN_ID = AccessTokenConverter.ATI + } } diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt index b0e7d9496..c9d173c36 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt @@ -32,7 +32,7 @@ import java.util.stream.Stream * This class can accept an EC keypair as well as an RSA keypair for signing. EC signatures * are significantly smaller than RSA signatures. */ -class ManagementPortalJwtAccessTokenConverter( +open class ManagementPortalJwtAccessTokenConverter( algorithm: Algorithm, verifiers: MutableList, private val refreshTokenVerifiers: List @@ -163,7 +163,7 @@ class ManagementPortalJwtAccessTokenConverter( } override fun isRefreshToken(token: OAuth2AccessToken): Boolean { - return token.additionalInformation.containsKey(JwtAccessTokenConverter.ACCESS_TOKEN_ID) + return token?.additionalInformation?.containsKey(JwtAccessTokenConverter.ACCESS_TOKEN_ID) == true } override fun encode(accessToken: OAuth2AccessToken, authentication: OAuth2Authentication): String { diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.java b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.java deleted file mode 100644 index 02bc31ff8..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.java +++ /dev/null @@ -1,198 +0,0 @@ -package org.radarbase.management.security.jwt; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; - -import org.springframework.security.core.Authentication; -import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken; -import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.common.OAuth2RefreshToken; -import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.approval.Approval; -import org.springframework.security.oauth2.provider.approval.ApprovalStore; -import org.springframework.security.oauth2.provider.token.TokenStore; - -/** - * Adapted version of {@link org.springframework.security.oauth2.provider.token.store.JwtTokenStore} - * which uses interface {@link JwtAccessTokenConverter} instead of tied instance. - * - *

- * A {@link TokenStore} implementation that just reads data from the tokens themselves. - * Not really a store since it never persists anything, and methods like - * {@link #getAccessToken(OAuth2Authentication)} always return null. But - * nevertheless a useful tool since it translates access tokens to and - * from authentications. Use this wherever a{@link TokenStore} is needed, - * but remember to use the same {@link JwtAccessTokenConverter} - * instance (or one with the same verifier) as was used when the tokens were minted. - *

- * - * @author Dave Syer - * @author nivethika - */ -public class ManagementPortalJwtTokenStore implements TokenStore { - private final JwtAccessTokenConverter jwtAccessTokenConverter; - - private ApprovalStore approvalStore; - - /** - * Create a ManagementPortalJwtTokenStore with this token converter - * (should be shared with the DefaultTokenServices if used). - * - * @param jwtAccessTokenConverter JwtAccessTokenConverter used in the application. - */ - public ManagementPortalJwtTokenStore(JwtAccessTokenConverter jwtAccessTokenConverter) { - this.jwtAccessTokenConverter = jwtAccessTokenConverter; - } - - /** - * Create a ManagementPortalJwtTokenStore with this token converter - * (should be shared with the DefaultTokenServices if used). - * - * @param jwtAccessTokenConverter JwtAccessTokenConverter used in the application. - * @param approvalStore TokenApprovalStore used in the application. - */ - public ManagementPortalJwtTokenStore(JwtAccessTokenConverter jwtAccessTokenConverter, - ApprovalStore approvalStore) { - this.jwtAccessTokenConverter = jwtAccessTokenConverter; - this.approvalStore = approvalStore; - } - - /** - * ApprovalStore to be used to validate and restrict refresh tokens. - * - * @param approvalStore the approvalStore to set - */ - public void setApprovalStore(ApprovalStore approvalStore) { - this.approvalStore = approvalStore; - } - - - @Override - public OAuth2Authentication readAuthentication(OAuth2AccessToken token) { - return readAuthentication(token.getValue()); - } - - @Override - public OAuth2Authentication readAuthentication(String token) { - return jwtAccessTokenConverter.extractAuthentication(jwtAccessTokenConverter.decode(token)); - } - - @Override - public void storeAccessToken(OAuth2AccessToken token, OAuth2Authentication authentication) { - // this is not really a store where we persist - } - - @Override - public OAuth2AccessToken readAccessToken(String tokenValue) { - OAuth2AccessToken accessToken = convertAccessToken(tokenValue); - - if (jwtAccessTokenConverter.isRefreshToken(accessToken)) { - throw new InvalidTokenException("Encoded token is a refresh token"); - } - return accessToken; - } - - private OAuth2AccessToken convertAccessToken(String tokenValue) { - return jwtAccessTokenConverter - .extractAccessToken(tokenValue, jwtAccessTokenConverter.decode(tokenValue)); - } - - @Override - public void removeAccessToken(OAuth2AccessToken token) { - // this is not really store where we persist - } - - @Override - public void storeRefreshToken(OAuth2RefreshToken refreshToken, - OAuth2Authentication authentication) { - // this is not really store where we persist - } - - @Override - public OAuth2RefreshToken readRefreshToken(String tokenValue) { - if (approvalStore != null) { - OAuth2Authentication authentication = readAuthentication(tokenValue); - if (authentication.getUserAuthentication() != null) { - String userId = authentication.getUserAuthentication().getName(); - String clientId = authentication.getOAuth2Request().getClientId(); - Collection approvals = approvalStore.getApprovals(userId, clientId); - Collection approvedScopes = new HashSet<>(); - for (Approval approval : approvals) { - if (approval.isApproved()) { - approvedScopes.add(approval.getScope()); - } - } - if (!approvedScopes.containsAll(authentication.getOAuth2Request().getScope())) { - return null; - } - } - } - OAuth2AccessToken encodedRefreshToken = convertAccessToken(tokenValue); - return createRefreshToken(encodedRefreshToken); - } - - private OAuth2RefreshToken createRefreshToken(OAuth2AccessToken encodedRefreshToken) { - if (!jwtAccessTokenConverter.isRefreshToken(encodedRefreshToken)) { - throw new InvalidTokenException("Encoded token is not a refresh token"); - } - if (encodedRefreshToken.getExpiration() != null) { - return new DefaultExpiringOAuth2RefreshToken(encodedRefreshToken.getValue(), - encodedRefreshToken.getExpiration()); - } - return new DefaultOAuth2RefreshToken(encodedRefreshToken.getValue()); - } - - @Override - public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken token) { - return readAuthentication(token.getValue()); - } - - @Override - public void removeRefreshToken(OAuth2RefreshToken token) { - remove(token.getValue()); - } - - private void remove(String token) { - if (approvalStore != null) { - OAuth2Authentication auth = readAuthentication(token); - String clientId = auth.getOAuth2Request().getClientId(); - Authentication user = auth.getUserAuthentication(); - if (user != null) { - Collection approvals = new ArrayList<>(); - for (String scope : auth.getOAuth2Request().getScope()) { - approvals.add(new Approval(user.getName(), clientId, scope, new Date(), - Approval.ApprovalStatus.APPROVED)); - } - approvalStore.revokeApprovals(approvals); - } - } - } - - @Override - public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken refreshToken) { - // this is not really store where we persist - } - - @Override - public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) { - // We don't want to accidentally issue a token, and we have no way to reconstruct - // the refresh token - return null; - } - - @Override - public Collection findTokensByClientIdAndUserName(String clientId, - String userName) { - return Collections.emptySet(); - } - - @Override - public Collection findTokensByClientId(String clientId) { - return Collections.emptySet(); - } -} diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.kt new file mode 100644 index 000000000..512b66433 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtTokenStore.kt @@ -0,0 +1,189 @@ +package org.radarbase.management.security.jwt + +import org.springframework.security.oauth2.common.DefaultExpiringOAuth2RefreshToken +import org.springframework.security.oauth2.common.DefaultOAuth2RefreshToken +import org.springframework.security.oauth2.common.OAuth2AccessToken +import org.springframework.security.oauth2.common.OAuth2RefreshToken +import org.springframework.security.oauth2.common.exceptions.InvalidTokenException +import org.springframework.security.oauth2.provider.OAuth2Authentication +import org.springframework.security.oauth2.provider.approval.Approval +import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus +import org.springframework.security.oauth2.provider.approval.ApprovalStore +import org.springframework.security.oauth2.provider.token.TokenStore +import java.util.* + +/** + * Adapted version of [org.springframework.security.oauth2.provider.token.store.JwtTokenStore] + * which uses interface [JwtAccessTokenConverter] instead of tied instance. + * + * + * + * A [TokenStore] implementation that just reads data from the tokens themselves. + * Not really a store since it never persists anything, and methods like + * [.getAccessToken] always return null. But + * nevertheless a useful tool since it translates access tokens to and + * from authentications. Use this wherever a[TokenStore] is needed, + * but remember to use the same [JwtAccessTokenConverter] + * instance (or one with the same verifier) as was used when the tokens were minted. + * + * + * @author Dave Syer + * @author nivethika + */ +class ManagementPortalJwtTokenStore : TokenStore { + private val jwtAccessTokenConverter: JwtAccessTokenConverter + private var approvalStore: ApprovalStore? = null + + /** + * Create a ManagementPortalJwtTokenStore with this token converter + * (should be shared with the DefaultTokenServices if used). + * + * @param jwtAccessTokenConverter JwtAccessTokenConverter used in the application. + */ + constructor(jwtAccessTokenConverter: JwtAccessTokenConverter) { + this.jwtAccessTokenConverter = jwtAccessTokenConverter + } + + /** + * Create a ManagementPortalJwtTokenStore with this token converter + * (should be shared with the DefaultTokenServices if used). + * + * @param jwtAccessTokenConverter JwtAccessTokenConverter used in the application. + * @param approvalStore TokenApprovalStore used in the application. + */ + constructor( + jwtAccessTokenConverter: JwtAccessTokenConverter, + approvalStore: ApprovalStore? + ) { + this.jwtAccessTokenConverter = jwtAccessTokenConverter + this.approvalStore = approvalStore + } + + /** + * ApprovalStore to be used to validate and restrict refresh tokens. + * + * @param approvalStore the approvalStore to set + */ + fun setApprovalStore(approvalStore: ApprovalStore?) { + this.approvalStore = approvalStore + } + + override fun readAuthentication(token: OAuth2AccessToken): OAuth2Authentication { + return readAuthentication(token.value) + } + + override fun readAuthentication(token: String): OAuth2Authentication { + return jwtAccessTokenConverter.extractAuthentication(jwtAccessTokenConverter.decode(token)) + } + + override fun storeAccessToken(token: OAuth2AccessToken, authentication: OAuth2Authentication) { + // this is not really a store where we persist + } + + override fun readAccessToken(tokenValue: String): OAuth2AccessToken { + val accessToken = convertAccessToken(tokenValue) + if (jwtAccessTokenConverter.isRefreshToken(accessToken)) { + throw InvalidTokenException("Encoded token is a refresh token") + } + return accessToken + } + + private fun convertAccessToken(tokenValue: String): OAuth2AccessToken { + return jwtAccessTokenConverter + .extractAccessToken(tokenValue, jwtAccessTokenConverter.decode(tokenValue)) + } + + override fun removeAccessToken(token: OAuth2AccessToken) { + // this is not really store where we persist + } + + override fun storeRefreshToken( + refreshToken: OAuth2RefreshToken, + authentication: OAuth2Authentication + ) { + // this is not really store where we persist + } + + override fun readRefreshToken(tokenValue: String): OAuth2RefreshToken? { + if (approvalStore != null) { + val authentication = readAuthentication(tokenValue) + if (authentication.userAuthentication != null) { + val userId = authentication.userAuthentication.name + val clientId = authentication.oAuth2Request.clientId + val approvals = approvalStore!!.getApprovals(userId, clientId) + val approvedScopes: MutableCollection = HashSet() + for (approval in approvals) { + if (approval.isApproved) { + approvedScopes.add(approval.scope) + } + } + if (!approvedScopes.containsAll(authentication.oAuth2Request.scope)) { + return null + } + } + } + val encodedRefreshToken = convertAccessToken(tokenValue) + return createRefreshToken(encodedRefreshToken) + } + + private fun createRefreshToken(encodedRefreshToken: OAuth2AccessToken): OAuth2RefreshToken { + if (!jwtAccessTokenConverter.isRefreshToken(encodedRefreshToken)) { + throw InvalidTokenException("Encoded token is not a refresh token") + } + return if (encodedRefreshToken.expiration != null) { + DefaultExpiringOAuth2RefreshToken( + encodedRefreshToken.value, + encodedRefreshToken.expiration + ) + } else DefaultOAuth2RefreshToken(encodedRefreshToken.value) + } + + override fun readAuthenticationForRefreshToken(token: OAuth2RefreshToken): OAuth2Authentication { + return readAuthentication(token.value) + } + + override fun removeRefreshToken(token: OAuth2RefreshToken) { + remove(token.value) + } + + private fun remove(token: String) { + if (approvalStore != null) { + val auth = readAuthentication(token) + val clientId = auth.oAuth2Request.clientId + val user = auth.userAuthentication + if (user != null) { + val approvals: MutableCollection = ArrayList() + for (scope in auth.oAuth2Request.scope) { + approvals.add( + Approval( + user.name, clientId, scope, Date(), + ApprovalStatus.APPROVED + ) + ) + } + approvalStore!!.revokeApprovals(approvals) + } + } + } + + override fun removeAccessTokenUsingRefreshToken(refreshToken: OAuth2RefreshToken) { + // this is not really store where we persist + } + + override fun getAccessToken(authentication: OAuth2Authentication): OAuth2AccessToken? { + // We don't want to accidentally issue a token, and we have no way to reconstruct + // the refresh token + return null + } + + override fun findTokensByClientIdAndUserName( + clientId: String, + userName: String + ): Collection { + return emptySet() + } + + override fun findTokensByClientId(clientId: String): Collection { + return emptySet() + } +} diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.java b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.java deleted file mode 100644 index aa9e2cf30..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.java +++ /dev/null @@ -1,324 +0,0 @@ -package org.radarbase.management.security.jwt; - -import com.auth0.jwt.JWT; -import com.auth0.jwt.JWTVerifier; -import com.auth0.jwt.algorithms.Algorithm; -import org.radarbase.auth.authentication.TokenValidator; -import org.radarbase.auth.jwks.JsonWebKeySet; -import org.radarbase.auth.jwks.JwkAlgorithmParser; -import org.radarbase.auth.jwks.JwksTokenVerifierLoader; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.security.jwt.algorithm.EcdsaJwtAlgorithm; -import org.radarbase.management.security.jwt.algorithm.JwtAlgorithm; -import org.radarbase.management.security.jwt.algorithm.RsaJwtAlgorithm; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.stereotype.Component; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import javax.servlet.ServletContext; -import java.io.IOException; -import java.security.KeyPair; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.UnrecoverableKeyException; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.RSAPrivateKey; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Stream; - -import static java.util.Objects.requireNonNull; -import static org.radarbase.management.security.jwt.ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL; - -/** - * Similar to Spring's - * {@link org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory}. However, - * this class does not assume a specific key type, while the Spring factory assumes RSA keys. - */ -@Component -public class ManagementPortalOauthKeyStoreHandler { - - private static final Logger logger = LoggerFactory.getLogger( - ManagementPortalOauthKeyStoreHandler.class); - - private static final List KEYSTORE_PATHS = Arrays.asList( - new ClassPathResource("/config/keystore.p12"), - new ClassPathResource("/config/keystore.jks")); - - private final char[] password; - - private final KeyStore store; - - private final Resource loadedResource; - - private final ManagementPortalProperties.Oauth oauthConfig; - - private final List verifierPublicKeyAliasList; - - private final String managementPortalBaseUrl; - - private final List verifiers; - private final List refreshTokenVerifiers; - - /** - * Keystore factory. This tries to load the first valid keystore listed in resources. - * - * @throws IllegalArgumentException if none of the provided resources can be used to load a - * keystore. - */ - @Autowired - public ManagementPortalOauthKeyStoreHandler( - Environment environment, - ServletContext servletContext, - ManagementPortalProperties managementPortalProperties) { - - checkOAuthConfig(managementPortalProperties); - - this.oauthConfig = managementPortalProperties.getOauth(); - this.password = oauthConfig.getKeyStorePassword().toCharArray(); - Map.Entry loadedStore = loadStore(); - this.loadedResource = loadedStore.getKey(); - this.store = loadedStore.getValue(); - this.verifierPublicKeyAliasList = loadVerifiersPublicKeyAliasList(); - - this.managementPortalBaseUrl = "http://localhost:" - + environment.getProperty("server.port") - + servletContext.getContextPath(); - logger.info("Using Management Portal base-url {}", this.managementPortalBaseUrl); - - List algorithms = loadAlgorithmsFromAlias() - .filter(Objects::nonNull) - .toList(); - - verifiers = algorithms.stream() - .map(algo -> JWT.require(algo).withAudience(RES_MANAGEMENT_PORTAL).build()) - .toList(); - // No need to check audience with a refresh token: it can be used - // to refresh tokens intended for other resources. - refreshTokenVerifiers = algorithms.stream() - .map(algo -> JWT.require(algo).build()) - .toList(); - } - - private static void checkOAuthConfig(ManagementPortalProperties managementPortalProperties) { - ManagementPortalProperties.Oauth oauthConfig = managementPortalProperties.getOauth(); - - if ( oauthConfig == null ) { - logger.error("Could not find valid Oauth Config. Please configure compulsary " - + "properties of Oauth configs of Management Portal"); - throw new IllegalArgumentException("OauthConfig is not provided"); - } - - if (oauthConfig.getKeyStorePassword() == null || oauthConfig.getKeyStorePassword() - .isEmpty()) { - logger.error("oauth.keyStorePassword is empty"); - throw new IllegalArgumentException("oauth.keyStorePassword is empty"); - } - - if (oauthConfig.getSigningKeyAlias() == null || oauthConfig.getSigningKeyAlias() - .isEmpty()) { - logger.error("oauth.signingKeyAlias is empty"); - throw new IllegalArgumentException("OauthConfig is not provided"); - } - - } - - @Nonnull - private Map.Entry loadStore() { - for (Resource resource : KEYSTORE_PATHS) { - if (!resource.exists()) { - logger.debug("JWT key store {} does not exist. Ignoring this resource", resource); - continue; - } - try { - String fileName = requireNonNull(resource.getFilename()).toLowerCase(Locale.ROOT); - String type = fileName.endsWith(".pfx") || fileName.endsWith(".p12") - ? "PKCS12" : "jks"; - KeyStore localStore = KeyStore.getInstance(type); - localStore.load(resource.getInputStream(), this.password); - logger.debug("Loaded JWT key store {}", resource); - return new AbstractMap.SimpleImmutableEntry<>(resource, localStore); - } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException - | IOException ex) { - logger.error("Cannot load JWT key store", ex); - } - } - throw new IllegalArgumentException("Cannot load any of the given JWT key stores " - + KEYSTORE_PATHS); - } - - private List loadVerifiersPublicKeyAliasList() { - List publicKeyAliases = new ArrayList<>(); - publicKeyAliases.add(oauthConfig.getSigningKeyAlias()); - if (oauthConfig.getCheckingKeyAliases() != null) { - publicKeyAliases.addAll(oauthConfig.getCheckingKeyAliases()); - } - return publicKeyAliases; - } - - /** - * Returns configured public keys of token verifiers. - * @return List of public keys for token verification. - */ - public JsonWebKeySet loadJwks() { - return new JsonWebKeySet(this.verifierPublicKeyAliasList.stream() - .map(this::getKeyPair) - .map(ManagementPortalOauthKeyStoreHandler::getJwtAlgorithm) - .filter(Objects::nonNull) - .map(JwtAlgorithm::getJwk) - .toList()); - } - - /** - * Load default verifiers from configured keystore and aliases. - */ - private Stream loadAlgorithmsFromAlias() { - return this.verifierPublicKeyAliasList.stream() - .map(this::getKeyPair) - .map(ManagementPortalOauthKeyStoreHandler::getJwtAlgorithm) - .filter(Objects::nonNull) - .map(JwtAlgorithm::getAlgorithm); - } - - public List getVerifiers() { - return this.verifiers; - } - - - /** - * Returns the signing algorithm extracted based on signing alias configured from keystore. - * @return signing algorithm. - */ - public Algorithm getAlgorithmForSigning() { - String signKey = oauthConfig.getSigningKeyAlias(); - logger.debug("Using JWT signing key {}", signKey); - KeyPair keyPair = getKeyPair(signKey); - if (keyPair == null) { - throw new IllegalArgumentException("Cannot load JWT signing key " + signKey - + " from JWT key store."); - } - - return getAlgorithmFromKeyPair(keyPair); - } - - /** - * Get a key pair from the store using the store password. - * @param alias key pair alias - * @return loaded key pair or {@code null} if the key store does not contain a loadable key with - * given alias. - * @throws IllegalArgumentException if the key alias password is wrong or the key cannot - * loaded. - */ - private @Nullable KeyPair getKeyPair(@Nullable String alias) { - return getKeyPair(alias, password); - } - - /** - * Get a key pair from the store with a given alias and password. - * @param alias key pair alias - * @param password key pair password - * @return loaded key pair or {@code null} if the key store does not contain a loadable key with - * given alias. - * @throws IllegalArgumentException if the key alias password is wrong or the key cannot - * loaded. - */ - private @Nullable KeyPair getKeyPair(@Nullable String alias, char[] password) { - try { - PrivateKey key = (PrivateKey) store.getKey(alias, password); - if (key == null) { - logger.warn("JWT key store {} does not contain private key pair for alias {}", - loadedResource, alias); - return null; - } - Certificate cert = store.getCertificate(alias); - if (cert == null) { - logger.warn("JWT key store {} does not contain certificate pair for alias {}", - loadedResource, alias); - return null; - } - PublicKey publicKey = cert.getPublicKey(); - if (publicKey == null) { - logger.warn("JWT key store {} does not contain public key pair for alias {}", - loadedResource, alias); - return null; - } - - return new KeyPair(publicKey, key); - } catch (NoSuchAlgorithmException ex) { - logger.warn( - "JWT key store {} contains unknown algorithm for key pair with alias {}: {}", - loadedResource, alias, ex.toString()); - return null; - } catch (UnrecoverableKeyException | KeyStoreException ex) { - throw new IllegalArgumentException("JWT key store " + loadedResource - + " contains unrecoverable key pair with alias " - + alias + " (the password may be wrong)", ex); - } - } - - /** - * Returns extracted {@link Algorithm} from the KeyPair. - * @param keyPair to find algorithm. - * @return extracted algorithm. - */ - private static Algorithm getAlgorithmFromKeyPair(KeyPair keyPair) { - JwtAlgorithm alg = getJwtAlgorithm(keyPair); - if (alg == null) { - throw new IllegalArgumentException("KeyPair type " - + keyPair.getPrivate().getAlgorithm() + " is unknown."); - } - return alg.getAlgorithm(); - } - - /** - * Get the JWT algorithm to sign or verify JWTs with. - * @param keyPair key pair for signing/verifying. - * @return algorithm or {@code null} if the key type is unknown. - */ - private static @Nullable JwtAlgorithm getJwtAlgorithm(@Nullable KeyPair keyPair) { - - if (keyPair == null) { - return null; - } - PrivateKey privateKey = keyPair.getPrivate(); - - if (privateKey instanceof ECPrivateKey) { - return new EcdsaJwtAlgorithm(keyPair); - } else if (privateKey instanceof RSAPrivateKey) { - return new RsaJwtAlgorithm(keyPair); - } else { - logger.warn("No JWT algorithm found for key type {}", privateKey.getClass()); - return null; - } - } - - /** Get the default token validator. */ - public TokenValidator getTokenValidator() { - var jwksLoader = new JwksTokenVerifierLoader( - managementPortalBaseUrl + "/oauth/token_key", - "res_ManagementPortal", - new JwkAlgorithmParser() - ); - return new TokenValidator(List.of(jwksLoader)); - } - - public List getRefreshTokenVerifiers() { - return refreshTokenVerifiers; - } -} diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt new file mode 100644 index 000000000..7fae1aed9 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt @@ -0,0 +1,289 @@ +package org.radarbase.management.security.jwt + +import com.auth0.jwt.JWT +import com.auth0.jwt.JWTVerifier +import com.auth0.jwt.algorithms.Algorithm +import org.radarbase.auth.authentication.TokenValidator +import org.radarbase.auth.jwks.JsonWebKeySet +import org.radarbase.auth.jwks.JwkAlgorithmParser +import org.radarbase.auth.jwks.JwksTokenVerifierLoader +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.config.ManagementPortalProperties.Oauth +import org.radarbase.management.security.jwt.algorithm.EcdsaJwtAlgorithm +import org.radarbase.management.security.jwt.algorithm.JwtAlgorithm +import org.radarbase.management.security.jwt.algorithm.RsaJwtAlgorithm +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.core.env.Environment +import org.springframework.core.io.ClassPathResource +import org.springframework.core.io.Resource +import org.springframework.stereotype.Component +import java.io.IOException +import java.lang.IllegalArgumentException +import java.security.KeyPair +import java.security.KeyStore +import java.security.KeyStoreException +import java.security.NoSuchAlgorithmException +import java.security.PrivateKey +import java.security.UnrecoverableKeyException +import java.security.cert.CertificateException +import java.security.interfaces.ECPrivateKey +import java.security.interfaces.RSAPrivateKey +import java.util.* +import java.util.AbstractMap.SimpleImmutableEntry +import java.util.stream.Stream +import javax.annotation.Nonnull +import javax.servlet.ServletContext +import kotlin.collections.Map.Entry + +/** + * Similar to Spring's + * [org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory]. However, + * this class does not assume a specific key type, while the Spring factory assumes RSA keys. + */ +@Component +class ManagementPortalOauthKeyStoreHandler @Autowired constructor( + environment: Environment, servletContext: ServletContext, managementPortalProperties: ManagementPortalProperties +) { + private val password: CharArray + private val store: KeyStore + private val loadedResource: Resource + private val oauthConfig: Oauth + private val verifierPublicKeyAliasList: List + private val managementPortalBaseUrl: String + val verifiers: MutableList + val refreshTokenVerifiers: MutableList + + /** + * Keystore factory. This tries to load the first valid keystore listed in resources. + * + * @throws IllegalArgumentException if none of the provided resources can be used to load a + * keystore. + */ + init { + checkOAuthConfig(managementPortalProperties) + oauthConfig = managementPortalProperties.oauth + password = oauthConfig.keyStorePassword.toCharArray() + val loadedStore: Entry = loadStore() + loadedResource = loadedStore.key + store = loadedStore.value + verifierPublicKeyAliasList = loadVerifiersPublicKeyAliasList() + managementPortalBaseUrl = + ("http://localhost:" + environment.getProperty("server.port") + servletContext.contextPath) + logger.info("Using Management Portal base-url {}", managementPortalBaseUrl) + val algorithms = loadAlgorithmsFromAlias().filter { obj: Algorithm? -> Objects.nonNull(obj) }.toList() + verifiers = algorithms.stream().map { algo: Algorithm? -> + JWT.require(algo).withAudience(ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL).build() + }.toList() + // No need to check audience with a refresh token: it can be used + // to refresh tokens intended for other resources. + refreshTokenVerifiers = algorithms.stream().map { algo: Algorithm? -> JWT.require(algo).build() }.toList() + } + + @Nonnull + private fun loadStore(): Entry { + for (resource in KEYSTORE_PATHS) { + if (!resource.exists()) { + logger.debug("JWT key store {} does not exist. Ignoring this resource", resource) + continue + } + try { + val fileName = Objects.requireNonNull(resource.filename).lowercase() + val type = if (fileName.endsWith(".pfx") || fileName.endsWith(".p12")) "PKCS12" else "jks" + val localStore = KeyStore.getInstance(type) + localStore.load(resource.inputStream, password) + logger.debug("Loaded JWT key store {}", resource) + if (resource != null && localStore != null) + return SimpleImmutableEntry(resource, localStore) + } catch (ex: CertificateException) { + logger.error("Cannot load JWT key store", ex) + } catch (ex: NoSuchAlgorithmException) { + logger.error("Cannot load JWT key store", ex) + } catch (ex: KeyStoreException) { + logger.error("Cannot load JWT key store", ex) + } catch (ex: IOException) { + logger.error("Cannot load JWT key store", ex) + } + } + throw IllegalArgumentException( + "Cannot load any of the given JWT key stores " + KEYSTORE_PATHS + ) + } + + private fun loadVerifiersPublicKeyAliasList(): List { + val publicKeyAliases: MutableList = ArrayList() + publicKeyAliases.add(oauthConfig.signingKeyAlias) + if (oauthConfig.checkingKeyAliases != null) { + publicKeyAliases.addAll(oauthConfig.checkingKeyAliases) + } + return publicKeyAliases + } + + /** + * Returns configured public keys of token verifiers. + * @return List of public keys for token verification. + */ + fun loadJwks(): JsonWebKeySet { + return JsonWebKeySet(verifierPublicKeyAliasList.map { alias: String? -> this.getKeyPair(alias) } + .map { keyPair: KeyPair? -> getJwtAlgorithm(keyPair) }.mapNotNull { obj: JwtAlgorithm? -> obj?.jwk }) + } + + /** + * Load default verifiers from configured keystore and aliases. + */ + private fun loadAlgorithmsFromAlias(): Stream { + return verifierPublicKeyAliasList.stream().map { alias: String? -> this.getKeyPair(alias) } + .map { keyPair: KeyPair? -> getJwtAlgorithm(keyPair) }.filter { obj: JwtAlgorithm? -> Objects.nonNull(obj) } + .map { obj: JwtAlgorithm? -> obj?.algorithm } + } + + val algorithmForSigning: Algorithm + /** + * Returns the signing algorithm extracted based on signing alias configured from keystore. + * @return signing algorithm. + */ + get() { + val signKey = oauthConfig.signingKeyAlias + logger.debug("Using JWT signing key {}", signKey) + val keyPair = getKeyPair(signKey) ?: throw IllegalArgumentException( + "Cannot load JWT signing key " + signKey + " from JWT key store." + ) + return getAlgorithmFromKeyPair(keyPair) + } + + /** + * Get a key pair from the store using the store password. + * @param alias key pair alias + * @return loaded key pair or `null` if the key store does not contain a loadable key with + * given alias. + * @throws IllegalArgumentException if the key alias password is wrong or the key cannot + * loaded. + */ + private fun getKeyPair(alias: String?): KeyPair? { + return getKeyPair(alias, password) + } + + /** + * Get a key pair from the store with a given alias and password. + * @param alias key pair alias + * @param password key pair password + * @return loaded key pair or `null` if the key store does not contain a loadable key with + * given alias. + * @throws IllegalArgumentException if the key alias password is wrong or the key cannot + * load. + */ + private fun getKeyPair(alias: String?, password: CharArray): KeyPair? { + return try { + val key = store.getKey(alias, password) as PrivateKey? + if (key == null) { + logger.warn( + "JWT key store {} does not contain private key pair for alias {}", loadedResource, alias + ) + return null + } + val cert = store.getCertificate(alias) + if (cert == null) { + logger.warn( + "JWT key store {} does not contain certificate pair for alias {}", loadedResource, alias + ) + return null + } + val publicKey = cert.publicKey + if (publicKey == null) { + logger.warn( + "JWT key store {} does not contain public key pair for alias {}", loadedResource, alias + ) + return null + } + KeyPair(publicKey, key) + } catch (ex: NoSuchAlgorithmException) { + logger.warn( + "JWT key store {} contains unknown algorithm for key pair with alias {}: {}", + loadedResource, + alias, + ex.toString() + ) + null + } catch (ex: UnrecoverableKeyException) { + throw IllegalArgumentException( + "JWT key store $loadedResource contains unrecoverable key pair with alias $alias (the password may be wrong)", + ex + ) + } catch (ex: KeyStoreException) { + throw IllegalArgumentException( + "JWT key store $loadedResource contains unrecoverable key pair with alias $alias (the password may be wrong)", + ex + ) + } + } + + val tokenValidator: TokenValidator + /** Get the default token validator. */ + get() { + val jwksLoader = JwksTokenVerifierLoader( + "$managementPortalBaseUrl/oauth/token_key", "res_ManagementPortal", JwkAlgorithmParser() + ) + return TokenValidator(java.util.List.of(jwksLoader)) + } + + companion object { + private val logger = LoggerFactory.getLogger( + ManagementPortalOauthKeyStoreHandler::class.java + ) + private val KEYSTORE_PATHS = Arrays.asList( + ClassPathResource("/config/keystore.p12"), ClassPathResource("/config/keystore.jks") + ) + + private fun checkOAuthConfig(managementPortalProperties: ManagementPortalProperties) { + val oauthConfig = managementPortalProperties.oauth + if (oauthConfig == null) { + logger.error( + "Could not find valid Oauth Config. Please configure compulsary " + "properties of Oauth configs of Management Portal" + ) + throw IllegalArgumentException("OauthConfig is not provided") + } + if (oauthConfig.keyStorePassword == null || oauthConfig.keyStorePassword.isEmpty()) { + logger.error("oauth.keyStorePassword is empty") + throw IllegalArgumentException("oauth.keyStorePassword is empty") + } + if (oauthConfig.signingKeyAlias == null || oauthConfig.signingKeyAlias.isEmpty()) { + logger.error("oauth.signingKeyAlias is empty") + throw IllegalArgumentException("OauthConfig is not provided") + } + } + + /** + * Returns extracted [Algorithm] from the KeyPair. + * @param keyPair to find algorithm. + * @return extracted algorithm. + */ + private fun getAlgorithmFromKeyPair(keyPair: KeyPair): Algorithm { + val alg = getJwtAlgorithm(keyPair) ?: throw IllegalArgumentException( + "KeyPair type " + keyPair.private.algorithm + " is unknown." + ) + return alg.algorithm + } + + /** + * Get the JWT algorithm to sign or verify JWTs with. + * @param keyPair key pair for signing/verifying. + * @return algorithm or `null` if the key type is unknown. + */ + private fun getJwtAlgorithm(keyPair: KeyPair?): JwtAlgorithm? { + if (keyPair == null) { + return null + } + val privateKey = keyPair.private + return if (privateKey is ECPrivateKey) { + EcdsaJwtAlgorithm(keyPair) + } else if (privateKey is RSAPrivateKey) { + RsaJwtAlgorithm(keyPair) + } else { + logger.warn( + "No JWT algorithm found for key type {}", privateKey.javaClass + ) + null + } + } + } +} diff --git a/src/main/java/org/radarbase/management/security/jwt/SignatureException.java b/src/main/java/org/radarbase/management/security/jwt/SignatureException.java deleted file mode 100644 index 958b95300..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/SignatureException.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.radarbase.management.security.jwt; - -public class SignatureException extends RuntimeException { - - public SignatureException() { - super(); - } - - public SignatureException(String message) { - super(message); - } - - public SignatureException(String message, Throwable ex) { - super(message, ex); - } - - public SignatureException(Throwable ex) { - super(ex); - } -} diff --git a/src/main/java/org/radarbase/management/security/jwt/SignatureException.kt b/src/main/java/org/radarbase/management/security/jwt/SignatureException.kt new file mode 100644 index 000000000..8f790fb7d --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/SignatureException.kt @@ -0,0 +1,8 @@ +package org.radarbase.management.security.jwt + +class SignatureException : RuntimeException { + constructor() : super() + constructor(message: String?) : super(message) + constructor(message: String?, ex: Throwable?) : super(message, ex) + constructor(ex: Throwable?) : super(ex) +} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.kt b/src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.kt new file mode 100644 index 000000000..303b078fb --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.kt @@ -0,0 +1,24 @@ +package org.radarbase.management.security.jwt.algorithm + +import org.radarbase.auth.jwks.JsonWebKey +import org.radarbase.auth.jwks.MPJsonWebKey +import java.security.KeyPair +import java.util.* + +abstract class AsymmetricalJwtAlgorithm protected constructor(protected val keyPair: KeyPair) : JwtAlgorithm { + protected abstract val encodedStringHeader: String + protected abstract val encodedStringFooter: String + protected abstract val keyType: String + override val verifierKeyEncodedString: String + get() = """ + ${encodedStringHeader} + ${String(Base64.getEncoder().encode(keyPair.public.encoded))} + ${encodedStringFooter} + """.trimIndent() + override val jwk: JsonWebKey + get() = MPJsonWebKey( + algorithm.name, + keyType, + verifierKeyEncodedString + ) +} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.kt b/src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.kt new file mode 100644 index 000000000..a886cdfdb --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.kt @@ -0,0 +1,25 @@ +package org.radarbase.management.security.jwt.algorithm + +import com.auth0.jwt.algorithms.Algorithm +import java.security.KeyPair +import java.security.interfaces.ECPrivateKey +import java.security.interfaces.ECPublicKey + +class EcdsaJwtAlgorithm(keyPair: KeyPair) : AsymmetricalJwtAlgorithm(keyPair) { + /** ECDSA JWT algorithm. */ + init { + require(keyPair.private is ECPrivateKey) { "Cannot make EcdsaJwtAlgorithm with " + keyPair.private.javaClass } + } + + override val algorithm: Algorithm + get() = Algorithm.ECDSA256( + keyPair.public as ECPublicKey, + keyPair.private as ECPrivateKey + ) + override val encodedStringHeader: String + get() = "-----BEGIN EC PUBLIC KEY-----" + override val encodedStringFooter: String + get() = "-----END EC PUBLIC KEY-----" + override val keyType: String + get() = "EC" +} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.kt b/src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.kt new file mode 100644 index 000000000..7429ad473 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.kt @@ -0,0 +1,25 @@ +package org.radarbase.management.security.jwt.algorithm + +import com.auth0.jwt.algorithms.Algorithm +import org.radarbase.auth.jwks.JsonWebKey + +/** + * Encodes a signing and verification algorithm for JWT. + */ +interface JwtAlgorithm { + /** + * Auth0 Algorithm used in JWTs. + */ + val algorithm: Algorithm + + /** + * Encoded public key for storage or transmission. + */ + val verifierKeyEncodedString: String + + /** + * JavaWebKey for given algorithm for token verification. + * @return instance of [JsonWebKey] + */ + val jwk: JsonWebKey +} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.kt b/src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.kt new file mode 100644 index 000000000..0592c9ba0 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.kt @@ -0,0 +1,25 @@ +package org.radarbase.management.security.jwt.algorithm + +import com.auth0.jwt.algorithms.Algorithm +import java.security.KeyPair +import java.security.interfaces.RSAPrivateKey +import java.security.interfaces.RSAPublicKey + +class RsaJwtAlgorithm(keyPair: KeyPair) : AsymmetricalJwtAlgorithm(keyPair) { + /** RSA JWT algorithm. */ + init { + require(keyPair.private is RSAPrivateKey) { "Cannot make RsaJwtAlgorithm with " + keyPair.private.javaClass } + } + + override val algorithm: Algorithm + get() = Algorithm.RSA256( + keyPair.public as RSAPublicKey, + keyPair.private as RSAPrivateKey + ) + override val encodedStringHeader: String + get() = "-----BEGIN PUBLIC KEY-----" + override val encodedStringFooter: String + get() = "-----END PUBLIC KEY-----" + override val keyType: String + get() = "RSA" +} diff --git a/src/main/java/org/radarbase/management/security/package-info.java b/src/main/java/org/radarbase/management/security/package-info.java deleted file mode 100644 index 30c9babd1..000000000 --- a/src/main/java/org/radarbase/management/security/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Spring Security configuration. - */ -package org.radarbase.management.security; diff --git a/src/main/java/org/radarbase/management/security/package-info.kt b/src/main/java/org/radarbase/management/security/package-info.kt new file mode 100644 index 000000000..9739a9a01 --- /dev/null +++ b/src/main/java/org/radarbase/management/security/package-info.kt @@ -0,0 +1,5 @@ +/** + * Spring Security configuration. + */ +package org.radarbase.management.security + diff --git a/src/main/java/org/radarbase/management/service/AuditEventService.java b/src/main/java/org/radarbase/management/service/AuditEventService.java deleted file mode 100644 index 219c81f92..000000000 --- a/src/main/java/org/radarbase/management/service/AuditEventService.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.config.audit.AuditEventConverter; -import org.radarbase.management.repository.PersistenceAuditEventRepository; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.time.LocalDateTime; -import java.util.Optional; - -/** - * Service for managing audit events.

This is the default implementation to support SpringBoot - * Actuator AuditEventRepository

- */ -@Service -@Transactional -public class AuditEventService { - - private final PersistenceAuditEventRepository persistenceAuditEventRepository; - - private final AuditEventConverter auditEventConverter; - - public AuditEventService( - PersistenceAuditEventRepository persistenceAuditEventRepository, - AuditEventConverter auditEventConverter) { - this.persistenceAuditEventRepository = persistenceAuditEventRepository; - this.auditEventConverter = auditEventConverter; - } - - public Page findAll(Pageable pageable) { - return persistenceAuditEventRepository.findAll(pageable) - .map(auditEventConverter::convertToAuditEvent); - } - - /** - * Find audit events by dates. - * - * @param fromDate start of the date range - * @param toDate end of the date range - * @param pageable the pageable - * @return a page of audit events - */ - public Page findByDates(LocalDateTime fromDate, LocalDateTime toDate, - Pageable pageable) { - return persistenceAuditEventRepository - .findAllByAuditEventDateBetween(fromDate, toDate, pageable) - .map(auditEventConverter::convertToAuditEvent); - } - - public Optional find(Long id) { - return persistenceAuditEventRepository.findById(id) - .map(auditEventConverter::convertToAuditEvent); - } -} diff --git a/src/main/java/org/radarbase/management/service/AuditEventService.kt b/src/main/java/org/radarbase/management/service/AuditEventService.kt new file mode 100644 index 000000000..9881c7195 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/AuditEventService.kt @@ -0,0 +1,64 @@ +package org.radarbase.management.service + +import org.radarbase.management.config.audit.AuditEventConverter +import org.radarbase.management.domain.PersistentAuditEvent +import org.radarbase.management.repository.PersistenceAuditEventRepository +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.time.LocalDateTime +import java.util.* + +/** + * Service for managing audit events. + * + * This is the default implementation to support SpringBoot + * Actuator AuditEventRepository + */ +@Service +@Transactional +class AuditEventService( + private val persistenceAuditEventRepository: PersistenceAuditEventRepository, + private val auditEventConverter: AuditEventConverter +) { + fun findAll(pageable: Pageable?): Page { + return persistenceAuditEventRepository.findAll(pageable) + .map { persistentAuditEvent: PersistentAuditEvent? -> + auditEventConverter.convertToAuditEvent( + persistentAuditEvent!! + ) + } + } + + /** + * Find audit events by dates. + * + * @param fromDate start of the date range + * @param toDate end of the date range + * @param pageable the pageable + * @return a page of audit events + */ + fun findByDates( + fromDate: LocalDateTime?, toDate: LocalDateTime?, + pageable: Pageable? + ): Page { + return persistenceAuditEventRepository + .findAllByAuditEventDateBetween(fromDate, toDate, pageable) + .map { persistentAuditEvent: PersistentAuditEvent? -> + auditEventConverter.convertToAuditEvent( + persistentAuditEvent!! + ) + } + } + + fun find(id: Long): Optional { + return persistenceAuditEventRepository.findById(id) + .map { persistentAuditEvent: PersistentAuditEvent? -> + auditEventConverter.convertToAuditEvent( + persistentAuditEvent!! + ) + } + } +} diff --git a/src/main/java/org/radarbase/management/service/GroupService.kt b/src/main/java/org/radarbase/management/service/GroupService.kt index b30b94195..3cda93ef0 100644 --- a/src/main/java/org/radarbase/management/service/GroupService.kt +++ b/src/main/java/org/radarbase/management/service/GroupService.kt @@ -48,14 +48,13 @@ open class GroupService( open fun getGroup(projectName: String, groupName: String): GroupDTO { return groupMapper.groupToGroupDTOFull( groupRepository.findByProjectNameAndName( - projectName, - groupName + projectName, groupName + ) ?: throw NotFoundException( + "Group $groupName not found in project $projectName", + EntityName.GROUP, + ErrorConstants.ERR_GROUP_NOT_FOUND ) - ?: throw NotFoundException( - "Group $groupName not found in project $projectName", - EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND - ) - ) + )!! } /** @@ -67,16 +66,14 @@ open class GroupService( */ @Transactional open fun deleteGroup(projectName: String, groupName: String, unlinkSubjects: Boolean) { - val group = groupRepository.findByProjectNameAndName(projectName, groupName) - ?: throw NotFoundException( - "Group $groupName not found in project $projectName", - EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND - ) + val group = groupRepository.findByProjectNameAndName(projectName, groupName) ?: throw NotFoundException( + "Group $groupName not found in project $projectName", EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + ) if (!unlinkSubjects) { val subjectCount = subjectRepository.countByGroupId(group.id) if (subjectCount > 0) { - val msg = ("Group " + groupName + " has subjects. " - + "Add `unlinkSubjects=true` query param to confirm deletion") + val msg = + ("Group " + groupName + " has subjects. " + "Add `unlinkSubjects=true` query param to confirm deletion") throw ConflictException(msg, EntityName.GROUP, ErrorConstants.ERR_VALIDATION) } } @@ -91,26 +88,30 @@ open class GroupService( * @throws ConflictException if the group name already exists. */ @Transactional - open fun createGroup(projectName: String, groupDto: GroupDTO): GroupDTO { - val project = projectRepository.findOneWithGroupsByName(projectName) - ?: throw NotFoundException( - "Project with name $projectName not found", - EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND - ) - if (project.groups.stream() - .anyMatch { g: Group -> g.name == groupDto.name } - ) { + open fun createGroup(projectName: String, groupDto: GroupDTO): GroupDTO? { + val project = projectRepository.findOneWithGroupsByName(projectName) ?: throw NotFoundException( + "Project with name $projectName not found", EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND + ) + if (project.groups.stream().anyMatch { g: Group -> g.name == groupDto.name }) { throw ConflictException( "Group " + groupDto.name + " already exists in project " + projectName, - EntityName.GROUP, ErrorConstants.ERR_GROUP_EXISTS + EntityName.GROUP, + ErrorConstants.ERR_GROUP_EXISTS ) } val group = groupMapper.groupDTOToGroup(groupDto) - group.project = project - val groupDtoResult = groupMapper.groupToGroupDTOFull(groupRepository.save(group)) - project.groups.add(group) - projectRepository.save(project) - return groupDtoResult + if (group != null) { + group.project = project + val groupDtoResult = groupMapper.groupToGroupDTOFull(groupRepository.save(group)) + project.groups.add(group) + projectRepository.save(project) + return groupDtoResult + } + else { + throw NotFoundException( + "Group ${groupDto.name} not found in project $projectName", EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + ) + } } /** @@ -119,11 +120,9 @@ open class GroupService( * @throws NotFoundException if the project is not found. */ fun listGroups(projectName: String): List { - val project = projectRepository.findOneWithGroupsByName(projectName) - ?: throw NotFoundException( - "Project with name $projectName not found", - EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND - ) + val project = projectRepository.findOneWithGroupsByName(projectName) ?: throw NotFoundException( + "Project with name $projectName not found", EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND + ) return groupMapper.groupToGroupDTOs(project.groups) } @@ -137,59 +136,51 @@ open class GroupService( */ @Transactional open fun updateGroupSubjects( - projectName: String, groupName: String, + projectName: String, + groupName: String, subjectsToAdd: List, subjectsToRemove: List ) { groupRepository ?: throw NullPointerException() - val group = groupRepository.findByProjectNameAndName(projectName, groupName) - ?: throw NotFoundException( - "Group $groupName not found in project $projectName", - EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND - ) + val group = groupRepository.findByProjectNameAndName(projectName, groupName) ?: throw NotFoundException( + "Group $groupName not found in project $projectName", EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + ) val entitiesToAdd = getSubjectEntities(projectName, subjectsToAdd) val entitiesToRemove = getSubjectEntities(projectName, subjectsToRemove) if (entitiesToAdd.isNotEmpty()) { - val idsToAdd = entitiesToAdd.stream() - .map(Subject::id) - .toList() - subjectRepository.setGroupIdByIds(group.id, idsToAdd) + val idsToAdd = entitiesToAdd.mapNotNull(Subject::id).toList() + subjectRepository.setGroupIdByIds(group.id!!, idsToAdd) } if (entitiesToRemove.isNotEmpty()) { - val idsToRemove = entitiesToRemove.stream() - .map(Subject::id) - .toList() + val idsToRemove = entitiesToRemove.mapNotNull(Subject::id) subjectRepository.unsetGroupIdByIds(idsToRemove) } } private fun getSubjectEntities( - projectName: String, - subjectsToModify: List + projectName: String, subjectsToModify: List ): List { val logins: MutableList = ArrayList() val ids: MutableList = ArrayList() extractSubjectIdentities(subjectsToModify, logins, ids) val subjectEntities: MutableList = ArrayList(subjectsToModify.size) - if (!ids.isEmpty()) { + if (ids.isNotEmpty()) { subjectEntities.addAll(subjectRepository.findAllById(ids)) } - if (!logins.isEmpty()) { + if (logins.isNotEmpty()) { subjectEntities.addAll(subjectRepository.findAllBySubjectLogins(logins)) } for (s in subjectEntities) { val login = s.user!!.login s.activeProject ?: throw BadRequestException( - "Subject $login is not assigned to a project", - EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION + "Subject $login is not assigned to a project", EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION ) if (projectName != s.activeProject!!.projectName) { throw BadRequestException( - "Subject $login belongs to a different project", - EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION + "Subject $login belongs to a different project", EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION ) } } @@ -197,9 +188,7 @@ open class GroupService( } private fun extractSubjectIdentities( - subjectsToModify: List, - logins: MutableList, - ids: MutableList + subjectsToModify: List, logins: MutableList, ids: MutableList ) { // Each item should specify either a login or an ID, // since having both will require an extra validation step @@ -211,15 +200,14 @@ open class GroupService( val id = item.id if (id == null && login == null) { throw BadRequestException( - "Subject identification must be specified", - EntityName.GROUP, ErrorConstants.ERR_VALIDATION + "Subject identification must be specified", EntityName.GROUP, ErrorConstants.ERR_VALIDATION ) } if (id != null && login != null) { throw BadRequestException( - "Subject identification must be specify either ID or Login. " - + "Do not provide both values to avoid potential confusion.", - EntityName.GROUP, ErrorConstants.ERR_VALIDATION + "Subject identification must be specify either ID or Login. " + "Do not provide both values to avoid potential confusion.", + EntityName.GROUP, + ErrorConstants.ERR_VALIDATION ) } if (id != null) { diff --git a/src/main/java/org/radarbase/management/service/MailService.java b/src/main/java/org/radarbase/management/service/MailService.java deleted file mode 100644 index 788222773..000000000 --- a/src/main/java/org/radarbase/management/service/MailService.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.radarbase.management.service; - -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.util.Locale; -import javax.mail.internet.MimeMessage; - -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.User; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.MessageSource; -import org.springframework.mail.javamail.JavaMailSender; -import org.springframework.mail.javamail.MimeMessageHelper; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; -import org.thymeleaf.context.Context; -import org.thymeleaf.spring5.SpringTemplateEngine; - -/** - * Service for sending emails.

We use the @Async annotation to send emails asynchronously.

- */ -@Service -public class MailService { - - private static final Logger log = LoggerFactory.getLogger(MailService.class); - - private static final String USER = "user"; - - private static final String BASE_URL = "baseUrl"; - - private static final String EXPIRY = "expiry"; - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Autowired - private JavaMailSender javaMailSender; - - @Autowired - private MessageSource messageSource; - - @Autowired - private SpringTemplateEngine templateEngine; - - /** - * Send an email. - * @param to email address to send to - * @param subject subject line - * @param content email contents - * @param isMultipart send as multipart - * @param isHtml send as html - */ - @Async - public void sendEmail(String to, String subject, String content, boolean isMultipart, - boolean isHtml) { - log.debug( - "Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}", - isMultipart, isHtml, to, subject, content); - - // Prepare message using a Spring helper - MimeMessage mimeMessage = javaMailSender.createMimeMessage(); - try { - MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, - StandardCharsets.UTF_8.name()); - message.setTo(to); - message.setFrom(managementPortalProperties.getMail().getFrom()); - message.setSubject(subject); - message.setText(content, isHtml); - javaMailSender.send(mimeMessage); - log.debug("Sent email to User '{}'", to); - } catch (Exception e) { - log.warn("Email could not be sent to user '{}'", to, e); - } - } - - /** - * Send an account activation email to a given user. - * @param user the user to send to - */ - @Async - public void sendActivationEmail(User user) { - log.debug("Sending activation email to '{}'", user.email); - Locale locale = Locale.forLanguageTag(user.langKey); - Context context = new Context(locale); - context.setVariable(USER, user); - context.setVariable(BASE_URL, - managementPortalProperties.getCommon().getManagementPortalBaseUrl()); - String content = templateEngine.process("activationEmail", context); - String subject = messageSource.getMessage("email.activation.title", null, locale); - sendEmail(user.email, subject, content, false, true); - } - - /** - * Send account creation email to a given user. - * @param user the user - */ - @Async - public void sendCreationEmail(User user, long duration) { - log.debug("Sending creation email to '{}'", user.email); - Locale locale = Locale.forLanguageTag(user.langKey); - Context context = new Context(locale); - context.setVariable(USER, user); - context.setVariable(BASE_URL, - managementPortalProperties.getCommon().getManagementPortalBaseUrl()); - context.setVariable(EXPIRY, Duration.ofSeconds(duration).toHours()); - String content = templateEngine.process("creationEmail", context); - String subject = messageSource.getMessage("email.activation.title", null, locale); - sendEmail(user.email, subject, content, false, true); - } - - /** - * Send account creation email for a user to an address different than the users' address. - * @param user the created user - * @param email the address to send to - */ - @Async - public void sendCreationEmailForGivenEmail(User user, String email) { - log.debug("Sending creation email to '{}'", email); - Locale locale = Locale.forLanguageTag(user.langKey); - Context context = new Context(locale); - context.setVariable(USER, user); - context.setVariable(BASE_URL, - managementPortalProperties.getCommon().getManagementPortalBaseUrl()); - String content = templateEngine.process("creationEmail", context); - String subject = messageSource.getMessage("email.activation.title", null, locale); - sendEmail(email, subject, content, false, true); - } - - /** - * Send a password reset email to a given user. - * @param user the user - */ - @Async - public void sendPasswordResetMail(User user) { - log.debug("Sending password reset email to '{}'", user.email); - Locale locale = Locale.forLanguageTag(user.langKey); - Context context = new Context(locale); - context.setVariable(USER, user); - context.setVariable(BASE_URL, - managementPortalProperties.getCommon().getManagementPortalBaseUrl()); - String content = templateEngine.process("passwordResetEmail", context); - String subject = messageSource.getMessage("email.reset.title", null, locale); - sendEmail(user.email, subject, content, false, true); - } -} diff --git a/src/main/java/org/radarbase/management/service/MailService.kt b/src/main/java/org/radarbase/management/service/MailService.kt new file mode 100644 index 000000000..3f894424d --- /dev/null +++ b/src/main/java/org/radarbase/management/service/MailService.kt @@ -0,0 +1,157 @@ +package org.radarbase.management.service + +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.User +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.MessageSource +import org.springframework.mail.javamail.JavaMailSender +import org.springframework.mail.javamail.MimeMessageHelper +import org.springframework.scheduling.annotation.Async +import org.springframework.stereotype.Service +import org.thymeleaf.context.Context +import org.thymeleaf.spring5.SpringTemplateEngine +import java.nio.charset.StandardCharsets +import java.time.Duration +import java.util.* + +/** + * Service for sending emails. + * + * We use the @Async annotation to send emails asynchronously. + */ +@Service +class MailService { + @Autowired + private val managementPortalProperties: ManagementPortalProperties? = null + + @Autowired + private val javaMailSender: JavaMailSender? = null + + @Autowired + private val messageSource: MessageSource? = null + + @Autowired + private val templateEngine: SpringTemplateEngine? = null + + /** + * Send an email. + * @param to email address to send to + * @param subject subject line + * @param content email contents + * @param isMultipart send as multipart + * @param isHtml send as html + */ + @Async + fun sendEmail( + to: String?, subject: String?, content: String?, isMultipart: Boolean, + isHtml: Boolean + ) { + log.debug( + "Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}", + isMultipart, isHtml, to, subject, content + ) + + // Prepare message using a Spring helper + val mimeMessage = javaMailSender!!.createMimeMessage() + try { + val message = MimeMessageHelper( + mimeMessage, isMultipart, + StandardCharsets.UTF_8.name() + ) + message.setTo(to) + message.setFrom(managementPortalProperties!!.mail.from) + message.setSubject(subject) + message.setText(content, isHtml) + javaMailSender.send(mimeMessage) + log.debug("Sent email to User '{}'", to) + } catch (e: Exception) { + log.warn("Email could not be sent to user '{}'", to, e) + } + } + + /** + * Send an account activation email to a given user. + * @param user the user to send to + */ + @Async + fun sendActivationEmail(user: User) { + log.debug("Sending activation email to '{}'", user.email) + val locale = Locale.forLanguageTag(user.langKey) + val context = Context(locale) + context.setVariable(USER, user) + context.setVariable( + BASE_URL, + managementPortalProperties!!.common.managementPortalBaseUrl + ) + val content = templateEngine!!.process("activationEmail", context) + val subject = messageSource!!.getMessage("email.activation.title", null, locale) + sendEmail(user.email, subject, content, false, true) + } + + /** + * Send account creation email to a given user. + * @param user the user + */ + @Async + fun sendCreationEmail(user: User, duration: Long) { + log.debug("Sending creation email to '{}'", user.email) + val locale = Locale.forLanguageTag(user.langKey) + val context = Context(locale) + context.setVariable(USER, user) + context.setVariable( + BASE_URL, + managementPortalProperties!!.common.managementPortalBaseUrl + ) + context.setVariable(EXPIRY, Duration.ofSeconds(duration).toHours()) + val content = templateEngine!!.process("creationEmail", context) + val subject = messageSource!!.getMessage("email.activation.title", null, locale) + sendEmail(user.email, subject, content, false, true) + } + + /** + * Send account creation email for a user to an address different than the users' address. + * @param user the created user + * @param email the address to send to + */ + @Async + fun sendCreationEmailForGivenEmail(user: User, email: String?) { + log.debug("Sending creation email to '{}'", email) + val locale = Locale.forLanguageTag(user.langKey) + val context = Context(locale) + context.setVariable(USER, user) + context.setVariable( + BASE_URL, + managementPortalProperties!!.common.managementPortalBaseUrl + ) + val content = templateEngine!!.process("creationEmail", context) + val subject = messageSource!!.getMessage("email.activation.title", null, locale) + sendEmail(email, subject, content, false, true) + } + + /** + * Send a password reset email to a given user. + * @param user the user + */ + @Async + fun sendPasswordResetMail(user: User) { + log.debug("Sending password reset email to '{}'", user.email) + val locale = Locale.forLanguageTag(user.langKey) + val context = Context(locale) + context.setVariable(USER, user) + context.setVariable( + BASE_URL, + managementPortalProperties!!.common.managementPortalBaseUrl + ) + val content = templateEngine!!.process("passwordResetEmail", context) + val subject = messageSource!!.getMessage("email.reset.title", null, locale) + sendEmail(user.email, subject, content, false, true) + } + + companion object { + private val log = LoggerFactory.getLogger(MailService::class.java) + private const val USER = "user" + private const val BASE_URL = "baseUrl" + private const val EXPIRY = "expiry" + } +} diff --git a/src/main/java/org/radarbase/management/service/MetaTokenService.kt b/src/main/java/org/radarbase/management/service/MetaTokenService.kt index 9a8bfe961..a89752a6b 100644 --- a/src/main/java/org/radarbase/management/service/MetaTokenService.kt +++ b/src/main/java/org/radarbase/management/service/MetaTokenService.kt @@ -76,8 +76,8 @@ open class MetaTokenService { // process the response if the token is not fetched or not expired return if (metaToken.isValid) { val refreshToken = oAuthClientService!!.createAccessToken( - metaToken.subject!!.user, - metaToken.clientId + metaToken.subject!!.user!!, + metaToken.clientId!! ) .refreshToken .value @@ -112,14 +112,12 @@ open class MetaTokenService { @Transactional(readOnly = true) open fun getToken(tokenName: String): MetaToken { return metaTokenRepository!!.findOneByTokenName(tokenName) - .orElseThrow { - NotFoundException( + ?: throw NotFoundException( "Meta token not found with tokenName", EntityName.META_TOKEN, ErrorConstants.ERR_TOKEN_NOT_FOUND, Collections.singletonMap("tokenName", tokenName) ) - } } /** @@ -169,14 +167,15 @@ open class MetaTokenService { subject, clientId, false, Instant.now().plus(timeout), persistent ) - return if (metaToken.id != null && metaToken.tokenName != null) { + val tokenName = metaToken.tokenName + return if (metaToken.id != null && tokenName != null) { // get base url from settings val baseUrl = managementPortalProperties!!.common.managementPortalBaseUrl // create complete uri string val tokenUrl = baseUrl + ResourceUriService.getUri(metaToken).getPath() // create response ClientPairInfoDTO( - URL(baseUrl), metaToken.tokenName, + URL(baseUrl), tokenName, URL(tokenUrl), timeout ) } else { diff --git a/src/main/java/org/radarbase/management/service/OAuthClientService.java b/src/main/java/org/radarbase/management/service/OAuthClientService.java deleted file mode 100644 index afc8fcf2e..000000000 --- a/src/main/java/org/radarbase/management/service/OAuthClientService.java +++ /dev/null @@ -1,188 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.domain.User; -import org.radarbase.management.service.dto.ClientDetailsDTO; -import org.radarbase.management.service.mapper.ClientDetailsMapper; -import org.radarbase.management.web.rest.errors.ConflictException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.InvalidRequestException; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.common.OAuth2AccessToken; -import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.security.oauth2.provider.NoSuchClientException; -import org.springframework.security.oauth2.provider.OAuth2Authentication; -import org.springframework.security.oauth2.provider.OAuth2Request; -import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; -import org.springframework.stereotype.Service; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.radarbase.management.web.rest.errors.EntityName.OAUTH_CLIENT; -import static org.springframework.security.oauth2.common.util.OAuth2Utils.GRANT_TYPE; - -/** - * The service layer to handle OAuthClient and Token related functions. - * Created by nivethika on 03/08/2018. - */ -@Service -public class OAuthClientService { - - private static final Logger log = LoggerFactory.getLogger(OAuthClientService.class); - - private static final String PROTECTED_KEY = "protected"; - - @Autowired - private JdbcClientDetailsService clientDetailsService; - - @Autowired - private ClientDetailsMapper clientDetailsMapper; - - @Autowired - private AuthorizationServerEndpointsConfiguration authorizationServerEndpointsConfiguration; - - public List findAllOAuthClients() { - return clientDetailsService.listClientDetails(); - } - - /** - * Find ClientDetails by OAuth client id. - * - * @param clientId The client ID to look up - * @return a ClientDetails object with the requested client ID - * @throws NotFoundException If there is no client with the requested ID - */ - public ClientDetails findOneByClientId(String clientId) { - try { - return clientDetailsService.loadClientByClientId(clientId); - } catch (NoSuchClientException e) { - log.error("Pair client request for unknown client id: {}", clientId); - Map errorParams = new HashMap<>(); - errorParams.put("clientId", clientId); - throw new NotFoundException("Client not found for client-id", OAUTH_CLIENT, - ErrorConstants.ERR_OAUTH_CLIENT_ID_NOT_FOUND, errorParams); - } - } - - /** - * Update Oauth-client with new information. - * - * @param clientDetailsDto information to update. - * @return Updated {@link ClientDetails} instance. - */ - public ClientDetails updateOauthClient(ClientDetailsDTO clientDetailsDto) { - ClientDetails details = - clientDetailsMapper.clientDetailsDTOToClientDetails(clientDetailsDto); - // update client. - clientDetailsService.updateClientDetails(details); - - ClientDetails updated = findOneByClientId(clientDetailsDto.getClientId()); - // updateClientDetails does not update secret, so check for it separately - if (clientDetailsDto.getClientSecret() != null && !clientDetailsDto.getClientSecret() - .equals(updated.getClientSecret())) { - clientDetailsService.updateClientSecret(clientDetailsDto.getClientId(), - clientDetailsDto.getClientSecret()); - } - return findOneByClientId(clientDetailsDto.getClientId()); - } - - /** - * Checks whether a client is a protected client. - * - * @param details ClientDetails. - */ - public static void checkProtected(ClientDetails details) { - Map info = details.getAdditionalInformation(); - if (Objects.nonNull(info) && info.containsKey(PROTECTED_KEY) && info.get(PROTECTED_KEY) - .toString().equalsIgnoreCase("true")) { - throw new InvalidRequestException("Cannot modify protected client", OAUTH_CLIENT, - ErrorConstants.ERR_OAUTH_CLIENT_PROTECTED, - Collections.singletonMap("client_id", details.getClientId())); - } - } - - /** - * Deletes an oauth client. - * @param clientId of the auth-client to delete. - */ - public void deleteClientDetails(String clientId) { - clientDetailsService.removeClientDetails(clientId); - } - - /** - * Creates new oauth-client. - * - * @param clientDetailsDto data to create oauth-client. - * @return created {@link ClientDetails}. - */ - public ClientDetails createClientDetail(ClientDetailsDTO clientDetailsDto) { - // check if the client id exists - try { - ClientDetails existingClient = - clientDetailsService.loadClientByClientId(clientDetailsDto.getClientId()); - if (existingClient != null) { - throw new ConflictException("OAuth client already exists with this id", - OAUTH_CLIENT, ErrorConstants.ERR_CLIENT_ID_EXISTS, - Collections.singletonMap("client_id", clientDetailsDto.getClientId())); - } - } catch (NoSuchClientException ex) { - // Client does not exist yet, we can go ahead and create it - log.info("No client existing with client-id {}. Proceeding to create new client", - clientDetailsDto.getClientId()); - } - ClientDetails details = - clientDetailsMapper.clientDetailsDTOToClientDetails(clientDetailsDto); - // create oauth client. - clientDetailsService.addClientDetails(details); - - return findOneByClientId(clientDetailsDto.getClientId()); - - } - - /** - * Internally creates an {@link OAuth2AccessToken} token using authorization-code flow. This - * method bypasses the usual authorization code flow mechanism, so it should only be used where - * appropriate, e.g., for subject impersonation. - * - * @param clientId oauth client id. - * @param user user of the token. - * @return Created {@link OAuth2AccessToken} instance. - */ - public OAuth2AccessToken createAccessToken(User user, String clientId) { - Set authorities = user.getAuthorities().stream() - .map(a -> new SimpleGrantedAuthority(a.name)) - .collect(Collectors.toSet()); - // lookup the OAuth client - // getOAuthClient checks if the id exists - ClientDetails client = findOneByClientId(clientId); - - Map requestParameters = Collections.singletonMap( - GRANT_TYPE , "authorization_code"); - - Set responseTypes = Collections.singleton("code"); - - OAuth2Request oAuth2Request = new OAuth2Request( - requestParameters, clientId, authorities, true, client.getScope(), - client.getResourceIds(), null, responseTypes, Collections.emptyMap()); - - Authentication authenticationToken = new UsernamePasswordAuthenticationToken( - user.getLogin(), null, authorities); - - return authorizationServerEndpointsConfiguration.getEndpointsConfigurer() - .getTokenServices() - .createAccessToken(new OAuth2Authentication(oAuth2Request, authenticationToken)); - } -} diff --git a/src/main/java/org/radarbase/management/service/OAuthClientService.kt b/src/main/java/org/radarbase/management/service/OAuthClientService.kt new file mode 100644 index 000000000..a0d6fd53f --- /dev/null +++ b/src/main/java/org/radarbase/management/service/OAuthClientService.kt @@ -0,0 +1,179 @@ +package org.radarbase.management.service + +import org.radarbase.management.domain.Authority +import org.radarbase.management.domain.User +import org.radarbase.management.service.dto.ClientDetailsDTO +import org.radarbase.management.service.mapper.ClientDetailsMapper +import org.radarbase.management.web.rest.errors.ConflictException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidRequestException +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.Authentication +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.oauth2.common.OAuth2AccessToken +import org.springframework.security.oauth2.common.util.OAuth2Utils +import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerEndpointsConfiguration +import org.springframework.security.oauth2.provider.ClientDetails +import org.springframework.security.oauth2.provider.NoSuchClientException +import org.springframework.security.oauth2.provider.OAuth2Authentication +import org.springframework.security.oauth2.provider.OAuth2Request +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService +import org.springframework.stereotype.Service +import java.util.* + +/** + * The service layer to handle OAuthClient and Token related functions. + * Created by nivethika on 03/08/2018. + */ +@Service +class OAuthClientService { + @Autowired + private val clientDetailsService: JdbcClientDetailsService? = null + + @Autowired + private val clientDetailsMapper: ClientDetailsMapper? = null + + @Autowired + private val authorizationServerEndpointsConfiguration: AuthorizationServerEndpointsConfiguration? = null + fun findAllOAuthClients(): List { + return clientDetailsService!!.listClientDetails() + } + + /** + * Find ClientDetails by OAuth client id. + * + * @param clientId The client ID to look up + * @return a ClientDetails object with the requested client ID + * @throws NotFoundException If there is no client with the requested ID + */ + fun findOneByClientId(clientId: String?): ClientDetails { + return try { + clientDetailsService!!.loadClientByClientId(clientId) + } catch (e: NoSuchClientException) { + log.error("Pair client request for unknown client id: {}", clientId) + val errorParams: MutableMap = HashMap() + errorParams["clientId"] = clientId + throw NotFoundException( + "Client not found for client-id", EntityName.Companion.OAUTH_CLIENT, + ErrorConstants.ERR_OAUTH_CLIENT_ID_NOT_FOUND, errorParams + ) + } + } + + /** + * Update Oauth-client with new information. + * + * @param clientDetailsDto information to update. + * @return Updated [ClientDetails] instance. + */ + fun updateOauthClient(clientDetailsDto: ClientDetailsDTO): ClientDetails { + val details: ClientDetails? = clientDetailsMapper!!.clientDetailsDTOToClientDetails(clientDetailsDto) + // update client. + clientDetailsService!!.updateClientDetails(details) + val updated = findOneByClientId(clientDetailsDto.clientId) + // updateClientDetails does not update secret, so check for it separately + if (clientDetailsDto.clientSecret != null && clientDetailsDto.clientSecret != updated.clientSecret) { + clientDetailsService.updateClientSecret( + clientDetailsDto.clientId, + clientDetailsDto.clientSecret + ) + } + return findOneByClientId(clientDetailsDto.clientId) + } + + /** + * Deletes an oauth client. + * @param clientId of the auth-client to delete. + */ + fun deleteClientDetails(clientId: String?) { + clientDetailsService!!.removeClientDetails(clientId) + } + + /** + * Creates new oauth-client. + * + * @param clientDetailsDto data to create oauth-client. + * @return created [ClientDetails]. + */ + fun createClientDetail(clientDetailsDto: ClientDetailsDTO): ClientDetails { + // check if the client id exists + try { + val existingClient = clientDetailsService!!.loadClientByClientId(clientDetailsDto.clientId) + if (existingClient != null) { + throw ConflictException( + "OAuth client already exists with this id", + EntityName.Companion.OAUTH_CLIENT, ErrorConstants.ERR_CLIENT_ID_EXISTS, + Collections.singletonMap("client_id", clientDetailsDto.clientId) + ) + } + } catch (ex: NoSuchClientException) { + // Client does not exist yet, we can go ahead and create it + log.info( + "No client existing with client-id {}. Proceeding to create new client", + clientDetailsDto.clientId + ) + } + val details: ClientDetails? = clientDetailsMapper!!.clientDetailsDTOToClientDetails(clientDetailsDto) + // create oauth client. + clientDetailsService!!.addClientDetails(details) + return findOneByClientId(clientDetailsDto.clientId) + } + + /** + * Internally creates an [OAuth2AccessToken] token using authorization-code flow. This + * method bypasses the usual authorization code flow mechanism, so it should only be used where + * appropriate, e.g., for subject impersonation. + * + * @param clientId oauth client id. + * @param user user of the token. + * @return Created [OAuth2AccessToken] instance. + */ + fun createAccessToken(user: User, clientId: String): OAuth2AccessToken { + val authorities = user.authorities!! + .map { a: Authority? -> SimpleGrantedAuthority(a?.name) } + // lookup the OAuth client + // getOAuthClient checks if the id exists + val client = findOneByClientId(clientId) + val requestParameters = Collections.singletonMap( + OAuth2Utils.GRANT_TYPE, "authorization_code" + ) + val responseTypes = setOf("code") + val oAuth2Request = OAuth2Request( + requestParameters, clientId, authorities, true, client.scope, + client.resourceIds, null, responseTypes, emptyMap() + ) + val authenticationToken: Authentication = UsernamePasswordAuthenticationToken( + user.login, null, authorities + ) + return authorizationServerEndpointsConfiguration!!.getEndpointsConfigurer() + .tokenServices + .createAccessToken(OAuth2Authentication(oAuth2Request, authenticationToken)) + } + + companion object { + private val log = LoggerFactory.getLogger(OAuthClientService::class.java) + private const val PROTECTED_KEY = "protected" + + /** + * Checks whether a client is a protected client. + * + * @param details ClientDetails. + */ + fun checkProtected(details: ClientDetails) { + val info = details.additionalInformation + if (Objects.nonNull(info) && info.containsKey(PROTECTED_KEY) && info[PROTECTED_KEY] + .toString().equals("true", ignoreCase = true) + ) { + throw InvalidRequestException( + "Cannot modify protected client", EntityName.Companion.OAUTH_CLIENT, + ErrorConstants.ERR_OAUTH_CLIENT_PROTECTED, + Collections.singletonMap("client_id", details.clientId) + ) + } + } + } +} diff --git a/src/main/java/org/radarbase/management/service/OrganizationService.java b/src/main/java/org/radarbase/management/service/OrganizationService.java deleted file mode 100644 index b1d7a1703..000000000 --- a/src/main/java/org/radarbase/management/service/OrganizationService.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.domain.Organization; -import org.radarbase.management.domain.Project; -import org.radarbase.management.repository.OrganizationRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.service.dto.OrganizationDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.mapper.OrganizationMapper; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Stream; - -import static org.radarbase.auth.authorization.Permission.ORGANIZATION_READ; - -/** - * Service Implementation for managing Organization. - */ -@Service -@Transactional -public class OrganizationService { - - private static final Logger log = LoggerFactory.getLogger(OrganizationService.class); - - @Autowired - private OrganizationRepository organizationRepository; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private OrganizationMapper organizationMapper; - - @Autowired - private ProjectMapper projectMapper; - - @Autowired - private AuthService authService; - - /** - * Save an organization. - * - * @param organizationDto the entity to save - * @return the persisted entity - */ - public OrganizationDTO save(OrganizationDTO organizationDto) { - log.debug("Request to save Organization : {}", organizationDto); - var org = organizationMapper.organizationDTOToOrganization(organizationDto); - org = organizationRepository.save(org); - return organizationMapper.organizationToOrganizationDTO(org); - } - - /** - * Get all the organizations. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public List findAll() { - List organizationsOfUser; - - var referents = authService.referentsByScope(ORGANIZATION_READ); - - if (referents.getGlobal()) { - organizationsOfUser = organizationRepository.findAll(); - } else { - Set projectNames = referents.getAllProjects(); - - Stream organizationsOfProject = !projectNames.isEmpty() - ? organizationRepository.findAllByProjectNames(projectNames).stream() - : Stream.of(); - - Stream organizationsOfRole = referents.getOrganizations() - .stream() - .flatMap(name -> organizationRepository.findOneByName(name).stream()); - - organizationsOfUser = Stream.concat(organizationsOfRole, organizationsOfProject) - .distinct() - .toList(); - } - - return organizationMapper.organizationsToOrganizationDTOs(organizationsOfUser); - } - - /** - * Get one organization by name. - * - * @param name the name of the entity - * @return the entity - */ - @Transactional(readOnly = true) - public Optional findByName(String name) { - log.debug("Request to get Organization by name: {}", name); - return organizationRepository.findOneByName(name) - .map(organizationMapper::organizationToOrganizationDTO); - } - - /** - * Get all projects belonging to the organization. - * - * @return the list of projects - */ - @Transactional(readOnly = true) - public List findAllProjectsByOrganizationName(String organizationName) { - var referents = authService.referentsByScope(ORGANIZATION_READ); - if (referents.isEmpty()) { - return Collections.emptyList(); - } - - Stream projectStream; - - if (referents.getGlobal() || referents.hasOrganization(organizationName)) { - projectStream = projectRepository.findAllByOrganizationName(organizationName).stream(); - } else if (referents.hasAnyProjects()) { - projectStream = projectRepository.findAllByOrganizationName(organizationName).stream() - .filter(project -> referents.hasAnyProject(project.projectName)); - } else { - return List.of(); - } - - return projectStream - .map(projectMapper::projectToProjectDTO) - .toList(); - } -} diff --git a/src/main/java/org/radarbase/management/service/OrganizationService.kt b/src/main/java/org/radarbase/management/service/OrganizationService.kt new file mode 100644 index 000000000..aeb07f9de --- /dev/null +++ b/src/main/java/org/radarbase/management/service/OrganizationService.kt @@ -0,0 +1,110 @@ +package org.radarbase.management.service + +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.Organization +import org.radarbase.management.domain.Project +import org.radarbase.management.repository.OrganizationRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.dto.OrganizationDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.mapper.OrganizationMapper +import org.radarbase.management.service.mapper.ProjectMapper +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +/** + * Service Implementation for managing Organization. + */ +@Service +@Transactional +open class OrganizationService( + @Autowired private val organizationRepository: OrganizationRepository, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val organizationMapper: OrganizationMapper, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val authService: AuthService +) { + + /** + * Save an organization. + * + * @param organizationDto the entity to save + * @return the persisted entity + */ + fun save(organizationDto: OrganizationDTO): OrganizationDTO { + log.debug("Request to save Organization : {}", organizationDto) + var org = organizationMapper.organizationDTOToOrganization(organizationDto) + org = organizationRepository.save(org) + return organizationMapper.organizationToOrganizationDTO(org) + } + + /** + * Get all the organizations. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(): List { + val organizationsOfUser: List + val referents = authService.referentsByScope(Permission.ORGANIZATION_READ) + organizationsOfUser = if (referents.global) { + organizationRepository.findAll() + } else { + val projectNames = referents.allProjects + val organizationsOfProject = + organizationRepository.findAllByProjectNames(projectNames) + val organizationsOfRole = referents.organizations + .mapNotNull { name: String -> organizationRepository.findOneByName(name) } + (organizationsOfRole + organizationsOfProject) + .distinct() + .toList() + } + return organizationMapper.organizationsToOrganizationDTOs(organizationsOfUser) + } + + /** + * Get one organization by name. + * + * @param name the name of the entity + * @return the entity + */ + @Transactional(readOnly = true) + open fun findByName(name: String): OrganizationDTO? { + log.debug("Request to get Organization by name: {}", name) + return organizationRepository.findOneByName(name)?.let { organizationMapper.organizationToOrganizationDTO(it) } + } + + /** + * Get all projects belonging to the organization. + * + * @return the list of projects + */ + @Transactional(readOnly = true) + open fun findAllProjectsByOrganizationName(organizationName: String): List { + val referents = authService.referentsByScope(Permission.ORGANIZATION_READ) + if (referents.isEmpty()) { + return emptyList() + } + val projectStream: List = if (referents.global || referents.hasOrganization(organizationName)) { + projectRepository.findAllByOrganizationName(organizationName) + } else if (referents.hasAnyProjects()) { + projectRepository.findAllByOrganizationName(organizationName) + .filter { project: Project -> + referents.hasAnyProject( + project.projectName!! + ) + } + } else { + return listOf() + } + return projectStream + .mapNotNull { project: Project? -> projectMapper.projectToProjectDTO(project) } + .toList() + } + + companion object { + private val log = LoggerFactory.getLogger(OrganizationService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/service/PasswordService.java b/src/main/java/org/radarbase/management/service/PasswordService.java deleted file mode 100644 index a4299cd23..000000000 --- a/src/main/java/org/radarbase/management/service/PasswordService.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.service; - -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; - -import java.security.SecureRandom; -import java.util.Locale; -import java.util.Random; - -import static org.radarbase.management.web.rest.errors.EntityName.USER; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_PASSWORD_TOO_LONG; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_PASSWORD_TOO_WEAK; - -@Service -public class PasswordService { - public static final int[] NUMERIC; - public static final int[] ALPHANUMERIC; - private static final int[] LOWER; - private static final int[] UPPER; - - static { - String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - String lower = upper.toLowerCase(Locale.ROOT); - String digits = "0123456789"; - UPPER = upper.chars().toArray(); - LOWER = lower.chars().toArray(); - NUMERIC = digits.chars().toArray(); - ALPHANUMERIC = (upper + lower + digits).chars().toArray(); - } - - private final PasswordEncoder passwordEncoder; - private final Random random = new SecureRandom(); - - public PasswordService(PasswordEncoder passwordEncoder) { - this.passwordEncoder = passwordEncoder; - } - - /** - * Encodes a plaintext password. - * @param password password to encode. - * @return encoded password. - */ - public String encode(String password) { - return passwordEncoder.encode(password); - } - - /** - * Generates a random password that is already encoded. - * @return encoded password. - */ - public String generateEncodedPassword() { - return encode(generateString(ALPHANUMERIC, 30)); - } - - /** - * Generates a random numeric reset key. - * @return reset key. - */ - public String generateResetKey() { - return generateString(NUMERIC, 20); - } - - private String generateString(int[] allowedCharacters, int length) { - return random.ints(0, allowedCharacters.length) - .map(i -> allowedCharacters[i]) - .limit(length) - .collect(() -> new StringBuilder(length), - StringBuilder::appendCodePoint, StringBuilder::append) - .toString(); - } - - /** - * Check that given password is strong enough, based on complexity and length. - * @param password password to check. - * @throws BadRequestException if the password is too weak or too long. - */ - public void checkPasswordStrength(String password) { - if (isPasswordWeak(password)) { - throw new BadRequestException("Weak password. Use a password with more variety of" - + "numeric, alphabetical and symbol characters.", USER, ERR_PASSWORD_TOO_WEAK); - } else if (password.length() > 100) { - throw new BadRequestException("Password too long", USER, ERR_PASSWORD_TOO_LONG); - } - } - - /** Check whether given password is too weak. */ - private boolean isPasswordWeak(String password) { - return password.length() < 8 - || noneInRange(password, UPPER[0], UPPER[UPPER.length - 1]) - || noneInRange(password, LOWER[0], LOWER[LOWER.length - 1]) - || noneInRange(password, NUMERIC[0], NUMERIC[NUMERIC.length - 1]); - } - - private boolean noneInRange(String str, int startInclusive, int endInclusive) { - return str.chars().noneMatch(c -> c >= startInclusive && c < endInclusive); - } -} diff --git a/src/main/java/org/radarbase/management/service/PasswordService.kt b/src/main/java/org/radarbase/management/service/PasswordService.kt new file mode 100644 index 000000000..9245e110e --- /dev/null +++ b/src/main/java/org/radarbase/management/service/PasswordService.kt @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.service + +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.stereotype.Service +import java.security.SecureRandom +import java.util.* + +@Service +class PasswordService(private val passwordEncoder: PasswordEncoder) { + private val random: Random = SecureRandom() + + /** + * Encodes a plaintext password. + * @param password password to encode. + * @return encoded password. + */ + fun encode(password: String?): String { + return passwordEncoder.encode(password) + } + + /** + * Generates a random password that is already encoded. + * @return encoded password. + */ + fun generateEncodedPassword(): String { + return encode(generateString(ALPHANUMERIC, 30)) + } + + /** + * Generates a random numeric reset key. + * @return reset key. + */ + fun generateResetKey(): String { + return generateString(NUMERIC, 20) + } + + private fun generateString(allowedCharacters: IntArray, length: Int): String { + return random.ints(0, allowedCharacters.size) + .map { i: Int -> allowedCharacters[i] } + .limit(length.toLong()) + .collect( + { StringBuilder(length) }, + { obj: StringBuilder, codePoint: Int -> obj.appendCodePoint(codePoint) }) { obj: StringBuilder, s: StringBuilder? -> + obj.append( + s + ) + } + .toString() + } + + /** + * Check that given password is strong enough, based on complexity and length. + * @param password password to check. + * @throws BadRequestException if the password is too weak or too long. + */ + fun checkPasswordStrength(password: String?) { + if (isPasswordWeak(password)) { + throw BadRequestException( + "Weak password. Use a password with more variety of" + + "numeric, alphabetical and symbol characters.", + EntityName.Companion.USER, + ErrorConstants.ERR_PASSWORD_TOO_WEAK + ) + } else if (password!!.length > 100) { + throw BadRequestException( + "Password too long", + EntityName.Companion.USER, + ErrorConstants.ERR_PASSWORD_TOO_LONG + ) + } + } + + /** Check whether given password is too weak. */ + private fun isPasswordWeak(password: String?): Boolean { + return (password!!.length < 8 || noneInRange(password, UPPER[0], UPPER[UPPER.size - 1]) + || noneInRange(password, LOWER[0], LOWER[LOWER.size - 1]) + || noneInRange(password, NUMERIC[0], NUMERIC[NUMERIC.size - 1])) + } + + private fun noneInRange(str: String?, startInclusive: Int, endInclusive: Int): Boolean { + return str!!.chars().noneMatch { c: Int -> c >= startInclusive && c < endInclusive } + } + + companion object { + val NUMERIC: IntArray + val ALPHANUMERIC: IntArray + private val LOWER: IntArray + private val UPPER: IntArray + + init { + val upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + val lower = upper.lowercase() + val digits = "0123456789" + UPPER = upper.chars().toArray() + LOWER = lower.chars().toArray() + NUMERIC = digits.chars().toArray() + ALPHANUMERIC = (upper + lower + digits).chars().toArray() + } + } +} diff --git a/src/main/java/org/radarbase/management/service/ProjectService.kt b/src/main/java/org/radarbase/management/service/ProjectService.kt index 5f273f341..5856587f0 100644 --- a/src/main/java/org/radarbase/management/service/ProjectService.kt +++ b/src/main/java/org/radarbase/management/service/ProjectService.kt @@ -37,11 +37,11 @@ open class ProjectService( * @param projectDto the entity to save * @return the persisted entity */ - fun save(projectDto: ProjectDTO?): ProjectDTO { + fun save(projectDto: ProjectDTO): ProjectDTO { log.debug("Request to save Project : {}", projectDto) var project = projectMapper.projectDTOToProject(projectDto) - project = projectRepository.save(project) - return projectMapper.projectToProjectDTO(project) + project = project?.let { projectRepository.save(it) } + return projectMapper.projectToProjectDTO(project)!! } /** @@ -50,8 +50,8 @@ open class ProjectService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(fetchMinimal: Boolean?, pageable: Pageable?): Page<*> { - val projects: Page? + open fun findAll(fetchMinimal: Boolean, pageable: Pageable): Page<*> { + val projects: Page val referents = authService.referentsByScope(Permission.PROJECT_READ) projects = if (referents.isEmpty()) { PageImpl(listOf()) @@ -62,10 +62,10 @@ open class ProjectService( pageable, referents.organizations, referents.allProjects ) } - return if (!fetchMinimal!!) { - projects!!.map { project: Project? -> projectMapper.projectToProjectDTO(project) } + return if (!fetchMinimal) { + projects.map { project: Project -> projectMapper.projectToProjectDTO(project) } } else { - projects!!.map { project: Project? -> projectMapper.projectToMinimalProjectDetailsDTO(project) } + projects.map { project: Project -> projectMapper.projectToMinimalProjectDetailsDTO(project) } } } @@ -76,15 +76,17 @@ open class ProjectService( * @return the entity */ @Transactional(readOnly = true) - open fun findOne(id: Long): ProjectDTO { + open fun findOne(id: Long): ProjectDTO? { log.debug("Request to get Project : {}", id) - return projectRepository.findOneWithEagerRelationships(id) - .let { project: Project? -> projectMapper.projectToProjectDTO(project) } ?: throw NotFoundException( - "Project not found with id", - EntityName.PROJECT, - ErrorConstants.ERR_PROJECT_ID_NOT_FOUND, - Collections.singletonMap("id", id.toString()) - ) + val project = projectRepository.findOneWithEagerRelationships(id) + ?: throw NotFoundException( + "Project not found with id", + EntityName.PROJECT, + ErrorConstants.ERR_PROJECT_ID_NOT_FOUND, + Collections.singletonMap("id", id.toString()) + ) + + return projectMapper.projectToProjectDTO(project) } /** @@ -96,13 +98,14 @@ open class ProjectService( @Transactional(readOnly = true) open fun findOneByName(name: String): ProjectDTO { log.debug("Request to get Project by name: {}", name) - return projectRepository.findOneWithEagerRelationshipsByName(name) - .let { project: Project? -> projectMapper.projectToProjectDTO(project) } ?: throw NotFoundException( - "Project not found with projectName $name", - EntityName.PROJECT, - ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND, - Collections.singletonMap("projectName", name) - ) + val project = projectRepository.findOneWithEagerRelationshipsByName(name) + ?: throw NotFoundException( + "Project not found with projectName $name", + EntityName.PROJECT, + ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND, + Collections.singletonMap("projectName", name)) + + return projectMapper.projectToProjectDTO(project)!! } /** @@ -112,10 +115,10 @@ open class ProjectService( * @return the list of source-types assigned. */ @Transactional(readOnly = true) - open fun findSourceTypesByProjectId(id: Long?): List { + open fun findSourceTypesByProjectId(id: Long): List { log.debug("Request to get Project.sourceTypes of project: {}", id) val sourceTypes = projectRepository.findSourceTypesByProjectId(id) - return sourceTypeMapper.sourceTypesToSourceTypeDTOs(sourceTypes) + return sourceTypeMapper.sourceTypesToSourceTypeDTOs(sourceTypes).filterNotNull() } /** diff --git a/src/main/java/org/radarbase/management/service/ResourceUriService.java b/src/main/java/org/radarbase/management/service/ResourceUriService.java deleted file mode 100644 index 1c23760c8..000000000 --- a/src/main/java/org/radarbase/management/service/ResourceUriService.java +++ /dev/null @@ -1,150 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.domain.MetaToken; -import org.radarbase.management.domain.Source; -import org.radarbase.management.domain.User; -import org.radarbase.management.service.dto.ClientDetailsDTO; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.OrganizationDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.dto.SourceDataDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.web.rest.util.HeaderUtil; - -import java.net.URI; -import java.net.URISyntaxException; - -/** - * Consolidates the generation of location URI's for all of the resources. - */ -public final class ResourceUriService { - - private ResourceUriService() { - // utility class - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(OrganizationDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "organizations", resource.getName())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(SubjectDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "subjects", resource.getLogin())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(ClientDetailsDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "oauth-clients", resource.getClientId())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(MinimalSourceDetailsDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "sources", resource.getSourceName())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(RoleDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "roles", resource.getProjectName(), - resource.getAuthorityName())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(SourceTypeDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "source-types", resource.getProducer(), - resource.getModel(), resource.getCatalogVersion())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(SourceDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "sources", resource.getSourceName())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(Source resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "sources", resource.sourceName)); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(User resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "users", resource.getLogin())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(SourceDataDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "source-data", resource.getSourceDataName())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(ProjectDTO resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "projects", resource.getProjectName())); - } - - /** - * Get the API location for the given resource. - * @param resource the resource - * @return the API location - * @throws URISyntaxException See {@link URI#URI(String)} - */ - public static URI getUri(MetaToken resource) throws URISyntaxException { - return new URI(HeaderUtil.buildPath("api", "meta-token", resource.getTokenName())); - } -} diff --git a/src/main/java/org/radarbase/management/service/ResourceUriService.kt b/src/main/java/org/radarbase/management/service/ResourceUriService.kt new file mode 100644 index 000000000..c02792779 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/ResourceUriService.kt @@ -0,0 +1,164 @@ +package org.radarbase.management.service + +import org.radarbase.management.domain.MetaToken +import org.radarbase.management.domain.Source +import org.radarbase.management.domain.User +import org.radarbase.management.service.dto.ClientDetailsDTO +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.OrganizationDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.dto.SourceDTO +import org.radarbase.management.service.dto.SourceDataDTO +import org.radarbase.management.service.dto.SourceTypeDTO +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.web.rest.util.HeaderUtil +import java.net.URI +import java.net.URISyntaxException + +/** + * Consolidates the generation of location URI's for all of the resources. + */ +object ResourceUriService { + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: OrganizationDTO): URI { + return URI(HeaderUtil.buildPath("api", "organizations", resource.name)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: SubjectDTO): URI { + return URI(resource.login?.let { HeaderUtil.buildPath("api", "subjects", it) }) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: ClientDetailsDTO): URI { + return URI(HeaderUtil.buildPath("api", "oauth-clients", resource.clientId)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: MinimalSourceDetailsDTO): URI { + return URI(HeaderUtil.buildPath("api", "sources", resource.sourceName!!)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: RoleDTO?): URI { + return URI( + HeaderUtil.buildPath( + "api", "roles", resource?.projectName!!, + resource.authorityName!! + ) + ) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: SourceTypeDTO): URI { + return URI( + HeaderUtil.buildPath( + "api", "source-types", resource.producer, + resource.model, resource.model + ) + ) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: SourceDTO): URI { + return URI(HeaderUtil.buildPath("api", "sources", resource.sourceName)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: Source): URI { + return URI(HeaderUtil.buildPath("api", "sources", resource.sourceName!!)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: User): URI { + return URI(HeaderUtil.buildPath("api", "users", resource.login)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: SourceDataDTO): URI { + return URI(HeaderUtil.buildPath("api", "source-data", resource.sourceDataName!!)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: ProjectDTO): URI { + return URI(HeaderUtil.buildPath("api", "projects", resource.projectName!!)) + } + + /** + * Get the API location for the given resource. + * @param resource the resource + * @return the API location + * @throws URISyntaxException See [URI.URI] + */ + @Throws(URISyntaxException::class) + fun getUri(resource: MetaToken): URI { + return URI(HeaderUtil.buildPath("api", "meta-token", resource.tokenName!!)) + } +} diff --git a/src/main/java/org/radarbase/management/service/RevisionService.kt b/src/main/java/org/radarbase/management/service/RevisionService.kt index dcf742280..14e45c0e8 100644 --- a/src/main/java/org/radarbase/management/service/RevisionService.kt +++ b/src/main/java/org/radarbase/management/service/RevisionService.kt @@ -151,9 +151,9 @@ open class RevisionService(@param:Autowired private val revisionEntityRepository * @param pageable Page information * @return the page of revisions [RevisionInfoDTO] */ - fun getRevisions(pageable: Pageable?): Page { + fun getRevisions(pageable: Pageable): Page { return revisionEntityRepository.findAll(pageable) - .map { rev: CustomRevisionEntity -> RevisionInfoDTO.from(rev, getChangesForRevision(rev.id)) } + .map { rev -> RevisionInfoDTO.from(rev!!, getChangesForRevision(rev.id)) } } /** diff --git a/src/main/java/org/radarbase/management/service/RoleService.kt b/src/main/java/org/radarbase/management/service/RoleService.kt index c350c19ea..7bc960bd1 100644 --- a/src/main/java/org/radarbase/management/service/RoleService.kt +++ b/src/main/java/org/radarbase/management/service/RoleService.kt @@ -27,24 +27,16 @@ import java.util.function.Consumer */ @Service @Transactional -open class RoleService { - @Autowired - private val roleRepository: RoleRepository? = null +open class RoleService( + @Autowired private val roleRepository: RoleRepository, + @Autowired private val authorityRepository: AuthorityRepository, + @Autowired private val organizationRepository: OrganizationRepository, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val roleMapper: RoleMapper, + @Autowired private val userService: UserService +) { - @Autowired - private val authorityRepository: AuthorityRepository? = null - - @Autowired - private val organizationRepository: OrganizationRepository? = null - - @Autowired - private val projectRepository: ProjectRepository? = null - - @Autowired - private val roleMapper: RoleMapper? = null - - @Autowired - private val userService: UserService? = null + private val log = LoggerFactory.getLogger(RoleService::class.java) /** * Save a role. @@ -52,11 +44,11 @@ open class RoleService { * @param roleDto the entity to save * @return the persisted entity */ - fun save(roleDto: RoleDTO?): RoleDTO { + fun save(roleDto: RoleDTO): RoleDTO? { log.debug("Request to save Role : {}", roleDto) - var role = roleMapper!!.roleDTOToRole(roleDto) - role = roleRepository!!.save(role) - return roleMapper.roleToRoleDTO(role) + var role = roleMapper.roleDTOToRole(roleDto) + role = role?.let { roleRepository.save(it) } + return role?.let { roleMapper.roleToRoleDTO(it) } } /** @@ -70,24 +62,21 @@ open class RoleService { */ @Transactional(readOnly = true) open fun findAll(): List { - val optUser = userService!!.userWithAuthorities - if (optUser.isEmpty) { - // return an empty list if we do not have a current user (e.g. with client credentials + val optUser = userService.userWithAuthorities + ?: // return an empty list if we do not have a current user (e.g. with client credentials // oauth2 grant) return emptyList() - } - val currentUser = optUser.get() - val currentUserAuthorities: List? = currentUser.authorities?.map { auth -> auth?.name!! } + val currentUserAuthorities: List? = optUser.authorities?.map { auth -> auth?.name!! } return if (currentUserAuthorities?.contains(RoleAuthority.SYS_ADMIN.authority) == true) { log.debug("Request to get all Roles") - roleRepository!!.findAll().stream().map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }.toList() + roleRepository.findAll().filterNotNull().map { role: Role -> roleMapper.roleToRoleDTO(role) }.toList() } else (if (currentUserAuthorities?.contains(RoleAuthority.PROJECT_ADMIN.authority) == true) { log.debug("Request to get project admin's project Projects") - currentUser.roles?.filter { role: Role? -> - (RoleAuthority.PROJECT_ADMIN.authority == role?.authority?.name) - }?.map { r: Role? -> r?.project?.projectName }?.distinct() - ?.flatMap { name: String? -> roleRepository!!.findAllRolesByProjectName(name) } - ?.map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }?.toList() + optUser.roles?.asSequence()?.filter { role: Role? -> + (RoleAuthority.PROJECT_ADMIN.authority == role?.authority?.name) + }?.mapNotNull { r: Role -> r.project?.projectName }?.distinct() + ?.flatMap { name: String -> roleRepository.findAllRolesByProjectName(name) } + ?.map { role -> roleMapper.roleToRoleDTO(role) }?.toList() } else { emptyList() }) as List @@ -101,8 +90,8 @@ open class RoleService { @Transactional(readOnly = true) open fun findSuperAdminRoles(): List { log.debug("Request to get admin Roles") - return roleRepository?.findRolesByAuthorityName(RoleAuthority.SYS_ADMIN.authority) - ?.map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }?.toList()!! + return roleRepository.findRolesByAuthorityName(RoleAuthority.SYS_ADMIN.authority) + .map { role: Role -> roleMapper.roleToRoleDTO(role) }.toList() } /** @@ -114,8 +103,8 @@ open class RoleService { @Transactional(readOnly = true) open fun findOne(id: Long): RoleDTO { log.debug("Request to get Role : {}", id) - val role = roleRepository!!.findById(id).get() - return roleMapper!!.roleToRoleDTO(role) + val role = roleRepository.findById(id).get() + return roleMapper.roleToRoleDTO(role) } /** @@ -125,7 +114,7 @@ open class RoleService { */ fun delete(id: Long) { log.debug("Request to delete Role : {}", id) - roleRepository!!.deleteById(id) + roleRepository.deleteById(id) } /** @@ -134,10 +123,11 @@ open class RoleService { * @return role from database */ fun getGlobalRole(role: RoleAuthority): Role { - return roleRepository!!.findRolesByAuthorityName(role.authority).stream().findAny() - .orElseGet { createNewRole(role) { r: Role? -> } } + return roleRepository.findRolesByAuthorityName(role.authority).firstOrNull() + ?: createNewRole(role) { _: Role? -> } } + /** * Get or create given organization role. * @param role to get or create @@ -145,20 +135,19 @@ open class RoleService { * @return role from database */ fun getOrganizationRole(role: RoleAuthority, organizationId: Long): Role { - return roleRepository!!.findOneByOrganizationIdAndAuthorityName( + return roleRepository.findOneByOrganizationIdAndAuthorityName( organizationId, role.authority - ).orElseGet { - createNewRole(role) { r: Role -> - r.organization = organizationRepository!!.findById(organizationId).orElseThrow { - NotFoundException( - "Cannot find organization for authority", - EntityName.USER, - ErrorConstants.ERR_INVALID_AUTHORITY, - Map.of( - "authorityName", role.authority, "projectId", organizationId.toString() - ) - ) - } + ) + ?: createNewRole(role) { r: Role -> + r.organization = organizationRepository.findById(organizationId).orElseThrow { + NotFoundException( + "Cannot find organization for authority", + EntityName.USER, + ErrorConstants.ERR_INVALID_AUTHORITY, + Map.of( + "authorityName", role.authority, "projectId", organizationId.toString() + ) + ) } } } @@ -170,19 +159,15 @@ open class RoleService { * @return role from database */ fun getProjectRole(role: RoleAuthority, projectId: Long): Role { - return roleRepository!!.findOneByProjectIdAndAuthorityName( + return roleRepository.findOneByProjectIdAndAuthorityName( projectId, role.authority - ).orElseGet { - createNewRole(role) { r: Role -> - r.project = projectRepository!!.findByIdWithOrganization(projectId) ?: throw NotFoundException( - "Cannot find project for authority", - EntityName.USER, - ErrorConstants.ERR_INVALID_AUTHORITY, - Map.of( - "authorityName", role.authority, "projectId", projectId.toString() - ) + ) + ?: createNewRole(role) { r: Role -> + r.project = projectRepository.findByIdWithOrganization(projectId) ?: throw NotFoundException( + "Cannot find project for authority", EntityName.USER, ErrorConstants.ERR_INVALID_AUTHORITY, Map.of( + "authorityName", role.authority, "projectId", projectId.toString() ) - } + ) } } @@ -193,20 +178,20 @@ open class RoleService { */ fun getRolesByProject(projectName: String): List { log.debug("Request to get all Roles for projectName $projectName") - return roleRepository!!.findAllRolesByProjectName(projectName).stream() - .map { role: Role? -> roleMapper!!.roleToRoleDTO(role) }.toList() + return roleRepository.findAllRolesByProjectName(projectName) + .map { role: Role -> roleMapper.roleToRoleDTO(role) }.toList() } private fun getAuthority(role: RoleAuthority): Authority { - return authorityRepository!!.findByAuthorityName(role.authority) - .orElseGet { authorityRepository.saveAndFlush(Authority(role)) } + return authorityRepository.findByAuthorityName(role.authority) + ?: authorityRepository.saveAndFlush(Authority(role)) } private fun createNewRole(role: RoleAuthority, apply: Consumer): Role { val newRole = Role() newRole.authority = getAuthority(role) apply.accept(newRole) - return roleRepository!!.save(newRole) + return roleRepository.save(newRole) } /** @@ -217,10 +202,10 @@ open class RoleService { */ fun findOneByProjectNameAndAuthorityName( projectName: String?, authorityName: String? - ): Optional { + ): RoleDTO? { log.debug("Request to get role of project {} and authority {}", projectName, authorityName) - return roleRepository!!.findOneByProjectNameAndAuthorityName(projectName, authorityName) - .map { role: Role? -> roleMapper!!.roleToRoleDTO(role) } + return roleRepository.findOneByProjectNameAndAuthorityName(projectName, authorityName) + .let { role -> role?.let { roleMapper.roleToRoleDTO(it) } } } companion object { @@ -237,7 +222,7 @@ open class RoleService { fun getRoleAuthority(roleDto: RoleDTO): RoleAuthority { val authority: RoleAuthority authority = try { - valueOfAuthority(roleDto.authorityName) + valueOfAuthority(roleDto.authorityName!!) } catch (ex: IllegalArgumentException) { throw BadRequestException( "Authority not found with " + "authorityName", diff --git a/src/main/java/org/radarbase/management/service/SiteSettingsService.java b/src/main/java/org/radarbase/management/service/SiteSettingsService.java deleted file mode 100644 index 57098f51e..000000000 --- a/src/main/java/org/radarbase/management/service/SiteSettingsService.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.config.ManagementPortalProperties.SiteSettings; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.service.dto.SiteSettingsDto; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -/** - * Service class for managing SiteSettings. - */ -@Service -@Transactional -public class SiteSettingsService { - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - /** - * Convert a {@link SiteSettings} to a {@link SiteSettingsDto} object. - * @param siteSettings The object to convert - * @return the newly created DTO object - */ - public SiteSettingsDto createSiteSettingsDto(SiteSettings siteSettings) { - - SiteSettingsDto siteSettingsDto = new SiteSettingsDto(); - - siteSettingsDto.setHiddenSubjectFields(siteSettings.getHiddenSubjectFields()); - return siteSettingsDto; - } - - // NAMING! - public SiteSettingsDto getSiteSettingsDto() { - return createSiteSettingsDto(managementPortalProperties.getSiteSettings()); - } -} diff --git a/src/main/java/org/radarbase/management/service/SiteSettingsService.kt b/src/main/java/org/radarbase/management/service/SiteSettingsService.kt new file mode 100644 index 000000000..9226f49a1 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/SiteSettingsService.kt @@ -0,0 +1,33 @@ +package org.radarbase.management.service + +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.config.ManagementPortalProperties.SiteSettings +import org.radarbase.management.service.dto.SiteSettingsDto +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +/** + * Service class for managing SiteSettings. + */ +@Service +@Transactional +class SiteSettingsService { + @Autowired + private val managementPortalProperties: ManagementPortalProperties? = null + + /** + * Convert a [SiteSettings] to a [SiteSettingsDto] object. + * @param siteSettings The object to convert + * @return the newly created DTO object + */ + fun createSiteSettingsDto(siteSettings: SiteSettings): SiteSettingsDto { + val siteSettingsDto = SiteSettingsDto() + siteSettingsDto.hiddenSubjectFields = siteSettings.hiddenSubjectFields + return siteSettingsDto + } + + val siteSettingsDto: SiteSettingsDto + // NAMING! + get() = createSiteSettingsDto(managementPortalProperties!!.siteSettings) +} diff --git a/src/main/java/org/radarbase/management/service/SourceDataService.java b/src/main/java/org/radarbase/management/service/SourceDataService.java deleted file mode 100644 index d838e170a..000000000 --- a/src/main/java/org/radarbase/management/service/SourceDataService.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.repository.SourceDataRepository; -import org.radarbase.management.service.dto.SourceDataDTO; -import org.radarbase.management.service.mapper.SourceDataMapper; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.Optional; - -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE_DATA; - -/** - * Service Implementation for managing SourceData. - */ -@Service -@Transactional -public class SourceDataService { - - private static final Logger log = LoggerFactory.getLogger(SourceDataService.class); - - private final SourceDataRepository sourceDataRepository; - - private final SourceDataMapper sourceDataMapper; - - public SourceDataService(SourceDataRepository sourceDataRepository, - SourceDataMapper sourceDataMapper) { - this.sourceDataRepository = sourceDataRepository; - this.sourceDataMapper = sourceDataMapper; - } - - /** - * Save a sourceData. - * - * @param sourceDataDto the entity to save - * @return the persisted entity - */ - public SourceDataDTO save(SourceDataDTO sourceDataDto) { - log.debug("Request to save SourceData : {}", sourceDataDto); - if (sourceDataDto.getSourceDataType() == null) { - throw new BadRequestException(ErrorConstants.ERR_VALIDATION, SOURCE_DATA, - "Source Data must contain a type or a topic."); - } - SourceData sourceData = sourceDataMapper.sourceDataDTOToSourceData(sourceDataDto); - sourceData = sourceDataRepository.save(sourceData); - return sourceDataMapper.sourceDataToSourceDataDTO(sourceData); - } - - /** - * Get all the sourceData. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public List findAll() { - log.debug("Request to get all SourceData"); - - return sourceDataRepository.findAll().stream() - .map(sourceDataMapper::sourceDataToSourceDataDTO) - .toList(); - } - - /** - * Get all the sourceData with pagination. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public Page findAll(Pageable pageable) { - log.debug("Request to get all SourceData"); - return sourceDataRepository.findAll(pageable) - .map(sourceDataMapper::sourceDataToSourceDataDTO); - } - - /** - * Get one sourceData by id. - * - * @param id the id of the entity - * @return the entity - */ - @Transactional(readOnly = true) - public SourceDataDTO findOne(Long id) { - log.debug("Request to get SourceData : {}", id); - SourceData sourceData = sourceDataRepository.findById(id).get(); - return sourceDataMapper.sourceDataToSourceDataDTO(sourceData); - } - - /** - * Get one sourceData by name. - * - * @param sourceDataName the sourceDataType of the entity - * @return the entity - */ - @Transactional(readOnly = true) - public Optional findOneBySourceDataName(String sourceDataName) { - log.debug("Request to get SourceData : {}", sourceDataName); - return sourceDataRepository.findOneBySourceDataName(sourceDataName) - .map(sourceDataMapper::sourceDataToSourceDataDTO); - } - - /** - * Delete the sourceData by id. - * - * @param id the id of the entity - */ - @Transactional - public void delete(Long id) { - log.debug("Request to delete SourceData : {}", id); - sourceDataRepository.deleteById(id); - } -} diff --git a/src/main/java/org/radarbase/management/service/SourceDataService.kt b/src/main/java/org/radarbase/management/service/SourceDataService.kt new file mode 100644 index 000000000..03ab7afd0 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/SourceDataService.kt @@ -0,0 +1,109 @@ +package org.radarbase.management.service + +import org.radarbase.management.domain.SourceData +import org.radarbase.management.repository.SourceDataRepository +import org.radarbase.management.service.dto.SourceDataDTO +import org.radarbase.management.service.mapper.SourceDataMapper +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.slf4j.LoggerFactory +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +/** + * Service Implementation for managing SourceData. + */ +@Service +@Transactional +open class SourceDataService( + private val sourceDataRepository: SourceDataRepository, + private val sourceDataMapper: SourceDataMapper +) { + /** + * Save a sourceData. + * + * @param sourceDataDto the entity to save + * @return the persisted entity + */ + fun save(sourceDataDto: SourceDataDTO?): SourceDataDTO? { + log.debug("Request to save SourceData : {}", sourceDataDto) + if (sourceDataDto!!.sourceDataType == null) { + throw BadRequestException( + ErrorConstants.ERR_VALIDATION, EntityName.Companion.SOURCE_DATA, + "Source Data must contain a type or a topic." + ) + } + var sourceData = sourceDataMapper.sourceDataDTOToSourceData(sourceDataDto) + sourceData = sourceDataRepository.save(sourceData) + return sourceDataMapper.sourceDataToSourceDataDTO(sourceData) + } + + /** + * Get all the sourceData. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(): List { + log.debug("Request to get all SourceData") + return sourceDataRepository.findAll().stream() + .map { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } + .toList() + } + + /** + * Get all the sourceData with pagination. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(pageable: Pageable?): Page { + log.debug("Request to get all SourceData") + return sourceDataRepository.findAll(pageable) + .map { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } + } + + /** + * Get one sourceData by id. + * + * @param id the id of the entity + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOne(id: Long): SourceDataDTO? { + log.debug("Request to get SourceData : {}", id) + val sourceData = sourceDataRepository.findById(id).get() + return sourceDataMapper.sourceDataToSourceDataDTO(sourceData) + } + + /** + * Get one sourceData by name. + * + * @param sourceDataName the sourceDataType of the entity + * @return the entity + */ + @Transactional(readOnly = true) + open fun findOneBySourceDataName(sourceDataName: String?): SourceDataDTO? { + log.debug("Request to get SourceData : {}", sourceDataName) + return sourceDataRepository.findOneBySourceDataName(sourceDataName) + .let { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } + } + + /** + * Delete the sourceData by id. + * + * @param id the id of the entity + */ + @Transactional + open fun delete(id: Long?) { + log.debug("Request to delete SourceData : {}", id) + sourceDataRepository.deleteById(id) + } + + companion object { + private val log = LoggerFactory.getLogger(SourceDataService::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/service/SourceService.kt b/src/main/java/org/radarbase/management/service/SourceService.kt index 2d6465f1c..ccf937a07 100644 --- a/src/main/java/org/radarbase/management/service/SourceService.kt +++ b/src/main/java/org/radarbase/management/service/SourceService.kt @@ -17,7 +17,6 @@ import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable -import org.springframework.data.history.Revision import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.util.* @@ -41,7 +40,7 @@ open class SourceService( * @param sourceDto the entity to save * @return the persisted entity */ - fun save(sourceDto: SourceDTO?): SourceDTO { + fun save(sourceDto: SourceDTO): SourceDTO { log.debug("Request to save Source : {}", sourceDto) var source = sourceMapper.sourceDTOToSource(sourceDto) source = sourceRepository.save(source) @@ -54,11 +53,11 @@ open class SourceService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(): List? { + open fun findAll(): List { return sourceRepository .findAll() - .stream() - .map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } + .filterNotNull() + .map { source: Source -> sourceMapper.sourceToSourceDTO(source) } .toList() } @@ -76,7 +75,7 @@ open class SourceService( it.let { it1 -> sourceRepository .findAll(it1) - ?.map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } + ?.map { source -> source?.let { it2 -> sourceMapper.sourceToSourceDTO(it2) } } } } } @@ -88,10 +87,10 @@ open class SourceService( * @return the entity */ @Transactional(readOnly = true) - open fun findOneByName(sourceName: String?): Optional { + open fun findOneByName(sourceName: String): SourceDTO? { log.debug("Request to get Source : {}", sourceName) return sourceRepository.findOneBySourceName(sourceName) - .map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } + .let { source: Source? -> source?.let { sourceMapper.sourceToSourceDTO(it) } } } /** @@ -104,7 +103,7 @@ open class SourceService( open fun findOneById(id: Long): Optional { log.debug("Request to get Source by id: {}", id) return Optional.ofNullable(sourceRepository.findById(id).orElse(null)) - .map { source: Source? -> sourceMapper.sourceToSourceDTO(source) } + .map { source: Source? -> source?.let { sourceMapper.sourceToSourceDTO(it) } } } /** @@ -117,7 +116,7 @@ open class SourceService( log.info("Request to delete Source : {}", id) val sourceHistory = sourceRepository.findRevisions(id) val sources = sourceHistory.content - .map { obj: Revision -> obj.entity } + .mapNotNull { obj -> obj.entity } .filter{ it.isAssigned ?: false } .toList() @@ -139,9 +138,9 @@ open class SourceService( * * @return list of sources */ - fun findAllByProjectId(projectId: Long?, pageable: Pageable?): Page { + fun findAllByProjectId(projectId: Long, pageable: Pageable): Page { return sourceRepository.findAllSourcesByProjectId(pageable, projectId) - .map { source: Source? -> sourceMapper.sourceToSourceWithoutProjectDTO(source) } + .map { source -> sourceMapper.sourceToSourceWithoutProjectDTO(source) } } /** @@ -150,11 +149,11 @@ open class SourceService( * @return list of sources */ fun findAllMinimalSourceDetailsByProject( - projectId: Long?, - pageable: Pageable? + projectId: Long, + pageable: Pageable ): Page { return sourceRepository.findAllSourcesByProjectId(pageable, projectId) - .map { source: Source? -> sourceMapper.sourceToMinimalSourceDetailsDTO(source) } + .map { source: Source -> sourceMapper.sourceToMinimalSourceDetailsDTO(source) } } /** @@ -212,10 +211,8 @@ open class SourceService( @Transactional @Throws(NotAuthorizedException::class) open fun updateSource(sourceDto: SourceDTO): SourceDTO? { - val existingSourceOpt = sourceRepository.findById(sourceDto.id) - if (existingSourceOpt.isEmpty) { - return null - } + val existingSourceOpt = sourceDto.id?.let { sourceRepository.findById(it) } ?: return null + val existingSource = existingSourceOpt.get() authService.checkPermission(Permission.SOURCE_UPDATE, { e: EntityDetails -> e.source = existingSource.sourceName @@ -230,7 +227,7 @@ open class SourceService( }) // if the source is being transferred to another project. - if (existingSource.project!!.id != sourceDto.project.id) { + if (existingSource.project?.id != sourceDto.project?.id) { if (existingSource.isAssigned!!) { throw InvalidRequestException( "Cannot transfer an assigned source", EntityName.SOURCE, @@ -242,17 +239,17 @@ open class SourceService( // to be transferred. val sourceType = projectRepository .findSourceTypeByProjectIdAndSourceTypeId( - sourceDto.project.id, - existingSource.sourceType!!.id + sourceDto.project?.id, + existingSource.sourceType?.id ) - if (sourceType!!.isEmpty) { - throw InvalidRequestException( + ?: throw InvalidRequestException( "Cannot transfer a source to a project which doesn't have compatible " + "source-type", IdentifierGenerator.ENTITY_NAME, "error.invalidTransfer" ) - } + + //TODO all the nullchecks are the result of jvmfiel;d annotations not allowing lateinits // set old source-type, ensures compatibility - sourceDto.sourceType = sourceTypeMapper.sourceTypeToSourceTypeDTO(existingSource.sourceType) + sourceDto.sourceType = existingSource.sourceType?.let { sourceTypeMapper.sourceTypeToSourceTypeDTO(it) }!! } return save(sourceDto) } diff --git a/src/main/java/org/radarbase/management/service/SourceTypeService.java b/src/main/java/org/radarbase/management/service/SourceTypeService.java deleted file mode 100644 index 7cdc9d44a..000000000 --- a/src/main/java/org/radarbase/management/service/SourceTypeService.java +++ /dev/null @@ -1,242 +0,0 @@ -package org.radarbase.management.service; - -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.repository.SourceDataRepository; -import org.radarbase.management.repository.SourceTypeRepository; -import org.radarbase.management.service.catalog.CatalogSourceData; -import org.radarbase.management.service.catalog.CatalogSourceType; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.service.mapper.CatalogSourceDataMapper; -import org.radarbase.management.service.mapper.CatalogSourceTypeMapper; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.service.mapper.SourceTypeMapper; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.validation.constraints.NotNull; -import java.util.Collections; -import java.util.List; - -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE_TYPE; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SOURCE_TYPE_NOT_FOUND; - -/** - * Service Implementation for managing SourceType. - */ -@Service -@Transactional -public class SourceTypeService { - - private static final Logger log = LoggerFactory.getLogger(SourceTypeService.class); - - @Autowired - private SourceTypeRepository sourceTypeRepository; - - @Autowired - private SourceTypeMapper sourceTypeMapper; - - @Autowired - private SourceDataRepository sourceDataRepository; - - @Autowired - private CatalogSourceTypeMapper catalogSourceTypeMapper; - - @Autowired - private CatalogSourceDataMapper catalogSourceDataMapper; - - @Autowired - private ProjectMapper projectMapper; - - /** - * Save a sourceType. - * - * @param sourceTypeDto the entity to save - * @return the persisted entity - */ - public SourceTypeDTO save(SourceTypeDTO sourceTypeDto) { - log.debug("Request to save SourceType : {}", sourceTypeDto); - SourceType sourceType = sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDto); - // populate the SourceType of our SourceData's - for (SourceData data : sourceType.sourceData) { - data.sourceType = sourceType; - } - sourceType = sourceTypeRepository.save(sourceType); - sourceDataRepository.saveAll(sourceType.sourceData); - return sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType); - } - - /** - * Get all the sourceTypes. - * - * @return the list of entities - */ - @Transactional(readOnly = true) - public List findAll() { - log.debug("Request to get all SourceTypes"); - List result = sourceTypeRepository.findAllWithEagerRelationships(); - return result.stream() - .map(sourceTypeMapper::sourceTypeToSourceTypeDTO) - .toList(); - - } - - /** - * Get all sourceTypes with pagination. - * - * @param pageable params - * @return the list of entities - */ - public Page findAll(Pageable pageable) { - log.debug("Request to get SourceTypes"); - return sourceTypeRepository.findAll(pageable) - .map(sourceTypeMapper::sourceTypeToSourceTypeDTO); - } - - /** - * Delete the sourceType by id. - * - * @param id the id of the entity - */ - public void delete(Long id) { - log.debug("Request to delete SourceType : {}", id); - sourceTypeRepository.deleteById(id); - } - - /** - * Fetch SourceType by producer and model. - */ - public SourceTypeDTO findByProducerAndModelAndVersion(@NotNull String producer, - @NotNull String model, @NotNull String version) { - log.debug("Request to get SourceType by producer and model and version: {}, {}, {}", - producer, model, version); - return sourceTypeRepository - .findOneWithEagerRelationshipsByProducerAndModelAndVersion(producer, model, version) - .map(sourceTypeMapper::sourceTypeToSourceTypeDTO).orElseThrow( - () -> new NotFoundException( - "SourceType not found with producer, model, " + "version ", SOURCE_TYPE, - ERR_SOURCE_TYPE_NOT_FOUND, Collections.singletonMap("producer-model-version", - producer + "-" + model + "-" + version))); - } - - /** - * Fetch SourceType by producer. - */ - public List findByProducer(String producer) { - log.debug("Request to get SourceType by producer: {}", producer); - List sourceTypes = sourceTypeRepository - .findWithEagerRelationshipsByProducer(producer); - return sourceTypeMapper.sourceTypesToSourceTypeDTOs( - sourceTypes); - } - - /** - * Fetch SourceType by producer and model. - */ - public List findByProducerAndModel(String producer, String model) { - log.debug("Request to get SourceType by producer and model: {}, {}", producer, model); - List sourceTypes = sourceTypeRepository - .findWithEagerRelationshipsByProducerAndModel(producer, model); - return sourceTypeMapper.sourceTypesToSourceTypeDTOs( - sourceTypes); - } - - /** - * Find projects associated to a particular SourceType. - * - * @param producer the SourceType producer - * @param model the SourceType model - * @param version the SourceType catalogVersion - * @return the list of projects associated with this SourceType - */ - public List findProjectsBySourceType(String producer, String model, String - version) { - return projectMapper.projectsToProjectDTOs(sourceTypeRepository - .findProjectsBySourceType(producer, model, version)); - } - - /** - * Converts given {@link CatalogSourceType} to {@link SourceType} and saves it to the databse - * after validations. - * @param catalogSourceTypes list of source-type from catalogue-server. - */ - @Transactional - public void saveSourceTypesFromCatalogServer(List catalogSourceTypes) { - for (CatalogSourceType catalogSourceType : catalogSourceTypes) { - SourceType sourceType = catalogSourceTypeMapper - .catalogSourceTypeToSourceType(catalogSourceType); - - if (!isSourceTypeValid(sourceType)) { - continue; - } - - // check whether a source-type is already available with given config - if (sourceTypeRepository.hasOneByProducerAndModelAndVersion( - sourceType.producer, sourceType.model, - sourceType.catalogVersion)) { - // skip for existing source-types - log.info("Source-type {} is already available ", sourceType.producer - + "_" + sourceType.model - + "_" + sourceType.catalogVersion); - } else { - try { - // create new source-type - sourceType = sourceTypeRepository.save(sourceType); - - // create source-data for the new source-type - for (CatalogSourceData catalogSourceData : catalogSourceType.getData()) { - saveSourceData(sourceType, catalogSourceData); - } - } catch (RuntimeException ex) { - log.error("Failed to import source type {}", sourceType, ex); - } - } - } - log.info("Completed source-type import from catalog-server"); - } - - private void saveSourceData(SourceType sourceType, CatalogSourceData catalogSourceData) { - try { - SourceData sourceData = catalogSourceDataMapper - .catalogSourceDataToSourceData(catalogSourceData); - // sourceDataName should be unique - // generated by combining sourceDataType and source-type configs - sourceData.sourceDataName(sourceType.producer - + "_" + sourceType.model - + "_" + sourceType.catalogVersion - + "_" + sourceData.sourceDataType); - sourceData.sourceType(sourceType); - sourceDataRepository.save(sourceData); - } catch (RuntimeException ex) { - log.error("Failed to import source data {}", catalogSourceData, ex); - } - } - - private static boolean isSourceTypeValid(SourceType sourceType) { - if (sourceType.producer == null) { - log.warn("Catalog source-type {} does not have a vendor. " - + "Skipping importing this type", sourceType.name); - return false; - } - - if (sourceType.model == null) { - log.warn("Catalog source-type {} does not have a model. " - + "Skipping importing this type", sourceType.name); - return false; - } - - if (sourceType.catalogVersion == null) { - log.warn("Catalog source-type {} does not have a version. " - + "Skipping importing this type", sourceType.name); - return false; - } - return true; - } -} diff --git a/src/main/java/org/radarbase/management/service/SourceTypeService.kt b/src/main/java/org/radarbase/management/service/SourceTypeService.kt new file mode 100644 index 000000000..f0025ff43 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/SourceTypeService.kt @@ -0,0 +1,245 @@ +package org.radarbase.management.service + +import org.radarbase.management.domain.SourceType +import org.radarbase.management.repository.SourceDataRepository +import org.radarbase.management.repository.SourceTypeRepository +import org.radarbase.management.service.catalog.CatalogSourceData +import org.radarbase.management.service.catalog.CatalogSourceType +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SourceTypeDTO +import org.radarbase.management.service.mapper.CatalogSourceDataMapper +import org.radarbase.management.service.mapper.CatalogSourceTypeMapper +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.service.mapper.SourceTypeMapper +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import java.util.* +import javax.validation.constraints.NotNull + +/** + * Service Implementation for managing SourceType. + */ +@Service +@Transactional +open class SourceTypeService( + @Autowired private val sourceTypeRepository: SourceTypeRepository, + @Autowired private val sourceTypeMapper: SourceTypeMapper, + @Autowired private val sourceDataRepository: SourceDataRepository, + @Autowired private val catalogSourceTypeMapper: CatalogSourceTypeMapper, + @Autowired private val catalogSourceDataMapper: CatalogSourceDataMapper, + @Autowired private val projectMapper: ProjectMapper +) { + + /** + * Save a sourceType. + * + * @param sourceTypeDto the entity to save + * @return the persisted entity + */ + fun save(sourceTypeDto: SourceTypeDTO): SourceTypeDTO { + log.debug("Request to save SourceType : {}", sourceTypeDto) + var sourceType = sourceTypeMapper.sourceTypeDTOToSourceType(sourceTypeDto) + // populate the SourceType of our SourceData's + for (data in sourceType.sourceData) { + data.sourceType = sourceType + } + sourceType = sourceTypeRepository.save(sourceType) + sourceDataRepository.saveAll(sourceType.sourceData) + return sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) + } + + /** + * Get all the sourceTypes. + * + * @return the list of entities + */ + @Transactional(readOnly = true) + open fun findAll(): List { + log.debug("Request to get all SourceTypes") + val result = sourceTypeRepository.findAllWithEagerRelationships() + return result + .map { sourceType: SourceType -> sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) } + .toList() + } + + /** + * Get all sourceTypes with pagination. + * + * @param pageable params + * @return the list of entities + */ + fun findAll(pageable: Pageable): Page { + log.debug("Request to get SourceTypes") + return sourceTypeRepository.findAll(pageable) + .map { sourceType: SourceType -> sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) } + } + + /** + * Delete the sourceType by id. + * + * @param id the id of the entity + */ + fun delete(id: Long) { + log.debug("Request to delete SourceType : {}", id) + sourceTypeRepository.deleteById(id) + } + + /** + * Fetch SourceType by producer and model. + */ + fun findByProducerAndModelAndVersion( + producer: @NotNull String, + model: @NotNull String, version: @NotNull String + ): SourceTypeDTO { + log.debug( + "Request to get SourceType by producer and model and version: {}, {}, {}", + producer, model, version + ) + return sourceTypeRepository + .findOneWithEagerRelationshipsByProducerAndModelAndVersion(producer, model, version) + .let { sourceType: SourceType? -> sourceType?.let { sourceTypeMapper.sourceTypeToSourceTypeDTO(it) } } + ?: throw NotFoundException( + "SourceType not found with producer, model, " + "version ", EntityName.Companion.SOURCE_TYPE, + ErrorConstants.ERR_SOURCE_TYPE_NOT_FOUND, Collections.singletonMap( + "producer-model-version", + "$producer-$model-$version" + ) + ) + } + + /** + * Fetch SourceType by producer. + */ + fun findByProducer(producer: String): List { + log.debug("Request to get SourceType by producer: {}", producer) + val sourceTypes = sourceTypeRepository + .findWithEagerRelationshipsByProducer(producer) + return sourceTypeMapper.sourceTypesToSourceTypeDTOs( + sourceTypes + ) + } + + /** + * Fetch SourceType by producer and model. + */ + fun findByProducerAndModel(producer: String, model: String): List { + log.debug("Request to get SourceType by producer and model: {}, {}", producer, model) + val sourceTypes = sourceTypeRepository + .findWithEagerRelationshipsByProducerAndModel(producer, model) + return sourceTypeMapper.sourceTypesToSourceTypeDTOs( + sourceTypes + ) + } + + /** + * Find projects associated to a particular SourceType. + * + * @param producer the SourceType producer + * @param model the SourceType model + * @param version the SourceType catalogVersion + * @return the list of projects associated with this SourceType + */ + fun findProjectsBySourceType(producer: String, model: String, version: String): List { + return projectMapper.projectsToProjectDTOs( + sourceTypeRepository + .findProjectsBySourceType(producer, model, version) + ) + } + + /** + * Converts given [CatalogSourceType] to [SourceType] and saves it to the databse + * after validations. + * @param catalogSourceTypes list of source-type from catalogue-server. + */ + @Transactional + open fun saveSourceTypesFromCatalogServer(catalogSourceTypes: List) { + for (catalogSourceType in catalogSourceTypes) { + var sourceType = catalogSourceTypeMapper + .catalogSourceTypeToSourceType(catalogSourceType) + if (!isSourceTypeValid(sourceType)) { + continue + } + + // check whether a source-type is already available with given config + if (sourceTypeRepository.hasOneByProducerAndModelAndVersion( + sourceType!!.producer!!, sourceType.model!!, + sourceType.catalogVersion!! + ) + ) { + // skip for existing source-types + log.info( + "Source-type {} is already available ", sourceType.producer + + "_" + sourceType.model + + "_" + sourceType.catalogVersion + ) + } else { + try { + // create new source-type + sourceType = sourceTypeRepository.save(sourceType) + + // create source-data for the new source-type + for (catalogSourceData in catalogSourceType.data!!) { + saveSourceData(sourceType, catalogSourceData) + } + } catch (ex: RuntimeException) { + log.error("Failed to import source type {}", sourceType, ex) + } + } + } + log.info("Completed source-type import from catalog-server") + } + + private fun saveSourceData(sourceType: SourceType?, catalogSourceData: CatalogSourceData?) { + try { + val sourceData = catalogSourceDataMapper + .catalogSourceDataToSourceData(catalogSourceData) + // sourceDataName should be unique + // generated by combining sourceDataType and source-type configs + sourceData!!.sourceDataName( + sourceType!!.producer + + "_" + sourceType.model + + "_" + sourceType.catalogVersion + + "_" + sourceData.sourceDataType + ) + sourceData.sourceType(sourceType) + sourceDataRepository.save(sourceData) + } catch (ex: RuntimeException) { + log.error("Failed to import source data {}", catalogSourceData, ex) + } + } + + companion object { + private val log = LoggerFactory.getLogger(SourceTypeService::class.java) + private fun isSourceTypeValid(sourceType: SourceType?): Boolean { + if (sourceType!!.producer == null) { + log.warn( + "Catalog source-type {} does not have a vendor. " + + "Skipping importing this type", sourceType.name + ) + return false + } + if (sourceType.model == null) { + log.warn( + "Catalog source-type {} does not have a model. " + + "Skipping importing this type", sourceType.name + ) + return false + } + if (sourceType.catalogVersion == null) { + log.warn( + "Catalog source-type {} does not have a version. " + + "Skipping importing this type", sourceType.name + ) + return false + } + return true + } + } +} diff --git a/src/main/java/org/radarbase/management/service/SubjectService.kt b/src/main/java/org/radarbase/management/service/SubjectService.kt index 56571a6b8..84dcd8ec1 100644 --- a/src/main/java/org/radarbase/management/service/SubjectService.kt +++ b/src/main/java/org/radarbase/management/service/SubjectService.kt @@ -77,8 +77,7 @@ open class SubjectService( */ @Transactional open fun createSubject(subjectDto: SubjectDTO): SubjectDTO? { - val subject = subjectMapper.subjectDTOToSubject(subjectDto) - if (subject == null) throw NullPointerException() + val subject = subjectMapper.subjectDTOToSubject(subjectDto) ?: throw NullPointerException() //assign roles val user = subject.user val project = projectMapper.projectDTOToProject(subjectDto.project) @@ -126,17 +125,20 @@ open class SubjectService( * @throws java.util.NoSuchElementException if the authority name is not in the database */ private fun getProjectParticipantRole(project: Project?, authority: RoleAuthority): Role { - return roleRepository.findOneByProjectIdAndAuthorityName( - project!!.id, authority.authority - ).orElseGet { - val subjectRole = Role() - val auth = authorityRepository.findByAuthorityName( - authority.authority - ).orElseGet { authorityRepository.save(Authority(authority)) } - subjectRole.authority = auth - subjectRole.project = project - roleRepository.save(subjectRole) - } + val ans: Role? = roleRepository.findOneByProjectIdAndAuthorityName( + project?.id, authority.authority + ) + return if (ans == null) { + val subjectRole = Role() + val auth: Authority = authorityRepository.findByAuthorityName( + authority.authority + ) ?: authorityRepository.save(Authority(authority)) + + subjectRole.authority = auth + subjectRole.project = project + roleRepository.save(subjectRole) + subjectRole + } else ans } /** @@ -169,18 +171,18 @@ open class SubjectService( } private fun updateParticipantRoles(subject: Subject, subjectDto: SubjectDTO): MutableSet? { - if (subjectDto.project == null || subjectDto.project.projectName == null) { + if (subjectDto.project == null || subjectDto.project!!.projectName == null) { return subject.user!!.roles } val existingRoles = subject.user!!.roles?.map { - // make participant inactive in projects that do not match the new project - if (it.authority!!.name == RoleAuthority.PARTICIPANT.authority && it.project!!.projectName != subjectDto.project.projectName) { - return@map getProjectParticipantRole(it.project, RoleAuthority.INACTIVE_PARTICIPANT) - } else { - // do not modify other roles. - return@map it - } - }?.toMutableSet() + // make participant inactive in projects that do not match the new project + if (it.authority!!.name == RoleAuthority.PARTICIPANT.authority && it.project!!.projectName != subjectDto.project!!.projectName) { + return@map getProjectParticipantRole(it.project, RoleAuthority.INACTIVE_PARTICIPANT) + } else { + // do not modify other roles. + return@map it + } + }?.toMutableSet() // Ensure that given project is present val newProjectRole = @@ -215,12 +217,12 @@ open class SubjectService( private fun ensureSubject(subjectDto: SubjectDTO): Subject { return subjectRepository.findById(subjectDto.id).orElseThrow { - NotFoundException( - "Subject with ID " + subjectDto.id + " not found.", - EntityName.SUBJECT, - ErrorConstants.ERR_SUBJECT_NOT_FOUND - ) - } + NotFoundException( + "Subject with ID " + subjectDto.id + " not found.", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND + ) + } } /** @@ -255,8 +257,8 @@ open class SubjectService( assignedSource = updateSourceAssignedSubject(subject, sourceRegistrationDto) } else if (sourceType.canRegisterDynamically!!) { val sources = subjectRepository.findSubjectSourcesBySourceType( - subject.user!!.login, sourceType.producer, sourceType.model, sourceType.catalogVersion - ) + subject.user!!.login, sourceType.producer, sourceType.model, sourceType.catalogVersion + ) // create a source and register metadata // we allow only one source of a source-type per subject if (sources.isNullOrEmpty()) { @@ -268,7 +270,7 @@ open class SubjectService( source.sourceName = sourceRegistrationDto.sourceName + "_" + source.sourceName } // make sure there is no source available on the same name. - if (sourceRepository.findOneBySourceName(source.sourceName).isPresent) { + if (sourceRepository.findOneBySourceName(source.sourceName!!) != null) { throw ConflictException( "SourceName already in use. Cannot create a " + "source with existing source-name ", EntityName.SUBJECT, @@ -312,18 +314,20 @@ open class SubjectService( ): Source { // for manually registered devices only add meta-data val source = subjectRepository.findSubjectSourcesBySourceId( - subject.user!!.login, sourceRegistrationDto.sourceId - ).orElseThrow { - val errorParams: MutableMap = HashMap() - errorParams["sourceId"] = sourceRegistrationDto.sourceId.toString() - errorParams["subject-login"] = subject.user!!.login - NotFoundException( - "No source with source-id to assigned to the " + "subject with subject-login", - EntityName.SUBJECT, - ErrorConstants.ERR_SOURCE_NOT_FOUND, - errorParams - ) - } + subject.user?.login, sourceRegistrationDto.sourceId + ) + if (source == null) { + val errorParams: MutableMap = HashMap() + errorParams["sourceId"] = sourceRegistrationDto.sourceId.toString() + errorParams["subject-login"] = subject.user?.login + throw NotFoundException( + "No source with source-id to assigned to the subject with subject-login", + EntityName.SUBJECT, + ErrorConstants.ERR_SOURCE_NOT_FOUND, + errorParams + ) + } + if (sourceRegistrationDto.sourceName != null) { source.sourceName = sourceRegistrationDto.sourceName } @@ -339,9 +343,8 @@ open class SubjectService( * @return list of sources */ fun getSources(subject: Subject): List { - val sources = subjectRepository.findSourcesBySubjectLogin( - subject.user?.login - ) + val sources = subjectRepository.findSourcesBySubjectLogin(subject.user?.login) + if (sources.isEmpty()) throw org.webjars.NotFoundException("Could not find sources for user ${subject.user}") return sourceMapper.sourcesToMinimalSourceDetailsDTOs(sources) } @@ -351,11 +354,16 @@ open class SubjectService( * @param login the login */ fun deleteSubject(login: String?) { - subjectRepository.findOneWithEagerBySubjectLogin(login).ifPresent { subject: Subject -> + subjectRepository.findOneWithEagerBySubjectLogin(login)?.let { subject: Subject -> unassignAllSources(subject) subjectRepository.delete(subject) log.debug("Deleted Subject: {}", subject) - } + } ?: throw NotFoundException( + "subject not found for given login.", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) } /** @@ -370,7 +378,7 @@ open class SubjectService( val sources: List? = revisions?.content?.flatMap { p: Revision -> p.entity.sources } ?.distinctBy { obj: Source -> obj.sourceId } - return sources?.map { p: Source? -> sourceMapper.sourceToMinimalSourceDetailsDTO(p) }?.toList() + return sources?.map { p: Source -> sourceMapper.sourceToMinimalSourceDetailsDTO(p) }?.toList() } /** @@ -388,14 +396,11 @@ open class SubjectService( // directly by e.g. findOneByLogin val latest = getLatestRevision(login) authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> - e.project(latest.project.projectName).subject(latest.getLogin()) + e.project(latest.project?.projectName).subject(latest.login) }) return revisionService.findRevision( - revision, - latest.id, - Subject::class.java, - subjectMapper::subjectToSubjectReducedProjectDTO - ) ?: throw NotFoundException( + revision, latest.id, Subject::class.java, subjectMapper::subjectToSubjectReducedProjectDTO + ) ?: throw NotFoundException( "subject not found for given login and revision.", EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND, @@ -413,25 +418,25 @@ open class SubjectService( @Throws(NotFoundException::class) fun getLatestRevision(login: String?): SubjectDTO { val user = revisionService.getLatestRevisionForEntity( - User::class.java, java.util.List.of(AuditEntity.property("login").eq(login)) + User::class.java, listOf(AuditEntity.property("login").eq(login)) ).orElseThrow { - NotFoundException( - "Subject latest revision not found " + "for login", - EntityName.SUBJECT, - ErrorConstants.ERR_SUBJECT_NOT_FOUND, - Collections.singletonMap("subjectLogin", login) - ) - } as UserDTO + NotFoundException( + "Subject latest revision not found " + "for login", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) + } as UserDTO return revisionService.getLatestRevisionForEntity( - Subject::class.java, java.util.List.of(AuditEntity.property("user").eq(user)) + Subject::class.java, listOf(AuditEntity.property("user").eq(user)) ).orElseThrow { - NotFoundException( - "Subject latest revision not found " + "for login", - EntityName.SUBJECT, - ErrorConstants.ERR_SUBJECT_NOT_FOUND, - Collections.singletonMap("subjectLogin", login) - ) - } as SubjectDTO + NotFoundException( + "Subject latest revision not found " + "for login", + EntityName.SUBJECT, + ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) + } as SubjectDTO } /** @@ -442,11 +447,9 @@ open class SubjectService( @Nonnull fun findOneByLogin(login: String?): Subject { val subject = subjectRepository.findOneWithEagerBySubjectLogin(login) - return subject.orElseThrow { - NotFoundException( - "Subject not found with login", EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND - ) - } + return subject ?: throw NotFoundException( + "Subject not found with login", EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND + ) } /** diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt index 36c8355cb..3adcb8c2f 100644 --- a/src/main/java/org/radarbase/management/service/UserService.kt +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -60,15 +60,20 @@ open class UserService( * @return an [Optional] which is populated with the activated user if the registration * key was found, and is empty otherwise. */ - fun activateRegistration(key: String?): Optional { + fun activateRegistration(key: String): User { log.debug("Activating user for activation key {}", key) - return userRepository.findOneByActivationKey(key).map { user: User -> - // activate given user for the registration key. - user.activated = true - user.activationKey = null - log.debug("Activated user: {}", user) - user - } + return userRepository.findOneByActivationKey(key).let { user: User? -> + // activate given user for the registration key. + user?.activated = true + user?.activationKey = null + log.debug("Activated user: {}", user) + user + } ?: throw NotFoundException( + "User with activation key $key not found", + EntityName.USER, + ErrorConstants.ERR_ENTITY_NOT_FOUND, + Map.of("activationKey", key) + ) } /** @@ -78,20 +83,18 @@ open class UserService( * @return an [Optional] which is populated with the user whose password was reset if * the reset key was found, and is empty otherwise */ - fun completePasswordReset(newPassword: String?, key: String?): Optional { + fun completePasswordReset(newPassword: String, key: String): User? { log.debug("Reset user password for reset key {}", key) - return userRepository.findOneByResetKey(key).filter { user: User -> - val oneDayAgo = ZonedDateTime.now().minusSeconds( - managementPortalProperties.common.activationKeyTimeoutInSeconds.toLong() - ) - user.resetDate!!.isAfter(oneDayAgo) - }.map { user: User -> - user.password = passwordService.encode(newPassword) - user.resetKey = null - user.resetDate = null - user.activated = true - user - } + val user = userRepository.findOneByResetKey(key) + val oneDayAgo = ZonedDateTime.now().minusSeconds( + managementPortalProperties.common.activationKeyTimeoutInSeconds.toLong() + ) + if (user?.resetDate?.isAfter(oneDayAgo) == true) user.password = passwordService.encode(newPassword) + user?.resetKey = null + user?.resetDate = null + user?.activated = true + + return user } /** @@ -103,12 +106,14 @@ open class UserService( * @return an [Optional] which holds the user if an deactivated user was found with the * given login, and is empty otherwise */ - fun requestActivationReset(login: String?): Optional { - return userRepository.findOneByLogin(login).filter { p: User -> !p.activated }.map { user: User -> - user.resetKey = passwordService.generateResetKey() - user.resetDate = ZonedDateTime.now() - user - } + fun requestActivationReset(login: String): User? { + val user = userRepository.findOneByLogin(login) + if (user?.activated != true) { + user?.resetKey = passwordService.generateResetKey() + user?.resetDate = ZonedDateTime.now() + } + + return user } /** @@ -117,12 +122,11 @@ open class UserService( * @return an [Optional] which holds the user if an activated user was found with the * given email address, and is empty otherwise */ - fun requestPasswordReset(mail: String?): Optional { - return userRepository.findOneByEmail(mail).filter(User::activated).map { user: User -> - user.resetKey = passwordService.generateResetKey() - user.resetDate = ZonedDateTime.now() - user - } + fun requestPasswordReset(mail: String): User? { + val user = userRepository.findOneByEmail(mail) + if (user?.activated == true) user.resetKey = passwordService.generateResetKey() + user?.resetDate = ZonedDateTime.now() + return user } /** @@ -151,30 +155,30 @@ open class UserService( user.resetKey = passwordService.generateResetKey() user.resetDate = ZonedDateTime.now() user.activated = false - user.roles = getUserRoles(userDto.roles, setOf()) + user.roles = userDto.roles?.let { getUserRoles(it, mutableSetOf()) } user = userRepository.save(user) log.debug("Created Information for User: {}", user) return user } @Throws(NotAuthorizedException::class) - private fun getUserRoles(roleDtos: Set?, oldRoles: Set): MutableSet? { + private fun getUserRoles(roleDtos: Set?, oldRoles: MutableSet): MutableSet? { if (roleDtos == null) { return null } - val roles = roleDtos.stream().map { roleDto: RoleDTO -> - val authority = getRoleAuthority(roleDto) - when (authority.scope) { - RoleAuthority.Scope.GLOBAL -> roleService.getGlobalRole(authority) - RoleAuthority.Scope.ORGANIZATION -> roleService.getOrganizationRole( - authority, roleDto.organizationId - ) + val roles = roleDtos.map { roleDto: RoleDTO -> + val authority = getRoleAuthority(roleDto) + when (authority.scope) { + RoleAuthority.Scope.GLOBAL -> roleService.getGlobalRole(authority) + RoleAuthority.Scope.ORGANIZATION -> roleService.getOrganizationRole( + authority, roleDto.organizationId!! + ) - RoleAuthority.Scope.PROJECT -> roleService.getProjectRole( - authority, roleDto.projectId - ) - } - }.collect(Collectors.toSet()) + RoleAuthority.Scope.PROJECT -> roleService.getProjectRole( + authority, roleDto.projectId!! + ) + } + }.toMutableSet() checkAuthorityForRoleChange(roles, oldRoles) return roles } @@ -220,12 +224,12 @@ open class UserService( * @param langKey language key */ fun updateUser( - userName: String, firstName: String?, lastName: String?, email: String, langKey: String? + userName: String, firstName: String?, lastName: String?, email: String?, langKey: String? ) { - val userWithEmail = userRepository.findOneByEmail(email) + val userWithEmail = email?.let { userRepository.findOneByEmail(it) } val user: User - if (userWithEmail.isPresent) { - user = userWithEmail.get() + if (userWithEmail != null) { + user = userWithEmail if (!user.login.equals(userName, ignoreCase = true)) { throw ConflictException( "Email address $email already in use", @@ -235,14 +239,12 @@ open class UserService( ) } } else { - user = userRepository.findOneByLogin(userName).orElseThrow { - NotFoundException( - "User with login $userName not found", - EntityName.USER, - ErrorConstants.ERR_ENTITY_NOT_FOUND, - Map.of("user", userName) - ) - } + user = userRepository.findOneByLogin(userName) ?: throw NotFoundException( + "User with login $userName not found", + EntityName.USER, + ErrorConstants.ERR_ENTITY_NOT_FOUND, + Map.of("user", userName) + ) } user.firstName = firstName user.lastName = lastName @@ -261,8 +263,8 @@ open class UserService( @Transactional @Throws(NotAuthorizedException::class) open fun updateUser(userDto: UserDTO): UserDTO? { - val userOpt = userRepository.findById(userDto.id) - return if (userOpt.isPresent) { + val userOpt = userDto.id?.let { userRepository.findById(it) } + return if (userOpt?.isPresent == true) { var user = userOpt.get() user.firstName = userDto.firstName user.lastName = userDto.lastName @@ -285,23 +287,26 @@ open class UserService( * Delete the user with the given login. * @param login the login to delete */ - fun deleteUser(login: String?) { - userRepository.findOneByLogin(login).ifPresent { user: User -> + fun deleteUser(login: String) { + val user = userRepository.findOneByLogin(login) + if (user != null) { userRepository.delete(user) log.debug("Deleted User: {}", user) } + else { + log.warn("could not delete User with login: {}", login) + } } /** * Change the password of the user with the given login. * @param password the new password */ - fun changePassword(password: String?) { - val currentUser = SecurityUtils.getCurrentUserLogin().orElseThrow { - InvalidRequestException( - "Cannot change password of unknown user", null, ErrorConstants.ERR_ENTITY_NOT_FOUND - ) - } + fun changePassword(password: String) { + val currentUser = SecurityUtils.currentUserLogin + ?: throw InvalidRequestException( + "Cannot change password of unknown user", "", ErrorConstants.ERR_ENTITY_NOT_FOUND + ) changePassword(currentUser, password) } @@ -310,12 +315,16 @@ open class UserService( * @param password the new password * @param login of the user to change password */ - fun changePassword(login: String?, password: String?) { - userRepository.findOneByLogin(login).ifPresent { user: User -> + fun changePassword(login: String, password: String) { + val user = userRepository.findOneByLogin(login) + + if (user != null) + { val encryptedPassword = passwordService.encode(password) user.password = encryptedPassword log.debug("Changed password for User: {}", user) } + } /** @@ -324,7 +333,7 @@ open class UserService( * @return the requested page of users */ @Transactional(readOnly = true) - open fun getAllManagedUsers(pageable: Pageable?): Page { + open fun getAllManagedUsers(pageable: Pageable): Page { log.debug("Request to get all Users") return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER) .map { user: User? -> userMapper.userToUserDTO(user) } @@ -337,18 +346,17 @@ open class UserService( * and is empty otherwise */ @Transactional(readOnly = true) - open fun getUserWithAuthoritiesByLogin(login: String?): Optional { - return userRepository.findOneWithRolesByLogin(login).map { user: User? -> userMapper.userToUserDTO(user) } + open fun getUserWithAuthoritiesByLogin(login: String): UserDTO? { + return userMapper.userToUserDTO(userRepository.findOneWithRolesByLogin(login)) } @get:Transactional(readOnly = true) - open val userWithAuthorities: Optional + open val userWithAuthorities: User? /** * Get the current user. * @return the currently authenticated user, or null if no user is currently authenticated */ - get() = SecurityUtils.getCurrentUserLogin() - .flatMap { currentUser: String? -> userRepository.findOneWithRolesByLogin(currentUser) } + get() = SecurityUtils.currentUserLogin?.let { userRepository.findOneWithRolesByLogin(it) } /** * Not activated users should be automatically deleted after 3 days. @@ -407,18 +415,20 @@ open class UserService( @Transactional @Throws(NotAuthorizedException::class) open fun updateRoles(login: String, roleDtos: Set?) { - val user = userRepository.findOneByLogin(login).orElseThrow { - NotFoundException( - "User with login $login not found", - EntityName.USER, - ErrorConstants.ERR_ENTITY_NOT_FOUND, - Map.of("user", login) - ) - } + val user = userRepository.findOneByLogin(login) + ?: throw NotFoundException( + "User with login $login not found", + EntityName.USER, + ErrorConstants.ERR_ENTITY_NOT_FOUND, + Map.of("user", login) + ) + val managedRoles = user.roles - val oldRoles = java.util.Set.copyOf(managedRoles) + val oldRoles = managedRoles?.toMutableSet() + managedRoles?.clear() - managedRoles?.addAll(getUserRoles(roleDtos, oldRoles)!!) + managedRoles?.addAll(roleDtos?.let { oldRoles?.let { oldroles -> getUserRoles(it, oldroles) } }!!) + ?: throw Exception("could not add rolser for user: $user") userRepository.save(user) } diff --git a/src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.java b/src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.java deleted file mode 100644 index 56892b301..000000000 --- a/src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.radarbase.management.service.catalog; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class CatalogSourceData { - @JsonProperty("app_provider") - private String appProvider; - - @JsonProperty("processing_state") - private String processingState; - - @JsonProperty - private String type; - - @JsonProperty - private String doc; - - @JsonProperty("sample_rate") - private SampleRateConfig sampleRate; - - @JsonProperty - private String unit; - - @JsonProperty - private List fields; - - private String topic; - - @JsonProperty("key_schema") - private String keySchema; - - @JsonProperty("value_schema") - private String valueSchema; - - private List tags; - - public String getTopic() { - return topic; - } - - public void setTopic(String topic) { - this.topic = topic; - } - - public String getKeySchema() { - return keySchema; - } - - public void setKeySchema(String keySchema) { - this.keySchema = keySchema; - } - - public String getValueSchema() { - return valueSchema; - } - - public void setValueSchema(String valueSchema) { - this.valueSchema = valueSchema; - } - - public List getTags() { - return tags; - } - - public void setTags(List tags) { - this.tags = tags; - } - - public String getType() { - return type; - } - - public String getDoc() { - return doc; - } - - public SampleRateConfig getSampleRate() { - return sampleRate; - } - - public String getUnit() { - return unit; - } - - public List getFields() { - return fields; - } - - public String getProcessingState() { - return processingState; - } - - public void setProcessingState(String processingState) { - this.processingState = processingState; - } - - public void setAppProvider(String appProvider) { - this.appProvider = appProvider; - } - - public String getAppProvider() { - return appProvider; - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static class DataField { - @JsonProperty - private String name; - - public String getName() { - return name; - } - - @Override - public String toString() { - return "DataField{" + "name='" + name + '\'' - + '}'; - } - } - - @Override - public String toString() { - return "CatalogSourceData{" + "appProvider='" + appProvider + '\'' - + ", processingState='" + processingState + '\'' - + ", type='" + type + '\'' - + ", doc='" + doc + '\'' - + ", sampleRate=" + sampleRate - + ", unit='" + unit + '\'' - + ", fields=" + fields - + ", topic='" + topic + '\'' - + ", keySchema='" + keySchema + '\'' - + ", valueSchema='" + valueSchema + '\'' - + ", tags=" + tags - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.kt b/src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.kt new file mode 100644 index 000000000..2f7dfa81e --- /dev/null +++ b/src/main/java/org/radarbase/management/service/catalog/CatalogSourceData.kt @@ -0,0 +1,61 @@ +package org.radarbase.management.service.catalog + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonIgnoreProperties(ignoreUnknown = true) +class CatalogSourceData { + @JsonProperty("app_provider") + var appProvider: String? = null + + @JsonProperty("processing_state") + var processingState: String? = null + + @JsonProperty + val type: String? = null + + @JsonProperty + val doc: String? = null + + @JsonProperty("sample_rate") + val sampleRate: SampleRateConfig? = null + + @JsonProperty + val unit: String? = null + + @JsonProperty + val fields: List? = null + var topic: String? = null + + @JsonProperty("key_schema") + var keySchema: String? = null + + @JsonProperty("value_schema") + var valueSchema: String? = null + var tags: List? = null + + @JsonIgnoreProperties(ignoreUnknown = true) + class DataField { + @JsonProperty + val name: String? = null + override fun toString(): String { + return ("DataField{" + "name='" + name + '\'' + + '}') + } + } + + override fun toString(): String { + return ("CatalogSourceData{" + "appProvider='" + appProvider + '\'' + + ", processingState='" + processingState + '\'' + + ", type='" + type + '\'' + + ", doc='" + doc + '\'' + + ", sampleRate=" + sampleRate + + ", unit='" + unit + '\'' + + ", fields=" + fields + + ", topic='" + topic + '\'' + + ", keySchema='" + keySchema + '\'' + + ", valueSchema='" + valueSchema + '\'' + + ", tags=" + tags + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.java b/src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.java deleted file mode 100644 index 9cfff8bd2..000000000 --- a/src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.radarbase.management.service.catalog; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import org.hibernate.validator.constraints.NotEmpty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class CatalogSourceType { - - @JsonProperty("assessment_type") - private String assessmentType; - - @JsonProperty("app_provider") - private String appProvider; - - @JsonProperty - private String vendor; - - @JsonProperty - private String model; - - @JsonProperty - private String version; - - @JsonProperty - private String name; - - @JsonProperty - private String doc; - - @JsonProperty - private String scope; - - @JsonProperty - private Map properties; - - @JsonProperty - @NotEmpty - private List data; - - public String getName() { - return name; - } - - public String getDoc() { - return doc; - } - - public Map getProperties() { - return properties; - } - - public String getAppProvider() { - return appProvider; - } - - public String getVendor() { - return vendor; - } - - public String getModel() { - return model; - } - - public String getVersion() { - return version; - } - - public String getScope() { - return scope; - } - - public List getData() { - return data; - } - - public String getAssessmentType() { - return assessmentType; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - CatalogSourceType that = (CatalogSourceType) o; - return Objects.equals(assessmentType, that.assessmentType) - && Objects.equals(appProvider, that.appProvider) - && Objects.equals(vendor, that.vendor) - && Objects.equals(model, that.model) - && Objects.equals(version, that.version) - && Objects.equals(name, that.name) - && Objects.equals(doc, that.doc) - && Objects.equals(scope, that.scope) - && Objects.equals(properties, that.properties) - && Objects.equals(data, that.data); - } - - @Override - public int hashCode() { - - return Objects - .hash(assessmentType, appProvider, vendor, model, version, name, doc, scope, properties, - data); - } -} diff --git a/src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.kt b/src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.kt new file mode 100644 index 000000000..fe5dfb76a --- /dev/null +++ b/src/main/java/org/radarbase/management/service/catalog/CatalogSourceType.kt @@ -0,0 +1,58 @@ +package org.radarbase.management.service.catalog + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty +import org.hibernate.validator.constraints.NotEmpty +import java.util.* + +@JsonIgnoreProperties(ignoreUnknown = true) +class CatalogSourceType { + @JsonProperty("assessment_type") + val assessmentType: String? = null + + @JsonProperty("app_provider") + val appProvider: String? = null + + @JsonProperty + val vendor: String? = null + + @JsonProperty + val model: String? = null + + @JsonProperty + val version: String? = null + + @JsonProperty + val name: String? = null + + @JsonProperty + val doc: String? = null + + @JsonProperty + val scope: String? = null + + @JsonProperty + val properties: Map = emptyMap() + + @JsonProperty + val data: @NotEmpty MutableList? = null + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val that = other as CatalogSourceType + return assessmentType == that.assessmentType && appProvider == that.appProvider && vendor == that.vendor && model == that.model && version == that.version && name == that.name && doc == that.doc && scope == that.scope && properties == that.properties && data == that.data + } + + override fun hashCode(): Int { + return Objects + .hash( + assessmentType, appProvider, vendor, model, version, name, doc, scope, properties, + data + ) + } +} diff --git a/src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.java b/src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.java deleted file mode 100644 index 9e323b639..000000000 --- a/src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.radarbase.management.service.catalog; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class SampleRateConfig { - - @JsonProperty - private Double interval; - - @JsonProperty - private Double frequency; - - @JsonProperty - private boolean dynamic; - - @JsonProperty - private boolean configurable; - - public Double getInterval() { - return interval; - } - - public Double getFrequency() { - return frequency; - } - - public boolean isDynamic() { - return dynamic; - } - - public boolean isConfigurable() { - return configurable; - } - - @Override - public String toString() { - return "SampleRateConfig{interval=" + interval - + ", frequency=" + frequency - + ", dynamic=" + dynamic - + ", configurable=" + configurable - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.kt b/src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.kt new file mode 100644 index 000000000..1bc02797c --- /dev/null +++ b/src/main/java/org/radarbase/management/service/catalog/SampleRateConfig.kt @@ -0,0 +1,26 @@ +package org.radarbase.management.service.catalog + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonIgnoreProperties(ignoreUnknown = true) +class SampleRateConfig { + @JsonProperty + val interval: Double? = null + + @JsonProperty + val frequency: Double? = null + + @JsonProperty + val isDynamic = false + + @JsonProperty + val isConfigurable = false + override fun toString(): String { + return ("SampleRateConfig{interval=" + interval + + ", frequency=" + frequency + + ", dynamic=" + isDynamic + + ", configurable=" + isConfigurable + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.java b/src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.java deleted file mode 100644 index ca505772d..000000000 --- a/src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.radarbase.management.service.catalog; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import java.util.List; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class SourceTypeResponse { - - @JsonProperty("passive-source-types") - private List passiveSources; - - @JsonProperty("active-source-types") - private List activeSources; - - @JsonProperty("monitor-source-types") - private List monitorSources; - - @JsonProperty("connector-source-types") - private List connectorSources; - - public List getPassiveSources() { - return passiveSources; - } - - public List getActiveSources() { - return activeSources; - } - - public List getMonitorSources() { - return monitorSources; - } - - public List getConnectorSources() { - return connectorSources; - } -} diff --git a/src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.kt b/src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.kt new file mode 100644 index 000000000..693f16bdb --- /dev/null +++ b/src/main/java/org/radarbase/management/service/catalog/SourceTypeResponse.kt @@ -0,0 +1,19 @@ +package org.radarbase.management.service.catalog + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonProperty + +@JsonIgnoreProperties(ignoreUnknown = true) +class SourceTypeResponse { + @JsonProperty("passive-source-types") + val passiveSources: List? = null + + @JsonProperty("active-source-types") + val activeSources: List? = null + + @JsonProperty("monitor-source-types") + val monitorSources: List? = null + + @JsonProperty("connector-source-types") + val connectorSources: List? = null +} diff --git a/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.java b/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.java deleted file mode 100644 index a4914b052..000000000 --- a/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.util.Objects; - -/** - * Created by nivethika on 30-8-17. - */ -public class AttributeMapDTO { - private String key; - - private String value; - - public AttributeMapDTO() { - this(null, null); - } - - public AttributeMapDTO(String key, String value) { - this.key = key; - this.value = value; - } - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - AttributeMapDTO attributeMapDto = (AttributeMapDTO) o; - - return Objects.equals(key, attributeMapDto.key) - && Objects.equals(value, attributeMapDto.value); - } - - @Override - public int hashCode() { - return Objects.hash(key, value); - } - - @Override - public String toString() { - return "AttributeMapDTO{" - + " key='" + key + "'" - + ", value='" + value + "'" - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt b/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt new file mode 100644 index 000000000..7f54176ee --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt @@ -0,0 +1,31 @@ +package org.radarbase.management.service.dto + +import java.util.* + +/** + * Created by nivethika on 30-8-17. + */ +class AttributeMapDTO @JvmOverloads constructor(var key: String? = null, var value: String? = null) { + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val attributeMapDto = o as AttributeMapDTO + return key == attributeMapDto.key && value == attributeMapDto.value + } + + override fun hashCode(): Int { + return Objects.hash(key, value) + } + + override fun toString(): String { + return ("AttributeMapDTO{" + + " key='" + key + "'" + + ", value='" + value + "'" + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/AuthorityDTO.java b/src/main/java/org/radarbase/management/service/dto/AuthorityDTO.java deleted file mode 100644 index c1d6d1b5c..000000000 --- a/src/main/java/org/radarbase/management/service/dto/AuthorityDTO.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.radarbase.management.service.dto; - -import org.radarbase.auth.authorization.RoleAuthority; - -public class AuthorityDTO { - private String name; - private String scope; - - public AuthorityDTO() { - // POJO constructor - } - - public AuthorityDTO(RoleAuthority role) { - this.name = role.getAuthority(); - this.scope = role.getScope().name(); - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getScope() { - return scope; - } - - public void setScope(String scope) { - this.scope = scope; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/AuthorityDTO.kt b/src/main/java/org/radarbase/management/service/dto/AuthorityDTO.kt new file mode 100644 index 000000000..f6bed0a64 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/AuthorityDTO.kt @@ -0,0 +1,14 @@ +package org.radarbase.management.service.dto + +import org.radarbase.auth.authorization.RoleAuthority + +class AuthorityDTO { + var name: String? = null + var scope: String? = null + + constructor() + constructor(role: RoleAuthority) { + name = role.authority + scope = role.scope.name + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.java b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.java deleted file mode 100644 index 39ccea7a9..000000000 --- a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.util.Map; -import java.util.Set; -import javax.validation.constraints.NotNull; - -/** - * Created by dverbeec on 7/09/2017. - */ -public class ClientDetailsDTO { - - @NotNull - private String clientId; - private String clientSecret; - private Set scope; - private Set resourceIds; - private Set authorizedGrantTypes; - private Set autoApproveScopes; - private Long accessTokenValiditySeconds; - private Long refreshTokenValiditySeconds; - private Set authorities; - private Set registeredRedirectUri; - private Map additionalInformation; - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public String getClientSecret() { - return clientSecret; - } - - public void setClientSecret(String clientSecret) { - this.clientSecret = clientSecret; - } - - public Set getScope() { - return scope; - } - - public void setScope(Set scope) { - this.scope = scope; - } - - public Set getResourceIds() { - return resourceIds; - } - - public void setResourceIds(Set resourceIds) { - this.resourceIds = resourceIds; - } - - public Set getAuthorizedGrantTypes() { - return authorizedGrantTypes; - } - - public void setAuthorizedGrantTypes(Set authorizedGrantTypes) { - this.authorizedGrantTypes = authorizedGrantTypes; - } - - public Set getAutoApproveScopes() { - return autoApproveScopes; - } - - public void setAutoApproveScopes(Set autoApproveScopes) { - this.autoApproveScopes = autoApproveScopes; - } - - public Long getAccessTokenValiditySeconds() { - return accessTokenValiditySeconds; - } - - public void setAccessTokenValiditySeconds(Long accessTokenValiditySeconds) { - this.accessTokenValiditySeconds = accessTokenValiditySeconds; - } - - public Long getRefreshTokenValiditySeconds() { - return refreshTokenValiditySeconds; - } - - public void setRefreshTokenValiditySeconds(Long refreshTokenValiditySeconds) { - this.refreshTokenValiditySeconds = refreshTokenValiditySeconds; - } - - public Set getAuthorities() { - return authorities; - } - - public void setAuthorities(Set authorities) { - this.authorities = authorities; - } - - public Set getRegisteredRedirectUri() { - return registeredRedirectUri; - } - - public void setRegisteredRedirectUri(Set registeredRedirectUri) { - this.registeredRedirectUri = registeredRedirectUri; - } - - public Map getAdditionalInformation() { - return additionalInformation; - } - - public void setAdditionalInformation(Map additionalInformation) { - this.additionalInformation = additionalInformation; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt new file mode 100644 index 000000000..b2a19c2f6 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt @@ -0,0 +1,20 @@ +package org.radarbase.management.service.dto + +import javax.validation.constraints.NotNull + +/** + * Created by dverbeec on 7/09/2017. + */ +class ClientDetailsDTO { + lateinit var clientId: @NotNull String + var clientSecret: String? = null + var scope: Set? = null + var resourceIds: Set? = null + var authorizedGrantTypes: Set? = null + var autoApproveScopes: Set? = null + var accessTokenValiditySeconds: Long? = null + var refreshTokenValiditySeconds: Long? = null + var authorities: Set? = null + var registeredRedirectUri: Set? = null + var additionalInformation: Map? = null +} diff --git a/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.java b/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.java deleted file mode 100644 index 865509b8a..000000000 --- a/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.net.URL; -import java.time.Duration; -import java.time.Instant; -import java.util.Objects; - -/** - * Created by dverbeec on 29/08/2017. - */ -public class ClientPairInfoDTO { - - private final String tokenName; - - private final URL tokenUrl; - - private final URL baseUrl; - - private final long timeout; - - private final Instant timesOutAt; - - - /** - * Initialize with the given refresh token. - * @param baseUrl the base url of the platform - * @param tokenName the refresh token - * @param tokenUrl the refresh token - */ - public ClientPairInfoDTO(URL baseUrl, String tokenName, URL tokenUrl, Duration timeout) { - if (tokenUrl == null) { - throw new IllegalArgumentException("tokenUrl can not be null"); - } - this.baseUrl = baseUrl; - this.tokenName = tokenName; - this.tokenUrl = tokenUrl; - this.timeout = timeout.toMillis(); - this.timesOutAt = Instant.now().plus(timeout); - } - - public String getTokenName() { - return tokenName; - } - - public URL getTokenUrl() { - return tokenUrl; - } - - public URL getBaseUrl() { - return baseUrl; - } - - public long getTimeout() { - return timeout; - } - - public Instant getTimesOutAt() { - return timesOutAt; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ClientPairInfoDTO that = (ClientPairInfoDTO) o; - return Objects.equals(tokenName, that.tokenName) - && Objects.equals(tokenUrl, that.tokenUrl) - && Objects.equals(baseUrl, that.baseUrl) - && Objects.equals(timeout, that.timeout) - && Objects.equals(timesOutAt, that.timesOutAt); - } - - @Override - public int hashCode() { - - return Objects.hash(baseUrl, tokenName, tokenUrl, timeout, timesOutAt); - } - - @Override - public String toString() { - return "ClientPairInfoDTO{" - + "tokenName='" + tokenName + '\'' - + ", tokenUrl=" + tokenUrl + '\'' - + ", timeout=" + timeout + '\'' - + ", timesOutAt=" + timesOutAt + '\'' - + ", baseUrl=" + baseUrl + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt b/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt new file mode 100644 index 000000000..9955c4d22 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt @@ -0,0 +1,56 @@ +package org.radarbase.management.service.dto + +import java.net.URL +import java.time.Duration +import java.time.Instant +import java.util.* + +/** + * Created by dverbeec on 29/08/2017. + */ +class ClientPairInfoDTO(baseUrl: URL, tokenName: String, tokenUrl: URL?, timeout: Duration) { + val tokenName: String + val tokenUrl: URL + val baseUrl: URL + val timeout: Long + val timesOutAt: Instant + + /** + * Initialize with the given refresh token. + * @param baseUrl the base url of the platform + * @param tokenName the refresh token + * @param tokenUrl the refresh token + */ + init { + requireNotNull(tokenUrl) { "tokenUrl can not be null" } + this.baseUrl = baseUrl + this.tokenName = tokenName + this.tokenUrl = tokenUrl + this.timeout = timeout.toMillis() + timesOutAt = Instant.now().plus(timeout) + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val that = o as ClientPairInfoDTO + return tokenName == that.tokenName && tokenUrl == that.tokenUrl && baseUrl == that.baseUrl && timeout == that.timeout && timesOutAt == that.timesOutAt + } + + override fun hashCode(): Int { + return Objects.hash(baseUrl, tokenName, tokenUrl, timeout, timesOutAt) + } + + override fun toString(): String { + return ("ClientPairInfoDTO{" + + "tokenName='" + tokenName + '\'' + + ", tokenUrl=" + tokenUrl + '\'' + + ", timeout=" + timeout + '\'' + + ", timesOutAt=" + timesOutAt + '\'' + + ", baseUrl=" + baseUrl + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/GroupDTO.java b/src/main/java/org/radarbase/management/service/dto/GroupDTO.java deleted file mode 100644 index 66e426ee9..000000000 --- a/src/main/java/org/radarbase/management/service/dto/GroupDTO.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.radarbase.management.service.dto; - -import com.fasterxml.jackson.annotation.JsonInclude; - -import javax.validation.constraints.NotNull; -import java.util.Objects; - -/** - * A DTO for the Group entity. - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class GroupDTO { - - private Long id; - - private Long projectId; - - @NotNull - private String name; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getProjectId() { - return projectId; - } - - public void setProjectId(Long projectId) { - this.projectId = projectId; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - GroupDTO groupDto = (GroupDTO) o; - - if (id == null || groupDto.id == null) { - return false; - } - - return Objects.equals(id, groupDto.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "GroupDTO{" - + "id=" + id - + ", name='" + name + "'" - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt b/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt new file mode 100644 index 000000000..7daa3ba88 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt @@ -0,0 +1,38 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import java.util.* +import javax.validation.constraints.NotNull + +/** + * A DTO for the Group entity. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +class GroupDTO { + var id: Long? = null + var projectId: Long? = null + var name: @NotNull String? = null + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val groupDto = o as GroupDTO + return if (id == null || groupDto.id == null) { + false + } else id == groupDto.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("GroupDTO{" + + "id=" + id + + ", name='" + name + "'" + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.java b/src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.java deleted file mode 100644 index 999df6474..000000000 --- a/src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.radarbase.management.service.dto; - -/** - * Created by nivethika on 21-6-17. - */ -public class MinimalProjectDetailsDTO { - - private Long id; - - private String projectName; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.kt new file mode 100644 index 000000000..01dec5bc1 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/MinimalProjectDetailsDTO.kt @@ -0,0 +1,9 @@ +package org.radarbase.management.service.dto + +/** + * Created by nivethika on 21-6-17. + */ +class MinimalProjectDetailsDTO { + var id: Long? = null + var projectName: String? = null +} diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.java b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.java deleted file mode 100644 index 03a6cb145..000000000 --- a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.java +++ /dev/null @@ -1,163 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * Created by nivethika on 13-6-17. - */ -public class MinimalSourceDetailsDTO { - - private Long id; - private Long sourceTypeId; - private String sourceTypeProducer; - private String sourceTypeModel; - private String sourceTypeCatalogVersion; - private String expectedSourceName; - private UUID sourceId; - private String sourceName; - private Boolean assigned; - private Map attributes = new HashMap<>(); - - public Long getId() { - return id; - } - - public MinimalSourceDetailsDTO id(Long id) { - this.id = id; - return this; - } - - public Long getSourceTypeId() { - return sourceTypeId; - } - - public MinimalSourceDetailsDTO sourceTypeId(Long sourceTypeId) { - this.sourceTypeId = sourceTypeId; - return this; - } - - public String getExpectedSourceName() { - return expectedSourceName; - } - - public MinimalSourceDetailsDTO setExpectedSourceName(String expectedSourceName) { - this.expectedSourceName = expectedSourceName; - return this; - } - - public UUID getSourceId() { - return sourceId; - } - - public MinimalSourceDetailsDTO sourceId(UUID sourceId) { - this.sourceId = sourceId; - return this; - } - - public Boolean isAssigned() { - return assigned; - } - - public MinimalSourceDetailsDTO assigned(Boolean assigned) { - this.assigned = assigned; - return this; - } - - public String getSourceName() { - return sourceName; - } - - public MinimalSourceDetailsDTO sourceName(String sourceName) { - this.sourceName = sourceName; - return this; - } - - public Map getAttributes() { - return attributes; - } - - public MinimalSourceDetailsDTO attributes(Map attributes) { - this.attributes = attributes; - return this; - } - - public String getSourceTypeCatalogVersion() { - return sourceTypeCatalogVersion; - } - - public MinimalSourceDetailsDTO sourceTypeCatalogVersion(String sourceTypeCatalogVersion) { - this.sourceTypeCatalogVersion = sourceTypeCatalogVersion; - return this; - } - - public String getSourceTypeModel() { - return sourceTypeModel; - } - - public MinimalSourceDetailsDTO sourceTypeModel(String sourceTypeModel) { - this.sourceTypeModel = sourceTypeModel; - return this; - } - - public String getSourceTypeProducer() { - return sourceTypeProducer; - } - - public MinimalSourceDetailsDTO sourceTypeProducer(String sourceTypeProducer) { - this.sourceTypeProducer = sourceTypeProducer; - return this; - } - - public void setId(Long id) { - this.id = id; - } - - public void setSourceTypeId(Long sourceTypeId) { - this.sourceTypeId = sourceTypeId; - } - - public void setSourceTypeProducer(String sourceTypeProducer) { - this.sourceTypeProducer = sourceTypeProducer; - } - - public void setSourceTypeModel(String sourceTypeModel) { - this.sourceTypeModel = sourceTypeModel; - } - - public void setSourceTypeCatalogVersion(String sourceTypeCatalogVersion) { - this.sourceTypeCatalogVersion = sourceTypeCatalogVersion; - } - - public void setSourceId(UUID sourceId) { - this.sourceId = sourceId; - } - - public void setSourceName(String sourceName) { - this.sourceName = sourceName; - } - - public void setAssigned(Boolean assigned) { - this.assigned = assigned; - } - - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - @Override - public String toString() { - return "MinimalSourceDetailsDTO{" - + "id=" + id - + ", sourceTypeId=" + sourceTypeId - + ", sourceTypeProducer='" + sourceTypeProducer + '\'' - + ", sourceTypeModel='" + sourceTypeModel + '\'' - + ", sourceTypeCatalogVersion='" + sourceTypeCatalogVersion + '\'' - + ", expectedSourceName='" + expectedSourceName + '\'' - + ", sourceId=" + sourceId - + ", sourceName='" + sourceName + '\'' - + ", assigned=" + assigned - + ", attributes=" + attributes + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt new file mode 100644 index 000000000..fe111ae5b --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt @@ -0,0 +1,83 @@ +package org.radarbase.management.service.dto + +import java.util.* + +/** + * Created by nivethika on 13-6-17. + */ +class MinimalSourceDetailsDTO { + var id: Long? = null + var sourceTypeId: Long? = null + var sourceTypeProducer: String? = null + var sourceTypeModel: String? = null + var sourceTypeCatalogVersion: String? = null + var expectedSourceName: String? = null + private set + lateinit var sourceId: UUID + var sourceName: String? = null + var isAssigned: Boolean? = null + var attributes: Map = HashMap() + fun id(id: Long?): MinimalSourceDetailsDTO { + this.id = id + return this + } + + fun sourceTypeId(sourceTypeId: Long?): MinimalSourceDetailsDTO { + this.sourceTypeId = sourceTypeId + return this + } + + fun setExpectedSourceName(expectedSourceName: String?): MinimalSourceDetailsDTO { + this.expectedSourceName = expectedSourceName + return this + } + + fun sourceId(sourceId: UUID): MinimalSourceDetailsDTO { + this.sourceId = sourceId + return this + } + + fun assigned(assigned: Boolean?): MinimalSourceDetailsDTO { + isAssigned = assigned + return this + } + + fun sourceName(sourceName: String?): MinimalSourceDetailsDTO { + this.sourceName = sourceName + return this + } + + fun attributes(attributes: Map): MinimalSourceDetailsDTO { + this.attributes = attributes + return this + } + + fun sourceTypeCatalogVersion(sourceTypeCatalogVersion: String?): MinimalSourceDetailsDTO { + this.sourceTypeCatalogVersion = sourceTypeCatalogVersion + return this + } + + fun sourceTypeModel(sourceTypeModel: String?): MinimalSourceDetailsDTO { + this.sourceTypeModel = sourceTypeModel + return this + } + + fun sourceTypeProducer(sourceTypeProducer: String?): MinimalSourceDetailsDTO { + this.sourceTypeProducer = sourceTypeProducer + return this + } + + override fun toString(): String { + return ("MinimalSourceDetailsDTO{" + + "id=" + id + + ", sourceTypeId=" + sourceTypeId + + ", sourceTypeProducer='" + sourceTypeProducer + '\'' + + ", sourceTypeModel='" + sourceTypeModel + '\'' + + ", sourceTypeCatalogVersion='" + sourceTypeCatalogVersion + '\'' + + ", expectedSourceName='" + expectedSourceName + '\'' + + ", sourceId=" + sourceId + + ", sourceName='" + sourceName + '\'' + + ", assigned=" + isAssigned + + ", attributes=" + attributes + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.java b/src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.java deleted file mode 100644 index 455dc89db..000000000 --- a/src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.radarbase.management.service.dto; - -/** - * Created by nivethika on 22-6-17. - */ -public class MinimalSourceTypeDTO { - - private long id; - - private String model; - - private String producer; - - private String catalogVersion; - - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - public String getModel() { - return model; - } - - public void setModel(String model) { - this.model = model; - } - - public String getProducer() { - return producer; - } - - public void setProducer(String producer) { - this.producer = producer; - } - - public String getCatalogVersion() { - return catalogVersion; - } - - public void setCatalogVersion(String catalogVersion) { - this.catalogVersion = catalogVersion; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.kt b/src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.kt new file mode 100644 index 000000000..c0a4dacbe --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/MinimalSourceTypeDTO.kt @@ -0,0 +1,11 @@ +package org.radarbase.management.service.dto + +/** + * Created by nivethika on 22-6-17. + */ +class MinimalSourceTypeDTO { + var id: Long = 0 + var model: String? = null + var producer: String? = null + var catalogVersion: String? = null +} diff --git a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.java b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.java deleted file mode 100644 index a4c216c76..000000000 --- a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.java +++ /dev/null @@ -1,99 +0,0 @@ -package org.radarbase.management.service.dto; - - -import com.fasterxml.jackson.annotation.JsonInclude; -import java.io.Serializable; -import java.util.List; -import java.util.Objects; -import javax.validation.constraints.NotNull; - -/** - * A DTO for the Organization entity. - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class OrganizationDTO implements Serializable { - private static final long serialVersionUID = 1L; - - private Long id; - - @NotNull - private String name; - - @NotNull - private String description; - - @NotNull - private String location; - - private List projects; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - - public List getProjects() { - return projects; - } - - public void setProjects(List projects) { - this.projects = projects; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - var orgDto = (OrganizationDTO) o; - return Objects.equals(name, orgDto.name) - && Objects.equals(description, orgDto.description) - && Objects.equals(location, orgDto.location); - } - - @Override - public int hashCode() { - return Objects.hashCode(name); - } - - @Override - public String toString() { - return "OrganizationDTO{" - + "id=" + id - + ", name='" + name + "'" - + ", description='" + description + "'" - + ", location='" + location + "'" - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt new file mode 100644 index 000000000..00aab1319 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt @@ -0,0 +1,45 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import java.io.Serializable +import java.util.* +import javax.validation.constraints.NotNull + +/** + * A DTO for the Organization entity. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +class OrganizationDTO : Serializable { + var id: Long? = null + lateinit var name: @NotNull String + lateinit var description: @NotNull String + lateinit var location: @NotNull String + var projects: List? = null + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val orgDto = other as OrganizationDTO + return name == orgDto.name && description == orgDto.description && location == orgDto.location + } + + override fun hashCode(): Int { + return Objects.hashCode(name) + } + + override fun toString(): String { + return ("OrganizationDTO{" + + "id=" + id + + ", name='" + name + "'" + + ", description='" + description + "'" + + ", location='" + location + "'" + + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.java b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.java deleted file mode 100644 index 62afd3d61..000000000 --- a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.java +++ /dev/null @@ -1,209 +0,0 @@ -package org.radarbase.management.service.dto; - - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import java.io.Serializable; -import java.time.ZonedDateTime; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import javax.validation.constraints.NotNull; -import org.radarbase.management.domain.enumeration.ProjectStatus; - -/** - * A DTO for the Project entity. - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class ProjectDTO implements Serializable { - private static final long serialVersionUID = 1L; - - public static final String EXTERNAL_PROJECT_URL_KEY = "External-project-url"; - public static final String EXTERNAL_PROJECT_ID_KEY = "External-project-id"; - public static final String WORK_PACKAGE_KEY = "Work-package"; - public static final String PHASE_KEY = "Phase"; - public static final String HUMAN_READABLE_PROJECT_NAME = "Human-readable-project-name"; - public static final String PRIVACY_POLICY_URL = "Privacy-policy-url"; - - private Long id; - - @NotNull - private String projectName; - - private String humanReadableProjectName; - - @NotNull - private String description; - - private OrganizationDTO organization; - - private String organizationName; - - @NotNull - private String location; - - private ZonedDateTime startDate; - - private ProjectStatus projectStatus; - - private ZonedDateTime endDate; - - @JsonInclude(Include.NON_EMPTY) - private Set sourceTypes; - - private Map attributes; - - @JsonInclude(Include.NON_EMPTY) - private Set groups; - - private Long persistentTokenTimeout; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public OrganizationDTO getOrganization() { - return organization; - } - - public void setOrganization(OrganizationDTO organization) { - this.organization = organization; - } - - public String getOrganizationName() { - return organizationName; - } - - public void setOrganizationName(String organizationName) { - this.organizationName = organizationName; - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - - public ZonedDateTime getStartDate() { - return startDate; - } - - public void setStartDate(ZonedDateTime startDate) { - this.startDate = startDate; - } - - public ProjectStatus getProjectStatus() { - return projectStatus; - } - - public void setProjectStatus(ProjectStatus projectStatus) { - this.projectStatus = projectStatus; - } - - public ZonedDateTime getEndDate() { - return endDate; - } - - public void setEndDate(ZonedDateTime endDate) { - this.endDate = endDate; - } - - public Set getSourceTypes() { - return sourceTypes; - } - - public void setSourceTypes(Set sourceTypes) { - this.sourceTypes = sourceTypes; - } - - public Map getAttributes() { - return attributes; - } - - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - public Set getGroups() { - return groups; - } - - public void setGroups(Set groups) { - this.groups = groups; - } - - public String getHumanReadableProjectName() { - return humanReadableProjectName; - } - - public void setHumanReadableProjectName(String humanReadableProjectName) { - this.humanReadableProjectName = humanReadableProjectName; - } - - public Long getPersistentTokenTimeout() { - return persistentTokenTimeout; - } - - public void setPersistentTokenTimeout(Long persistentTokenTimeout) { - this.persistentTokenTimeout = persistentTokenTimeout; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - ProjectDTO projectDto = (ProjectDTO) o; - if (id == null || projectDto.id == null) { - return false; - } - - return Objects.equals(id, projectDto.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "ProjectDTO{" - + "id=" + id - + ", projectName='" + projectName + "'" - + ", description='" + description + "'" - + ", organization='" + organization + "'" - + ", organizationName='" + organizationName + "'" - + ", location='" + location + "'" - + ", startDate='" + startDate + "'" - + ", projectStatus='" + projectStatus + "'" - + ", endDate='" + endDate + "'" - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt new file mode 100644 index 000000000..3d4655f89 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt @@ -0,0 +1,73 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import org.radarbase.management.domain.enumeration.ProjectStatus +import java.io.Serializable +import java.time.ZonedDateTime +import java.util.* +import javax.validation.constraints.NotNull + +/** + * A DTO for the Project entity. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +class ProjectDTO : Serializable { + var id: Long? = null + var projectName: @NotNull String? = null + var humanReadableProjectName: String? = null + var description: @NotNull String? = null + var organization: OrganizationDTO? = null + var organizationName: String? = null + var location: @NotNull String? = null + var startDate: ZonedDateTime? = null + var projectStatus: ProjectStatus? = null + var endDate: ZonedDateTime? = null + + @JsonInclude(JsonInclude.Include.NON_EMPTY) + var sourceTypes: Set? = null + var attributes: Map? = null + + @JsonInclude(JsonInclude.Include.NON_EMPTY) + var groups: Set? = null + var persistentTokenTimeout: Long? = null + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val projectDto = o as ProjectDTO + return if (id == null || projectDto.id == null) { + false + } else id == projectDto.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("ProjectDTO{" + + "id=" + id + + ", projectName='" + projectName + "'" + + ", description='" + description + "'" + + ", organization='" + organization + "'" + + ", organizationName='" + organizationName + "'" + + ", location='" + location + "'" + + ", startDate='" + startDate + "'" + + ", projectStatus='" + projectStatus + "'" + + ", endDate='" + endDate + "'" + + '}') + } + + companion object { + private const val serialVersionUID = 1L + const val EXTERNAL_PROJECT_URL_KEY = "External-project-url" + const val EXTERNAL_PROJECT_ID_KEY = "External-project-id" + const val WORK_PACKAGE_KEY = "Work-package" + const val PHASE_KEY = "Phase" + const val HUMAN_READABLE_PROJECT_NAME = "Human-readable-project-name" + const val PRIVACY_POLICY_URL = "Privacy-policy-url" + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java b/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java deleted file mode 100644 index 9cf948d11..000000000 --- a/src/main/java/org/radarbase/management/service/dto/RevisionDTO.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.radarbase.management.service.dto; - -import org.hibernate.envers.RevisionType; -import org.radarbase.management.domain.audit.CustomRevisionEntity; -import org.springframework.data.history.Revision; - -import java.time.Instant; - -public class RevisionDTO { - private int id; - private Instant timestamp; - private String author; - private Object entity; - private RevisionType revisionType; - - public RevisionDTO() { - // JSON initializer - } - - /** - * Create a DTO from a revision, type and entity. - * @param revision the revision - * @param revisionType the type - * @param entity the entity - */ - public RevisionDTO(Revision revision, RevisionType revisionType, Object entity) { - id = revision.getRequiredRevisionNumber().intValue(); - timestamp = revision.getRequiredRevisionInstant(); - author = ((CustomRevisionEntity) revision.getMetadata().getDelegate()).auditor; - this.entity = entity; - this.revisionType = revisionType; - } - - public int getId() { - return id; - } - - public Instant getTimestamp() { - return timestamp; - } - - public String getAuthor() { - return author; - } - - public Object getEntity() { - return entity; - } - - public RevisionType getRevisionType() { - return revisionType; - } - - public RevisionDTO setId(int id) { - this.id = id; - return this; - } - - public RevisionDTO setTimestamp(Instant timestamp) { - this.timestamp = timestamp; - return this; - } - - public RevisionDTO setAuthor(String author) { - this.author = author; - return this; - } - - public RevisionDTO setEntity(Object entity) { - this.entity = entity; - return this; - } - - public RevisionDTO setRevisionType(RevisionType revisionType) { - this.revisionType = revisionType; - return this; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/RevisionDTO.kt b/src/main/java/org/radarbase/management/service/dto/RevisionDTO.kt new file mode 100644 index 000000000..de8c97c42 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/RevisionDTO.kt @@ -0,0 +1,60 @@ +package org.radarbase.management.service.dto + +import org.hibernate.envers.RevisionType +import org.radarbase.management.domain.audit.CustomRevisionEntity +import org.springframework.data.history.Revision +import java.time.Instant + +class RevisionDTO { + var id = 0 + private set + var timestamp: Instant? = null + private set + var author: String? = null + private set + var entity: Any? = null + private set + var revisionType: RevisionType? = null + private set + + constructor() + + /** + * Create a DTO from a revision, type and entity. + * @param revision the revision + * @param revisionType the type + * @param entity the entity + */ + constructor(revision: Revision<*, *>, revisionType: RevisionType?, entity: Any?) { + id = revision.requiredRevisionNumber.toInt() + timestamp = revision.requiredRevisionInstant + author = (revision.metadata.getDelegate() as CustomRevisionEntity).auditor + this.entity = entity + this.revisionType = revisionType + } + + fun setId(id: Int): RevisionDTO { + this.id = id + return this + } + + fun setTimestamp(timestamp: Instant?): RevisionDTO { + this.timestamp = timestamp + return this + } + + fun setAuthor(author: String?): RevisionDTO { + this.author = author + return this + } + + fun setEntity(entity: Any?): RevisionDTO { + this.entity = entity + return this + } + + fun setRevisionType(revisionType: RevisionType?): RevisionDTO { + this.revisionType = revisionType + return this + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java b/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java deleted file mode 100644 index 1b957e1de..000000000 --- a/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.util.Locale; -import java.util.stream.Collectors; -import org.hibernate.envers.RevisionType; -import org.radarbase.management.domain.audit.CustomRevisionEntity; - -import java.io.Serializable; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * Class for representing comprehensive information about a revision. - */ -public class RevisionInfoDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - private int id; - - private Date timestamp; - - private String author; - - // Groups the changes by revision type and class name - private Map>> changes; - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public Date getTimestamp() { - return timestamp; - } - - public void setTimestamp(Date timestamp) { - this.timestamp = timestamp; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - public Map>> getChanges() { - return changes; - } - - public void setChanges(Map>> changes) { - this.changes = changes; - } - - /** - * Create a RevisionInfoDTO from a {@link CustomRevisionEntity} and a set of changes grouped - * by revision type. - * - *

This method is convenient when using a CustomRevisionEntity in combination with - * {@link org.hibernate.envers.CrossTypeRevisionChangesReader}. The Map will be transformed - * so changes are additionally grouped by class name.

- * @param revisionEntity the revision entity - * @param changes the changes - * @return the RevisionInfoDTO object - */ - public static RevisionInfoDTO from(CustomRevisionEntity revisionEntity, Map> changes) { - RevisionInfoDTO result = new RevisionInfoDTO(); - result.setAuthor(revisionEntity.auditor); - result.setTimestamp(revisionEntity.timestamp); - result.setId(revisionEntity.id); - result.setChanges(changes.entrySet().stream() - .filter(e -> e.getValue() != null) - .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().stream() - .filter(Objects::nonNull) - .collect(Collectors.groupingBy(obj -> obj.getClass() - .getSimpleName() - .replaceAll("DTO$","") - .toLowerCase(Locale.US)))))); - return result; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.kt b/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.kt new file mode 100644 index 000000000..1309b2ee8 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/RevisionInfoDTO.kt @@ -0,0 +1,52 @@ +package org.radarbase.management.service.dto + +import org.hibernate.envers.RevisionType +import org.radarbase.management.domain.audit.CustomRevisionEntity +import java.io.Serializable +import java.util.* + +/** + * Class for representing comprehensive information about a revision. + */ +class RevisionInfoDTO : Serializable { + var id = 0 + var timestamp: Date? = null + var author: String? = null + + // Groups the changes by revision type and class name + var changes: Map>>? = null + + companion object { + private const val serialVersionUID = 1L + + /** + * Create a RevisionInfoDTO from a [CustomRevisionEntity] and a set of changes grouped + * by revision type. + * + * + * This method is convenient when using a CustomRevisionEntity in combination with + * [org.hibernate.envers.CrossTypeRevisionChangesReader]. The Map will be transformed + * so changes are additionally grouped by class name. + * @param revisionEntity the revision entity + * @param changes the changes + * @return the RevisionInfoDTO object + */ + fun from(revisionEntity: CustomRevisionEntity, changes: Map>): RevisionInfoDTO { + val result = RevisionInfoDTO() + result.author = revisionEntity.auditor + result.timestamp = revisionEntity.timestamp + result.id = revisionEntity.id + result.changes = changes.entries + .associateBy ( + { obj -> obj.key }, + { + it.value.groupBy { obj -> + obj.javaClass.getSimpleName().replace("DTO$".toRegex(), "").lowercase() + } + } + ) + + return result + } + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/RoleDTO.java b/src/main/java/org/radarbase/management/service/dto/RoleDTO.java deleted file mode 100644 index 8ecf6fc7d..000000000 --- a/src/main/java/org/radarbase/management/service/dto/RoleDTO.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.radarbase.management.service.dto; - -import com.fasterxml.jackson.annotation.JsonInclude; - -import java.util.Objects; - -/** - * Created by nivethika on 23-5-17. - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class RoleDTO { - private Long id; - - private Long organizationId; - - private String organizationName; - - private Long projectId; - - private String projectName; - - private String authorityName; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getOrganizationId() { - return organizationId; - } - - public void setOrganizationId(Long organizationId) { - this.organizationId = organizationId; - } - - public String getOrganizationName() { - return organizationName; - } - - public void setOrganizationName(String organizationName) { - this.organizationName = organizationName; - } - - public Long getProjectId() { - return projectId; - } - - public void setProjectId(Long projectId) { - this.projectId = projectId; - } - - public String getAuthorityName() { - return authorityName; - } - - public void setAuthorityName(String authorityName) { - this.authorityName = authorityName; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - @Override - public String toString() { - return "RoleDTO{" + "id=" + id - + ", organizationId=" + organizationId - + ", projectId=" + projectId - + ", authorityName='" + authorityName + '\'' - + '}'; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - RoleDTO roleDto = (RoleDTO) o; - - return Objects.equals(id, roleDto.id) - && Objects.equals(organizationId, roleDto.organizationId) - && Objects.equals(organizationName, roleDto.organizationName) - && Objects.equals(projectId, roleDto.projectId) - && Objects.equals(projectName, roleDto.projectName) - && Objects.equals(authorityName, roleDto.authorityName); - } - - @Override - public int hashCode() { - return id != null ? id.hashCode() : 0; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt b/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt new file mode 100644 index 000000000..73f60a599 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt @@ -0,0 +1,38 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude + +/** + * Created by nivethika on 23-5-17. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +class RoleDTO { + var id: Long? = null + var organizationId: Long? = null + var organizationName: String? = null + var projectId: Long? = null + var projectName: String? = null + var authorityName: String? = null + override fun toString(): String { + return ("RoleDTO{" + "id=" + id + + ", organizationId=" + organizationId + + ", projectId=" + projectId + + ", authorityName='" + authorityName + '\'' + + '}') + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val roleDto = o as RoleDTO + return id == roleDto.id && organizationId == roleDto.organizationId && organizationName == roleDto.organizationName && projectId == roleDto.projectId && projectName == roleDto.projectName && authorityName == roleDto.authorityName + } + + override fun hashCode(): Int { + return if (id != null) id.hashCode() else 0 + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.java b/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.java deleted file mode 100644 index 6798501f8..000000000 --- a/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.radarbase.management.service.dto; - - -import org.radarbase.management.config.ManagementPortalProperties; - -import java.io.Serializable; -import java.util.List; -import java.util.Objects; - -/** - * A DTO for the {@link ManagementPortalProperties.SiteSettings} entity. - */ -public class SiteSettingsDto implements Serializable { - - private List hiddenSubjectFields = List.of(); - - public List getHiddenSubjectFields() { - return hiddenSubjectFields; - } - - public void setHiddenSubjectFields(List hiddenSubjectFields) { - this.hiddenSubjectFields = hiddenSubjectFields; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o == null || getClass() != o.getClass()) { - return false; - } - SiteSettingsDto that = (SiteSettingsDto) o; - return Objects.equals(hiddenSubjectFields, that.hiddenSubjectFields); - } - - @Override - public int hashCode() { - return Objects.hash(hiddenSubjectFields); - } - - @Override - public String toString() { - return "SiteSettingsDTO{" - + "hiddenSubjectProperties=" - + hiddenSubjectFields - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt b/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt new file mode 100644 index 000000000..b45250e80 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt @@ -0,0 +1,33 @@ +package org.radarbase.management.service.dto + +import org.radarbase.management.config.ManagementPortalProperties +import java.io.Serializable +import java.util.* + +/** + * A DTO for the [ManagementPortalProperties.SiteSettings] entity. + */ +class SiteSettingsDto : Serializable { + var hiddenSubjectFields = listOf() + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val that = o as SiteSettingsDto + return hiddenSubjectFields == that.hiddenSubjectFields + } + + override fun hashCode(): Int { + return Objects.hash(hiddenSubjectFields) + } + + override fun toString(): String { + return ("SiteSettingsDTO{" + + "hiddenSubjectProperties=" + + hiddenSubjectFields + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDTO.java b/src/main/java/org/radarbase/management/service/dto/SourceDTO.java deleted file mode 100644 index c2ec2e436..000000000 --- a/src/main/java/org/radarbase/management/service/dto/SourceDTO.java +++ /dev/null @@ -1,152 +0,0 @@ -package org.radarbase.management.service.dto; - - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import java.io.Serializable; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; -import javax.validation.constraints.NotNull; - -/** - * A DTO for the Source entity. - */ -public class SourceDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - private Long id; - - private UUID sourceId; - - @NotNull - private String sourceName; - - private String expectedSourceName; - - @NotNull - private Boolean assigned; - - @NotNull - private SourceTypeDTO sourceType; - - private String subjectLogin; - - @JsonInclude(Include.NON_NULL) - private MinimalProjectDetailsDTO project; - - private Map attributes; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public UUID getSourceId() { - return sourceId; - } - - public void setSourceId(UUID sourceId) { - this.sourceId = sourceId; - } - - public Boolean getAssigned() { - return assigned; - } - - public void setAssigned(Boolean assigned) { - this.assigned = assigned; - } - - public SourceTypeDTO getSourceType() { - return sourceType; - } - - public void setSourceType(SourceTypeDTO sourceType) { - this.sourceType = sourceType; - } - - public MinimalProjectDetailsDTO getProject() { - return project; - } - - public void setProject(MinimalProjectDetailsDTO project) { - this.project = project; - } - - public Map getAttributes() { - return attributes; - } - - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - public String getSourceName() { - return sourceName; - } - - public void setSourceName(String sourceName) { - this.sourceName = sourceName; - } - - public String getExpectedSourceName() { - return expectedSourceName; - } - - public void setExpectedSourceName(String expectedSourceName) { - this.expectedSourceName = expectedSourceName; - } - - public String getSubjectLogin() { - return subjectLogin; - } - - public void setSubjectLogin(String subjectLogin) { - this.subjectLogin = subjectLogin; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - SourceDTO source = (SourceDTO) o; - return Objects.equals(id, source.id) - && Objects.equals(sourceId, source.sourceId) - && Objects.equals(sourceName, source.sourceName) - && Objects.equals(expectedSourceName, source.expectedSourceName) - && Objects.equals(assigned, source.assigned) - && Objects.equals(sourceType, source.sourceType) - && Objects.equals(subjectLogin, source.subjectLogin) - && Objects.equals(project, source.project) - && Objects.equals(attributes, source.attributes); - } - - @Override - public int hashCode() { - - return Objects.hash(id, sourceId, sourceName, expectedSourceName, assigned, sourceType, - subjectLogin, project, attributes); - } - - @Override - public String toString() { - return "SourceDTO{" - + "id=" + id - + ", sourceId='" + sourceId + '\'' - + ", sourceName='" + sourceName + '\'' - + ", assigned=" + assigned - + ", sourceType=" + sourceType - + ", project=" + project - + ", subjectLogin=" + subjectLogin - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt new file mode 100644 index 000000000..b7ff95330 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt @@ -0,0 +1,56 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import java.io.Serializable +import java.util.* +import javax.validation.constraints.NotNull + +/** + * A DTO for the Source entity. + */ +class SourceDTO : Serializable { + var id: Long? = null + var sourceId: UUID? = null + lateinit var sourceName: @NotNull String + var expectedSourceName: String? = null + var assigned: @NotNull Boolean? = null + lateinit var sourceType: @NotNull SourceTypeDTO + var subjectLogin: String? = null + + @JsonInclude(JsonInclude.Include.NON_NULL) + var project: MinimalProjectDetailsDTO? = null + var attributes: Map? = null + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val source = other as SourceDTO + return id == source.id && sourceId == source.sourceId && sourceName == source.sourceName && expectedSourceName == source.expectedSourceName && assigned == source.assigned && sourceType == source.sourceType && subjectLogin == source.subjectLogin && project == source.project && attributes == source.attributes + } + + override fun hashCode(): Int { + return Objects.hash( + id, sourceId, sourceName, expectedSourceName, assigned, sourceType, + subjectLogin, project, attributes + ) + } + + override fun toString(): String { + return ("SourceDTO{" + + "id=" + id + + ", sourceId='" + sourceId + '\'' + + ", sourceName='" + sourceName + '\'' + + ", assigned=" + assigned + + ", sourceType=" + sourceType + + ", project=" + project + + ", subjectLogin=" + subjectLogin + + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.java b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.java deleted file mode 100644 index fbf5019d4..000000000 --- a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.java +++ /dev/null @@ -1,195 +0,0 @@ -package org.radarbase.management.service.dto; - - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; - -import java.io.Serializable; -import java.util.Objects; - -/** - * A DTO for the SourceData entity. - */ -public class SourceDataDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - private Long id; - - //Source data type. - private String sourceDataType; - - private String sourceDataName; - - //Default data frequency - private String frequency; - - //Measurement unit. - private String unit; - - // Define if the samples are RAW data or instead they the result of some computation - private String processingState; - - // the storage - private String dataClass; - - private String keySchema; - - private String valueSchema; - - private String topic; - - private String provider; - - private boolean enabled = true; - - @JsonInclude(Include.NON_NULL) - private MinimalSourceTypeDTO sourceType; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getFrequency() { - return frequency; - } - - public void setFrequency(String frequency) { - this.frequency = frequency; - } - - /** Get source data type. Defaults to the topic of the source data. */ - public String getSourceDataType() { - if (sourceDataType == null) { - return topic; - } else { - return sourceDataType; - } - } - - public void setSourceDataType(String sourceDataType) { - this.sourceDataType = sourceDataType; - } - - public String getUnit() { - return unit; - } - - public void setUnit(String unit) { - this.unit = unit; - } - - public String getProcessingState() { - return processingState; - } - - public void setProcessingState(String processingState) { - this.processingState = processingState; - } - - public String getDataClass() { - return dataClass; - } - - public void setDataClass(String dataClass) { - this.dataClass = dataClass; - } - - public String getKeySchema() { - return keySchema; - } - - public void setKeySchema(String keySchema) { - this.keySchema = keySchema; - } - - public String getValueSchema() { - return valueSchema; - } - - public void setValueSchema(String valueSchema) { - this.valueSchema = valueSchema; - } - - public String getTopic() { - return topic; - } - - public void setTopic(String topic) { - this.topic = topic; - } - - public String getProvider() { - return provider; - } - - public void setProvider(String provider) { - this.provider = provider; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getSourceDataName() { - return sourceDataName; - } - - public void setSourceDataName(String sourceDataName) { - this.sourceDataName = sourceDataName; - } - - public MinimalSourceTypeDTO getSourceType() { - return sourceType; - } - - public void setSourceType(MinimalSourceTypeDTO sourceType) { - this.sourceType = sourceType; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - SourceDataDTO sourceDataDto = (SourceDataDTO) o; - if (sourceDataDto.id == null || id == null) { - return false; - } - return Objects.equals(id, sourceDataDto.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "SourceDataDTO{" - + "id=" + id - + ", sourceDataType='" + sourceDataType + '\'' - + ", sourceDataName='" + sourceDataName + '\'' - + ", frequency='" + frequency + '\'' - + ", unit='" + unit + '\'' - + ", processingState=" + processingState - + ", dataClass=" + dataClass - + ", keySchema='" + keySchema + '\'' - + ", valueSchema='" + valueSchema + '\'' - + ", topic='" + topic + '\'' - + ", provider='" + provider + '\'' - + ", enabled=" + enabled - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt new file mode 100644 index 000000000..187af33bd --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt @@ -0,0 +1,74 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import java.io.Serializable +import java.util.* + +/** + * A DTO for the SourceData entity. + */ +class SourceDataDTO : Serializable { + var id: Long? = null + + //Source data type. + var sourceDataType: String? = null + var sourceDataName: String? = null + + //Default data frequency + var frequency: String? = null + + //Measurement unit. + var unit: String? = null + + // Define if the samples are RAW data or the result of some computation + var processingState: String? = null + + // the storage + var dataClass: String? = null + var keySchema: String? = null + var valueSchema: String? = null + var topic: String? = null + var provider: String? = null + var isEnabled = true + + @JsonInclude(JsonInclude.Include.NON_NULL) + var sourceType: MinimalSourceTypeDTO? = null + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val sourceDataDto = o as SourceDataDTO + return if (sourceDataDto.id == null || id == null) { + false + } else id == sourceDataDto.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("SourceDataDTO{" + + "id=" + id + + ", sourceDataType='" + sourceDataType + '\'' + + ", sourceDataName='" + sourceDataName + '\'' + + ", frequency='" + frequency + '\'' + + ", unit='" + unit + '\'' + + ", processingState=" + processingState + + ", dataClass=" + dataClass + + ", keySchema='" + keySchema + '\'' + + ", valueSchema='" + valueSchema + '\'' + + ", topic='" + topic + '\'' + + ", provider='" + provider + '\'' + + ", enabled=" + isEnabled + + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.java b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.java deleted file mode 100644 index 16ca3da5b..000000000 --- a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.java +++ /dev/null @@ -1,177 +0,0 @@ -package org.radarbase.management.service.dto; - - -import java.io.Serializable; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import javax.validation.constraints.NotNull; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; - -/** - * A DTO for the SourceType entity. - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class SourceTypeDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - private Long id; - - @NotNull - private String producer; - - @NotNull - private String model; - - @NotNull - private String catalogVersion; - - @NotNull - private String sourceTypeScope; - - @NotNull - private Boolean canRegisterDynamically = false; - - private String name; - - private String description; - - private String assessmentType; - - private String appProvider; - - @JsonInclude(JsonInclude.Include.NON_EMPTY) - private Set sourceData = new HashSet<>(); - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getProducer() { - return producer; - } - - public void setProducer(String producer) { - this.producer = producer; - } - - public String getModel() { - return model; - } - - public String getCatalogVersion() { - return catalogVersion; - } - - public void setCatalogVersion(String catalogVersion) { - this.catalogVersion = catalogVersion; - } - - public void setModel(String model) { - this.model = model; - } - - public String getSourceTypeScope() { - return sourceTypeScope; - } - - public void setSourceTypeScope(String sourceTypeScope) { - this.sourceTypeScope = sourceTypeScope; - } - - public Set getSourceData() { - return sourceData; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setSourceData(Set sourceData) { - this.sourceData = sourceData; - } - - public Boolean getCanRegisterDynamically() { - return canRegisterDynamically; - } - - public void setCanRegisterDynamically(Boolean canRegisterDynamically) { - this.canRegisterDynamically = canRegisterDynamically; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getAssessmentType() { - return assessmentType; - } - - public void setAssessmentType(String assessmentType) { - this.assessmentType = assessmentType; - } - - public String getAppProvider() { - return appProvider; - } - - public void setAppProvider(String appProvider) { - this.appProvider = appProvider; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - SourceTypeDTO sourceTypeDto = (SourceTypeDTO) o; - - if (id == null || sourceTypeDto.id == null) { - return false; - } - - return Objects.equals(id, sourceTypeDto.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "SourceTypeDTO{" - + "id=" + id - + ", producer='" + producer + "'" - + ", model='" + model + "'" - + ", catalogVersion='" + catalogVersion + "'" - + ", sourceTypeScope='" + sourceTypeScope + "'" - + ", canRegisterDynamically='" + canRegisterDynamically + "'" - + ", name='" + name + '\'' - + ", description=" + description - + ", appProvider=" + appProvider - + ", assessmentType=" + assessmentType - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt new file mode 100644 index 000000000..1eb8c3b85 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt @@ -0,0 +1,64 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import java.io.Serializable +import java.util.* +import javax.validation.constraints.NotNull + +/** + * A DTO for the SourceType entity. + */ +@JsonInclude(JsonInclude.Include.NON_NULL) +class SourceTypeDTO : Serializable { + var id: Long? = null + lateinit var producer: @NotNull String + lateinit var model: @NotNull String + lateinit var catalogVersion: @NotNull String + lateinit var sourceTypeScope: @NotNull String + var canRegisterDynamically: @NotNull Boolean = false + var name: String? = null + var description: String? = null + var assessmentType: String? = null + var appProvider: String? = null + + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonInclude(JsonInclude.Include.NON_EMPTY) + var sourceData: Set = HashSet() + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val sourceTypeDto = other as SourceTypeDTO + return if (id == null || sourceTypeDto.id == null) { + false + } else id == sourceTypeDto.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("SourceTypeDTO{" + + "id=" + id + + ", producer='" + producer + "'" + + ", model='" + model + "'" + + ", catalogVersion='" + catalogVersion + "'" + + ", sourceTypeScope='" + sourceTypeScope + "'" + + ", canRegisterDynamically='" + canRegisterDynamically + "'" + + ", name='" + name + '\'' + + ", description=" + description + + ", appProvider=" + appProvider + + ", assessmentType=" + assessmentType + + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/SubjectDTO.java b/src/main/java/org/radarbase/management/service/dto/SubjectDTO.java deleted file mode 100644 index 4c5eeb39d..000000000 --- a/src/main/java/org/radarbase/management/service/dto/SubjectDTO.java +++ /dev/null @@ -1,256 +0,0 @@ -package org.radarbase.management.service.dto; - - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.annotation.Nulls; - -import java.io.Serializable; -import java.time.LocalDate; -import java.time.ZonedDateTime; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; -import java.util.ArrayList; - -/** - * A DTO for the Subject entity. - */ -public class SubjectDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - public enum SubjectStatus { - DEACTIVATED, // activated = false, removed = false - ACTIVATED, // activated = true, removed = false - DISCONTINUED, // activated = false, removed = true - INVALID // activated = true, removed = true (invalid state, makes no sense) - } - - public static final String HUMAN_READABLE_IDENTIFIER_KEY = "Human-readable-identifier"; - - private Long id; - - private String login; - - private String externalLink; - - private String externalId; - - private SubjectStatus status = SubjectStatus.DEACTIVATED; - - @JsonInclude(Include.NON_NULL) - private String createdBy; - - @JsonInclude(Include.NON_NULL) - private ZonedDateTime createdDate; - - @JsonInclude(Include.NON_NULL) - private String lastModifiedBy; - - @JsonInclude(Include.NON_NULL) - private ZonedDateTime lastModifiedDate; - - @JsonInclude(Include.NON_NULL) - private ProjectDTO project; - - private String group; - - private LocalDate dateOfBirth; - - private ZonedDateTime enrollmentDate; - - private String personName; - - private List roles = new ArrayList<>(); - - private Set sources = new HashSet<>(); - - private Map attributes = new HashMap<>(); - - public SubjectStatus getStatus() { - return status; - } - - public String getPersonName() { - return personName; - } - - public void setPersonName(String personName) { - this.personName = personName; - } - - public void setStatus(SubjectStatus status) { - this.status = status; - } - - - public String getCreatedBy() { - return createdBy; - } - - public void setCreatedBy(String createdBy) { - this.createdBy = createdBy; - } - - public ProjectDTO getProject() { - return project; - } - - public void setProject(ProjectDTO project) { - this.project = project; - } - - public String getGroup() { - return group; - } - - public void setGroup(String group) { - this.group = group; - } - - public LocalDate getDateOfBirth() { - return this.dateOfBirth; - } - - public void setDateOfBirth(LocalDate dateOfBirth) { - this.dateOfBirth = dateOfBirth; - } - - public void setEnrollmentDate(ZonedDateTime enrollmentDate) { - this.enrollmentDate = enrollmentDate; - } - - public ZonedDateTime getEnrollmentDate() { - return this.enrollmentDate; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public ZonedDateTime getCreatedDate() { - return createdDate; - } - - public void setCreatedDate(ZonedDateTime createdDate) { - this.createdDate = createdDate; - } - - public String getLastModifiedBy() { - return lastModifiedBy; - } - - public void setLastModifiedBy(String lastModifiedBy) { - this.lastModifiedBy = lastModifiedBy; - } - - public ZonedDateTime getLastModifiedDate() { - return lastModifiedDate; - } - - public void setLastModifiedDate(ZonedDateTime lastModifiedDate) { - this.lastModifiedDate = lastModifiedDate; - } - - public String getExternalLink() { - return externalLink; - } - - public void setExternalLink(String externalLink) { - this.externalLink = externalLink; - } - - public String getExternalId() { - return externalId; - } - - public void setExternalId(String externalId) { - this.externalId = externalId; - } - - public List getRoles() { - return roles; - } - - @JsonSetter(nulls = Nulls.AS_EMPTY) - public void setRoles(List roles) { - this.roles = roles; - } - - /** - * Gets the login. If no login is present, a new UUID is generated and stored as the login - * before returning it. - * @return the login - */ - public String getLogin() { - if (this.login == null) { - this.login = UUID.randomUUID().toString(); - } - return login; - } - - public void setLogin(String login) { - this.login = login; - } - - public Set getSources() { - return sources; - } - - public void setSources(Set sources) { - this.sources = sources; - } - - public Map getAttributes() { - return attributes; - } - - public void setAttributes(Map attributes) { - this.attributes = attributes; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - SubjectDTO subjectDto = (SubjectDTO) o; - - if (id == null || subjectDto.id == null) { - return false; - } - - return !Objects.equals(id, subjectDto.id); - } - - @Override - public int hashCode() { - return Objects.hashCode(id); - } - - @Override - public String toString() { - return "SubjectDTO{" - + "id=" + id - + ", login='" + login + '\'' - + ", externalLink='" + externalLink + '\'' - + ", externalId='" + externalId + '\'' - + ", status=" + status - + ", project=" + (project == null ? "null" : project.getProjectName()) - + ", attributes=" + attributes + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt b/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt new file mode 100644 index 000000000..337ec975d --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt @@ -0,0 +1,96 @@ +package org.radarbase.management.service.dto + +import com.fasterxml.jackson.annotation.JsonInclude +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.annotation.Nulls +import java.io.Serializable +import java.time.LocalDate +import java.time.ZonedDateTime +import java.util.* + +/** + * A DTO for the Subject entity. + */ +class SubjectDTO : Serializable { + enum class SubjectStatus { + DEACTIVATED, + + // activated = false, removed = false + ACTIVATED, + + // activated = true, removed = false + DISCONTINUED, + + // activated = false, removed = true + INVALID // activated = true, removed = true (invalid state, makes no sense) + } + + var id: Long? = null + private var _login: String? = null + var login: String? + get() = { + if (_login == null) { + _login = UUID.randomUUID().toString() + _login + } else { + _login + } + }.toString() + set(value) { + _login = value + } + + var externalLink: String? = null + var externalId: String? = null + var status = SubjectStatus.DEACTIVATED + + @JsonInclude(JsonInclude.Include.NON_NULL) + var createdBy: String? = null + + @JsonInclude(JsonInclude.Include.NON_NULL) + var createdDate: ZonedDateTime? = null + + @JsonInclude(JsonInclude.Include.NON_NULL) + var lastModifiedBy: String? = null + + @JsonInclude(JsonInclude.Include.NON_NULL) + var lastModifiedDate: ZonedDateTime? = null + + @JsonInclude(JsonInclude.Include.NON_NULL) + var project: ProjectDTO? = null + var group: String? = null + var dateOfBirth: LocalDate? = null + var enrollmentDate: ZonedDateTime? = null + var personName: String? = null + + @set:JsonSetter(nulls = Nulls.AS_EMPTY) + var roles: List = ArrayList() + var sources: Set = HashSet() + var attributes: Map = HashMap() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || javaClass != other.javaClass) { + return false + } + val subjectDto = other as SubjectDTO + return if (id == null || subjectDto.id == null) { + false + } else id != subjectDto.id + } + + override fun hashCode(): Int { + return Objects.hashCode(id) + } + + override fun toString(): String { + return ("SubjectDTO{" + "id=" + id + ", login='" + login + '\'' + ", externalLink='" + externalLink + '\'' + ", externalId='" + externalId + '\'' + ", status=" + status + ", project=" + (project?.projectName) + ", attributes=" + attributes + '}') + } + + companion object { + private const val serialVersionUID = 1L + const val HUMAN_READABLE_IDENTIFIER_KEY = "Human-readable-identifier" + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/TokenDTO.java b/src/main/java/org/radarbase/management/service/dto/TokenDTO.java deleted file mode 100644 index ca891ff6e..000000000 --- a/src/main/java/org/radarbase/management/service/dto/TokenDTO.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.net.URL; -import java.util.Objects; - -public class TokenDTO { - private final String refreshToken; - - private final URL baseUrl; - - private final URL privacyPolicyUrl; - - /** - * Create a meta-token using refreshToken, baseUrl of platform, and privacyPolicyURL for this - * token. - * @param refreshToken refreshToken. - * @param baseUrl baseUrl of the platform - * @param privacyPolicyUrl privacyPolicyUrl for this token. - */ - public TokenDTO(String refreshToken, URL baseUrl, URL privacyPolicyUrl) { - this.refreshToken = refreshToken; - this.baseUrl = baseUrl; - this.privacyPolicyUrl = privacyPolicyUrl; - } - - public String getRefreshToken() { - return refreshToken; - } - - public URL getBaseUrl() { - return baseUrl; - } - - public URL getPrivacyPolicyUrl() { - return privacyPolicyUrl; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TokenDTO that = (TokenDTO) o; - return Objects.equals(refreshToken, that.refreshToken) - && Objects.equals(baseUrl, that.baseUrl) - && Objects.equals(privacyPolicyUrl, that.privacyPolicyUrl); - } - - @Override - public int hashCode() { - - return Objects.hash(refreshToken, baseUrl, privacyPolicyUrl); - } - - @Override - public String toString() { - return "TokenDTO{" - + "refreshToken='" + refreshToken - + ", baseUrl=" + baseUrl - + ", privacyPolicyUrl=" + privacyPolicyUrl - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt b/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt new file mode 100644 index 000000000..df681db36 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt @@ -0,0 +1,37 @@ +package org.radarbase.management.service.dto + +import java.net.URL +import java.util.* + +class TokenDTO +/** + * Create a meta-token using refreshToken, baseUrl of platform, and privacyPolicyURL for this + * token. + * @param refreshToken refreshToken. + * @param baseUrl baseUrl of the platform + * @param privacyPolicyUrl privacyPolicyUrl for this token. + */(val refreshToken: String, val baseUrl: URL, val privacyPolicyUrl: URL) { + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val that = o as TokenDTO + return refreshToken == that.refreshToken && baseUrl == that.baseUrl && privacyPolicyUrl == that.privacyPolicyUrl + } + + override fun hashCode(): Int { + return Objects.hash(refreshToken, baseUrl, privacyPolicyUrl) + } + + override fun toString(): String { + return ("TokenDTO{" + + "refreshToken='" + refreshToken + + ", baseUrl=" + baseUrl + + ", privacyPolicyUrl=" + privacyPolicyUrl + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/UserDTO.java b/src/main/java/org/radarbase/management/service/dto/UserDTO.java deleted file mode 100644 index 8965981b3..000000000 --- a/src/main/java/org/radarbase/management/service/dto/UserDTO.java +++ /dev/null @@ -1,177 +0,0 @@ -package org.radarbase.management.service.dto; - -import java.time.ZonedDateTime; -import java.util.Set; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; -import org.hibernate.validator.constraints.Email; -import org.radarbase.management.security.Constants; - -/** - * A DTO representing a user, with his authorities. - */ -public class UserDTO { - - private Long id; - - @Pattern(regexp = Constants.ENTITY_ID_REGEX) - @Size(min = 1, max = 50) - private String login; - - @Size(max = 50) - private String firstName; - - @Size(max = 50) - private String lastName; - - @Email - @Size(min = 5, max = 100) - private String email; - - private boolean activated = false; - - @Size(min = 2, max = 5) - private String langKey; - - private String createdBy; - - private ZonedDateTime createdDate; - - private String lastModifiedBy; - - private ZonedDateTime lastModifiedDate; - - private Set roles; - - private Set authorities; - - private String accessToken; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getLogin() { - return login; - } - - public void setLogin(String login) { - this.login = login; - } - - public String getFirstName() { - return firstName; - } - - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - public String getLastName() { - return lastName; - } - - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public boolean isActivated() { - return activated; - } - - public void setActivated(boolean activated) { - this.activated = activated; - } - - public String getLangKey() { - return langKey; - } - - public void setLangKey(String langKey) { - this.langKey = langKey; - } - - public String getCreatedBy() { - return createdBy; - } - - public void setCreatedBy(String createdBy) { - this.createdBy = createdBy; - } - - public ZonedDateTime getCreatedDate() { - return createdDate; - } - - public void setCreatedDate(ZonedDateTime createdDate) { - this.createdDate = createdDate; - } - - public String getLastModifiedBy() { - return lastModifiedBy; - } - - public void setLastModifiedBy(String lastModifiedBy) { - this.lastModifiedBy = lastModifiedBy; - } - - public ZonedDateTime getLastModifiedDate() { - return lastModifiedDate; - } - - public void setLastModifiedDate(ZonedDateTime lastModifiedDate) { - this.lastModifiedDate = lastModifiedDate; - } - - public Set getAuthorities() { - return authorities; - } - - public void setAuthorities(Set authorities) { - this.authorities = authorities; - } - - public Set getRoles() { - return roles; - } - - public void setRoles(Set roles) { - this.roles = roles; - } - - public String getAccessToken() { - return accessToken; - } - - public void setAccessToken(String accessToken) { - this.accessToken = accessToken; - } - - @Override - public String toString() { - return "UserDTO{" - + "login='" + login + '\'' - + ", firstName='" + firstName + '\'' - + ", lastName='" + lastName + '\'' - + ", email='" + email + '\'' - + ", activated=" + activated - + ", langKey='" + langKey + '\'' - + ", createdBy=" + createdBy - + ", createdDate=" + createdDate - + ", lastModifiedBy='" + lastModifiedBy + '\'' - + ", lastModifiedDate=" + lastModifiedDate - + "}"; - } -} diff --git a/src/main/java/org/radarbase/management/service/dto/UserDTO.kt b/src/main/java/org/radarbase/management/service/dto/UserDTO.kt new file mode 100644 index 000000000..204bf4b4a --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/UserDTO.kt @@ -0,0 +1,40 @@ +package org.radarbase.management.service.dto + +import org.hibernate.validator.constraints.Email +import java.time.ZonedDateTime +import javax.validation.constraints.Pattern +import javax.validation.constraints.Size + +/** + * A DTO representing a user, with his authorities. + */ +open class UserDTO { + var id: Long? = null + lateinit var login: @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") @Size(max = 50, min = 1) String + var firstName: @Size(max = 50) String? = null + var lastName: @Size(max = 50) String? = null + var email: @Email @Size(min = 5, max = 100) String? = null + var isActivated = false + var langKey: @Size(min = 2, max = 5) String? = null + var createdBy: String? = null + var createdDate: ZonedDateTime? = null + var lastModifiedBy: String? = null + var lastModifiedDate: ZonedDateTime? = null + var roles: Set? = null + var authorities: Set? = null + var accessToken: String? = null + override fun toString(): String { + return ("UserDTO{" + + "login='" + login + '\'' + + ", firstName='" + firstName + '\'' + + ", lastName='" + lastName + '\'' + + ", email='" + email + '\'' + + ", activated=" + isActivated + + ", langKey='" + langKey + '\'' + + ", createdBy=" + createdBy + + ", createdDate=" + createdDate + + ", lastModifiedBy='" + lastModifiedBy + '\'' + + ", lastModifiedDate=" + lastModifiedDate + + "}") + } +} diff --git a/src/main/java/org/radarbase/management/service/dto/package-info.java b/src/main/java/org/radarbase/management/service/dto/package-info.java deleted file mode 100644 index 56a5af8f8..000000000 --- a/src/main/java/org/radarbase/management/service/dto/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Data Transfer Objects. - * - *

The names of the classes in this package should end in {@code DTO}.

- */ -package org.radarbase.management.service.dto; diff --git a/src/main/java/org/radarbase/management/service/dto/package-info.kt b/src/main/java/org/radarbase/management/service/dto/package-info.kt new file mode 100644 index 000000000..7725988f2 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/dto/package-info.kt @@ -0,0 +1,8 @@ +/** + * Data Transfer Objects. + * + * + * The names of the classes in this package should end in `DTO`. + */ +package org.radarbase.management.service.dto + diff --git a/src/main/java/org/radarbase/management/service/mapper/CatalogSourceDataMapper.java b/src/main/java/org/radarbase/management/service/mapper/CatalogSourceDataMapper.kt similarity index 55% rename from src/main/java/org/radarbase/management/service/mapper/CatalogSourceDataMapper.java rename to src/main/java/org/radarbase/management/service/mapper/CatalogSourceDataMapper.kt index 3c5fd6af4..3e405ffa1 100644 --- a/src/main/java/org/radarbase/management/service/mapper/CatalogSourceDataMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/CatalogSourceDataMapper.kt @@ -1,14 +1,12 @@ -package org.radarbase.management.service.mapper; +package org.radarbase.management.service.mapper -import java.util.List; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.service.catalog.CatalogSourceData; +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.radarbase.management.domain.SourceData +import org.radarbase.management.service.catalog.CatalogSourceData @Mapper(componentModel = "spring") -public interface CatalogSourceDataMapper { - +interface CatalogSourceDataMapper { @Mapping(target = "id", ignore = true) @Mapping(source = "type", target = "sourceDataType") @Mapping(target = "sourceDataName", ignore = true) @@ -17,8 +15,8 @@ public interface CatalogSourceDataMapper { @Mapping(source = "appProvider", target = "provider") @Mapping(target = "enabled", expression = "java(true)") @Mapping(target = "sourceType", ignore = true) - SourceData catalogSourceDataToSourceData(CatalogSourceData catalogSourceData); - - List catalogSourceDataListToSourceDataList( - List catalogSourceType); + fun catalogSourceDataToSourceData(catalogSourceData: CatalogSourceData?): SourceData? + fun catalogSourceDataListToSourceDataList( + catalogSourceType: List? + ): List? } diff --git a/src/main/java/org/radarbase/management/service/mapper/CatalogSourceTypeMapper.java b/src/main/java/org/radarbase/management/service/mapper/CatalogSourceTypeMapper.kt similarity index 56% rename from src/main/java/org/radarbase/management/service/mapper/CatalogSourceTypeMapper.java rename to src/main/java/org/radarbase/management/service/mapper/CatalogSourceTypeMapper.kt index d822315e0..98a8cfe9b 100644 --- a/src/main/java/org/radarbase/management/service/mapper/CatalogSourceTypeMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/CatalogSourceTypeMapper.kt @@ -1,14 +1,12 @@ -package org.radarbase.management.service.mapper; +package org.radarbase.management.service.mapper -import java.util.List; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.service.catalog.CatalogSourceType; +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.radarbase.management.domain.SourceType +import org.radarbase.management.service.catalog.CatalogSourceType @Mapper(componentModel = "spring") -public interface CatalogSourceTypeMapper { - +interface CatalogSourceTypeMapper { @Mapping(source = "vendor", target = "producer") @Mapping(source = "version", target = "catalogVersion") @Mapping(source = "doc", target = "description") @@ -17,7 +15,6 @@ public interface CatalogSourceTypeMapper { @Mapping(target = "id", ignore = true) @Mapping(target = "projects", ignore = true) @Mapping(target = "canRegisterDynamically", ignore = true) - SourceType catalogSourceTypeToSourceType(CatalogSourceType catalogSourceType); - - List catalogSourceTypesToSourceTypes(List catalogSourceType); + fun catalogSourceTypeToSourceType(catalogSourceType: CatalogSourceType?): SourceType? + fun catalogSourceTypesToSourceTypes(catalogSourceType: List?): List? } diff --git a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java deleted file mode 100644 index 70f8d0c9f..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.radarbase.management.service.mapper; - -import org.mapstruct.DecoratedWith; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.radarbase.management.service.dto.ClientDetailsDTO; -import org.radarbase.management.service.mapper.decorator.ClientDetailsMapperDecorator; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.security.oauth2.provider.client.BaseClientDetails; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * Created by dverbeec on 7/09/2017. - */ -@Mapper(componentModel = "spring", uses = {BaseClientDetails.class}) -@DecoratedWith(ClientDetailsMapperDecorator.class) -public interface ClientDetailsMapper { - - @Mapping(target = "clientSecret", ignore = true) - @Mapping(target = "autoApproveScopes", ignore = true) - ClientDetailsDTO clientDetailsToClientDetailsDTO(ClientDetails details); - - List clientDetailsToClientDetailsDTO(List detailsList); - - BaseClientDetails clientDetailsDTOToClientDetails(ClientDetailsDTO detailsDto); - - List clientDetailsDTOToClientDetails(List detailsDtoList); - - /** - * Map a set of authorities represented as strings to a collection of {@link GrantedAuthority}s. - * @param authorities the set of authorities to be mapped - * @return a collection of {@link GrantedAuthority}s - */ - default Collection map(Set authorities) { - if (Objects.isNull(authorities)) { - return Collections.emptySet(); - } - return authorities.stream() - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - } - - /** - * Map a collection of authorities represented as {@link GrantedAuthority}s to a set of strings. - * @param authorities the collection of {@link GrantedAuthority}s to be mapped - * @return the set of strings - */ - default Set map(Collection authorities) { - if (Objects.isNull(authorities)) { - return Collections.emptySet(); - } - return authorities.stream() - .map(GrantedAuthority::getAuthority) - .collect(Collectors.toSet()); - } - - /** - * Transforms the values in the input map to strings so the result is a - * {@link Map}. - * @param additionalInformation a {@link Map} to be transformed - * @return a new map with the same keys as the input map, but the values are transformed to - * strings using their {@link Object#toString()} method - */ - default Map map(Map additionalInformation) { - if (Objects.isNull(additionalInformation)) { - return Collections.emptyMap(); - } - return additionalInformation.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString())); - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt new file mode 100644 index 000000000..7d4258077 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt @@ -0,0 +1,72 @@ +package org.radarbase.management.service.mapper + +import org.mapstruct.DecoratedWith +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.radarbase.management.service.dto.ClientDetailsDTO +import org.radarbase.management.service.mapper.decorator.ClientDetailsMapperDecorator +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.oauth2.provider.ClientDetails +import org.springframework.security.oauth2.provider.client.BaseClientDetails +import java.util.* +import java.util.stream.Collectors + +/** + * Created by dverbeec on 7/09/2017. + */ +@Mapper(componentModel = "spring", uses = [BaseClientDetails::class]) +@DecoratedWith( + ClientDetailsMapperDecorator::class +) +interface ClientDetailsMapper { + @Mapping(target = "clientSecret", ignore = true) + @Mapping(target = "autoApproveScopes", ignore = true) + fun clientDetailsToClientDetailsDTO(details: ClientDetails): ClientDetailsDTO + fun clientDetailsToClientDetailsDTO(detailsList: List): List? + fun clientDetailsDTOToClientDetails(detailsDto: ClientDetailsDTO?): BaseClientDetails + fun clientDetailsDTOToClientDetails(detailsDtoList: List): List + + /** + * Map a set of authorities represented as strings to a collection of [GrantedAuthority]s. + * @param authorities the set of authorities to be mapped + * @return a collection of [GrantedAuthority]s + */ + fun map(authorities: Set): Collection? { + return if (Objects.isNull(authorities)) { + emptySet() + } else authorities.stream() + .map { role: String? -> SimpleGrantedAuthority(role) } + .collect(Collectors.toList()) + } + + /** + * Map a collection of authorities represented as [GrantedAuthority]s to a set of strings. + * @param authorities the collection of [GrantedAuthority]s to be mapped + * @return the set of strings + */ + fun map(authorities: Collection): Set? { + return if (Objects.isNull(authorities)) { + emptySet() + } else authorities.stream() + .map { obj: GrantedAuthority -> obj.authority } + .collect(Collectors.toSet()) + } + + /** + * Transforms the values in the input map to strings so the result is a + * [Map]. + * @param additionalInformation a [Map] to be transformed + * @return a new map with the same keys as the input map, but the values are transformed to + * strings using their [Object.toString] method + */ + fun map(additionalInformation: Map): Map? { + return if (Objects.isNull(additionalInformation)) { + emptyMap() + } else additionalInformation.entries + .associateBy( + { it.key }, + { e -> e.value.toString() } + ) + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/GroupMapper.java b/src/main/java/org/radarbase/management/service/mapper/GroupMapper.kt similarity index 53% rename from src/main/java/org/radarbase/management/service/mapper/GroupMapper.java rename to src/main/java/org/radarbase/management/service/mapper/GroupMapper.kt index 50962275f..451741d3b 100644 --- a/src/main/java/org/radarbase/management/service/mapper/GroupMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/GroupMapper.kt @@ -6,38 +6,34 @@ * * See the file LICENSE in the root of this repository. */ +package org.radarbase.management.service.mapper -package org.radarbase.management.service.mapper; - -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.MappingConstants; -import org.mapstruct.Named; -import org.radarbase.management.domain.Group; -import org.radarbase.management.service.dto.GroupDTO; - -import java.util.Collection; -import java.util.List; +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.MappingConstants +import org.mapstruct.Named +import org.radarbase.management.domain.Group +import org.radarbase.management.service.dto.GroupDTO @Mapper(componentModel = MappingConstants.ComponentModel.SPRING) -public interface GroupMapper { +interface GroupMapper { @Named("groupToGroupDTO") @Mapping(target = "id", ignore = true) @Mapping(target = "projectId", ignore = true) @Mapping(target = "name", source = "name") - GroupDTO groupToGroupDTO(Group group); + fun groupToGroupDTO(group: Group): GroupDTO @Named("groupToGroupDTOFull") @Mapping(source = "project.id", target = "projectId") @Mapping(target = "name", source = "name") - GroupDTO groupToGroupDTOFull(Group group); + fun groupToGroupDTOFull(group: Group): GroupDTO @Mapping(target = "id", ignore = true) @Mapping(target = "project.id", ignore = true) @Mapping(target = "name", source = "name") - Group groupDTOToGroup(GroupDTO groupDto); + fun groupDTOToGroup(groupDto: GroupDTO): Group - @IterableMapping(qualifiedByName = "groupToGroupDTOFull") - List groupToGroupDTOs(Collection groups); + @IterableMapping(qualifiedByName = ["groupToGroupDTOFull"]) + fun groupToGroupDTOs(groups: Collection): List } diff --git a/src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.java b/src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.java deleted file mode 100644 index 120f24a45..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.radarbase.management.service.mapper; - -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.radarbase.management.domain.Organization; -import org.radarbase.management.service.dto.OrganizationDTO; - -import java.util.List; - -/** - * Mapper for the entity Organization and its DTO OrganizationDTO. - */ -@Mapper(componentModel = "spring", uses = {ProjectMapper.class}) -public interface OrganizationMapper { - @Named("organizationToOrganizationDTO") - @Mapping(target = "projects", qualifiedByName = "projectReducedDTO") - OrganizationDTO organizationToOrganizationDTO(Organization organization); - - @Named("organizationToOrganizationDTOWithoutProjects") - @Mapping(target = "projects", ignore = true) - OrganizationDTO organizationToOrganizationDTOWithoutProjects(Organization organization); - - @Mapping(target = "projects", ignore = true) - Organization organizationDTOToOrganization(OrganizationDTO organizationDto); - - @IterableMapping(qualifiedByName = "organizationToOrganizationDTO") - List organizationsToOrganizationDTOs(List organizations); -} diff --git a/src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.kt b/src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.kt new file mode 100644 index 000000000..f5fe06a37 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/OrganizationMapper.kt @@ -0,0 +1,28 @@ +package org.radarbase.management.service.mapper + +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.Named +import org.radarbase.management.domain.Organization +import org.radarbase.management.service.dto.OrganizationDTO + +/** + * Mapper for the entity Organization and its DTO OrganizationDTO. + */ +@Mapper(componentModel = "spring", uses = [ProjectMapper::class]) +interface OrganizationMapper { + @Named("organizationToOrganizationDTO") + @Mapping(target = "projects", qualifiedByName = ["projectReducedDTO"]) + fun organizationToOrganizationDTO(organization: Organization): OrganizationDTO + + @Named("organizationToOrganizationDTOWithoutProjects") + @Mapping(target = "projects", ignore = true) + fun organizationToOrganizationDTOWithoutProjects(organization: Organization): OrganizationDTO + + @Mapping(target = "projects", ignore = true) + fun organizationDTOToOrganization(organizationDto: OrganizationDTO): Organization + + @IterableMapping(qualifiedByName = ["organizationToOrganizationDTO"]) + fun organizationsToOrganizationDTOs(organizations: List): List +} diff --git a/src/main/java/org/radarbase/management/service/mapper/ProjectMapper.java b/src/main/java/org/radarbase/management/service/mapper/ProjectMapper.java deleted file mode 100644 index 48df0de89..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/ProjectMapper.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.radarbase.management.service.mapper; - -import java.util.List; -import org.mapstruct.DecoratedWith; -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.radarbase.management.domain.Project; -import org.radarbase.management.service.dto.MinimalProjectDetailsDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.mapper.decorator.ProjectMapperDecorator; - -/** - * Mapper for the entity Project and its DTO ProjectDTO. - */ -@Mapper(componentModel = "spring", - uses = {GroupMapper.class, SourceTypeMapper.class, OrganizationMapper.class}) -@DecoratedWith(ProjectMapperDecorator.class) -public interface ProjectMapper { - @Mapping(target = "humanReadableProjectName", ignore = true) - @Mapping(target = "organization", source = "organization", - qualifiedByName = "organizationToOrganizationDTOWithoutProjects") - @Mapping(target = "persistentTokenTimeout", ignore = true) - @Mapping(target = "groups", qualifiedByName = "groupToGroupDTO") - @Mapping(target = "sourceTypes", qualifiedByName = "sourceTypeToSourceTypeDTOReduced") - ProjectDTO projectToProjectDTO(Project project); - - @Named(value = "projectReducedDTO") - @Mapping(target = "humanReadableProjectName", ignore = true) - @Mapping(target = "organization", ignore = true) - @Mapping(target = "sourceTypes", ignore = true) - @Mapping(target = "persistentTokenTimeout", ignore = true) - @Mapping(target = "groups", qualifiedByName = "groupToGroupDTO") - ProjectDTO projectToProjectDTOReduced(Project project); - - @IterableMapping(qualifiedByName = "projectReducedDTO") - List projectsToProjectDTOs(List projects); - - @Mapping(target = "roles", ignore = true) - @Mapping(target = "groups", ignore = true) - @Mapping(target = "organization", ignore = true) - Project projectDTOToProject(ProjectDTO projectDto); - - List projectDTOsToProjects(List projectDtos); - - MinimalProjectDetailsDTO projectToMinimalProjectDetailsDTO(Project project); - - List projectsToMinimalProjectDetailsDTOs(List projects); - - @Mapping(target = "description", ignore = true) - @Mapping(target = "roles", ignore = true) - @Mapping(target = "organizationName", ignore = true) - @Mapping(target = "organization", ignore = true) - @Mapping(target = "location", ignore = true) - @Mapping(target = "startDate", ignore = true) - @Mapping(target = "endDate", ignore = true) - @Mapping(target = "projectStatus", ignore = true) - @Mapping(target = "sourceTypes", ignore = true) - @Mapping(target = "attributes", ignore = true) - @Mapping(target = "groups", ignore = true) - Project descriptiveDTOToProject(MinimalProjectDetailsDTO minimalProjectDetailsDto); - - List descriptiveDTOsToProjects( - List minimalProjectDetailsDtos); -} diff --git a/src/main/java/org/radarbase/management/service/mapper/ProjectMapper.kt b/src/main/java/org/radarbase/management/service/mapper/ProjectMapper.kt new file mode 100644 index 000000000..dfba59d60 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/ProjectMapper.kt @@ -0,0 +1,66 @@ +package org.radarbase.management.service.mapper + +import org.mapstruct.DecoratedWith +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.Named +import org.radarbase.management.domain.Project +import org.radarbase.management.service.dto.MinimalProjectDetailsDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.mapper.decorator.ProjectMapperDecorator + +/** + * Mapper for the entity Project and its DTO ProjectDTO. + */ +@Mapper(componentModel = "spring", uses = [GroupMapper::class, SourceTypeMapper::class, OrganizationMapper::class]) +@DecoratedWith( + ProjectMapperDecorator::class +) +interface ProjectMapper { + @Mapping(target = "humanReadableProjectName", ignore = true) + @Mapping( + target = "organization", + source = "organization", + qualifiedByName = ["organizationToOrganizationDTOWithoutProjects"] + ) + @Mapping(target = "persistentTokenTimeout", ignore = true) + @Mapping(target = "groups", qualifiedByName = ["groupToGroupDTO"]) + @Mapping(target = "sourceTypes", qualifiedByName = ["sourceTypeToSourceTypeDTOReduced"]) + fun projectToProjectDTO(project: Project?): ProjectDTO? + + @Named(value = "projectReducedDTO") + @Mapping(target = "humanReadableProjectName", ignore = true) + @Mapping(target = "organization", ignore = true) + @Mapping(target = "sourceTypes", ignore = true) + @Mapping(target = "persistentTokenTimeout", ignore = true) + @Mapping(target = "groups", qualifiedByName = ["groupToGroupDTO"]) + fun projectToProjectDTOReduced(project: Project?): ProjectDTO? + + @IterableMapping(qualifiedByName = ["projectReducedDTO"]) + fun projectsToProjectDTOs(projects: List): List + + @Mapping(target = "roles", ignore = true) + @Mapping(target = "groups", ignore = true) + @Mapping(target = "organization", ignore = true) + fun projectDTOToProject(projectDto: ProjectDTO?): Project? + fun projectDTOsToProjects(projectDtos: List): List + fun projectToMinimalProjectDetailsDTO(project: Project): MinimalProjectDetailsDTO + fun projectsToMinimalProjectDetailsDTOs(projects: List): List + + @Mapping(target = "description", ignore = true) + @Mapping(target = "roles", ignore = true) + @Mapping(target = "organizationName", ignore = true) + @Mapping(target = "organization", ignore = true) + @Mapping(target = "location", ignore = true) + @Mapping(target = "startDate", ignore = true) + @Mapping(target = "endDate", ignore = true) + @Mapping(target = "projectStatus", ignore = true) + @Mapping(target = "sourceTypes", ignore = true) + @Mapping(target = "attributes", ignore = true) + @Mapping(target = "groups", ignore = true) + fun descriptiveDTOToProject(minimalProjectDetailsDto: MinimalProjectDetailsDTO?): Project? + fun descriptiveDTOsToProjects( + minimalProjectDetailsDtos: List + ): List +} diff --git a/src/main/java/org/radarbase/management/service/mapper/RoleMapper.java b/src/main/java/org/radarbase/management/service/mapper/RoleMapper.kt similarity index 52% rename from src/main/java/org/radarbase/management/service/mapper/RoleMapper.java rename to src/main/java/org/radarbase/management/service/mapper/RoleMapper.kt index 7602a66ef..16606507f 100644 --- a/src/main/java/org/radarbase/management/service/mapper/RoleMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/RoleMapper.kt @@ -1,37 +1,30 @@ -package org.radarbase.management.service.mapper; +package org.radarbase.management.service.mapper - -import java.util.Set; - -import org.mapstruct.DecoratedWith; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.radarbase.management.domain.Role; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.mapper.decorator.RoleMapperDecorator; +import org.mapstruct.DecoratedWith +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.radarbase.management.domain.Role +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.mapper.decorator.RoleMapperDecorator /** * Created by nivethika on 23-5-17. */ -@Mapper(componentModel = "spring", uses = {ProjectMapper.class}) -@DecoratedWith(RoleMapperDecorator.class) -public interface RoleMapper { - +@Mapper(componentModel = "spring", uses = [ProjectMapper::class]) +@DecoratedWith(RoleMapperDecorator::class) +interface RoleMapper { @Mapping(source = "authority.name", target = "authorityName") @Mapping(source = "project.id", target = "projectId") @Mapping(source = "project.projectName", target = "projectName") @Mapping(source = "organization.id", target = "organizationId") @Mapping(source = "organization.name", target = "organizationName") - RoleDTO roleToRoleDTO(Role role); + fun roleToRoleDTO(role: Role): RoleDTO @Mapping(target = "authority", ignore = true) @Mapping(source = "projectId", target = "project.id") @Mapping(target = "users", ignore = true) @Mapping(source = "organizationId", target = "organization.id") - Role roleDTOToRole(RoleDTO roleDtp); - - Set roleDTOsToRoles(Set roleDtos); - - Set rolesToRoleDTOs(Set roles); - + fun roleDTOToRole(roleDto: RoleDTO?): Role? + fun roleDTOsToRoles(roleDtos: Set): Set + fun rolesToRoleDTOs(roles: Set): Set } diff --git a/src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.java b/src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.java deleted file mode 100644 index 753221e28..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.radarbase.management.service.mapper; - -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.service.dto.SourceDataDTO; - -import java.util.List; - -/** - * Mapper for the entity SourceData and its DTO SourceDataDTO. - */ -@Mapper(componentModel = "spring", uses = {SourceTypeMapper.class}) -public interface SourceDataMapper { - - @Named("sourceDataDTO") - SourceDataDTO sourceDataToSourceDataDTO(SourceData sourceData); - - @Named("sourceDataReducedDTO") - @Mapping(target = "sourceType", ignore = true) - SourceDataDTO sourceDataToSourceDataDTOReduced(SourceData sourceData); - - @IterableMapping(qualifiedByName = "sourceDataReducedDTO") - List sourceDataToSourceDataDTOs(List sourceData); - - SourceData sourceDataDTOToSourceData(SourceDataDTO sourceDataDto); - - List sourceDataDTOsToSourceData(List sourceDataDtos); - - /** - * generating the fromId for all mappers if the databaseType is sql, as the class has - * relationship to it might need it, instead of creating a new attribute to know if the entity - * has any relationship from some other entity. - * - * @param id id of the entity - * @return the entity instance - */ - - default SourceData sourceDataFromId(Long id) { - if (id == null) { - return null; - } - SourceData sourceData = new SourceData(); - sourceData.setId(id); - return sourceData; - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.kt b/src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.kt new file mode 100644 index 000000000..7413d4a15 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/SourceDataMapper.kt @@ -0,0 +1,43 @@ +package org.radarbase.management.service.mapper + +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.Named +import org.radarbase.management.domain.SourceData +import org.radarbase.management.service.dto.SourceDataDTO + +/** + * Mapper for the entity SourceData and its DTO SourceDataDTO. + */ +@Mapper(componentModel = "spring", uses = [SourceTypeMapper::class]) +interface SourceDataMapper { + @Named("sourceDataDTO") + fun sourceDataToSourceDataDTO(sourceData: SourceData?): SourceDataDTO? + + @Named("sourceDataReducedDTO") + @Mapping(target = "sourceType", ignore = true) + fun sourceDataToSourceDataDTOReduced(sourceData: SourceData): SourceDataDTO + + @IterableMapping(qualifiedByName = ["sourceDataReducedDTO"]) + fun sourceDataToSourceDataDTOs(sourceData: List): List + fun sourceDataDTOToSourceData(sourceDataDto: SourceDataDTO): SourceData + fun sourceDataDTOsToSourceData(sourceDataDtos: List): List + + /** + * generating the fromId for all mappers if the databaseType is sql, as the class has + * relationship to it might need it, instead of creating a new attribute to know if the entity + * has any relationship from some other entity. + * + * @param id id of the entity + * @return the entity instance + */ + fun sourceDataFromId(id: Long?): SourceData? { + if (id == null) { + return null + } + val sourceData = SourceData() + sourceData.id = id + return sourceData + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/SourceMapper.java b/src/main/java/org/radarbase/management/service/mapper/SourceMapper.java deleted file mode 100644 index 5d6f21eeb..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/SourceMapper.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.radarbase.management.service.mapper; - -import org.mapstruct.DecoratedWith; -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.radarbase.management.domain.Source; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.mapper.decorator.SourceMapperDecorator; - -import java.util.List; - -/** - * Mapper for the entity Source and its DTO SourceDTO. - */ -@Mapper(componentModel = "spring", uses = {SourceTypeMapper.class, ProjectMapper.class}) -@DecoratedWith(SourceMapperDecorator.class) -public interface SourceMapper { - - @Mapping(source = "source.subject.user.login", target = "subjectLogin") - SourceDTO sourceToSourceDTO(Source source); - - @Named("sourceWithoutProjectDTO") - @Mapping(source = "source.subject.user.login", target = "subjectLogin") - @Mapping(target = "project", ignore = true) - SourceDTO sourceToSourceWithoutProjectDTO(Source source); - - @IterableMapping(qualifiedByName = "sourceWithoutProjectDTO") - List sourcesToSourceDTOs(List sources); - - @Mapping(source = "sourceType.id", target = "sourceTypeId") - @Mapping(source = "sourceType.producer", target = "sourceTypeProducer") - @Mapping(source = "sourceType.model", target = "sourceTypeModel") - @Mapping(source = "sourceType.catalogVersion", target = "sourceTypeCatalogVersion") - @Mapping(source = "assigned" , target = "assigned") - MinimalSourceDetailsDTO sourceToMinimalSourceDetailsDTO(Source source); - - List sourcesToMinimalSourceDetailsDTOs(List sources); - - @Mapping(target = "sourceType", ignore = true) - @Mapping(target = "project", ignore = true) - @Mapping(target = "subject", ignore = true) - @Mapping(target = "deleted", constant = "false") - Source minimalSourceDTOToSource(MinimalSourceDetailsDTO minimalSourceDetailsDto); - - @Mapping(target = "subject", ignore = true) - @Mapping(target = "deleted", constant = "false") - Source sourceDTOToSource(SourceDTO sourceDto); -} diff --git a/src/main/java/org/radarbase/management/service/mapper/SourceMapper.kt b/src/main/java/org/radarbase/management/service/mapper/SourceMapper.kt new file mode 100644 index 000000000..097ede263 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/SourceMapper.kt @@ -0,0 +1,49 @@ +package org.radarbase.management.service.mapper + +import org.mapstruct.DecoratedWith +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.Named +import org.radarbase.management.domain.Source +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.SourceDTO +import org.radarbase.management.service.mapper.decorator.SourceMapperDecorator + +/** + * Mapper for the entity Source and its DTO SourceDTO. + */ +@Mapper(componentModel = "spring", uses = [SourceTypeMapper::class, ProjectMapper::class]) +@DecoratedWith( + SourceMapperDecorator::class +) +interface SourceMapper { + @Mapping(source = "source.subject.user.login", target = "subjectLogin") + fun sourceToSourceDTO(source: Source): SourceDTO + + @Named("sourceWithoutProjectDTO") + @Mapping(source = "source.subject.user.login", target = "subjectLogin") + @Mapping(target = "project", ignore = true) + fun sourceToSourceWithoutProjectDTO(source: Source): SourceDTO + + @IterableMapping(qualifiedByName = ["sourceWithoutProjectDTO"]) + fun sourcesToSourceDTOs(sources: List): List + + @Mapping(source = "sourceType.id", target = "sourceTypeId") + @Mapping(source = "sourceType.producer", target = "sourceTypeProducer") + @Mapping(source = "sourceType.model", target = "sourceTypeModel") + @Mapping(source = "sourceType.catalogVersion", target = "sourceTypeCatalogVersion") + @Mapping(source = "assigned", target = "assigned") + fun sourceToMinimalSourceDetailsDTO(source: Source): MinimalSourceDetailsDTO + fun sourcesToMinimalSourceDetailsDTOs(sources: List): List + + @Mapping(target = "sourceType", ignore = true) + @Mapping(target = "project", ignore = true) + @Mapping(target = "subject", ignore = true) + @Mapping(target = "deleted", constant = "false") + fun minimalSourceDTOToSource(minimalSourceDetailsDto: MinimalSourceDetailsDTO): Source? + + @Mapping(target = "subject", ignore = true) + @Mapping(target = "deleted", constant = "false") + fun sourceDTOToSource(sourceDto: SourceDTO): Source +} diff --git a/src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.java b/src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.java deleted file mode 100644 index f4b9e0a4a..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.radarbase.management.service.mapper; - -import java.util.List; -import java.util.Set; -import org.mapstruct.IterableMapping; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.Named; -import org.radarbase.management.domain.SourceData; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.service.dto.MinimalSourceTypeDTO; -import org.radarbase.management.service.dto.SourceDataDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; - -/** - * Mapper for the entity SourceType and its DTO SourceTypeDTO. - */ -@Mapper(componentModel = "spring", uses = {SourceDataMapper.class,}) -public interface SourceTypeMapper { - @Named("sourceTypeToSourceTypeDTO") - SourceTypeDTO sourceTypeToSourceTypeDTO(SourceType sourceType); - - @Named("sourceTypeToSourceTypeDTOReduced") - @Mapping(target = "sourceData", ignore = true) - @Mapping(target = "assessmentType", ignore = true) - @Mapping(target = "appProvider", ignore = true) - @Mapping(target = "description", ignore = true) - SourceTypeDTO sourceTypeToSourceTypeDTOReduced(SourceType sourceType); - - @IterableMapping(qualifiedByName = "sourceTypeToSourceTypeDTOReduced") - List sourceTypesToSourceTypeDTOs(List sourceTypes); - - @Mapping(target = "projects", ignore = true) - SourceType sourceTypeDTOToSourceType(SourceTypeDTO sourceTypeDto); - - List sourceTypeDTOsToSourceTypes(List sourceTypeDtos); - - MinimalSourceTypeDTO sourceTypeToMinimalSourceTypeDetailsDTO(SourceType sourceType); - - List sourceTypesToMinimalSourceTypeDetailsDTOs( - List sourceTypes); - - @IterableMapping(qualifiedByName = "sourceDataReducedDTO") - Set map(Set sourceData); - - @Mapping(target = "sourceTypeScope", ignore = true) - @Mapping(target = "sourceData", ignore = true) - @Mapping(target = "canRegisterDynamically", ignore = true) - @Mapping(target = "name", ignore = true) - @Mapping(target = "description", ignore = true) - @Mapping(target = "assessmentType", ignore = true) - @Mapping(target = "projects", ignore = true) - @Mapping(target = "appProvider", ignore = true) - SourceType minimalDTOToSourceType(MinimalSourceTypeDTO minimalSourceTypeDetailsDto); - - List minimalDTOsToSourceTypes(List minimalProjectDetailsDtos); - - /** - * Generating the fromId for all mappers if the databaseType is sql, as the class has - * relationship to it might need it, instead of creating a new attribute to know if the entity - * has any relationship from some other entity. - * - * @param id id of the entity - * @return the entity instance - */ - - default SourceType sourceTypeFromId(Long id) { - if (id == null) { - return null; - } - SourceType sourceType = new SourceType(); - sourceType.setId(id); - return sourceType; - } - - -} diff --git a/src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.kt b/src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.kt new file mode 100644 index 000000000..e32b769e7 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/SourceTypeMapper.kt @@ -0,0 +1,69 @@ +package org.radarbase.management.service.mapper + +import org.mapstruct.IterableMapping +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import org.mapstruct.Named +import org.radarbase.management.domain.SourceData +import org.radarbase.management.domain.SourceType +import org.radarbase.management.service.dto.MinimalSourceTypeDTO +import org.radarbase.management.service.dto.SourceDataDTO +import org.radarbase.management.service.dto.SourceTypeDTO + +/** + * Mapper for the entity SourceType and its DTO SourceTypeDTO. + */ +@Mapper(componentModel = "spring", uses = [SourceDataMapper::class]) +interface SourceTypeMapper { + @Named("sourceTypeToSourceTypeDTO") + fun sourceTypeToSourceTypeDTO(sourceType: SourceType): SourceTypeDTO + + @Named("sourceTypeToSourceTypeDTOReduced") + @Mapping(target = "sourceData", ignore = true) + @Mapping(target = "assessmentType", ignore = true) + @Mapping(target = "appProvider", ignore = true) + @Mapping(target = "description", ignore = true) + fun sourceTypeToSourceTypeDTOReduced(sourceType: SourceType?): SourceTypeDTO? + + @IterableMapping(qualifiedByName = ["sourceTypeToSourceTypeDTOReduced"]) + fun sourceTypesToSourceTypeDTOs(sourceTypes: List): List + + @Mapping(target = "projects", ignore = true) + fun sourceTypeDTOToSourceType(sourceTypeDto: SourceTypeDTO): SourceType + fun sourceTypeDTOsToSourceTypes(sourceTypeDtos: List): List + fun sourceTypeToMinimalSourceTypeDetailsDTO(sourceType: SourceType): MinimalSourceTypeDTO + fun sourceTypesToMinimalSourceTypeDetailsDTOs( + sourceTypes: List + ): List + + @IterableMapping(qualifiedByName = ["sourceDataReducedDTO"]) + fun map(sourceData: Set?): Set? + + @Mapping(target = "sourceTypeScope", ignore = true) + @Mapping(target = "sourceData", ignore = true) + @Mapping(target = "canRegisterDynamically", ignore = true) + @Mapping(target = "name", ignore = true) + @Mapping(target = "description", ignore = true) + @Mapping(target = "assessmentType", ignore = true) + @Mapping(target = "projects", ignore = true) + @Mapping(target = "appProvider", ignore = true) + fun minimalDTOToSourceType(minimalSourceTypeDetailsDto: MinimalSourceTypeDTO?): SourceType? + fun minimalDTOsToSourceTypes(minimalProjectDetailsDtos: List?): List? + + /** + * Generating the fromId for all mappers if the databaseType is sql, as the class has + * relationship to it might need it, instead of creating a new attribute to know if the entity + * has any relationship from some other entity. + * + * @param id id of the entity + * @return the entity instance + */ + fun sourceTypeFromId(id: Long?): SourceType? { + if (id == null) { + return null + } + val sourceType = SourceType() + sourceType.id = id + return sourceType + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java deleted file mode 100644 index c98f70bfe..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.radarbase.management.service.mapper.decorator; - - -import org.radarbase.management.service.dto.ClientDetailsDTO; -import org.radarbase.management.service.mapper.ClientDetailsMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.security.oauth2.provider.ClientDetails; - -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -/** - * Decorator for ClientDetailsMapper. The ClientDetails interface does not expose a method to get - * all auto-approve scopes, instead it only has a method to check if a given scope is auto-approve. - * This decorator adds the subset of scopes for which isAutoApprove returns true to the DTO. - */ -public abstract class ClientDetailsMapperDecorator implements ClientDetailsMapper { - - @Autowired - @Qualifier("delegate") - private ClientDetailsMapper delegate; - - @Override - public ClientDetailsDTO clientDetailsToClientDetailsDTO(ClientDetails details) { - ClientDetailsDTO clientDetailsDto = delegate.clientDetailsToClientDetailsDTO(details); - // collect the scopes that are auto-approve and set them in our DTO - clientDetailsDto.setAutoApproveScopes(details.getScope().stream() - .filter(details::isAutoApprove) - .collect(Collectors.toSet())); - return clientDetailsDto; - } - - @Override - public List clientDetailsToClientDetailsDTO(List details) { - if (Objects.isNull(details)) { - return null; - } - return details.stream() - .map(this::clientDetailsToClientDetailsDTO) - .toList(); - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt new file mode 100644 index 000000000..e0e6217cf --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt @@ -0,0 +1,36 @@ +package org.radarbase.management.service.mapper.decorator + +import org.radarbase.management.service.dto.ClientDetailsDTO +import org.radarbase.management.service.mapper.ClientDetailsMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.security.oauth2.provider.ClientDetails +import java.util.* +import java.util.stream.Collectors + +/** + * Decorator for ClientDetailsMapper. The ClientDetails interface does not expose a method to get + * all auto-approve scopes, instead it only has a method to check if a given scope is auto-approve. + * This decorator adds the subset of scopes for which isAutoApprove returns true to the DTO. + */ +abstract class ClientDetailsMapperDecorator : ClientDetailsMapper { + @Autowired + @Qualifier("delegate") + private val delegate: ClientDetailsMapper? = null + override fun clientDetailsToClientDetailsDTO(details: ClientDetails): ClientDetailsDTO { + val clientDetailsDto = delegate!!.clientDetailsToClientDetailsDTO(details) + // collect the scopes that are auto-approve and set them in our DTO + clientDetailsDto.autoApproveScopes = details.scope.stream() + .filter { scope: String? -> details.isAutoApprove(scope) } + .collect(Collectors.toSet()) + return clientDetailsDto + } + + override fun clientDetailsToClientDetailsDTO(detailsList: List): List? { + return if (Objects.isNull(detailsList)) { + null + } else detailsList.stream() + .map { details: ClientDetails -> this.clientDetailsToClientDetailsDTO(details) } + .toList() + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java deleted file mode 100644 index 4d60d9afa..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.radarbase.management.service.mapper.decorator; - -import org.radarbase.management.domain.Project; -import org.radarbase.management.repository.OrganizationRepository; -import org.radarbase.management.repository.ProjectRepository; -import org.radarbase.management.service.MetaTokenService; -import org.radarbase.management.service.dto.MinimalProjectDetailsDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.mapper.ProjectMapper; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -import static org.radarbase.management.service.dto.ProjectDTO.HUMAN_READABLE_PROJECT_NAME; -import static org.radarbase.management.web.rest.errors.EntityName.ORGANIZATION; - -import java.util.Collections; - -/** - * Created by nivethika on 30-8-17. - */ -public abstract class ProjectMapperDecorator implements ProjectMapper { - - @Autowired - @Qualifier("delegate") - private ProjectMapper delegate; - - @Autowired - private OrganizationRepository organizationRepository; - - @Autowired - private ProjectRepository projectRepository; - - @Autowired - private MetaTokenService metaTokenService; - - @Override - public ProjectDTO projectToProjectDTO(Project project) { - if (project == null) { - return null; - } - ProjectDTO dto = delegate.projectToProjectDTO(project); - - dto.setHumanReadableProjectName(project.attributes.get(HUMAN_READABLE_PROJECT_NAME)); - - try { - dto.setPersistentTokenTimeout( - metaTokenService.getMetaTokenTimeout(true, project).toMillis()); - } catch (BadRequestException ex) { - dto.setPersistentTokenTimeout(null); - } - - return dto; - } - - - @Override - public ProjectDTO projectToProjectDTOReduced(Project project) { - if (project == null) { - return null; - } - ProjectDTO dto = delegate.projectToProjectDTOReduced(project); - dto.setHumanReadableProjectName(project.attributes.get(HUMAN_READABLE_PROJECT_NAME)); - dto.setSourceTypes(null); - return dto; - } - - @Override - public Project projectDTOToProject(ProjectDTO projectDto) { - if (projectDto == null) { - return null; - } - - Project project = delegate.projectDTOToProject(projectDto); - String projectName = projectDto.getHumanReadableProjectName(); - if (projectName != null && !projectName.isEmpty()) { - project.attributes.put(HUMAN_READABLE_PROJECT_NAME, projectName); - } - - var orgDto = projectDto.getOrganization(); - if (orgDto != null && orgDto.getName() != null) { - var org = organizationRepository.findOneByName(orgDto.getName()) - .orElseThrow(() -> new NotFoundException("Organization not found with name", - ORGANIZATION, - ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, - Collections.singletonMap("name", orgDto.getName()))); - project.organization = org; - } - - return project; - } - - @Override - public Project descriptiveDTOToProject(MinimalProjectDetailsDTO minimalProjectDetailsDto) { - if (minimalProjectDetailsDto == null) { - return null; - } - return projectRepository.getById(minimalProjectDetailsDto.getId()); - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt new file mode 100644 index 000000000..48d862398 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt @@ -0,0 +1,77 @@ +package org.radarbase.management.service.mapper.decorator + +import org.radarbase.management.domain.Project +import org.radarbase.management.repository.OrganizationRepository +import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.MetaTokenService +import org.radarbase.management.service.dto.MinimalProjectDetailsDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.mapper.ProjectMapper +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import java.util.* + +/** + * Created by nivethika on 30-8-17. + */ +abstract class ProjectMapperDecorator( + @Autowired @Qualifier("delegate") private val delegate: ProjectMapper, + @Autowired private val organizationRepository: OrganizationRepository, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val metaTokenService: MetaTokenService +) : ProjectMapper { + + override fun projectToProjectDTO(project: Project?): ProjectDTO? { + val dto = delegate.projectToProjectDTO(project) + dto?.humanReadableProjectName = project?.attributes?.get(ProjectDTO.HUMAN_READABLE_PROJECT_NAME) + try { + dto?.persistentTokenTimeout = metaTokenService.getMetaTokenTimeout(true, project).toMillis() + } catch (ex: BadRequestException) { + dto?.persistentTokenTimeout = null + } + return dto + } + + override fun projectToProjectDTOReduced(project: Project?): ProjectDTO? { + if (project == null) { + return null + } + val dto = delegate.projectToProjectDTOReduced(project) + dto?.humanReadableProjectName = project.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] + dto?.sourceTypes = null + return dto + } + + override fun projectDTOToProject(projectDto: ProjectDTO?): Project? { + if (projectDto == null) { + return null + } + val project = delegate.projectDTOToProject(projectDto) + val projectName = projectDto.humanReadableProjectName + if (!projectName.isNullOrEmpty()) { + project!!.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] = projectName + } + val orgDto = projectDto.organization + if (orgDto?.name != null) { + val org = organizationRepository.findOneByName(orgDto.name) + ?: throw NotFoundException( + "Organization not found with name", + EntityName.Companion.ORGANIZATION, + ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, + Collections.singletonMap("name", orgDto.name) + ) + project!!.organization = org + } + return project + } + + override fun descriptiveDTOToProject(minimalProjectDetailsDto: MinimalProjectDetailsDTO?): Project? { + return if (minimalProjectDetailsDto == null) { + null + } else minimalProjectDetailsDto.id?.let { projectRepository.getById(it) } + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java deleted file mode 100644 index 581ca9995..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.radarbase.management.service.mapper.decorator; - -import org.radarbase.management.domain.Role; -import org.radarbase.management.repository.AuthorityRepository; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.service.mapper.RoleMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -/** - * Created by nivethika on 03-8-18. - */ -public abstract class RoleMapperDecorator implements RoleMapper { - - @Autowired - @Qualifier("delegate") - private RoleMapper delegate; - - @Autowired - private AuthorityRepository authorityRepository; - - /** - * Overrides standard RoleMapperImpl and loads authority from repository if not specified. - * @param roleDto to convert to Role. - * @return converted Role instance. - */ - @Override - public Role roleDTOToRole(RoleDTO roleDto) { - if (roleDto == null) { - return null; - } - - Role role = delegate.roleDTOToRole(roleDto); - - if (role.authority == null) { - role.authority = authorityRepository.getById(roleDto.getAuthorityName()); - } - - return role; - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt new file mode 100644 index 000000000..0fb761825 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt @@ -0,0 +1,36 @@ +package org.radarbase.management.service.mapper.decorator + +import org.radarbase.management.domain.Role +import org.radarbase.management.repository.AuthorityRepository +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.service.mapper.RoleMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier + +/** + * Created by nivethika on 03-8-18. + */ +abstract class RoleMapperDecorator : RoleMapper { + @Autowired + @Qualifier("delegate") + private val delegate: RoleMapper? = null + + @Autowired + private val authorityRepository: AuthorityRepository? = null + + /** + * Overrides standard RoleMapperImpl and loads authority from repository if not specified. + * @param roleDto to convert to Role. + * @return converted Role instance. + */ + override fun roleDTOToRole(roleDto: RoleDTO?): Role? { + if (roleDto == null) { + return null + } + val role = delegate!!.roleDTOToRole(roleDto) + if (role!!.authority == null) { + role.authority = roleDto.authorityName?.let { authorityRepository!!.getById(it) } + } + return role + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java deleted file mode 100644 index fd69ec511..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.radarbase.management.service.mapper.decorator; - -import org.radarbase.management.domain.Source; -import org.radarbase.management.repository.SourceRepository; -import org.radarbase.management.repository.SubjectRepository; -import org.radarbase.management.service.dto.MinimalSourceDetailsDTO; -import org.radarbase.management.service.dto.SourceDTO; -import org.radarbase.management.service.mapper.SourceMapper; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -import java.util.Map; -import java.util.NoSuchElementException; - -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_SOURCE_NOT_FOUND; - -/** - * Created by nivethika on 13-6-17. - */ - -public abstract class SourceMapperDecorator implements SourceMapper { - - @Autowired - @Qualifier("delegate") - private SourceMapper delegate; - - @Autowired - private SourceRepository sourceRepository; - - @Autowired - private SubjectRepository subjectRepository; - - @Override - public Source minimalSourceDTOToSource(MinimalSourceDetailsDTO minimalSource) { - Source source = sourceRepository - .findOneBySourceId(minimalSource.getSourceId()) - .orElseThrow(() -> new NotFoundException( - "Source ID " + minimalSource.getSourceId() + " not found", - SOURCE, ERR_SOURCE_NOT_FOUND, - Map.of("sourceId", minimalSource.getSourceId().toString()))); - source.setAssigned(minimalSource.isAssigned()); - return source; - } - - @Override - public Source sourceDTOToSource(SourceDTO sourceDto) { - Source source = delegate.sourceDTOToSource(sourceDto); - if (sourceDto.getId() != null) { - Source existingSource = sourceRepository.findById(sourceDto.getId()) - .orElseThrow(() -> new NotFoundException( - "Source ID " + sourceDto.getId() + " not found", - SOURCE, ERR_SOURCE_NOT_FOUND, - Map.of("sourceId", sourceDto.getId().toString()))); - if (sourceDto.getSubjectLogin() == null) { - source.subject = existingSource.subject; - } else { - source.subject = subjectRepository - .findOneWithEagerBySubjectLogin(sourceDto.getSubjectLogin()) - .orElseThrow(NoSuchElementException::new); - } - } - return source; - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt new file mode 100644 index 000000000..eb418185c --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt @@ -0,0 +1,61 @@ +package org.radarbase.management.service.mapper.decorator + +import org.radarbase.management.domain.Source +import org.radarbase.management.repository.SourceRepository +import org.radarbase.management.repository.SubjectRepository +import org.radarbase.management.service.dto.MinimalSourceDetailsDTO +import org.radarbase.management.service.dto.SourceDTO +import org.radarbase.management.service.mapper.SourceMapper +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import java.util.Map + +/** + * Created by nivethika on 13-6-17. + */ +abstract class SourceMapperDecorator( + @Autowired @Qualifier("delegate") private val delegate: SourceMapper, + @Autowired private val sourceRepository: SourceRepository, + @Autowired private val subjectRepository: SubjectRepository +) : SourceMapper { + + override fun minimalSourceDTOToSource(minimalSourceDetailsDto: MinimalSourceDetailsDTO): Source? { + val source = sourceRepository + .findOneBySourceId(minimalSourceDetailsDto.sourceId) + ?: throw + NotFoundException( + "Source ID " + minimalSourceDetailsDto.sourceId + " not found", + EntityName.Companion.SOURCE, ErrorConstants.ERR_SOURCE_NOT_FOUND, + Map.of("sourceId", minimalSourceDetailsDto.sourceId.toString()) + ) + source.isAssigned = minimalSourceDetailsDto.isAssigned + return source + } + + override fun sourceDTOToSource(sourceDto: SourceDTO): Source { + val source = delegate.sourceDTOToSource(sourceDto) + if (sourceDto.id != null) { + val existingSource = sourceDto.id?.let { + sourceRepository.findById(it) + .orElseThrow { + NotFoundException( + "Source ID " + sourceDto.id + " not found", + EntityName.Companion.SOURCE, ErrorConstants.ERR_SOURCE_NOT_FOUND, + Map.of("sourceId", sourceDto.id.toString()) + ) + } + }!! + if (sourceDto.subjectLogin == null) { + source.subject = existingSource.subject + } else { + source.subject = subjectRepository + .findOneWithEagerBySubjectLogin(sourceDto.subjectLogin) + ?: throw NoSuchElementException() + } + } + return source + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt index 3317d9b05..19ece43e4 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt @@ -33,8 +33,8 @@ abstract class SubjectMapperDecorator( } val dto = subjectToSubjectWithoutProjectDTO(subject) val project = subject.activeProject - .let { p -> projectRepository.findOneWithEagerRelationships(p?.id) } - dto!!.project = projectMapper.projectToProjectDTO(project) + .let { p -> projectRepository.findOneWithEagerRelationships(p?.id!!) } + dto?.project = projectMapper.projectToProjectDTO(project) addAuditInfo(subject, dto) return dto } @@ -44,7 +44,7 @@ abstract class SubjectMapperDecorator( return null } val dto = subjectToSubjectWithoutProjectDTO(subject) - subject.activeProject?.let { project -> dto!!.project = projectMapper.projectToProjectDTOReduced(project) } + subject.activeProject?.let { project -> dto?.project = projectMapper.projectToProjectDTOReduced(project) } addAuditInfo(subject, dto) return dto } @@ -62,7 +62,7 @@ abstract class SubjectMapperDecorator( return null } val dto = delegate.subjectToSubjectWithoutProjectDTO(subject) - dto!!.status = getSubjectStatus(subject) + dto?.status = getSubjectStatus(subject) return dto } @@ -72,24 +72,24 @@ abstract class SubjectMapperDecorator( } val subject = delegate.subjectDTOToSubject(subjectDto) setSubjectStatus(subjectDto, subject) - subject!!.group = getGroup(subjectDto) + subject?.group = getGroup(subjectDto) return subject } private fun getGroup(subjectDto: SubjectDTO?): Group? { return if (subjectDto!!.group == null) { null - } else if (subjectDto.project.id != null) { - groupRepository.findByProjectIdAndName(subjectDto.project.id, subjectDto.group) + } else if (subjectDto.project?.id != null) { + groupRepository.findByProjectIdAndName(subjectDto.project?.id, subjectDto.group) ?: throw BadRequestException( "Group " + subjectDto.group + " not found in project " - + subjectDto.project.id, + + subjectDto.project?.id, EntityName.SUBJECT, ErrorConstants.ERR_GROUP_NOT_FOUND) - } else if (subjectDto.project.projectName != null) { - groupRepository.findByProjectNameAndName(subjectDto.project.projectName, subjectDto.group) + } else if (subjectDto.project?.projectName != null) { + groupRepository.findByProjectNameAndName(subjectDto.project?.projectName, subjectDto.group) ?: throw BadRequestException( "Group " + subjectDto.group + " not found in project " - + subjectDto.project.projectName, + + subjectDto.project?.projectName, EntityName.SUBJECT, ErrorConstants.ERR_GROUP_NOT_FOUND ) } else { diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.java deleted file mode 100644 index 839bd6ff3..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.radarbase.management.service.mapper.decorator; - -import org.radarbase.management.domain.User; -import org.radarbase.management.domain.audit.EntityAuditInfo; -import org.radarbase.management.service.RevisionService; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.UserMapper; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -public abstract class UserMapperDecorator implements UserMapper { - - @Autowired - @Qualifier("delegate") - private UserMapper delegate; - - @Autowired - private RevisionService revisionService; - - @Override - public UserDTO userToUserDTO(User user) { - if (user == null) { - return null; - } - - UserDTO dto = delegate.userToUserDTO(user); - - EntityAuditInfo auditInfo = revisionService.getAuditInfo(user); - dto.setCreatedDate(auditInfo.getCreatedAt()); - dto.setCreatedBy(auditInfo.getCreatedBy()); - dto.setLastModifiedDate(auditInfo.getLastModifiedAt()); - dto.setLastModifiedBy(auditInfo.getLastModifiedBy()); - - return dto; - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt new file mode 100644 index 000000000..02f4fa2eb --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt @@ -0,0 +1,29 @@ +package org.radarbase.management.service.mapper.decorator + +import org.radarbase.management.domain.User +import org.radarbase.management.service.RevisionService +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.UserMapper +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier + +abstract class UserMapperDecorator : UserMapper { + @Autowired + @Qualifier("delegate") + private val delegate: UserMapper? = null + + @Autowired + private val revisionService: RevisionService? = null + override fun userToUserDTO(user: User?): UserDTO? { + if (user == null) { + return null + } + val dto = delegate!!.userToUserDTO(user) + val auditInfo = revisionService!!.getAuditInfo(user) + dto?.createdDate = auditInfo.createdAt + dto?.createdBy = auditInfo.createdBy + dto?.lastModifiedDate = auditInfo.lastModifiedAt + dto?.lastModifiedBy = auditInfo.lastModifiedBy + return dto + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/package-info.java b/src/main/java/org/radarbase/management/service/mapper/package-info.kt similarity index 62% rename from src/main/java/org/radarbase/management/service/mapper/package-info.java rename to src/main/java/org/radarbase/management/service/mapper/package-info.kt index 0b5b3b448..0f781e947 100644 --- a/src/main/java/org/radarbase/management/service/mapper/package-info.java +++ b/src/main/java/org/radarbase/management/service/mapper/package-info.kt @@ -1,4 +1,5 @@ /** * MapStruct mappers for mapping domain objects and Data Transfer Objects. */ -package org.radarbase.management.service.mapper; +package org.radarbase.management.service.mapper + diff --git a/src/main/java/org/radarbase/management/service/package-info.java b/src/main/java/org/radarbase/management/service/package-info.java deleted file mode 100644 index 30311a71e..000000000 --- a/src/main/java/org/radarbase/management/service/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Service layer beans. - */ -package org.radarbase.management.service; diff --git a/src/main/java/org/radarbase/management/service/package-info.kt b/src/main/java/org/radarbase/management/service/package-info.kt new file mode 100644 index 000000000..763684f5a --- /dev/null +++ b/src/main/java/org/radarbase/management/service/package-info.kt @@ -0,0 +1,5 @@ +/** + * Service layer beans. + */ +package org.radarbase.management.service + diff --git a/src/main/java/org/radarbase/management/web/rest/AccountResource.java b/src/main/java/org/radarbase/management/web/rest/AccountResource.java deleted file mode 100644 index c9f959762..000000000 --- a/src/main/java/org/radarbase/management/web/rest/AccountResource.java +++ /dev/null @@ -1,233 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import org.radarbase.auth.authorization.Permission; -import org.radarbase.auth.token.DataRadarToken; -import org.radarbase.auth.token.RadarToken; -import org.radarbase.management.config.ManagementPortalProperties; -import org.radarbase.management.domain.User; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.MailService; -import org.radarbase.management.service.PasswordService; -import org.radarbase.management.service.UserService; -import org.radarbase.management.service.dto.UserDTO; -import org.radarbase.management.service.mapper.UserMapper; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.errors.RadarWebApplicationException; -import org.radarbase.management.web.rest.vm.KeyAndPasswordVM; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.Authentication; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import javax.validation.Valid; - -import static org.radarbase.management.security.JwtAuthenticationFilter.setRadarToken; -import static org.radarbase.management.web.rest.errors.EntityName.USER; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_ACCESS_DENIED; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_EMAIL_NOT_REGISTERED; - -/** - * REST controller for managing the current user's account. - */ -@RestController -@RequestMapping("/api") -public class AccountResource { - - private static final Logger log = LoggerFactory.getLogger(AccountResource.class); - - @Autowired - private UserService userService; - - @Autowired - private MailService mailService; - - @Autowired - private UserMapper userMapper; - - @Autowired - private ManagementPortalProperties managementPortalProperties; - - @Autowired - private AuthService authService; - - @Autowired - private PasswordService passwordService; - - @Autowired(required = false) - private RadarToken token; - - /** - * GET /activate : activate the registered user. - * - * @param key the activation key - * @return the ResponseEntity with status 200 (OK) and the activated user in body, or status 500 - * (Internal Server Error) if the user couldn't be activated - */ - @GetMapping("/activate") - @Timed - public ResponseEntity activateAccount(@RequestParam(value = "key") String key) { - return userService.activateRegistration(key) - .map(user -> new ResponseEntity(HttpStatus.OK)) - .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND)); - } - - /** - * POST /login : check if the user is authenticated. - * - * @param session the HTTP session - * @return user account details if the user is authenticated - */ - @PostMapping("/login") - @Timed - public UserDTO login(HttpSession session) throws NotAuthorizedException { - if (token == null) { - throw new NotAuthorizedException("Cannot login without credentials"); - } - log.debug("Logging in user to session with principal {}", token.getUsername()); - setRadarToken(session, new DataRadarToken(token)); - return getAccount(); - } - - /** - * POST /logout : log out. - * - * @param request the HTTP request - * @return no content response if the user is authenticated - */ - @PostMapping("/logout") - @Timed - public ResponseEntity logout(HttpServletRequest request) { - log.debug("Unauthenticate a user"); - HttpSession session = request.getSession(false); - if (session != null) { - session.invalidate(); - } - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - /** - * GET /account : get the current user. - * - * @return the ResponseEntity with status 200 (OK) and the current user in body, or status 401 - * (Internal Server Error) if the user couldn't be returned - */ - @GetMapping("/account") - @Timed - public UserDTO getAccount() { - User currentUser = userService.getUserWithAuthorities() - .orElseThrow(() -> new RadarWebApplicationException(HttpStatus.FORBIDDEN, - "Cannot get account without user", USER, ERR_ACCESS_DENIED)); - - UserDTO userDto = userMapper.userToUserDTO(currentUser); - if (managementPortalProperties.getAccount().getEnableExposeToken()) { - userDto.setAccessToken(token.getToken()); - } - return userDto; - } - - /** - * POST /account : update the current user information. - * - * @param userDto the current user information - * @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) or 500 (Internal - * Server Error) if the user couldn't be updated - */ - @PostMapping("/account") - @Timed - public ResponseEntity saveAccount(@Valid @RequestBody UserDTO userDto, - Authentication authentication) throws NotAuthorizedException { - authService.checkPermission(Permission.USER_UPDATE, e -> e.user(userDto.getLogin())); - userService.updateUser(authentication.getName(), userDto.getFirstName(), - userDto.getLastName(), userDto.getEmail(), userDto.getLangKey()); - - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - /** - * POST /account/change_password : changes the current user's password. - * - * @param password the new password - * @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) if the new - * password is not strong enough - */ - @PostMapping(path = "/account/change_password", - produces = MediaType.TEXT_PLAIN_VALUE) - @Timed - public ResponseEntity changePassword(@RequestBody String password) { - passwordService.checkPasswordStrength(password); - userService.changePassword(password); - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - - /** - * POST /account/reset-activation/init : Resend the password activation email - * to the user. - * - * @param login the login of the user - * @return the ResponseEntity with status 200 (OK) if the email was sent, or status 400 (Bad - * Request) if the email address is not registered or user is not deactivated - */ - @PostMapping(path = "/account/reset-activation/init") - @Timed - public ResponseEntity requestActivationReset(@RequestBody String login) { - User user = userService.requestActivationReset(login) - .orElseThrow(() -> new BadRequestException( - "Cannot find a deactivated user with login " + login, - USER, ERR_EMAIL_NOT_REGISTERED)); - - mailService.sendCreationEmail(user, managementPortalProperties.getCommon() - .getActivationKeyTimeoutInSeconds()); - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - /** - * POST /account/reset_password/init : Email the user a password reset link. - * - * @param mail the mail of the user - * @return the ResponseEntity with status 200 (OK) if the email was sent, or status 400 (Bad - * Request) if the email address is not registered - */ - @PostMapping(path = "/account/reset_password/init") - @Timed - public ResponseEntity requestPasswordReset(@RequestBody String mail) { - User user = userService.requestPasswordReset(mail) - .orElseThrow(() -> new BadRequestException("email address not registered", - USER, ERR_EMAIL_NOT_REGISTERED)); - - mailService.sendPasswordResetMail(user); - return new ResponseEntity<>(HttpStatus.NO_CONTENT); - } - - /** - * POST /account/reset_password/finish : Finish to reset the password of the user. - * - * @param keyAndPassword the generated key and the new password - * @return the ResponseEntity with status 200 (OK) if the password has been reset, or status 400 - * (Bad Request) or 500 (Internal Server Error) if the password could not be reset - */ - @PostMapping(path = "/account/reset_password/finish", - produces = MediaType.TEXT_PLAIN_VALUE) - @Timed - public ResponseEntity finishPasswordReset( - @RequestBody KeyAndPasswordVM keyAndPassword) { - passwordService.checkPasswordStrength(keyAndPassword.getNewPassword()); - return userService - .completePasswordReset(keyAndPassword.getNewPassword(), keyAndPassword.getKey()) - .map(user -> new ResponseEntity(HttpStatus.NO_CONTENT)) - .orElse(new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR)); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/AccountResource.kt b/src/main/java/org/radarbase/management/web/rest/AccountResource.kt new file mode 100644 index 000000000..852d433a1 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/AccountResource.kt @@ -0,0 +1,234 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.auth.token.DataRadarToken +import org.radarbase.auth.token.RadarToken +import org.radarbase.management.config.ManagementPortalProperties +import org.radarbase.management.domain.User +import org.radarbase.management.security.JwtAuthenticationFilter +import org.radarbase.management.security.JwtAuthenticationFilter.Companion.radarToken +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.MailService +import org.radarbase.management.service.PasswordService +import org.radarbase.management.service.UserService +import org.radarbase.management.service.dto.UserDTO +import org.radarbase.management.service.mapper.UserMapper +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.RadarWebApplicationException +import org.radarbase.management.web.rest.vm.KeyAndPasswordVM +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.http.ResponseEntity +import org.springframework.security.core.Authentication +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import java.lang.Exception +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpSession +import javax.validation.Valid + +/** + * REST controller for managing the current user's account. + */ +@RestController +@RequestMapping("/api") +class AccountResource( + @Autowired private val userService: UserService, + @Autowired private val mailService: MailService, + @Autowired private val userMapper: UserMapper, + @Autowired private val managementPortalProperties: ManagementPortalProperties, + @Autowired private val authService: AuthService, + @Autowired private val passwordService: PasswordService +) { + + @Autowired(required = false) + private val token: RadarToken? = null + + /** + * GET /activate : activate the registered user. + * + * @param key the activation key + * @return the ResponseEntity with status 200 (OK) and the activated user in body, or status 500 + * (Internal Server Error) if the user couldn't be activated + */ + @GetMapping("/activate") + @Timed + fun activateAccount(@RequestParam(value = "key") key: String): ResponseEntity { + return try { + userService.activateRegistration(key) + ResponseEntity(HttpStatus.OK) + } catch (e: Exception) { + ResponseEntity(HttpStatus.NOT_FOUND) + } + } + + /** + * POST /login : check if the user is authenticated. + * + * @param session the HTTP session + * @return user account details if the user is authenticated + */ + @PostMapping("/login") + @Timed + @Throws(NotAuthorizedException::class) + fun login(session: HttpSession?): UserDTO? { + if (token == null) { + throw NotAuthorizedException("Cannot login without credentials") + } + log.debug("Logging in user to session with principal {}", token.username) + session?.radarToken = DataRadarToken(token) + return account + } + + /** + * POST /logout : log out. + * + * @param request the HTTP request + * @return no content response if the user is authenticated + */ + @PostMapping("/logout") + @Timed + fun logout(request: HttpServletRequest): ResponseEntity { + log.debug("Unauthenticate a user") + val session = request.getSession(false) + session?.invalidate() + return ResponseEntity(HttpStatus.NO_CONTENT) + } + + @get:Timed + @get:GetMapping("/account") + val account: UserDTO? + /** + * GET /account : get the current user. + * + * @return the ResponseEntity with status 200 (OK) and the current user in body, or status 401 + * (Internal Server Error) if the user couldn't be returned + */ + get() { + val currentUser = userService.userWithAuthorities + ?: throw RadarWebApplicationException( + HttpStatus.FORBIDDEN, + "Cannot get account without user", EntityName.Companion.USER, ErrorConstants.ERR_ACCESS_DENIED + ) + val userDto = userMapper.userToUserDTO(currentUser) + if (managementPortalProperties.account.enableExposeToken) { + userDto?.accessToken = token!!.token + } + return userDto + } + + /** + * POST /account : update the current user information. + * + * @param userDto the current user information + * @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) or 500 (Internal + * Server Error) if the user couldn't be updated + */ + @PostMapping("/account") + @Timed + @Throws(NotAuthorizedException::class) + fun saveAccount( + @RequestBody userDto: @Valid UserDTO, + authentication: Authentication + ): ResponseEntity { + authService.checkPermission(Permission.USER_UPDATE, { e: EntityDetails -> + e.user(userDto.login) }) + userService.updateUser( + authentication.name, userDto.firstName, + userDto.lastName, userDto.email, userDto.langKey + ) + return ResponseEntity(HttpStatus.NO_CONTENT) + } + + /** + * POST /account/change_password : changes the current user's password. + * + * @param password the new password + * @return the ResponseEntity with status 200 (OK), or status 400 (Bad Request) if the new + * password is not strong enough + */ + @PostMapping(path = ["/account/change_password"], produces = [MediaType.TEXT_PLAIN_VALUE]) + @Timed + fun changePassword(@RequestBody password: String): ResponseEntity { + passwordService.checkPasswordStrength(password) + userService.changePassword(password) + return ResponseEntity(HttpStatus.NO_CONTENT) + } + + /** + * POST /account/reset-activation/init : Resend the password activation email + * to the user. + * + * @param login the login of the user + * @return the ResponseEntity with status 200 (OK) if the email was sent, or status 400 (Bad + * Request) if the email address is not registered or user is not deactivated + */ + @PostMapping(path = ["/account/reset-activation/init"]) + @Timed + fun requestActivationReset(@RequestBody login: String): ResponseEntity { + val user = userService.requestActivationReset(login) + ?: throw BadRequestException( + "Cannot find a deactivated user with login $login", + EntityName.Companion.USER, ErrorConstants.ERR_EMAIL_NOT_REGISTERED + ) + + mailService.sendCreationEmail( + user, managementPortalProperties.common + .activationKeyTimeoutInSeconds.toLong() + ) + return ResponseEntity(HttpStatus.NO_CONTENT) + } + + /** + * POST /account/reset_password/init : Email the user a password reset link. + * + * @param mail the mail of the user + * @return the ResponseEntity with status 200 (OK) if the email was sent, or status 400 (Bad + * Request) if the email address is not registered + */ + @PostMapping(path = ["/account/reset_password/init"]) + @Timed + fun requestPasswordReset(@RequestBody mail: String): ResponseEntity { + val user = userService.requestPasswordReset(mail) + ?: throw BadRequestException( + "email address not registered", + EntityName.Companion.USER, ErrorConstants.ERR_EMAIL_NOT_REGISTERED + ) + mailService.sendPasswordResetMail(user) + return ResponseEntity(HttpStatus.NO_CONTENT) + } + + /** + * POST /account/reset_password/finish : Finish to reset the password of the user. + * + * @param keyAndPassword the generated key and the new password + * @return the ResponseEntity with status 200 (OK) if the password has been reset, or status 400 + * (Bad Request) or 500 (Internal Server Error) if the password could not be reset + */ + @PostMapping(path = ["/account/reset_password/finish"], produces = [MediaType.TEXT_PLAIN_VALUE]) + @Timed + fun finishPasswordReset( + @RequestBody keyAndPassword: KeyAndPasswordVM + ): ResponseEntity { + passwordService.checkPasswordStrength(keyAndPassword.newPassword) + userService.completePasswordReset(keyAndPassword.newPassword, keyAndPassword.key) + ?: return ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR) + + return ResponseEntity(HttpStatus.NO_CONTENT) + } + + companion object { + private val log = LoggerFactory.getLogger(AccountResource::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/AuditResource.java b/src/main/java/org/radarbase/management/web/rest/AuditResource.java deleted file mode 100644 index a7f87675d..000000000 --- a/src/main/java/org/radarbase/management/web/rest/AuditResource.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.swagger.v3.oas.annotations.Parameter; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuditEventService; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.springframework.boot.actuate.audit.AuditEvent; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import tech.jhipster.web.util.ResponseUtil; - -import java.time.LocalDate; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.AUDIT_READ; - -/** - * REST controller for getting the audit events. - */ -@RestController -@RequestMapping("/management/audits") -public class AuditResource { - private final AuditEventService auditEventService; - private final AuthService authService; - - public AuditResource(AuditEventService auditEventService, AuthService authService) { - this.auditEventService = auditEventService; - this.authService = authService; - } - - /** - * GET /audits : get a page of AuditEvents. - * - * @param pageable the pagination information - * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body - */ - @GetMapping - public ResponseEntity> getAll(@Parameter Pageable pageable) - throws NotAuthorizedException { - authService.checkPermission(AUDIT_READ); - Page page = auditEventService.findAll(pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/management/audits"); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } - - /** - * GET /audits : get a page of AuditEvents between the fromDate and toDate. - * - * @param fromDate the start of the time period of AuditEvents to get - * @param toDate the end of the time period of AuditEvents to get - * @param pageable the pagination information - * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body - */ - - @GetMapping(params = {"fromDate", "toDate"}) - public ResponseEntity> getByDates( - @RequestParam(value = "fromDate") LocalDate fromDate, - @RequestParam(value = "toDate") LocalDate toDate, - @Parameter Pageable pageable) throws NotAuthorizedException { - authService.checkPermission(AUDIT_READ); - Page page = auditEventService - .findByDates(fromDate.atTime(0, 0), toDate.atTime(23, 59), pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/management/audits"); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); - } - - /** - * GET /audits/:id : get an AuditEvent by id. - * - * @param id the id of the entity to get - * @return the ResponseEntity with status 200 (OK) and the AuditEvent in body, or status - * 404 (Not Found) - */ - @GetMapping("/{id:.+}") - public ResponseEntity get(@PathVariable Long id) throws NotAuthorizedException { - authService.checkPermission(AUDIT_READ); - return ResponseUtil.wrapOrNotFound(auditEventService.find(id)); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/AuditResource.kt b/src/main/java/org/radarbase/management/web/rest/AuditResource.kt new file mode 100644 index 000000000..04b80b4c4 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/AuditResource.kt @@ -0,0 +1,77 @@ +package org.radarbase.management.web.rest + +import io.swagger.v3.oas.annotations.Parameter +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuditEventService +import org.radarbase.management.service.AuthService +import org.radarbase.management.web.rest.util.PaginationUtil +import org.springframework.boot.actuate.audit.AuditEvent +import org.springframework.data.domain.Pageable +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.time.LocalDate + +/** + * REST controller for getting the audit events. + */ +@RestController +@RequestMapping("/management/audits") +class AuditResource(private val auditEventService: AuditEventService, private val authService: AuthService) { + /** + * GET /audits : get a page of AuditEvents. + * + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body + */ + @GetMapping + @Throws(NotAuthorizedException::class) + fun getAll(@Parameter pageable: Pageable?): ResponseEntity> { + authService.checkPermission(Permission.AUDIT_READ) + val page = auditEventService.findAll(pageable) + val headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits") + return ResponseEntity(page!!.content, headers, HttpStatus.OK) + } + + /** + * GET /audits : get a page of AuditEvents between the fromDate and toDate. + * + * @param fromDate the start of the time period of AuditEvents to get + * @param toDate the end of the time period of AuditEvents to get + * @param pageable the pagination information + * @return the ResponseEntity with status 200 (OK) and the list of AuditEvents in body + */ + @GetMapping(params = ["fromDate", "toDate"]) + @Throws(NotAuthorizedException::class) + fun getByDates( + @RequestParam(value = "fromDate") fromDate: LocalDate, + @RequestParam(value = "toDate") toDate: LocalDate, + @Parameter pageable: Pageable? + ): ResponseEntity> { + authService.checkPermission(Permission.AUDIT_READ) + val page = auditEventService + .findByDates(fromDate.atTime(0, 0), toDate.atTime(23, 59), pageable) + val headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits") + return ResponseEntity(page!!.content, headers, HttpStatus.OK) + } + + /** + * GET /audits/:id : get an AuditEvent by id. + * + * @param id the id of the entity to get + * @return the ResponseEntity with status 200 (OK) and the AuditEvent in body, or status + * 404 (Not Found) + */ + @GetMapping("/{id:.+}") + @Throws(NotAuthorizedException::class) + operator fun get(@PathVariable id: Long): ResponseEntity { + authService.checkPermission(Permission.AUDIT_READ) + return ResponseUtil.wrapOrNotFound(auditEventService.find(id)) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/GroupResource.java b/src/main/java/org/radarbase/management/web/rest/GroupResource.java deleted file mode 100644 index 3bafc1289..000000000 --- a/src/main/java/org/radarbase/management/web/rest/GroupResource.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.web.rest; - -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.GroupService; -import org.radarbase.management.service.dto.GroupDTO; -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.radarbase.management.web.rest.vm.GroupPatchOperation; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; - -import javax.validation.Valid; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.PROJECT_READ; -import static org.radarbase.auth.authorization.Permission.PROJECT_UPDATE; -import static org.radarbase.auth.authorization.Permission.SUBJECT_UPDATE; -import static org.radarbase.management.web.rest.errors.EntityName.GROUP; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_VALIDATION; - -@RestController -@RequestMapping("/api/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/groups") -public class GroupResource { - @Autowired - private GroupService groupService; - - @Autowired - private AuthService authService; - - /** - * Create group. - * @param projectName project name - * @param groupDto group specification - * @return created response - * @throws NotAuthorizedException if PROJECT_UPDATE permissions are not present. - */ - @PostMapping - public ResponseEntity createGroup( - @PathVariable String projectName, - @Valid @RequestBody GroupDTO groupDto) throws NotAuthorizedException { - authService.checkPermission(PROJECT_UPDATE, e -> e.project(projectName)); - GroupDTO groupDtoResult = groupService.createGroup(projectName, groupDto); - URI location = MvcUriComponentsBuilder.fromController(getClass()) - .path("/{groupName}") - .buildAndExpand(projectName, groupDtoResult.getName()) - .toUri(); - return ResponseEntity.created(location) - .body(groupDtoResult); - } - - /** - * List groups. - * @param projectName project name - * @return list of groups - * @throws NotAuthorizedException if PROJECT_READ permissions are not present. - */ - @GetMapping - public List listGroups( - @PathVariable String projectName) throws NotAuthorizedException { - authService.checkPermission(PROJECT_READ, e -> e.project(projectName)); - return groupService.listGroups(projectName); - } - - /** - * Get a single group. - * @param projectName project name - * @param groupName group name - * @return group - * @throws NotAuthorizedException if PROJECT_READ permissions are not present. - */ - @GetMapping("/{groupName:" + Constants.ENTITY_ID_REGEX + "}") - public GroupDTO getGroup( - @PathVariable String projectName, - @PathVariable String groupName) throws NotAuthorizedException { - authService.checkPermission(PROJECT_READ, e -> e.project(projectName)); - return groupService.getGroup(projectName, groupName); - } - - /** - * Delete a single group. - * @param projectName project name - * @param groupName group name - * @throws NotAuthorizedException if PROJECT_UPDATE permissions are not present. - */ - @DeleteMapping("/{groupName:" + Constants.ENTITY_ID_REGEX + "}") - public ResponseEntity deleteGroup( - @RequestParam(defaultValue = "false") Boolean unlinkSubjects, - @PathVariable String projectName, - @PathVariable String groupName) throws NotAuthorizedException { - authService.checkPermission(PROJECT_UPDATE, e -> e.project(projectName)); - groupService.deleteGroup(projectName, groupName, unlinkSubjects); - return ResponseEntity.noContent().build(); - } - - /** - * Add subjects to a single group. - * @param projectName project name - * @param groupName group name - * @param patchOperations json-patch request body - * @throws NotAuthorizedException if PROJECT_UPDATE permissions are not present. - */ - @PatchMapping("/{groupName:" + Constants.ENTITY_ID_REGEX + "}/subjects") - public ResponseEntity changeGroupSubjects( - @PathVariable String projectName, - @PathVariable String groupName, - @RequestBody List patchOperations) throws NotAuthorizedException { - // Technically, this request modifies subjects, - // so it would make sense to check permissions per subject, - // but I assume that only those who are authorized to perform project-wide actions - // should be allowed to use this endpoint - authService.checkPermission(SUBJECT_UPDATE, e -> e.project(projectName)); - - var addedItems = new ArrayList(); - var removedItems = new ArrayList(); - for (GroupPatchOperation operation : patchOperations) { - String opCode = operation.getOp(); - switch (opCode) { - case "add": - addedItems.addAll(operation.getValue()); - break; - case "remove": - removedItems.addAll(operation.getValue()); - break; - default: - throw new BadRequestException( - "Group patch operation '" + opCode + "' is not supported", - GROUP, ERR_VALIDATION); - } - } - - groupService.updateGroupSubjects(projectName, groupName, addedItems, removedItems); - return ResponseEntity.noContent().build(); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/GroupResource.kt b/src/main/java/org/radarbase/management/web/rest/GroupResource.kt new file mode 100644 index 000000000..22ab46839 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/GroupResource.kt @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.web.rest + +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.GroupService +import org.radarbase.management.service.dto.GroupDTO +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.vm.GroupPatchOperation +import org.radarbase.management.web.rest.vm.GroupPatchOperation.SubjectPatchValue +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PatchMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder +import javax.validation.Valid + +@RestController +@RequestMapping("/api/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/groups") +class GroupResource { + @Autowired + private val groupService: GroupService? = null + + @Autowired + private val authService: AuthService? = null + + /** + * Create group. + * @param projectName project name + * @param groupDto group specification + * @return created response + * @throws NotAuthorizedException if PROJECT_UPDATE permissions are not present. + */ + @PostMapping + @Throws(NotAuthorizedException::class) + fun createGroup( + @PathVariable projectName: String?, + @RequestBody groupDto: @Valid GroupDTO? + ): ResponseEntity { + authService!!.checkPermission(Permission.PROJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) + val groupDtoResult = groupService!!.createGroup(projectName!!, groupDto!!) + val location = MvcUriComponentsBuilder.fromController(javaClass) + .path("/{groupName}") + .buildAndExpand(projectName, groupDtoResult?.name) + .toUri() + return ResponseEntity.created(location) + .body(groupDtoResult) + } + + /** + * List groups. + * @param projectName project name + * @return list of groups + * @throws NotAuthorizedException if PROJECT_READ permissions are not present. + */ + @GetMapping + @Throws(NotAuthorizedException::class) + fun listGroups( + @PathVariable projectName: String? + ): List { + authService!!.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.project(projectName) }) + return groupService!!.listGroups(projectName!!) + } + + /** + * Get a single group. + * @param projectName project name + * @param groupName group name + * @return group + * @throws NotAuthorizedException if PROJECT_READ permissions are not present. + */ + @GetMapping("/{groupName:" + Constants.ENTITY_ID_REGEX + "}") + @Throws( + NotAuthorizedException::class + ) + fun getGroup( + @PathVariable projectName: String?, + @PathVariable groupName: String? + ): GroupDTO { + authService!!.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.project(projectName) }) + return groupService!!.getGroup(projectName!!, groupName!!) + } + + /** + * Delete a single group. + * @param projectName project name + * @param groupName group name + * @throws NotAuthorizedException if PROJECT_UPDATE permissions are not present. + */ + @DeleteMapping("/{groupName:" + Constants.ENTITY_ID_REGEX + "}") + @Throws( + NotAuthorizedException::class + ) + fun deleteGroup( + @RequestParam(defaultValue = "false") unlinkSubjects: Boolean?, + @PathVariable projectName: String?, + @PathVariable groupName: String? + ): ResponseEntity<*> { + authService!!.checkPermission(Permission.PROJECT_UPDATE, { (_, project): EntityDetails -> project }) + groupService!!.deleteGroup(projectName!!, groupName!!, unlinkSubjects!!) + return ResponseEntity.noContent().build() + } + + /** + * Add subjects to a single group. + * @param projectName project name + * @param groupName group name + * @param patchOperations json-patch request body + * @throws NotAuthorizedException if PROJECT_UPDATE permissions are not present. + */ + @PatchMapping("/{groupName:" + Constants.ENTITY_ID_REGEX + "}/subjects") + @Throws( + NotAuthorizedException::class + ) + fun changeGroupSubjects( + @PathVariable projectName: String?, + @PathVariable groupName: String?, + @RequestBody patchOperations: List + ): ResponseEntity<*> { + // Technically, this request modifies subjects, + // so it would make sense to check permissions per subject, + // but I assume that only those who are authorized to perform project-wide actions + // should be allowed to use this endpoint + authService!!.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) + val addedItems = ArrayList() + val removedItems = ArrayList() + for (operation in patchOperations) { + val opCode = operation.op + when (opCode) { + "add" -> operation.value?.let { addedItems.addAll(it) } + "remove" -> operation.value?.let { removedItems.addAll(it) } + else -> throw BadRequestException( + "Group patch operation '$opCode' is not supported", + EntityName.Companion.GROUP, ErrorConstants.ERR_VALIDATION + ) + } + } + groupService!!.updateGroupSubjects(projectName!!, groupName!!, addedItems.filterNotNull(), removedItems.filterNotNull()) + return ResponseEntity.noContent().build() + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/LogsResource.java b/src/main/java/org/radarbase/management/web/rest/LogsResource.java deleted file mode 100644 index 16101a535..000000000 --- a/src/main/java/org/radarbase/management/web/rest/LogsResource.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.radarbase.management.web.rest; - -import ch.qos.logback.classic.Level; -import ch.qos.logback.classic.LoggerContext; -import io.micrometer.core.annotation.Timed; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.web.rest.vm.LoggerVM; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.security.access.annotation.Secured; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; - -/** - * Controller for view and managing Log Level at runtime. - */ -@RestController -@RequestMapping("/management") -public class LogsResource { - - /** - * Returns all the logger configurations from current logger context. - * @return the logger configurations - */ - @GetMapping("/logs") - @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public List getList() { - LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); - return context.getLoggerList() - .stream() - .map(LoggerVM::new) - .toList(); - } - - /** - * Changes logger level. - * @param jsonLogger param - */ - @PutMapping("/logs") - @ResponseStatus(HttpStatus.NO_CONTENT) - @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public void changeLevel(@RequestBody LoggerVM jsonLogger) { - LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); - context.getLogger(jsonLogger.getName()).setLevel(Level.valueOf(jsonLogger.getLevel())); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/LogsResource.kt b/src/main/java/org/radarbase/management/web/rest/LogsResource.kt new file mode 100644 index 000000000..d5d8a93ad --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/LogsResource.kt @@ -0,0 +1,53 @@ +package org.radarbase.management.web.rest + +import ch.qos.logback.classic.Level +import ch.qos.logback.classic.Logger +import ch.qos.logback.classic.LoggerContext +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.web.rest.vm.LoggerVM +import org.slf4j.LoggerFactory +import org.springframework.http.HttpStatus +import org.springframework.security.access.annotation.Secured +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.ResponseStatus +import org.springframework.web.bind.annotation.RestController + +/** + * Controller for view and managing Log Level at runtime. + */ +@RestController +@RequestMapping("/management") +class LogsResource { + @get:Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + @get:Timed + @get:GetMapping("/logs") + val list: List + /** + * Returns all the logger configurations from current logger context. + * @return the logger configurations + */ + get() { + val context = LoggerFactory.getILoggerFactory() as LoggerContext + return context.getLoggerList() + .stream() + .map { logger: Logger -> LoggerVM(logger) } + .toList() + } + + /** + * Changes logger level. + * @param jsonLogger param + */ + @PutMapping("/logs") + @ResponseStatus(HttpStatus.NO_CONTENT) + @Timed + @Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + fun changeLevel(@RequestBody jsonLogger: LoggerVM) { + val context = LoggerFactory.getILoggerFactory() as LoggerContext + context.getLogger(jsonLogger.name).setLevel(Level.valueOf(jsonLogger.level)) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt index efd23ea2e..71bdf0406 100644 --- a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt @@ -171,7 +171,7 @@ class OAuthClientsResource { @PostMapping("/oauth-clients") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createOAuthClient(@RequestBody clientDetailsDto: @Valid ClientDetailsDTO?): ResponseEntity { + fun createOAuthClient(@RequestBody clientDetailsDto: @Valid ClientDetailsDTO): ResponseEntity { authService!!.checkPermission(Permission.OAUTHCLIENTS_CREATE) val created = oAuthClientService!!.createClientDetail(clientDetailsDto) return ResponseEntity.created(ResourceUriService.getUri(clientDetailsDto)) @@ -202,11 +202,9 @@ class OAuthClientsResource { authService!!.checkScope(Permission.SUBJECT_UPDATE) val currentUser = userService!!.userWithAuthorities // We only allow this for actual logged in users for now, not for client_credentials - .orElseThrow { - AccessDeniedException( + ?: throw AccessDeniedException( "You must be a logged in user to access this resource" ) - } // lookup the subject val subject = subjectService!!.findOneByLogin(login) diff --git a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt index 582e81030..ad99b72e5 100644 --- a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt @@ -1,130 +1,124 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.OrganizationService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.dto.OrganizationDTO; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.NotFoundException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.ORGANIZATION_CREATE; -import static org.radarbase.auth.authorization.Permission.ORGANIZATION_READ; -import static org.radarbase.auth.authorization.Permission.ORGANIZATION_UPDATE; -import static org.radarbase.auth.authorization.Permission.PROJECT_READ; -import static org.radarbase.management.web.rest.errors.EntityName.ORGANIZATION; +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.OrganizationService +import org.radarbase.management.service.ResourceUriService.getUri +import org.radarbase.management.service.dto.OrganizationDTO +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.NotFoundException +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityCreationAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createFailureAlert +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import java.net.URISyntaxException +import java.util.* +import javax.validation.Valid /** * REST controller for managing Organization. */ @RestController @RequestMapping("/api") -public class OrganizationResource { - - private static final Logger log = LoggerFactory.getLogger(OrganizationResource.class); - - private static final String ENTITY_NAME = "organization"; - +class OrganizationResource { @Autowired - private OrganizationService organizationService; + private val organizationService: OrganizationService? = null @Autowired - private AuthService authService; + private val authService: AuthService? = null /** * POST /organizations : Create a new organization. * * @param organizationDto the organizationDto to create * @return the ResponseEntity with status 201 (Created) - * and with body the new organizationDto, - * or with status 400 (Bad Request) if the organization already has an ID + * and with body the new organizationDto, + * or with status 400 (Bad Request) if the organization already has an ID * @throws URISyntaxException if the Location URI syntax is incorrect */ @PostMapping("/organizations") @Timed - public ResponseEntity createOrganization( - @Valid @RequestBody OrganizationDTO organizationDto - ) throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save Organization : {}", organizationDto); - authService.checkPermission(ORGANIZATION_CREATE); - if (organizationDto.getId() != null) { - var msg = "A new organization cannot already have an ID"; - var headers = HeaderUtil.createFailureAlert(ENTITY_NAME, "idexists", msg); - return ResponseEntity.badRequest().headers(headers).body(null); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createOrganization( + @RequestBody organizationDto: @Valid OrganizationDTO? + ): ResponseEntity { + log.debug("REST request to save Organization : {}", organizationDto) + authService!!.checkPermission(Permission.ORGANIZATION_CREATE) + if (organizationDto!!.id != null) { + val msg = "A new organization cannot already have an ID" + val headers = createFailureAlert(ENTITY_NAME, "idexists", msg) + return ResponseEntity.badRequest().headers(headers).body(null) } - var existingOrg = organizationService.findByName(organizationDto.getName()); - if (existingOrg.isPresent()) { - var msg = "An organization with this name already exists"; - var headers = HeaderUtil.createFailureAlert(ENTITY_NAME, "nameexists", msg); - return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers).body(null); + val existingOrg = organizationService!!.findByName(organizationDto.name) + if (existingOrg != null) { + val msg = "An organization with this name already exists" + val headers = createFailureAlert(ENTITY_NAME, "nameexists", msg) + return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers).body(null) } - var result = organizationService.save(organizationDto); - return ResponseEntity.created(ResourceUriService.getUri(result)) - .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getName())) - .body(result); + val result = organizationService.save(organizationDto) + return ResponseEntity.created(getUri(result)) + .headers(createEntityCreationAlert(ENTITY_NAME, result.name)) + .body(result) } - /** - * GET /organizations : get all the organizations. - * - * @return the ResponseEntity with status 200 (OK) - * and the list of organizations in body - */ - @GetMapping("/organizations") - @Timed - public ResponseEntity getAllOrganizations() throws NotAuthorizedException { - log.debug("REST request to get Organizations"); - authService.checkScope(ORGANIZATION_READ); - var orgs = organizationService.findAll(); - return new ResponseEntity<>(orgs, HttpStatus.OK); - } + @get:Throws(NotAuthorizedException::class) + @get:Timed + @get:GetMapping("/organizations") + val allOrganizations: ResponseEntity<*> + /** + * GET /organizations : get all the organizations. + * + * @return the ResponseEntity with status 200 (OK) + * and the list of organizations in body + */ + get() { + log.debug("REST request to get Organizations") + authService!!.checkScope(Permission.ORGANIZATION_READ) + val orgs = organizationService!!.findAll() + return ResponseEntity(orgs, HttpStatus.OK) + } /** * PUT /organizations : Updates an existing organization. * * @param organizationDto the organizationDto to update * @return the ResponseEntity - * with status 200 and with the updated organizationDto as body, - * or with status 400 if the organizationDto is not valid, - * or with status 500 if the organizationDto couldnt be updated + * with status 200 and with the updated organizationDto as body, + * or with status 400 if the organizationDto is not valid, + * or with status 500 if the organizationDto couldnt be updated * @throws URISyntaxException if the Location URI syntax is incorrect */ @PutMapping("/organizations") @Timed - public ResponseEntity updateOrganization( - @Valid @RequestBody OrganizationDTO organizationDto - ) throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update Organization : {}", organizationDto); - if (organizationDto.getId() == null) { - return createOrganization(organizationDto); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun updateOrganization( + @RequestBody organizationDto: @Valid OrganizationDTO? + ): ResponseEntity { + log.debug("REST request to update Organization : {}", organizationDto) + if (organizationDto!!.id == null) { + return createOrganization(organizationDto) } - var name = organizationDto.getName(); - authService.checkPermission(ORGANIZATION_UPDATE, e -> e.organization(name)); - var result = organizationService.save(organizationDto); + val name = organizationDto.name + authService!!.checkPermission(Permission.ORGANIZATION_UPDATE, { (organization): EntityDetails -> organization }) + val result = organizationService!!.save(organizationDto) return ResponseEntity.ok() - .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getName())) - .body(result); + .headers(createEntityCreationAlert(ENTITY_NAME, result.name)) + .body(result) } /** @@ -132,39 +126,53 @@ public class OrganizationResource { * * @param name the name of the organizationDTO to retrieve * @return the ResponseEntity with status 200 (OK) - * and with body the organizationDTO, - * or with status 404 (Not Found) + * and with body the organizationDTO, + * or with status 404 (Not Found) */ @GetMapping("/organizations/{name:" + Constants.ENTITY_ID_REGEX + "}") @Timed - public ResponseEntity getOrganization( - @PathVariable String name) throws NotAuthorizedException { - log.debug("REST request to get Organization : {}", name); - authService.checkPermission(ORGANIZATION_READ, e -> e.organization(name)); - var org = organizationService.findByName(name); - var dto = org.orElseThrow(() -> new NotFoundException( - "Organization not found with name " + name, - ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, - Collections.singletonMap("name", name))); - return ResponseEntity.ok(dto); + @Throws( + NotAuthorizedException::class + ) + fun getOrganization( + @PathVariable name: String + ): ResponseEntity { + log.debug("REST request to get Organization : {}", name) + authService!!.checkPermission(Permission.ORGANIZATION_READ, { (organization): EntityDetails -> organization }) + val org = organizationService!!.findByName(name) + val dto = org ?: throw NotFoundException( + "Organization not found with name $name", + EntityName.ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, + Collections.singletonMap("name", name) + ) + return ResponseEntity.ok(dto) } /** * GET /organizations/:organizationName/projects - * : get projects belonging to the organization with this name. + * : get projects belonging to the organization with this name. * * @param name the name of the organization * @return the ResponseEntity - * with status 200 (OK) and with body containing the project list, - * or with status 404 (Not Found) + * with status 200 (OK) and with body containing the project list, + * or with status 404 (Not Found) */ @GetMapping("/organizations/{name:" + Constants.ENTITY_ID_REGEX + "}/projects") @Timed - public ResponseEntity> getOrganizationProjects( - @PathVariable String name) throws NotAuthorizedException { - log.debug("REST request to get Projects of the Organization : {}", name); - authService.checkPermission(PROJECT_READ, e -> e.organization(name)); - var projects = organizationService.findAllProjectsByOrganizationName(name); - return ResponseEntity.ok(projects); + @Throws( + NotAuthorizedException::class + ) + fun getOrganizationProjects( + @PathVariable name: String? + ): ResponseEntity> { + log.debug("REST request to get Projects of the Organization : {}", name) + authService!!.checkPermission(Permission.PROJECT_READ, { (organization): EntityDetails -> organization }) + val projects = organizationService!!.findAllProjectsByOrganizationName(name!!) + return ResponseEntity.ok(projects) + } + + companion object { + private val log = LoggerFactory.getLogger(OrganizationResource::class.java) + private const val ENTITY_NAME = "organization" } } diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index d622155e6..842c51558 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -23,8 +23,11 @@ import org.radarbase.management.web.rest.criteria.SubjectCriteria import org.radarbase.management.web.rest.errors.BadRequestException import org.radarbase.management.web.rest.errors.ErrorConstants import org.radarbase.management.web.rest.errors.ErrorVM -import org.radarbase.management.web.rest.util.HeaderUtil -import org.radarbase.management.web.rest.util.HeaderUtil.* +import org.radarbase.management.web.rest.util.HeaderUtil.buildPath +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityCreationAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityDeletionAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityUpdateAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createFailureAlert import org.radarbase.management.web.rest.util.PaginationUtil import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired @@ -43,6 +46,7 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController import java.net.URISyntaxException +import java.util.NoSuchElementException import javax.validation.Valid /** @@ -105,7 +109,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, .headers( createEntityCreationAlert( ENTITY_NAME, - result.projectName + result?.projectName ) ) .body(result) @@ -139,8 +143,8 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, } // When clients want to transfer a project, // they must have permissions to modify both new & old organizations - val existingProject = projectService.findOne(projectDto.id) - if (existingProject.projectName != projectDto.projectName) { + val existingProject = projectService.findOne(projectDto.id!!) + if (existingProject?.projectName != projectDto.projectName) { throw BadRequestException( "The project name cannot be modified.", ENTITY_NAME, ErrorConstants.ERR_VALIDATION @@ -151,9 +155,9 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, Permission.PROJECT_UPDATE, { e: EntityDetails -> e.organization(newOrgName) - e.project(existingProject.projectName) + e.project(existingProject?.projectName) }) - val oldOrgName = existingProject.organization.name + val oldOrgName = existingProject?.organization?.name if (newOrgName != oldOrgName) { authService.checkPermission( Permission.PROJECT_UPDATE, @@ -179,8 +183,8 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, @Timed @Throws(NotAuthorizedException::class) fun getAllProjects( - @PageableDefault(size = Int.MAX_VALUE) pageable: Pageable?, - @RequestParam(name = "minimized", required = false, defaultValue = "false") minimized: Boolean? + @PageableDefault(size = Int.MAX_VALUE) pageable: Pageable, + @RequestParam(name = "minimized", required = false, defaultValue = "false") minimized: Boolean ): ResponseEntity<*> { log.debug("REST request to get Projects") authService.checkPermission(Permission.PROJECT_READ) @@ -207,7 +211,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, log.debug("REST request to get Project : {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> - e.organization(projectDto.organization.name) + e.organization(projectDto.organization?.name) e.project(projectDto.projectName) }) return ResponseEntity.ok(projectDto) @@ -230,10 +234,10 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, log.debug("REST request to get Project : {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> - e.organization(projectDto.organization.name) + e.organization(projectDto.organization?.name) e.project(projectDto.projectName) }) - return projectService.findSourceTypesByProjectId(projectDto.id) + return projectService.findSourceTypesByProjectId(projectDto.id!!) } /** @@ -252,11 +256,11 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, log.debug("REST request to delete Project : {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.PROJECT_DELETE, { e: EntityDetails -> - e.organization(projectDto.organization.name) + e.organization(projectDto.organization?.name) e.project(projectDto.projectName) }) return try { - projectService.delete(projectDto.id) + projectService.delete(projectDto.id!!) ResponseEntity.ok() .headers(createEntityDeletionAlert(ENTITY_NAME, projectName)) .build() @@ -281,7 +285,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, log.debug("REST request to get all Roles for project {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.ROLE_READ, { e: EntityDetails -> - e.organization(projectDto.organization.name) + e.organization(projectDto.organization?.name) e.project(projectDto.projectName) }) return ResponseEntity.ok(roleService.getRolesByProject(projectName)) @@ -298,16 +302,17 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, NotAuthorizedException::class ) fun getAllSourcesForProject( - @Parameter pageable: Pageable?, - @PathVariable projectName: String?, + @Parameter pageable: Pageable, + @PathVariable projectName: String, @RequestParam(value = "assigned", required = false) assigned: Boolean?, @RequestParam(name = "minimized", required = false, defaultValue = "false") minimized: Boolean ): ResponseEntity<*> { authService.checkScope(Permission.SOURCE_READ) log.debug("REST request to get all Sources") - val projectDto = projectService.findOneByName(projectName!!) + val projectDto = projectService.findOneByName(projectName) ?: throw NoSuchElementException() + authService.checkPermission(Permission.SOURCE_READ, { e: EntityDetails -> - e.organization(projectDto.organization.name) + e.organization(projectDto.organization?.name) e.project(projectDto.projectName) }) return if (assigned != null) { @@ -327,7 +332,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, } else { if (minimized) { val page = sourceService - .findAllMinimalSourceDetailsByProject(projectDto.id, pageable) + .findAllMinimalSourceDetailsByProject(projectDto.id!!, pageable) val headers = PaginationUtil .generatePaginationHttpHeaders( page, buildPath( @@ -338,7 +343,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, ResponseEntity(page.content, headers, HttpStatus.OK) } else { val page = sourceService - .findAllByProjectId(projectDto.id, pageable) + .findAllByProjectId(projectDto.id!!, pageable) val headers = PaginationUtil .generatePaginationHttpHeaders( page, buildPath( @@ -365,23 +370,27 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, subjectCriteria: @Valid SubjectCriteria? ): ResponseEntity> { authService.checkScope(Permission.SUBJECT_READ) - val projectName = subjectCriteria!!.projectName + + + val projectName = subjectCriteria!!.projectName ?: throw NoSuchElementException() // this checks if the project exists - val projectDto = projectService.findOneByName(projectName) + val projectDto = projectName.let { projectService.findOneByName(it) } authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> - e.organization(projectDto.organization.name) + e.organization(projectDto.organization?.name) e.project(projectDto.projectName) }) // this checks if the project exists projectService.findOneByName(projectName) + + subjectCriteria.projectName = projectName log.debug( "REST request to get all subjects for project {} using criteria {}", projectName, subjectCriteria ) val page = subjectService.findAll(subjectCriteria) - .map { subject: Subject? -> subjectMapper.subjectToSubjectWithoutProjectDTO(subject) } + .map { subject: Subject -> subjectMapper.subjectToSubjectWithoutProjectDTO(subject) } val baseUri = buildPath("api", "projects", projectName, "subjects") val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( page, baseUri, subjectCriteria diff --git a/src/main/java/org/radarbase/management/web/rest/RevisionResource.kt b/src/main/java/org/radarbase/management/web/rest/RevisionResource.kt index 2c7312f3b..235c2f6fe 100644 --- a/src/main/java/org/radarbase/management/web/rest/RevisionResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/RevisionResource.kt @@ -1,34 +1,27 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.service.RevisionService; -import org.radarbase.management.service.dto.RevisionInfoDTO; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.annotation.Secured; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.service.RevisionService +import org.radarbase.management.service.dto.RevisionInfoDTO +import org.radarbase.management.web.rest.util.PaginationUtil.generatePaginationHttpHeaders +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Pageable +import org.springframework.data.web.PageableDefault +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.security.access.annotation.Secured +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/api") -public class RevisionResource { - - private static final Logger log = LoggerFactory.getLogger(RevisionResource.class); - +class RevisionResource { @Autowired - private RevisionService revisionService; + private val revisionService: RevisionService? = null /** * Pageable API to get revisions. @@ -38,13 +31,13 @@ public class RevisionResource { */ @GetMapping("/revisions") @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public ResponseEntity> getRevisions( - @PageableDefault(page = 0, size = Integer.MAX_VALUE) Pageable pageable) { - log.debug("REST request to get page of revisions"); - Page page = revisionService.getRevisions(pageable); - return new ResponseEntity<>(page.getContent(), PaginationUtil - .generatePaginationHttpHeaders(page, "/api/revisions"), HttpStatus.OK); + @Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + fun getRevisions( + @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable? + ): ResponseEntity> { + log.debug("REST request to get page of revisions") + val page = revisionService!!.getRevisions(pageable!!) + return ResponseEntity(page.content, generatePaginationHttpHeaders(page, "/api/revisions"), HttpStatus.OK) } /** @@ -55,9 +48,13 @@ public class RevisionResource { */ @GetMapping("/revisions/{id}") @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public ResponseEntity getRevision(@PathVariable("id") Integer id) { - log.debug("REST request to get single revision: {}", id.toString()); - return ResponseEntity.ok(revisionService.getRevision(id)); + @Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + fun getRevision(@PathVariable("id") id: Int): ResponseEntity { + log.debug("REST request to get single revision: {}", id.toString()) + return ResponseEntity.ok(revisionService!!.getRevision(id)) + } + + companion object { + private val log = LoggerFactory.getLogger(RevisionResource::class.java) } } diff --git a/src/main/java/org/radarbase/management/web/rest/RoleResource.java b/src/main/java/org/radarbase/management/web/rest/RoleResource.java deleted file mode 100644 index 0593e7d80..000000000 --- a/src/main/java/org/radarbase/management/web/rest/RoleResource.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.radarbase.management.web.rest; - -import io.micrometer.core.annotation.Timed; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.RoleService; -import org.radarbase.management.service.dto.RoleDTO; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.annotation.Secured; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import tech.jhipster.web.util.ResponseUtil; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.List; - -import static org.radarbase.auth.authorization.Permission.ROLE_CREATE; -import static org.radarbase.auth.authorization.Permission.ROLE_READ; -import static org.radarbase.auth.authorization.Permission.ROLE_UPDATE; - -/** - * REST controller for managing Role. - */ -@RestController -@RequestMapping("/api") -public class RoleResource { - - private static final Logger log = LoggerFactory.getLogger(RoleResource.class); - - private static final String ENTITY_NAME = "role"; - - @Autowired - private RoleService roleService; - @Autowired - private AuthService authService; - - /** - * POST /Roles : Create a new role. - * - * @param roleDto the roleDto to create - * @return the ResponseEntity with status 201 (Created) and with body the new RoleDTO, or with - * status 400 (Bad Request) if the Role has already an ID - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PostMapping("/roles") - @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public ResponseEntity createRole(@Valid @RequestBody RoleDTO roleDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save Role : {}", roleDto); - authService.checkPermission(ROLE_CREATE, e -> e - .organization(roleDto.getOrganizationName()) - .project(roleDto.getProjectName())); - if (roleDto.getId() != null) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, - "idexists", "A new role cannot already have an ID")).body(null); - } - RoleDTO result = roleService.save(roleDto); - return ResponseEntity.created(ResourceUriService.getUri(result)) - .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, displayName(result))) - .body(result); - } - - /** - * PUT /roles : Updates an existing role. - * - * @param roleDto the roleDto to update - * @return the ResponseEntity with status 200 (OK) and with body the updated roleDto, or with - * status 400 (Bad Request) if the roleDto is not valid, or with status 500 (Internal Server - * Error) if the roleDto couldnt be updated - * @throws URISyntaxException if the Location URI syntax is incorrect - */ - @PutMapping("/roles") - @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public ResponseEntity updateRole(@Valid @RequestBody RoleDTO roleDto) - throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update Role : {}", roleDto); - if (roleDto.getId() == null) { - return createRole(roleDto); - } - authService.checkPermission(ROLE_UPDATE, e -> e - .organization(roleDto.getOrganizationName()) - .project(roleDto.getProjectName())); - RoleDTO result = roleService.save(roleDto); - return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, displayName(roleDto))) - .body(result); - } - - /** - * GET /roles : get all the roles. - * - * @return the ResponseEntity with status 200 (OK) and the list of roles in body - */ - @GetMapping("/roles") - @Timed - public List getAllRoles() throws NotAuthorizedException { - log.debug("REST request to get all Roles"); - authService.checkPermission(ROLE_READ); - return roleService.findAll(); - } - - /** - * GET /roles : get all the roles. - * - * @return the ResponseEntity with status 200 (OK) and the list of roles in body - */ - @GetMapping("/roles/admin") - @Timed - @Secured({RoleAuthority.SYS_ADMIN_AUTHORITY}) - public List getAllAdminRoles() { - log.debug("REST request to get all Admin Roles"); - return roleService.findSuperAdminRoles(); - } - - /** - * GET /roles/:projectName/:authorityName : get the role of the specified project and - * authority. - * - * @param projectName The project name - * @param authorityName The authority name - * @return the ResponseEntity with status 200 (OK) and with body the roleDTO, or with status 404 - * (Not Found) - */ - @GetMapping("/roles/{projectName:" + Constants.ENTITY_ID_REGEX + "}/{authorityName:" - + Constants.ENTITY_ID_REGEX + "}") - @Timed - public ResponseEntity getRole(@PathVariable String projectName, - @PathVariable String authorityName) throws NotAuthorizedException { - log.debug("REST request to get all Roles"); - authService.checkPermission(ROLE_READ, e -> e.project(projectName)); - return ResponseUtil.wrapOrNotFound(roleService - .findOneByProjectNameAndAuthorityName(projectName, authorityName)); - } - - /** - * Create a user-friendly display name for a given role. Useful for passing to the notification - * system - * - * @param role The role to create a user-friendly display for - * @return the display name - */ - private String displayName(RoleDTO role) { - return role.getProjectName() + ": " + role.getAuthorityName(); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/RoleResource.kt b/src/main/java/org/radarbase/management/web/rest/RoleResource.kt new file mode 100644 index 000000000..ed4cb384a --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/RoleResource.kt @@ -0,0 +1,174 @@ +package org.radarbase.management.web.rest + +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.EntityDetails +import org.radarbase.auth.authorization.Permission +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ResourceUriService +import org.radarbase.management.service.RoleService +import org.radarbase.management.service.dto.RoleDTO +import org.radarbase.management.web.rest.util.HeaderUtil +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.security.access.annotation.Secured +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.net.URISyntaxException +import java.util.* +import javax.validation.Valid + +/** + * REST controller for managing Role. + */ +@RestController +@RequestMapping("/api") +class RoleResource( + @Autowired private val roleService: RoleService, + @Autowired private val authService: AuthService +) { + + /** + * POST /Roles : Create a new role. + * + * @param roleDto the roleDto to create + * @return the ResponseEntity with status 201 (Created) and with body the new RoleDTO, or with + * status 400 (Bad Request) if the Role has already an ID + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PostMapping("/roles") + @Timed + @Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + @Throws( + URISyntaxException::class, NotAuthorizedException::class + ) + fun createRole(@RequestBody roleDto: @Valid RoleDTO): ResponseEntity { + log.debug("REST request to save Role : {}", roleDto) + authService.checkPermission(Permission.ROLE_CREATE, { e: EntityDetails -> + e.project = roleDto.projectName + }) + if (roleDto.id != null) { + return ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, + "idexists", "A new role cannot already have an ID" + ) + ).body(null) + } + val result = roleService.save(roleDto) + return ResponseEntity.created(ResourceUriService.getUri(result)) + .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, displayName(result))) + .body(result) + } + + /** + * PUT /roles : Updates an existing role. + * + * @param roleDto the roleDto to update + * @return the ResponseEntity with status 200 (OK) and with body the updated roleDto, or with + * status 400 (Bad Request) if the roleDto is not valid, or with status 500 (Internal Server + * Error) if the roleDto couldnt be updated + * @throws URISyntaxException if the Location URI syntax is incorrect + */ + @PutMapping("/roles") + @Timed + @Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + @Throws( + URISyntaxException::class, NotAuthorizedException::class + ) + fun updateRole(@RequestBody roleDto: @Valid RoleDTO): ResponseEntity { + log.debug("REST request to update Role : {}", roleDto) + if (roleDto.id == null) { + return createRole(roleDto) + } + authService.checkPermission(Permission.ROLE_UPDATE, { e: EntityDetails -> + e.project = roleDto.projectName + }) + val result = roleService.save(roleDto) + return ResponseEntity.ok() + .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, displayName(roleDto))) + .body(result) + } + + @get:Throws(NotAuthorizedException::class) + @get:Timed + @get:GetMapping("/roles") + val allRoles: List + /** + * GET /roles : get all the roles. + * + * @return the ResponseEntity with status 200 (OK) and the list of roles in body + */ + get() { + log.debug("REST request to get all Roles") + authService.checkPermission(Permission.ROLE_READ) + return roleService.findAll() + } + + @get:Secured(RoleAuthority.SYS_ADMIN_AUTHORITY) + @get:Timed + @get:GetMapping("/roles/admin") + val allAdminRoles: List + /** + * GET /roles : get all the roles. + * + * @return the ResponseEntity with status 200 (OK) and the list of roles in body + */ + get() { + log.debug("REST request to get all Admin Roles") + return roleService.findSuperAdminRoles() + } + + /** + * GET /roles/:projectName/:authorityName : get the role of the specified project and + * authority. + * + * @param projectName The project name + * @param authorityName The authority name + * @return the ResponseEntity with status 200 (OK) and with body the roleDTO, or with status 404 + * (Not Found) + */ + @GetMapping( + "/roles/{projectName:" + Constants.ENTITY_ID_REGEX + "}/{authorityName:" + + Constants.ENTITY_ID_REGEX + "}" + ) + @Timed + @Throws( + NotAuthorizedException::class + ) + fun getRole( + @PathVariable projectName: String?, + @PathVariable authorityName: String? + ): ResponseEntity { + log.debug("REST request to get all Roles") + authService.checkPermission(Permission.ROLE_READ, { e: EntityDetails -> e.project(projectName) }) + return ResponseUtil.wrapOrNotFound( + Optional.ofNullable(roleService.findOneByProjectNameAndAuthorityName(projectName, authorityName)) + ) + } + + /** + * Create a user-friendly display name for a given role. Useful for passing to the notification + * system + * + * @param role The role to create a user-friendly display for + * @return the display name + */ + private fun displayName(role: RoleDTO?): String { + return role?.projectName + ": " + role?.authorityName + } + + companion object { + private val log = LoggerFactory.getLogger(RoleResource::class.java) + private const val ENTITY_NAME = "role" + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt index f3709979e..10a99b4ff 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt @@ -1,88 +1,83 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.SourceDataService; -import org.radarbase.management.service.dto.SourceDataDTO; -import org.radarbase.management.web.rest.errors.ConflictException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import tech.jhipster.web.util.ResponseUtil; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - -import static org.radarbase.auth.authorization.Permission.SOURCEDATA_CREATE; -import static org.radarbase.auth.authorization.Permission.SOURCEDATA_DELETE; -import static org.radarbase.auth.authorization.Permission.SOURCEDATA_READ; -import static org.radarbase.auth.authorization.Permission.SOURCEDATA_UPDATE; -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE_DATA; +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ResourceUriService.getUri +import org.radarbase.management.service.SourceDataService +import org.radarbase.management.service.dto.SourceDataDTO +import org.radarbase.management.web.rest.errors.ConflictException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityCreationAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityDeletionAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createEntityUpdateAlert +import org.radarbase.management.web.rest.util.HeaderUtil.createFailureAlert +import org.radarbase.management.web.rest.util.PaginationUtil.generatePaginationHttpHeaders +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Pageable +import org.springframework.data.web.PageableDefault +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.net.URISyntaxException +import java.util.* +import javax.validation.Valid /** * REST controller for managing SourceData. */ @RestController @RequestMapping("/api") -public class SourceDataResource { - - private static final Logger log = LoggerFactory.getLogger(SourceDataResource.class); - - @Autowired - private SourceDataService sourceDataService; - @Autowired - private AuthService authService; +class SourceDataResource( + @Autowired private val sourceDataService: SourceDataService, + @Autowired private val authService: AuthService +) { /** * POST /source-data : Create a new sourceData. * * @param sourceDataDto the sourceDataDto to create * @return the ResponseEntity with status 201 (Created) and with body the new sourceDataDto, or - * with status 400 (Bad Request) if the sourceData has already an ID + * with status 400 (Bad Request) if the sourceData has already an ID * @throws URISyntaxException if the Location URI syntax is incorrect */ @PostMapping("/source-data") @Timed - public ResponseEntity createSourceData(@Valid @RequestBody SourceDataDTO - sourceDataDto) throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save SourceData : {}", sourceDataDto); - authService.checkPermission(SOURCEDATA_CREATE); - if (sourceDataDto.getId() != null) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(SOURCE_DATA, - "idexists", "A new sourceData cannot already have an ID")).build(); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createSourceData(@RequestBody sourceDataDto: @Valid SourceDataDTO?): ResponseEntity { + log.debug("REST request to save SourceData : {}", sourceDataDto) + authService.checkPermission(Permission.SOURCEDATA_CREATE) + if (sourceDataDto!!.id != null) { + return ResponseEntity.badRequest().headers( + createFailureAlert( + EntityName.SOURCE_DATA, + "idexists", "A new sourceData cannot already have an ID" + ) + ).build() } - String name = sourceDataDto.getSourceDataName(); - if (sourceDataService.findOneBySourceDataName(name).isPresent()) { - throw new ConflictException("SourceData already available with source-name", - SOURCE_DATA, "error.sourceDataNameAvailable", - Collections.singletonMap("sourceDataName", name)); + val name = sourceDataDto.sourceDataName + if (sourceDataService.findOneBySourceDataName(name) != null) { + throw ConflictException( + "SourceData already available with source-name", + EntityName.SOURCE_DATA, "error.sourceDataNameAvailable", + Collections.singletonMap("sourceDataName", name) + ) } - SourceDataDTO result = sourceDataService.save(sourceDataDto); - return ResponseEntity.created(ResourceUriService.getUri(sourceDataDto)) - .headers(HeaderUtil.createEntityCreationAlert(SOURCE_DATA, name)) - .body(result); + val result = sourceDataService.save(sourceDataDto) + return ResponseEntity.created(getUri(sourceDataDto)) + .headers(createEntityCreationAlert(EntityName.SOURCE_DATA, name)) + .body(result) } /** @@ -90,23 +85,23 @@ public class SourceDataResource { * * @param sourceDataDto the sourceDataDto to update * @return the ResponseEntity with status 200 (OK) and with body the updated sourceDataDto, or - * with status 400 (Bad Request) if the sourceDataDto is not valid, or with status 500 - * (Internal Server Error) if the sourceDataDto couldnt be updated + * with status 400 (Bad Request) if the sourceDataDto is not valid, or with status 500 + * (Internal Server Error) if the sourceDataDto couldnt be updated * @throws URISyntaxException if the Location URI syntax is incorrect */ @PutMapping("/source-data") @Timed - public ResponseEntity updateSourceData(@Valid @RequestBody SourceDataDTO - sourceDataDto) throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update SourceData : {}", sourceDataDto); - if (sourceDataDto.getId() == null) { - return createSourceData(sourceDataDto); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun updateSourceData(@RequestBody sourceDataDto: @Valid SourceDataDTO?): ResponseEntity { + log.debug("REST request to update SourceData : {}", sourceDataDto) + if (sourceDataDto!!.id == null) { + return createSourceData(sourceDataDto) } - authService.checkPermission(SOURCEDATA_UPDATE); - SourceDataDTO result = sourceDataService.save(sourceDataDto); - return ResponseEntity.ok().headers(HeaderUtil - .createEntityUpdateAlert(SOURCE_DATA, sourceDataDto.getSourceDataName())) - .body(result); + authService.checkPermission(Permission.SOURCEDATA_UPDATE) + val result = sourceDataService.save(sourceDataDto) + return ResponseEntity.ok() + .headers(createEntityUpdateAlert(EntityName.SOURCE_DATA, sourceDataDto.sourceDataName)) + .body(result) } /** @@ -117,15 +112,15 @@ public class SourceDataResource { */ @GetMapping("/source-data") @Timed - public ResponseEntity> getAllSourceData( - @PageableDefault(page = 0, size = Integer.MAX_VALUE) Pageable pageable) - throws NotAuthorizedException { - log.debug("REST request to get all SourceData"); - authService.checkScope(SOURCEDATA_READ); - Page page = sourceDataService.findAll(pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/api/source-data"); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + @Throws(NotAuthorizedException::class) + fun getAllSourceData( + @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable? + ): ResponseEntity> { + log.debug("REST request to get all SourceData") + authService.checkScope(Permission.SOURCEDATA_READ) + val page = sourceDataService.findAll(pageable) + val headers = generatePaginationHttpHeaders(page, "/api/source-data") + return ResponseEntity(page.content, headers, HttpStatus.OK) } /** @@ -133,15 +128,21 @@ public class SourceDataResource { * * @param sourceDataName the sourceDataName of the sourceDataDTO to retrieve * @return the ResponseEntity with status 200 (OK) and with body the sourceDataDTO, or with - * status 404 (Not Found) + * status 404 (Not Found) */ @GetMapping("/source-data/{sourceDataName:" + Constants.ENTITY_ID_REGEX + "}") @Timed - public ResponseEntity getSourceData(@PathVariable String sourceDataName) - throws NotAuthorizedException { - authService.checkScope(SOURCEDATA_READ); - return ResponseUtil.wrapOrNotFound(sourceDataService - .findOneBySourceDataName(sourceDataName)); + @Throws( + NotAuthorizedException::class + ) + fun getSourceData(@PathVariable sourceDataName: String?): ResponseEntity { + authService.checkScope(Permission.SOURCEDATA_READ) + return ResponseUtil.wrapOrNotFound( + Optional.ofNullable( + sourceDataService + .findOneBySourceDataName(sourceDataName) + ) + ) } /** @@ -152,17 +153,18 @@ public class SourceDataResource { */ @DeleteMapping("/source-data/{sourceDataName:" + Constants.ENTITY_ID_REGEX + "}") @Timed - public ResponseEntity deleteSourceData(@PathVariable String sourceDataName) - throws NotAuthorizedException { - authService.checkPermission(SOURCEDATA_DELETE); - Optional sourceDataDto = sourceDataService - .findOneBySourceDataName(sourceDataName); - if (sourceDataDto.isEmpty()) { - return ResponseEntity.notFound().build(); - } - sourceDataService.delete(sourceDataDto.get().getId()); - return ResponseEntity.ok().headers(HeaderUtil - .createEntityDeletionAlert(SOURCE_DATA, sourceDataName)).build(); + @Throws( + NotAuthorizedException::class + ) + fun deleteSourceData(@PathVariable sourceDataName: String?): ResponseEntity { + authService.checkPermission(Permission.SOURCEDATA_DELETE) + val sourceDataDto = sourceDataService + .findOneBySourceDataName(sourceDataName) ?: return ResponseEntity.notFound().build() + sourceDataService.delete(sourceDataDto.id) + return ResponseEntity.ok().headers(createEntityDeletionAlert(EntityName.SOURCE_DATA, sourceDataName)).build() } + companion object { + private val log = LoggerFactory.getLogger(SourceDataResource::class.java) + } } diff --git a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt index e00a6714e..3e14ca0a5 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt @@ -55,53 +55,46 @@ class SourceResource( @PostMapping("/sources") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createSource(@RequestBody sourceDto: @Valid SourceDTO?): ResponseEntity { + fun createSource(@RequestBody sourceDto: @Valid SourceDTO?): ResponseEntity { log.debug("REST request to save Source : {}", sourceDto) val project = sourceDto!!.project - authService.checkPermission(Permission.SOURCE_CREATE, { (_, project1): EntityDetails -> + authService.checkPermission(Permission.SOURCE_CREATE, { e: EntityDetails -> if (project != null) { - project1 + e.project(project.projectName) } }) + return if (sourceDto.id != null) { ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( - ENTITY_NAME, - "idexists", "A new source cannot already have an ID" + ENTITY_NAME, "idexists", "A new source cannot already have an ID" ) ).build() - } else if (sourceDto.sourceId != null) { + } else if (sourceDto.sourceId != null) { ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( - ENTITY_NAME, - "sourceIdExists", "A new source cannot already have a Source ID" + ENTITY_NAME, "sourceIdExists", "A new source cannot already have a Source ID" ) ).build() - } else if (sourceRepository.findOneBySourceName(sourceDto.sourceName).isPresent) { + } else if (sourceRepository.findOneBySourceName(sourceDto.sourceName) != null) { ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( - ENTITY_NAME, - "sourceNameExists", "Source name already in use" + ENTITY_NAME, "sourceNameExists", "Source name already in use" ) ).build() } else if (sourceDto.assigned == null) { - ResponseEntity.badRequest() - .headers( - HeaderUtil.createFailureAlert( - ENTITY_NAME, "sourceAssignedRequired", - "A new source must have the 'assigned' field specified" - ) - ).body(null) + ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + ENTITY_NAME, "sourceAssignedRequired", "A new source must have the 'assigned' field specified" + ) + ).body(null) } else { val result = sourceService.save(sourceDto) - ResponseEntity.created(ResourceUriService.getUri(result)) - .headers( + ResponseEntity.created(ResourceUriService.getUri(result)).headers( HeaderUtil.createEntityCreationAlert( - ENTITY_NAME, - result.sourceName + ENTITY_NAME, result.sourceName ) - ) - .body(result) + ).body(result) } } @@ -117,15 +110,15 @@ class SourceResource( @PutMapping("/sources") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun updateSource(@RequestBody sourceDto: @Valid SourceDTO?): ResponseEntity { + fun updateSource(@RequestBody sourceDto: @Valid SourceDTO): ResponseEntity { log.debug("REST request to update Source : {}", sourceDto) - if (sourceDto!!.id == null) { + if (sourceDto.id == null) { return createSource(sourceDto) } val project = sourceDto.project - authService.checkPermission(Permission.SOURCE_UPDATE, { (_, project1): EntityDetails -> + authService.checkPermission(Permission.SOURCE_UPDATE, { e: EntityDetails -> if (project != null) { - project1 + e.project(project.projectName) } }) val updatedSource: SourceDTO? = sourceService.updateSource(sourceDto) @@ -150,8 +143,7 @@ class SourceResource( authService.checkPermission(Permission.SUBJECT_READ) log.debug("REST request to get all Sources") val page = sourceService.findAll(pageable) - val headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/api/sources") + val headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/sources") return ResponseEntity(page!!.content, headers, HttpStatus.OK) } @@ -167,21 +159,19 @@ class SourceResource( @Throws( NotAuthorizedException::class ) - fun getSource(@PathVariable sourceName: String?): ResponseEntity { + fun getSource(@PathVariable sourceName: String): ResponseEntity { log.debug("REST request to get Source : {}", sourceName) authService.checkScope(Permission.SOURCE_READ) - val sourceOpt = sourceService.findOneByName(sourceName) - if (sourceOpt.isPresent) { - val source = sourceOpt.get() - authService.checkPermission(Permission.SOURCE_READ, { (_, project, subject): EntityDetails -> + val source = sourceService.findOneByName(sourceName) + if (source != null) { + authService.checkPermission(Permission.SOURCE_READ, { e: EntityDetails -> if (source.project != null) { - project + e.project(source.project!!.projectName) } - subject - //.source(source.sourceName) + e.subject(source.subjectLogin).source(source.sourceName) }) } - return ResponseUtil.wrapOrNotFound(sourceOpt) + return ResponseUtil.wrapOrNotFound(Optional.ofNullable(source)) } /** @@ -195,45 +185,40 @@ class SourceResource( @Throws( NotAuthorizedException::class ) - fun deleteSource(@PathVariable sourceName: String?): ResponseEntity { + fun deleteSource(@PathVariable sourceName: String): ResponseEntity { log.debug("REST request to delete Source : {}", sourceName) authService.checkScope(Permission.SOURCE_DELETE) - val sourceDtoOpt = sourceService.findOneByName(sourceName) - if (sourceDtoOpt.isEmpty) { - return ResponseEntity.notFound().build() - } - val sourceDto = sourceDtoOpt.get() - authService.checkPermission(Permission.SOURCE_DELETE, { (_, project, subject): EntityDetails -> + val sourceDto = sourceService.findOneByName(sourceName) + ?: return ResponseEntity.notFound().build() + authService.checkPermission(Permission.SOURCE_DELETE, { e: EntityDetails -> if (sourceDto.project != null) { - project + e.project(sourceDto.project!!.projectName); } - subject - //.source(sourceDto.sourceName) + e.subject(sourceDto.subjectLogin) + .source(sourceDto.sourceName) }) - if (sourceDto.assigned) { + if (sourceDto.assigned == true) { return ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( - ENTITY_NAME, - "sourceIsAssigned", "Cannot delete an assigned source" + ENTITY_NAME, "sourceIsAssigned", "Cannot delete an assigned source" ) ).build() } - val sourceId = sourceDtoOpt.get().id - val sourceHistory = sourceRepository.findRevisions(sourceId) - val sources = sourceHistory.content.mapNotNull { obj: Revision -> obj.entity } - .filter { it.isAssigned == true }.toList() - if (sources.isNotEmpty()) { + val sourceId = sourceDto.id + val sourceHistory = sourceId?.let { sourceRepository.findRevisions(it) } + val sources = + sourceHistory?.mapNotNull { obj: Revision -> obj.entity }?.filter { it.isAssigned == true } + ?.toList() + if (sources?.isNotEmpty() == true) { val failureAlert = HeaderUtil.createFailureAlert( - ENTITY_NAME, - "sourceRevisionIsAssigned", "Cannot delete a previously assigned source" + ENTITY_NAME, "sourceRevisionIsAssigned", "Cannot delete a previously assigned source" ) return ResponseEntity.status(HttpStatus.CONFLICT).headers(failureAlert).build() } - sourceService.delete(sourceId) + sourceId?.let { sourceService.delete(it) } return ResponseEntity.ok().headers( HeaderUtil.createEntityDeletionAlert( - ENTITY_NAME, - sourceName + ENTITY_NAME, sourceName ) ).build() } diff --git a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt index eb0bce7ee..5a34bac73 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt @@ -1,109 +1,97 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.domain.SourceType; -import org.radarbase.management.repository.SourceTypeRepository; -import org.radarbase.management.security.Constants; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.ResourceUriService; -import org.radarbase.management.service.SourceTypeService; -import org.radarbase.management.service.dto.ProjectDTO; -import org.radarbase.management.service.dto.SourceTypeDTO; -import org.radarbase.management.web.rest.errors.ConflictException; -import org.radarbase.management.web.rest.errors.ErrorConstants; -import org.radarbase.management.web.rest.errors.InvalidRequestException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.radarbase.management.web.rest.util.PaginationUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import tech.jhipster.web.util.ResponseUtil; - -import javax.validation.Valid; -import java.net.URISyntaxException; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - -import static org.radarbase.auth.authorization.Permission.SOURCETYPE_CREATE; -import static org.radarbase.auth.authorization.Permission.SOURCETYPE_DELETE; -import static org.radarbase.auth.authorization.Permission.SOURCETYPE_READ; -import static org.radarbase.auth.authorization.Permission.SOURCETYPE_UPDATE; -import static org.radarbase.management.web.rest.errors.EntityName.SOURCE_TYPE; +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.Permission +import org.radarbase.management.domain.SourceType +import org.radarbase.management.repository.SourceTypeRepository +import org.radarbase.management.security.Constants +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.ResourceUriService.getUri +import org.radarbase.management.service.SourceTypeService +import org.radarbase.management.service.dto.ProjectDTO +import org.radarbase.management.service.dto.SourceTypeDTO +import org.radarbase.management.web.rest.errors.ConflictException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.radarbase.management.web.rest.errors.InvalidRequestException +import org.radarbase.management.web.rest.util.HeaderUtil +import org.radarbase.management.web.rest.util.PaginationUtil +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Pageable +import org.springframework.data.web.PageableDefault +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import tech.jhipster.web.util.ResponseUtil +import java.net.URISyntaxException +import java.util.* +import java.util.stream.Collectors +import javax.validation.Valid /** * REST controller for managing SourceType. */ @RestController @RequestMapping("/api") -public class SourceTypeResource { - private static final Logger log = LoggerFactory.getLogger(SourceTypeResource.class); - - @Autowired - private SourceTypeService sourceTypeService; - - @Autowired - private SourceTypeRepository sourceTypeRepository; - @Autowired - private AuthService authService; +class SourceTypeResource( + @Autowired private val sourceTypeService: SourceTypeService, + @Autowired private val sourceTypeRepository: SourceTypeRepository, + @Autowired private val authService: AuthService +) { /** * POST /source-types : Create a new sourceType. * * @param sourceTypeDto the sourceTypeDto to create * @return the ResponseEntity with status 201 (Created) and with body the new sourceTypeDto, or - * with status 400 (Bad Request) if the sourceType has already an ID + * with status 400 (Bad Request) if the sourceType has already an ID * @throws URISyntaxException if the Location URI syntax is incorrect */ @PostMapping("/source-types") @Timed - public ResponseEntity createSourceType(@Valid @RequestBody - SourceTypeDTO sourceTypeDto) throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to save SourceType : {}", sourceTypeDto); - authService.checkPermission(SOURCETYPE_CREATE); - if (sourceTypeDto.getId() != null) { - return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(SOURCE_TYPE, - "idexists", "A new sourceType cannot already have an ID")).build(); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun createSourceType(@RequestBody sourceTypeDto: @Valid SourceTypeDTO?): ResponseEntity { + log.debug("REST request to save SourceType : {}", sourceTypeDto) + authService!!.checkPermission(Permission.SOURCETYPE_CREATE) + if (sourceTypeDto!!.id != null) { + return ResponseEntity.badRequest().headers( + HeaderUtil.createFailureAlert( + EntityName.SOURCE_TYPE, + "idexists", "A new sourceType cannot already have an ID" + ) + ).build() } - Optional existing = sourceTypeRepository - .findOneWithEagerRelationshipsByProducerAndModelAndVersion( - sourceTypeDto.getProducer(), sourceTypeDto.getModel(), - sourceTypeDto.getCatalogVersion()); - - if (existing.isPresent()) { - Map errorParams = new HashMap<>(); - errorParams.put("message", "A SourceType with the specified producer, model and " - + "version already exists. This combination needs to be unique."); - errorParams.put("producer", sourceTypeDto.getProducer()); - errorParams.put("model", sourceTypeDto.getModel()); - errorParams.put("catalogVersion", sourceTypeDto.getCatalogVersion()); - throw new ConflictException("A SourceType with the specified producer, model and" - + "version already exists. This combination needs to be unique.", SOURCE_TYPE, - ErrorConstants.ERR_SOURCE_TYPE_EXISTS, errorParams); + val existing: SourceType? = sourceTypeRepository + .findOneWithEagerRelationshipsByProducerAndModelAndVersion( + sourceTypeDto.producer, sourceTypeDto.model, + sourceTypeDto.catalogVersion + ) + if (existing != null) { + val errorParams: MutableMap = HashMap() + errorParams["message"] = ("A SourceType with the specified producer, model and " + + "version already exists. This combination needs to be unique.") + errorParams["producer"] = sourceTypeDto.producer + errorParams["model"] = sourceTypeDto.model + errorParams["catalogVersion"] = sourceTypeDto.catalogVersion + throw ConflictException( + "A SourceType with the specified producer, model and" + + "version already exists. This combination needs to be unique.", EntityName.SOURCE_TYPE, + ErrorConstants.ERR_SOURCE_TYPE_EXISTS, errorParams + ) } - SourceTypeDTO result = sourceTypeService.save(sourceTypeDto); - return ResponseEntity.created(ResourceUriService.getUri(result)) - .headers(HeaderUtil.createEntityCreationAlert(SOURCE_TYPE, displayName(result))) - .body(result); + val result = sourceTypeService!!.save(sourceTypeDto) + return ResponseEntity.created(getUri(result)) + .headers(HeaderUtil.createEntityCreationAlert(EntityName.SOURCE_TYPE, displayName(result))) + .body(result) } /** @@ -111,24 +99,25 @@ public class SourceTypeResource { * * @param sourceTypeDto the sourceTypeDto to update * @return the ResponseEntity with status 200 (OK) and with body the updated sourceTypeDto, or - * with status 400 (Bad Request) if the sourceTypeDto is not valid, or with status 500 - * (Internal Server Error) if the sourceTypeDto couldnt be updated + * with status 400 (Bad Request) if the sourceTypeDto is not valid, or with status 500 + * (Internal Server Error) if the sourceTypeDto couldnt be updated * @throws URISyntaxException if the Location URI syntax is incorrect */ @PutMapping("/source-types") @Timed - public ResponseEntity updateSourceType(@Valid @RequestBody - SourceTypeDTO sourceTypeDto) throws URISyntaxException, NotAuthorizedException { - log.debug("REST request to update SourceType : {}", sourceTypeDto); - if (sourceTypeDto.getId() == null) { - return createSourceType(sourceTypeDto); + @Throws(URISyntaxException::class, NotAuthorizedException::class) + fun updateSourceType(@RequestBody sourceTypeDto: @Valid SourceTypeDTO?): ResponseEntity { + log.debug("REST request to update SourceType : {}", sourceTypeDto) + if (sourceTypeDto!!.id == null) { + return createSourceType(sourceTypeDto) } - authService.checkPermission(SOURCETYPE_UPDATE); - SourceTypeDTO result = sourceTypeService.save(sourceTypeDto); + authService!!.checkPermission(Permission.SOURCETYPE_UPDATE) + val result = sourceTypeService!!.save(sourceTypeDto) return ResponseEntity.ok() - .headers( - HeaderUtil.createEntityUpdateAlert(SOURCE_TYPE, displayName(sourceTypeDto))) - .body(result); + .headers( + HeaderUtil.createEntityUpdateAlert(EntityName.SOURCE_TYPE, displayName(sourceTypeDto)) + ) + .body(result) } /** @@ -139,14 +128,15 @@ public class SourceTypeResource { */ @GetMapping("/source-types") @Timed - public ResponseEntity> getAllSourceTypes( - @PageableDefault(page = 0, size = Integer.MAX_VALUE) Pageable pageable) - throws NotAuthorizedException { - authService.checkPermission(SOURCETYPE_READ); - Page page = sourceTypeService.findAll(pageable); - HttpHeaders headers = PaginationUtil - .generatePaginationHttpHeaders(page, "/api/source-types"); - return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK); + @Throws(NotAuthorizedException::class) + fun getAllSourceTypes( + @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable? + ): ResponseEntity> { + authService!!.checkPermission(Permission.SOURCETYPE_READ) + val page = sourceTypeService!!.findAll(pageable!!) + val headers = PaginationUtil + .generatePaginationHttpHeaders(page, "/api/source-types") + return ResponseEntity(page.content, headers, HttpStatus.OK) } /** @@ -157,10 +147,12 @@ public class SourceTypeResource { */ @GetMapping("/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}") @Timed - public ResponseEntity> getSourceTypes(@PathVariable String producer) - throws NotAuthorizedException { - authService.checkPermission(SOURCETYPE_READ); - return ResponseEntity.ok(sourceTypeService.findByProducer(producer)); + @Throws( + NotAuthorizedException::class + ) + fun getSourceTypes(@PathVariable producer: String?): ResponseEntity> { + authService!!.checkPermission(Permission.SOURCETYPE_READ) + return ResponseEntity.ok(sourceTypeService!!.findByProducer(producer!!)) } /** @@ -171,13 +163,24 @@ public class SourceTypeResource { * @param model The model * @return A list of objects matching the producer and model */ - @GetMapping("/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}/{model:" - + Constants.ENTITY_ID_REGEX + "}") + @GetMapping( + "/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}/{model:" + + Constants.ENTITY_ID_REGEX + "}" + ) @Timed - public ResponseEntity> getSourceTypes(@PathVariable String producer, - @PathVariable String model) throws NotAuthorizedException { - authService.checkPermission(SOURCETYPE_READ); - return ResponseEntity.ok(sourceTypeService.findByProducerAndModel(producer, model)); + @Throws( + NotAuthorizedException::class + ) + fun getSourceTypes( + @PathVariable producer: String?, + @PathVariable model: String? + ): ResponseEntity> { + authService!!.checkPermission(Permission.SOURCETYPE_READ) + return ResponseEntity.ok( + sourceTypeService!!.findByProducerAndModel( + producer!!, model!! + ) + ) } /** @@ -188,15 +191,24 @@ public class SourceTypeResource { * @param version The version * @return A single SourceType object matching the producer, model and version */ - @GetMapping("/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}/{model:" - + Constants.ENTITY_ID_REGEX + "}/{version:" + Constants.ENTITY_ID_REGEX + "}") + @GetMapping( + "/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}/{model:" + + Constants.ENTITY_ID_REGEX + "}/{version:" + Constants.ENTITY_ID_REGEX + "}" + ) @Timed - public ResponseEntity getSourceTypes(@PathVariable String producer, - @PathVariable String model, @PathVariable String version) - throws NotAuthorizedException { - authService.checkPermission(SOURCETYPE_READ); - return ResponseUtil.wrapOrNotFound(Optional.ofNullable( - sourceTypeService.findByProducerAndModelAndVersion(producer, model, version))); + @Throws( + NotAuthorizedException::class + ) + fun getSourceTypes( + @PathVariable producer: String?, + @PathVariable model: String?, @PathVariable version: String? + ): ResponseEntity { + authService!!.checkPermission(Permission.SOURCETYPE_READ) + return ResponseUtil.wrapOrNotFound( + Optional.ofNullable( + sourceTypeService!!.findByProducerAndModelAndVersion(producer!!, model!!, version!!) + ) + ) } /** @@ -208,37 +220,57 @@ public class SourceTypeResource { * @param version The version * @return the ResponseEntity with status 200 (OK) */ - @DeleteMapping("/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}/{model:" - + Constants.ENTITY_ID_REGEX + "}/{version:" + Constants.ENTITY_ID_REGEX + "}") + @DeleteMapping( + "/source-types/{producer:" + Constants.ENTITY_ID_REGEX + "}/{model:" + + Constants.ENTITY_ID_REGEX + "}/{version:" + Constants.ENTITY_ID_REGEX + "}" + ) @Timed - public ResponseEntity deleteSourceType(@PathVariable String producer, - @PathVariable String model, @PathVariable String version) - throws NotAuthorizedException { - authService.checkPermission(SOURCETYPE_DELETE); - SourceTypeDTO sourceTypeDto = sourceTypeService - .findByProducerAndModelAndVersion(producer, model, version); + @Throws( + NotAuthorizedException::class + ) + fun deleteSourceType( + @PathVariable producer: String?, + @PathVariable model: String?, @PathVariable version: String? + ): ResponseEntity { + authService!!.checkPermission(Permission.SOURCETYPE_DELETE) + val sourceTypeDto = sourceTypeService + .findByProducerAndModelAndVersion(producer!!, model!!, version!!) if (Objects.isNull(sourceTypeDto)) { - return ResponseEntity.notFound().build(); + return ResponseEntity.notFound().build() } - List projects = sourceTypeService.findProjectsBySourceType(producer, model, - version); + val projects = sourceTypeService!!.findProjectsBySourceType( + producer, model, + version + ) if (!projects.isEmpty()) { - throw new InvalidRequestException( - // we know the list is not empty so calling get() is safe here - "Cannot delete a source-type that " + "is being used by project(s)", SOURCE_TYPE, - ErrorConstants.ERR_SOURCE_TYPE_IN_USE, Collections.singletonMap("project-names", - projects + throw InvalidRequestException( // we know the list is not empty so calling get() is safe here + "Cannot delete a source-type that " + "is being used by project(s)", EntityName.SOURCE_TYPE, + ErrorConstants.ERR_SOURCE_TYPE_IN_USE, Collections.singletonMap( + "project-names", + projects .stream() - .map(ProjectDTO::getProjectName) - .collect(Collectors.joining("-")))); + .map(ProjectDTO::projectName) + .collect(Collectors.joining("-")) + ) + ) } - sourceTypeService.delete(sourceTypeDto.getId()); - return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(SOURCE_TYPE, - displayName(sourceTypeDto))).build(); + sourceTypeService.delete(sourceTypeDto.id!!) + return ResponseEntity.ok().headers( + HeaderUtil.createEntityDeletionAlert( + EntityName.SOURCE_TYPE, + displayName(sourceTypeDto) + ) + ).build() + } + + private fun displayName(sourceType: SourceTypeDTO?): String { + return java.lang.String.join( + " ", sourceType!!.producer, sourceType.model, + sourceType.catalogVersion + ) } - private String displayName(SourceTypeDTO sourceType) { - return String.join(" ", sourceType.getProducer(), sourceType.getModel(), - sourceType.getCatalogVersion()); + companion object { + private val log = LoggerFactory.getLogger(SourceTypeResource::class.java) } } diff --git a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt index 11b049d16..e83ff61fb 100644 --- a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt @@ -37,6 +37,7 @@ import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.actuate.audit.AuditEvent import org.springframework.boot.actuate.audit.AuditEventRepository +import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity @@ -94,13 +95,10 @@ class SubjectResource( EntityName.SUBJECT, "idexists" ) } - if (subjectDto.getLogin() == null) { - throw BadRequestException("A subject login is required", EntityName.SUBJECT, "loginrequired") - } - if (subjectDto.externalId != null && subjectDto.externalId.isNotEmpty() + if (!subjectDto.externalId.isNullOrEmpty() && subjectRepository.findOneByProjectNameAndExternalId( projectName, subjectDto.externalId - ).isPresent + ) != null ) { throw BadRequestException( "A subject with given project-id and" @@ -109,18 +107,18 @@ class SubjectResource( } val result = subjectService.createSubject(subjectDto) return ResponseEntity.created(ResourceUriService.getUri(subjectDto)) - .headers(HeaderUtil.createEntityCreationAlert(EntityName.SUBJECT, result?.getLogin())) + .headers(HeaderUtil.createEntityCreationAlert(EntityName.SUBJECT, result?.login)) .body(result) } private fun getProjectName(subjectDto: SubjectDTO): String { - if (subjectDto.project == null || subjectDto.project.id == null || subjectDto.project.projectName == null) { + if (subjectDto.project == null || subjectDto.project!!.id == null || subjectDto.project!!.projectName == null) { throw BadRequestException( "A subject should be assigned to a project", EntityName.SUBJECT, "projectrequired" ) } - return subjectDto.project.projectName + return subjectDto.project!!.projectName!! } /** @@ -144,11 +142,11 @@ class SubjectResource( authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> e .project(projectName) - .subject(subjectDto.getLogin()) + .subject(subjectDto.login) }) val result = subjectService.updateSubject(subjectDto) return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(EntityName.SUBJECT, subjectDto.getLogin())) + .headers(HeaderUtil.createEntityUpdateAlert(EntityName.SUBJECT, subjectDto.login)) .body(result) } @@ -159,7 +157,7 @@ class SubjectResource( * @param subjectDto the subjectDto to update * @return the ResponseEntity with status 200 (OK) and with body the updated subjectDto, or with * status 400 (Bad Request) if the subjectDto is not valid, or with status 500 (Internal - * Server Error) if the subjectDto couldnt be updated + * Server Error) if the subjectDto couldn't be updated */ @PutMapping("/subjects/discontinue") @Timed @@ -173,20 +171,20 @@ class SubjectResource( authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> e .project(projectName) - .subject(subjectDto.getLogin()) + .subject(subjectDto.login) }) // In principle this is already captured by the PostUpdate event listener, adding this // event just makes it more clear a subject was discontinued. eventRepository.add( AuditEvent( - SecurityUtils.getCurrentUserLogin().orElse(null), - "SUBJECT_DISCONTINUE", "subject_login=" + subjectDto.getLogin() + SecurityUtils.currentUserLogin, + "SUBJECT_DISCONTINUE", "subject_login=" + subjectDto.login ) ) val result = subjectService.discontinueSubject(subjectDto) return ResponseEntity.ok() - .headers(HeaderUtil.createEntityUpdateAlert(EntityName.SUBJECT, subjectDto.getLogin())) + .headers(HeaderUtil.createEntityUpdateAlert(EntityName.SUBJECT, subjectDto.login)) .body(result) } @@ -211,26 +209,26 @@ class SubjectResource( .map { obj: SubjectAuthority -> obj.name } .toList() return if (projectName != null && externalId != null) { - val subject = subjectRepository + val subject = Optional.ofNullable(subjectRepository .findOneByProjectNameAndExternalIdAndAuthoritiesIn( projectName, externalId, authoritiesToInclude ) - ?.map { s: Subject? -> + ?.let { s: Subject? -> listOf( subjectMapper.subjectToSubjectReducedProjectDTO(s) ) - } + }); ResponseUtil.wrapOrNotFound(subject) } else if (projectName == null && externalId != null) { val page = subjectService.findAll(subjectCriteria) - .map { s: Subject? -> subjectMapper.subjectToSubjectWithoutProjectDTO(s) } + .map { s: Subject -> subjectMapper.subjectToSubjectWithoutProjectDTO(s) } val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( page, "/api/subjects", subjectCriteria ) ResponseEntity(page.content, headers, HttpStatus.OK) } else { val page = subjectService.findAll(subjectCriteria) - .map { subject: Subject? -> subjectMapper.subjectToSubjectWithoutProjectDTO(subject) } + .map { subject: Subject -> subjectMapper.subjectToSubjectWithoutProjectDTO(subject) } val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( page, "/api/subjects", subjectCriteria ) @@ -255,7 +253,7 @@ class SubjectResource( authService.checkScope(Permission.SUBJECT_READ) val subject = subjectService.findOneByLogin(login) val project: Project? = subject.activeProject - ?.let { p -> projectRepository.findOneWithEagerRelationships(p.id) } + ?.let { p -> p.id?.let { projectRepository.findOneWithEagerRelationships(it) } } authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> if (project != null) { e.project(project.projectName) @@ -280,7 +278,7 @@ class SubjectResource( ) fun getSubjectRevisions( @Parameter pageable: Pageable?, - @PathVariable login: String? + @PathVariable login: String ): ResponseEntity> { authService.checkScope(Permission.SUBJECT_READ) log.debug("REST request to get revisions for Subject : {}", login) @@ -315,14 +313,14 @@ class SubjectResource( @Timed @Throws(NotAuthorizedException::class) fun getSubjectRevision( - @PathVariable login: String?, + @PathVariable login: String, @PathVariable revisionNb: Int? ): ResponseEntity { authService.checkScope(Permission.SUBJECT_READ) log.debug("REST request to get Subject : {}, for revisionNb: {}", login, revisionNb) val subjectDto = subjectService.findRevision(login, revisionNb) authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> - e.project(subjectDto.project.projectName) + e.project(subjectDto.project?.projectName) .subject(subjectDto.login) }) return ResponseEntity.ok(subjectDto) @@ -404,10 +402,10 @@ class SubjectResource( } sourceTypeId = sourceTypeService .findByProducerAndModelAndVersion( - sourceDto.sourceTypeProducer, - sourceDto.sourceTypeModel, - sourceDto.sourceTypeCatalogVersion - )?.id + sourceDto.sourceTypeProducer!!, + sourceDto.sourceTypeModel!!, + sourceDto.sourceTypeCatalogVersion!! + ).id // also update the sourceDto, since we pass it on to SubjectService later sourceDto.sourceTypeId = sourceTypeId } @@ -431,14 +429,12 @@ class SubjectResource( // find whether the relevant source-type is available in the subject's project val sourceType = projectRepository .findSourceTypeByProjectIdAndSourceTypeId(currentProject.id, sourceTypeId) - ?.orElseThrow { - BadRequestException( + ?: throw BadRequestException( "No valid source-type found for project." + " You must provide either valid source-type id or producer, model," + " version of a source-type that is assigned to project", EntityName.SUBJECT, ErrorConstants.ERR_SOURCE_TYPE_NOT_PROVIDED ) - } // check if any of id, sourceID, sourceName were non-null val existing = Stream.of( @@ -449,7 +445,7 @@ class SubjectResource( // handle the source registration val sourceRegistered = subjectService - .assignOrUpdateSource(sub, sourceType!!, currentProject, sourceDto) + .assignOrUpdateSource(sub, sourceType, currentProject, sourceDto) // Return the correct response type, either created if a new source was created, or ok if // an existing source was provided. If an existing source was given but not found, the @@ -494,7 +490,7 @@ class SubjectResource( val withInactiveSources = withInactiveSourcesParam != null && withInactiveSourcesParam // check the subject id val subject = subjectRepository.findOneWithEagerBySubjectLogin(login) - .orElseThrow { NoSuchElementException() } + ?: throw NoSuchElementException() authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> e .project(subject.associatedProject?.projectName) @@ -546,13 +542,11 @@ class SubjectResource( // check the subject id val subject = subjectRepository.findOneWithEagerBySubjectLogin(login) - .orElseThrow { - NotFoundException( - "Subject ID not found", - EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND, - Collections.singletonMap("subjectLogin", login) - ) - } + ?: throw NotFoundException( + "Subject ID not found", + EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND, + Collections.singletonMap("subjectLogin", login) + ) authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> e .project(subject.associatedProject?.projectName) diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.kt b/src/main/java/org/radarbase/management/web/rest/UserResource.kt index bae3ea2e4..0c49f4aa1 100644 --- a/src/main/java/org/radarbase/management/web/rest/UserResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/UserResource.kt @@ -106,13 +106,13 @@ class UserResource( ) ).body(null) // Lowercase the user login before comparing with database - } else if (userRepository.findOneByLogin(managedUserVm.login.lowercase()).isPresent) { + } else if (managedUserVm.login.lowercase().let { userRepository.findOneByLogin(it) } != null) { ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( EntityName.USER, "userexists", "Login already in use" ) ).body(null) - } else if (userRepository.findOneByEmail(managedUserVm.email).isPresent) { + } else if (managedUserVm.email?.let { userRepository.findOneByEmail(it) } != null) { ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( EntityName.USER, "emailexists", "Email already in use" @@ -145,18 +145,20 @@ class UserResource( fun updateUser(@RequestBody managedUserVm: ManagedUserVM): ResponseEntity { log.debug("REST request to update User : {}", managedUserVm) authService.checkPermission(Permission.USER_UPDATE, { e: EntityDetails -> e.user(managedUserVm.login) }) - var existingUser = userRepository.findOneByEmail(managedUserVm.email) - if (existingUser.isPresent && existingUser.get().id != managedUserVm.id) { + var existingUser = managedUserVm.email?.let { userRepository.findOneByEmail(it) } + if (existingUser?.id != managedUserVm.id) { throw BadRequestException("Email already in use", EntityName.USER, "emailexists") } - existingUser = userRepository.findOneByLogin( - managedUserVm.login.lowercase() - ) - if (existingUser.isPresent && existingUser.get().id != managedUserVm.id) { + existingUser = managedUserVm.login.lowercase()?.let { + userRepository.findOneByLogin( + it + ) + } + if (existingUser != null && existingUser.id != managedUserVm.id) { throw BadRequestException("Login already in use", EntityName.USER, "emailexists") } val subject = subjectRepository.findOneWithEagerBySubjectLogin(managedUserVm.login) - if (subject.isPresent && managedUserVm.isActivated && subject.get().isRemoved!!) { + if (subject != null && managedUserVm.isActivated && subject.isRemoved!!) { // if the subject is also a user, check if the removed/activated states are valid throw InvalidRequestException( "Subject cannot be the user to request " + "this changes", EntityName.USER, "error.invalidsubjectstate" @@ -210,11 +212,11 @@ class UserResource( @Throws( NotAuthorizedException::class ) - fun getUser(@PathVariable login: String?): ResponseEntity { + fun getUser(@PathVariable login: String): ResponseEntity { log.debug("REST request to get User : {}", login) authService.checkPermission(Permission.USER_READ, { e: EntityDetails -> e.user(login) }) return ResponseUtil.wrapOrNotFound( - userService.getUserWithAuthoritiesByLogin(login) + Optional.ofNullable(userService.getUserWithAuthoritiesByLogin(login)) ) } @@ -229,7 +231,7 @@ class UserResource( @Throws( NotAuthorizedException::class ) - fun deleteUser(@PathVariable login: String?): ResponseEntity { + fun deleteUser(@PathVariable login: String): ResponseEntity { log.debug("REST request to delete User: {}", login) authService.checkPermission(Permission.USER_DELETE, { e: EntityDetails -> e.user(login) }) userService.deleteUser(login) @@ -247,11 +249,12 @@ class UserResource( @Throws( NotAuthorizedException::class ) - fun getUserRoles(@PathVariable login: String?): ResponseEntity> { + fun getUserRoles(@PathVariable login: String): ResponseEntity> { log.debug("REST request to read User roles: {}", login) authService.checkPermission(Permission.ROLE_READ, { e: EntityDetails -> e.user(login) }) - return ResponseUtil.wrapOrNotFound(userService.getUserWithAuthoritiesByLogin(login) - .map { obj: UserDTO -> obj.roles }) + return ResponseUtil.wrapOrNotFound( + Optional.ofNullable(userService.getUserWithAuthoritiesByLogin(login) + .let { obj: UserDTO? -> obj?.roles })) } /** diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.java b/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.java deleted file mode 100644 index 08bc8049a..000000000 --- a/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.web.rest.criteria; - -public class CriteriaRange> { - private T from = null; - private T to = null; - private T is = null; - - public T getFrom() { - return getIs() == null ? from : null; - } - - public void setFrom(T from) { - this.from = from; - } - - public T getTo() { - return getIs() == null ? to : null; - } - - public void setTo(T to) { - this.to = to; - } - - public void setIs(T is) { - this.is = is; - } - - /** Whether the criteria is equal to this value. */ - public T getIs() { - if (is != null) { - return is; - } else if (from != null && from.equals(to)) { - return from; - } else { - return null; - } - } - - /** - * Whether the criteria range contains any values at all. - */ - public boolean isEmpty() { - return from == null && to == null && is == null; - } - - /** - * Validate this criteria range whether the from and to ranges are in order. - */ - public void validate() { - if (is == null && from != null && to != null && from.compareTo(to) > 0) { - throw new IllegalArgumentException( - "CriteriaRange must have a from range that is smaller then the to range."); - } - } - - @Override - public String toString() { - return "CriteriaRange{" + "from=" + getFrom() - + ", to=" + getTo() - + ", is=" + getIs() - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt b/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt new file mode 100644 index 000000000..965f32fc0 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.web.rest.criteria + +open class CriteriaRange?>(var from: T? = null, var to: T? = null, + var iss: T? = null +) { + fun from(): T? { + return if (this.iss == null) from else null + } + + fun to(): T? { + return if (this.iss == null) to else null + } + + val isEmpty: Boolean + /** + * Whether the criteria range contains any values at all. + */ + get() = from == null && to == null && iss == null + + /** + * Validate this criteria range whether the from and to ranges are in order. + */ + fun validate() { + require(!(iss == null && from != null && to != null && from!!.compareTo(to!!) > 0)) { "CriteriaRange must have a from range that is smaller then the to range." } + } + + override fun toString(): String { + return ("CriteriaRange{" + "from=" + from() + + ", to=" + to() + + ", is=" + this.iss + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/LocalDateCriteriaRange.java b/src/main/java/org/radarbase/management/web/rest/criteria/LocalDateCriteriaRange.kt similarity index 60% rename from src/main/java/org/radarbase/management/web/rest/criteria/LocalDateCriteriaRange.java rename to src/main/java/org/radarbase/management/web/rest/criteria/LocalDateCriteriaRange.kt index ca032efef..9af9a1a4c 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/LocalDateCriteriaRange.java +++ b/src/main/java/org/radarbase/management/web/rest/criteria/LocalDateCriteriaRange.kt @@ -6,10 +6,8 @@ * * See the file LICENSE in the root of this repository. */ +package org.radarbase.management.web.rest.criteria -package org.radarbase.management.web.rest.criteria; +import java.time.LocalDate -import java.time.LocalDate; - -public class LocalDateCriteriaRange extends CriteriaRange { -} +class LocalDateCriteriaRange : CriteriaRange() diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectAuthority.java b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectAuthority.kt similarity index 69% rename from src/main/java/org/radarbase/management/web/rest/criteria/SubjectAuthority.java rename to src/main/java/org/radarbase/management/web/rest/criteria/SubjectAuthority.kt index 964674766..3b19818d2 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectAuthority.java +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectAuthority.kt @@ -6,10 +6,9 @@ * * See the file LICENSE in the root of this repository. */ +package org.radarbase.management.web.rest.criteria -package org.radarbase.management.web.rest.criteria; - -public enum SubjectAuthority { +enum class SubjectAuthority { ROLE_PARTICIPANT, - ROLE_INACTIVE_PARTICIPANT; + ROLE_INACTIVE_PARTICIPANT } diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.java b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.java deleted file mode 100644 index a13d3ddb2..000000000 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.java +++ /dev/null @@ -1,238 +0,0 @@ -package org.radarbase.management.web.rest.criteria; - -import org.radarbase.management.web.rest.errors.BadRequestException; -import org.springframework.data.annotation.Transient; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; - -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.time.LocalDate; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import static org.radarbase.management.web.rest.errors.EntityName.SUBJECT; -import static org.radarbase.management.web.rest.errors.ErrorConstants.ERR_VALIDATION; - -public class SubjectCriteria { - private List authority = List.of(SubjectAuthority.ROLE_PARTICIPANT); - private LocalDateCriteriaRange dateOfBirth = null; - private ZonedDateTimeCriteriaRange enrollmentDate = null; - private Long groupId = null; - private String humanReadableIdentifier = null; - private SubjectCriteriaLast last = null; - @Min(0) - private int page = 0; - @Min(1) - private int size = 20; - private List sort; - private String personName = null; - private String projectName = null; - private String externalId = null; - private String login = null; - - @Transient - private List parsedSort = null; - - public List getAuthority() { - return authority; - } - - public void setAuthority(List authority) { - this.authority = authority; - } - - public CriteriaRange getDateOfBirth() { - return dateOfBirth; - } - - public void setDateOfBirth(LocalDateCriteriaRange dateOfBirth) { - this.dateOfBirth = dateOfBirth; - } - - public CriteriaRange getEnrollmentDate() { - return enrollmentDate; - } - - public void setEnrollmentDate(ZonedDateTimeCriteriaRange enrollmentDate) { - this.enrollmentDate = enrollmentDate; - } - - public Long getGroupId() { - return groupId; - } - - public void setGroupId(Long groupId) { - this.groupId = groupId; - } - - public String getHumanReadableIdentifier() { - return humanReadableIdentifier; - } - - public void setHumanReadableIdentifier(String humanReadableIdentifier) { - this.humanReadableIdentifier = humanReadableIdentifier; - } - - public SubjectCriteriaLast getLast() { - return last; - } - - public void setLast(SubjectCriteriaLast last) { - this.last = last; - } - - /** Get the criteria paging settings, excluding sorting. */ - @NotNull - public Pageable getPageable() { - return PageRequest.of(page, size); - } - - public int getPage() { - return page; - } - - public void setPage(int page) { - this.page = page; - } - - public int getSize() { - return size; - } - - public void setSize(int size) { - this.size = size; - } - - public String getPersonName() { - return personName; - } - - public void setPersonName(String personName) { - this.personName = personName; - } - - public String getProjectName() { - return projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - public String getExternalId() { - return externalId; - } - - public void setExternalId(String externalId) { - this.externalId = externalId; - } - - public String getLogin() { - return login; - } - - public void setLogin(String login) { - this.login = login; - } - - public List getSort() { - return sort; - } - - /** Parse the sort criteria. */ - public List getParsedSort() { - if (this.parsedSort == null) { - List flatSort = sort != null - ? sort.stream() - .flatMap(s -> Arrays.stream(s.split(","))) - .toList() - : List.of(); - - List parsedSort = new ArrayList<>(flatSort.size()); - - boolean hasDirection = true; - SubjectSortOrder previous = null; - for (String part : flatSort) { - if (!hasDirection) { - Optional direction = Sort.Direction.fromOptionalString(part); - if (direction.isPresent()) { - previous.setDirection(direction.get()); - hasDirection = true; - continue; - } - } else { - hasDirection = false; - } - previous = new SubjectSortOrder(getSubjectSortBy(part)); - parsedSort.add(previous); - } - - optimizeSortList(parsedSort); - this.parsedSort = Collections.unmodifiableList(parsedSort); - } - return this.parsedSort; - } - - /** - * Remove duplication and redundancy from sort list and make the result order consistent. - * @param sort modifiable ordered sort collection. - */ - private static void optimizeSortList(Collection sort) { - Set seenSortBy = EnumSet.noneOf(SubjectSortBy.class); - boolean hasUnique = false; - Iterator iterator = sort.iterator(); - while (iterator.hasNext()) { - SubjectSortOrder order = iterator.next(); - if (hasUnique || !seenSortBy.add(order.getSortBy())) { - iterator.remove(); - } - if (order.getSortBy().isUnique()) { - hasUnique = true; - } - } - if (!hasUnique) { - sort.add(new SubjectSortOrder(SubjectSortBy.ID)); - } - } - - private static SubjectSortBy getSubjectSortBy(String param) { - return Arrays.stream(SubjectSortBy.values()) - .filter(s -> s.getQueryParam().equalsIgnoreCase(param)) - .findAny() - .orElseThrow(() -> new BadRequestException( - "Cannot convert sort parameter " + param - + " to subject property", SUBJECT, ERR_VALIDATION)); - } - - public void setSort(List sort) { - this.parsedSort = null; - this.sort = sort; - } - - @Override - public String toString() { - return "SubjectCriteria{" + "authority=" + authority - + ", dateOfBirth=" + dateOfBirth - + ", enrollmentDate=" + enrollmentDate - + ", groupId='" + groupId + '\'' - + ", humanReadableIdentifier='" + humanReadableIdentifier + '\'' - + ", last=" + last - + ", page=" + page - + ", sort=" + sort - + ", personName='" + personName + '\'' - + ", projectName='" + projectName + '\'' - + ", externalId='" + externalId + '\'' - + ", login='" + login + '\'' - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt new file mode 100644 index 000000000..1ec053778 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt @@ -0,0 +1,125 @@ +package org.radarbase.management.web.rest.criteria + +import org.radarbase.management.web.rest.errors.BadRequestException +import org.radarbase.management.web.rest.errors.EntityName +import org.radarbase.management.web.rest.errors.ErrorConstants +import org.springframework.data.annotation.Transient +import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Pageable +import org.springframework.data.domain.Sort +import java.util.* +import javax.validation.constraints.Min +import javax.validation.constraints.NotNull + +class SubjectCriteria { + var authority = listOf(SubjectAuthority.ROLE_PARTICIPANT) + var dateOfBirth: LocalDateCriteriaRange? = null + var enrollmentDate: ZonedDateTimeCriteriaRange? = null + var groupId: Long? = null + var humanReadableIdentifier: String? = null + var last: SubjectCriteriaLast? = null + var page: @Min(0) Int = 0 + var size: @Min(1) Int = 20 + private var sort: List? = null + var personName: String? = null + var projectName: String? = null + var externalId: String? = null + var login: String? = null + + @Transient + private var parsedSort: List? = null + + val pageable: @NotNull Pageable + /** Get the criteria paging settings, excluding sorting. */ + get() = PageRequest.of(page, size) + + fun getSort(): List? { + return sort + } + + /** Parse the sort criteria. */ + fun getParsedSort(): List? { + if (parsedSort == null) { + val flatSort = if (sort != null) sort!!.stream() + .flatMap { s: String -> + Arrays.stream(s.split(",".toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray()) + } + .toList() else listOf() + val parsedSort: MutableList = ArrayList(flatSort.size) + var hasDirection = true + var previous: SubjectSortOrder? = null + for (part in flatSort) { + if (!hasDirection) { + val direction = Sort.Direction.fromOptionalString(part) + if (direction.isPresent) { + previous?.direction = direction.get() + hasDirection = true + continue + } + } else { + hasDirection = false + } + previous = SubjectSortOrder(getSubjectSortBy(part)) + parsedSort.add(previous) + } + optimizeSortList(parsedSort) + this.parsedSort = Collections.unmodifiableList(parsedSort).filterNotNull() + } + return parsedSort + } + + override fun toString(): String { + return ("SubjectCriteria{" + "authority=" + authority + + ", dateOfBirth=" + dateOfBirth + + ", enrollmentDate=" + enrollmentDate + + ", groupId='" + groupId + '\'' + + ", humanReadableIdentifier='" + humanReadableIdentifier + '\'' + + ", last=" + last + + ", page=" + page + + ", sort=" + sort + + ", personName='" + personName + '\'' + + ", projectName='" + projectName + '\'' + + ", externalId='" + externalId + '\'' + + ", login='" + login + '\'' + + '}') + } + + companion object { + /** + * Remove duplication and redundancy from sort list and make the result order consistent. + * @param sort modifiable ordered sort collection. + */ + private fun optimizeSortList(sort: MutableCollection) { + val seenSortBy: EnumSet? = EnumSet.noneOf( + SubjectSortBy::class.java + ) + var hasUnique = false + val iterator = sort.iterator() + while (iterator.hasNext()) { + val order = iterator.next() + if (hasUnique || seenSortBy?.add(order?.sortBy) != true) { + iterator.remove() + } + if (order?.sortBy?.isUnique == true) { + hasUnique = true + } + } + if (!hasUnique) { + sort.add(SubjectSortOrder(SubjectSortBy.ID)) + } + } + + private fun getSubjectSortBy(param: String): SubjectSortBy { + return Arrays.stream(SubjectSortBy.values()) + .filter { s: SubjectSortBy -> s.queryParam.equals(param, ignoreCase = true) } + .findAny() + .orElseThrow { + BadRequestException( + "Cannot convert sort parameter " + param + + " to subject property", EntityName.Companion.SUBJECT, ErrorConstants.ERR_VALIDATION + ) + } + } + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.java b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.java deleted file mode 100644 index fde0bd62e..000000000 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.web.rest.criteria; - -public class SubjectCriteriaLast { - private String id = null; - private String externalId = null; - private String login = null; - private SubjectAuthority authority = null; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getExternalId() { - return externalId; - } - - public void setExternalId(String externalId) { - this.externalId = externalId; - } - - public String getLogin() { - return login; - } - - public void setLogin(String login) { - this.login = login; - } - - public SubjectAuthority getAuthority() { - return authority; - } - - public void setAuthority(SubjectAuthority authority) { - this.authority = authority; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.kt new file mode 100644 index 000000000..645016331 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteriaLast.kt @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.web.rest.criteria + +class SubjectCriteriaLast { + var id: String? = null + var externalId: String? = null + var login: String? = null + var authority: SubjectAuthority? = null +} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.java b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.java deleted file mode 100644 index 0294239b3..000000000 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.web.rest.criteria; - -public enum SubjectSortBy { - ID("id", true), - EXTERNAL_ID("externalId", false), - USER_LOGIN("login", true); - - private final String queryParam; - private final boolean isUnique; - - SubjectSortBy(String queryParam, boolean isUnique) { - this.queryParam = queryParam; - this.isUnique = isUnique; - } - - /** Query parameter name. */ - public String getQueryParam() { - return this.queryParam; - } - - /** Whether this property is unique across all subjects. */ - public boolean isUnique() { - return isUnique; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.kt new file mode 100644 index 000000000..d9c85e74f --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortBy.kt @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.web.rest.criteria + +enum class SubjectSortBy( + /** Query parameter name. */ + val queryParam: String, + /** Whether this property is unique across all subjects. */ + val isUnique: Boolean +) { + ID("id", true), + EXTERNAL_ID("externalId", false), + USER_LOGIN("login", true) + +} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.java b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.java deleted file mode 100644 index 47f8e368a..000000000 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2021. The Hyve - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * - * See the file LICENSE in the root of this repository. - */ - -package org.radarbase.management.web.rest.criteria; - -import org.springframework.data.domain.Sort; - -import javax.validation.constraints.NotNull; -import java.util.Objects; - -public class SubjectSortOrder { - private Sort.Direction direction; - private final SubjectSortBy sortBy; - - public SubjectSortOrder(@NotNull SubjectSortBy sortBy, - @NotNull Sort.Direction direction) { - this.direction = direction; - this.sortBy = sortBy; - } - - public SubjectSortOrder(SubjectSortBy sortBy) { - this(sortBy, Sort.Direction.ASC); - } - - public void setDirection(@NotNull Sort.Direction direction) { - this.direction = direction; - } - - @NotNull - public Sort.Direction getDirection() { - return direction; - } - - @NotNull - public SubjectSortBy getSortBy() { - return sortBy; - } - - @Override - public String toString() { - return sortBy.name() + ',' + direction.name(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - SubjectSortOrder that = (SubjectSortOrder) o; - - return sortBy == that.sortBy && direction == that.direction; - } - - @Override - public int hashCode() { - return Objects.hash(direction, sortBy); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt new file mode 100644 index 000000000..c2cad7a04 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021. The Hyve + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * + * See the file LICENSE in the root of this repository. + */ +package org.radarbase.management.web.rest.criteria + +import org.springframework.data.domain.Sort +import java.util.* +import javax.validation.constraints.NotNull + +class SubjectSortOrder @JvmOverloads constructor( + val sortBy: @NotNull SubjectSortBy, + var direction: @NotNull Sort.Direction = Sort.Direction.ASC +) { + + override fun toString(): String { + return sortBy.name + ',' + direction.name + } + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val that = o as SubjectSortOrder + return sortBy == that.sortBy && direction == that.direction + } + + override fun hashCode(): Int { + return Objects.hash(direction, sortBy) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/ZonedDateTimeCriteriaRange.java b/src/main/java/org/radarbase/management/web/rest/criteria/ZonedDateTimeCriteriaRange.kt similarity index 58% rename from src/main/java/org/radarbase/management/web/rest/criteria/ZonedDateTimeCriteriaRange.java rename to src/main/java/org/radarbase/management/web/rest/criteria/ZonedDateTimeCriteriaRange.kt index 33275bec6..6fe17fe94 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/ZonedDateTimeCriteriaRange.java +++ b/src/main/java/org/radarbase/management/web/rest/criteria/ZonedDateTimeCriteriaRange.kt @@ -6,10 +6,8 @@ * * See the file LICENSE in the root of this repository. */ +package org.radarbase.management.web.rest.criteria -package org.radarbase.management.web.rest.criteria; +import java.time.ZonedDateTime -import java.time.ZonedDateTime; - -public class ZonedDateTimeCriteriaRange extends CriteriaRange { -} +class ZonedDateTimeCriteriaRange : CriteriaRange() diff --git a/src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.java b/src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.java deleted file mode 100644 index 840c3e27e..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.springframework.http.HttpStatus; - -import java.util.Map; - -/** - * The request could not be understood by the server due to malformed syntax. - * The client SHOULD NOT repeat the request without modifications. - * (e.g. malformed request syntax, size too large, invalid request message framing, - * or deceptive request routing). - */ -public class BadRequestException extends RadarWebApplicationException { - - /** - * Create a BadRequestException with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - */ - public BadRequestException(String message, String entityName, String errorCode) { - super(HttpStatus.BAD_REQUEST, message, entityName, errorCode); - } - - /** - * Create a BadRequestException with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - * @param paramMap map of additional information. - */ - public BadRequestException(String message, String entityName, String errorCode, - Map paramMap) { - super(HttpStatus.BAD_REQUEST, message, entityName, errorCode, paramMap); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.kt b/src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.kt new file mode 100644 index 000000000..b69f5a6e2 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/BadRequestException.kt @@ -0,0 +1,38 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus + +/** + * The request could not be understood by the server due to malformed syntax. + * The client SHOULD NOT repeat the request without modifications. + * (e.g. malformed request syntax, size too large, invalid request message framing, + * or deceptive request routing). + */ +class BadRequestException : RadarWebApplicationException { + /** + * Create a BadRequestException with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + */ + constructor(message: String?, entityName: String, errorCode: String?) : super( + HttpStatus.BAD_REQUEST, + message, + entityName, + errorCode + ) + + /** + * Create a BadRequestException with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + * @param paramMap map of additional information. + */ + constructor( + message: String?, entityName: String, errorCode: String?, + paramMap: Map? + ) : super(HttpStatus.BAD_REQUEST, message, entityName, errorCode, paramMap) +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ConflictException.java b/src/main/java/org/radarbase/management/web/rest/errors/ConflictException.java deleted file mode 100644 index b1a3c457b..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/ConflictException.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.springframework.http.HttpStatus; - -import java.util.Map; - - -/** - * Created by dverbeec on 13/09/2017. - *

- * The request could not be completed due to a conflict with the current state of the resource. - * This code is only allowed in situations where it is expected that the user might be able to - * resolve the conflict and resubmit the request. The response body SHOULD include enough - * information for the user to recognize the source of the conflict. Ideally, the response - * entity would include enough information for the user or user agent to fix the problem; - * however, that might not be possible and is not required. - *

- */ -public class ConflictException extends RadarWebApplicationException { - - /** - * Create a {@link ConflictException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - */ - public ConflictException(String message, String entityName, String errorCode) { - super(HttpStatus.CONFLICT, message, entityName, errorCode); - } - - /** - * Create a {@link ConflictException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - * @param paramMap map of additional information. - */ - public ConflictException(String message, String entityName, String errorCode, - Map paramMap) { - super(HttpStatus.CONFLICT, message, entityName, errorCode, paramMap); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ConflictException.kt b/src/main/java/org/radarbase/management/web/rest/errors/ConflictException.kt new file mode 100644 index 000000000..2dcbc7949 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/ConflictException.kt @@ -0,0 +1,44 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus + +/** + * Created by dverbeec on 13/09/2017. + * + * + * The request could not be completed due to a conflict with the current state of the resource. + * This code is only allowed in situations where it is expected that the user might be able to + * resolve the conflict and resubmit the request. The response body SHOULD include enough + * information for the user to recognize the source of the conflict. Ideally, the response + * entity would include enough information for the user or user agent to fix the problem; + * however, that might not be possible and is not required. + * + */ +class ConflictException : RadarWebApplicationException { + /** + * Create a [ConflictException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + */ + constructor(message: String?, entityName: String, errorCode: String?) : super( + HttpStatus.CONFLICT, + message, + entityName, + errorCode + ) + + /** + * Create a [ConflictException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + * @param paramMap map of additional information. + */ + constructor( + message: String?, entityName: String, errorCode: String?, + paramMap: Map? + ) : super(HttpStatus.CONFLICT, message, entityName, errorCode, paramMap) +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/EntityName.java b/src/main/java/org/radarbase/management/web/rest/errors/EntityName.java deleted file mode 100644 index a8dc96baf..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/EntityName.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -public interface EntityName { - - String OAUTH_CLIENT = "oauthClient"; - String SOURCE_DATA = "sourceData"; - String SOURCE_TYPE = "sourceType"; - String SUBJECT = "subject"; - String USER = "userManagement"; - String SOURCE = "source"; - String META_TOKEN = "meta-token"; - String ORGANIZATION = "organization"; - String PROJECT = "project"; - String REVISION = "revision"; - String GROUP = "group"; - -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/EntityName.kt b/src/main/java/org/radarbase/management/web/rest/errors/EntityName.kt new file mode 100644 index 000000000..786101b32 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/EntityName.kt @@ -0,0 +1,17 @@ +package org.radarbase.management.web.rest.errors + +interface EntityName { + companion object { + const val OAUTH_CLIENT = "oauthClient" + const val SOURCE_DATA = "sourceData" + const val SOURCE_TYPE = "sourceType" + const val SUBJECT = "subject" + const val USER = "userManagement" + const val SOURCE = "source" + const val META_TOKEN = "meta-token" + const val ORGANIZATION = "organization" + const val PROJECT = "project" + const val REVISION = "revision" + const val GROUP = "group" + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.java b/src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.java deleted file mode 100644 index 3719b57d6..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -public final class ErrorConstants { - - public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure"; - public static final String ERR_ACCESS_DENIED = "error.accessDenied"; - public static final String ERR_VALIDATION = "error.validation"; - public static final String ERR_METHOD_NOT_SUPPORTED = "error.methodNotSupported"; - public static final String ERR_MEDIA_TYPE_NOT_SUPPORTED = "error.mediaTypeNotSupported"; - public static final String ERR_INTERNAL_SERVER_ERROR = "error.internalServerError"; - public static final String ERR_SOURCE_TYPE_EXISTS = "error.sourceTypeExists"; - public static final String ERR_CLIENT_ID_EXISTS = "error.clientIdExists"; - public static final String ERR_OAUTH_CLIENT_PROTECTED = "error.oAuthClientProtected"; - public static final String ERR_OAUTH_CLIENT_ALREADY_EXISTS = "error.oAuthClientExists"; - public static final String ERR_OAUTH_CLIENT_ID_NOT_FOUND = "error.oAuthClientIdNotFound"; - public static final String ERR_SUBJECT_NOT_FOUND = "error.subjectNotFound"; - public static final String ERR_SOURCE_NAME_EXISTS = "error.sourceNameExists"; - public static final String ERR_SOURCE_NOT_FOUND = "error.sourceNotFound"; - public static final String ERR_SOURCE_TYPE_IN_USE = "error.sourceTypeInUse"; - public static final String ERR_SOURCE_TYPE_NOT_FOUND = "error.sourceTypeNotFound"; - public static final String ERR_GROUP_NOT_FOUND = "error.groupNotFound"; - public static final String ERR_GROUP_EXISTS = "error.groupExists"; - public static final String ERR_INVALID_AUTHORITY = "error.invalidAuthority"; - public static final String ERR_EMAIL_EXISTS = "error.emailexists"; - public static final String ERR_ORGANIZATION_NAME_NOT_FOUND = "error" - + ".organizationNameNotFound"; - public static final String ERR_PROJECT_ID_NOT_FOUND = "error.projectIdNotFound"; - public static final String ERR_PROJECT_NAME_NOT_FOUND = "error.projectNameNotFound"; - public static final String ERR_REVISIONS_NOT_FOUND = "error.revisionsNotFound"; - public static final String ERR_ENTITY_NOT_FOUND = "error.entityNotFound"; - public static final String ERR_TOKEN_NOT_FOUND = "error.tokenNotFound"; - public static final String ERR_SOURCE_TYPE_NOT_PROVIDED = "error.sourceTypeNotProvided"; - public static final String ERR_PERSISTENT_TOKEN_DISABLED = "error.persistentTokenDisabled"; - public static final String ERR_ACTIVE_PARTICIPANT_PROJECT_NOT_FOUND = "error" - + ".activeParticipantProjectNotFound"; - public static final String ERR_NO_VALID_PRIVACY_POLICY_URL_CONFIGURED = "error" - + ".noValidPrivacyPolicyUrl"; - public static final String ERR_NO_SUCH_CLIENT = "error.noSuchClient"; - public static final String ERR_PROJECT_NOT_EMPTY = "error.projectNotEmpty"; - public static final String ERR_PASSWORD_TOO_LONG = "error.longPassword"; - public static final String ERR_PASSWORD_TOO_WEAK = "error.weakPassword"; - - public static final String ERR_EMAIL_NOT_REGISTERED = "error.emailNotRegistered"; - - private ErrorConstants() { - } - -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.kt b/src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.kt new file mode 100644 index 000000000..3073a1102 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/ErrorConstants.kt @@ -0,0 +1,42 @@ +package org.radarbase.management.web.rest.errors + +object ErrorConstants { + const val ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure" + const val ERR_ACCESS_DENIED = "error.accessDenied" + const val ERR_VALIDATION = "error.validation" + const val ERR_METHOD_NOT_SUPPORTED = "error.methodNotSupported" + const val ERR_MEDIA_TYPE_NOT_SUPPORTED = "error.mediaTypeNotSupported" + const val ERR_INTERNAL_SERVER_ERROR = "error.internalServerError" + const val ERR_SOURCE_TYPE_EXISTS = "error.sourceTypeExists" + const val ERR_CLIENT_ID_EXISTS = "error.clientIdExists" + const val ERR_OAUTH_CLIENT_PROTECTED = "error.oAuthClientProtected" + const val ERR_OAUTH_CLIENT_ALREADY_EXISTS = "error.oAuthClientExists" + const val ERR_OAUTH_CLIENT_ID_NOT_FOUND = "error.oAuthClientIdNotFound" + const val ERR_SUBJECT_NOT_FOUND = "error.subjectNotFound" + const val ERR_SOURCE_NAME_EXISTS = "error.sourceNameExists" + const val ERR_SOURCE_NOT_FOUND = "error.sourceNotFound" + const val ERR_SOURCE_TYPE_IN_USE = "error.sourceTypeInUse" + const val ERR_SOURCE_TYPE_NOT_FOUND = "error.sourceTypeNotFound" + const val ERR_GROUP_NOT_FOUND = "error.groupNotFound" + const val ERR_GROUP_EXISTS = "error.groupExists" + const val ERR_INVALID_AUTHORITY = "error.invalidAuthority" + const val ERR_EMAIL_EXISTS = "error.emailexists" + const val ERR_ORGANIZATION_NAME_NOT_FOUND = ("error" + + ".organizationNameNotFound") + const val ERR_PROJECT_ID_NOT_FOUND = "error.projectIdNotFound" + const val ERR_PROJECT_NAME_NOT_FOUND = "error.projectNameNotFound" + const val ERR_REVISIONS_NOT_FOUND = "error.revisionsNotFound" + const val ERR_ENTITY_NOT_FOUND = "error.entityNotFound" + const val ERR_TOKEN_NOT_FOUND = "error.tokenNotFound" + const val ERR_SOURCE_TYPE_NOT_PROVIDED = "error.sourceTypeNotProvided" + const val ERR_PERSISTENT_TOKEN_DISABLED = "error.persistentTokenDisabled" + const val ERR_ACTIVE_PARTICIPANT_PROJECT_NOT_FOUND = ("error" + + ".activeParticipantProjectNotFound") + const val ERR_NO_VALID_PRIVACY_POLICY_URL_CONFIGURED = ("error" + + ".noValidPrivacyPolicyUrl") + const val ERR_NO_SUCH_CLIENT = "error.noSuchClient" + const val ERR_PROJECT_NOT_EMPTY = "error.projectNotEmpty" + const val ERR_PASSWORD_TOO_LONG = "error.longPassword" + const val ERR_PASSWORD_TOO_WEAK = "error.weakPassword" + const val ERR_EMAIL_NOT_REGISTERED = "error.emailNotRegistered" +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.java b/src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.java deleted file mode 100644 index 2c31c74bb..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -/** - * View Model for transferring error message with a list of field errors. - */ -public class ErrorVM implements Serializable { - - private static final long serialVersionUID = 1L; - - private final String message; - private final String description; - - private List fieldErrors; - - public ErrorVM(String message) { - this(message, null); - } - - public ErrorVM(String message, String description) { - this.message = message; - this.description = description; - } - - /** - * Add a field error. - * @param objectName the object name - * @param field the field name - * @param message the error message - */ - public void add(String objectName, String field, String message) { - if (fieldErrors == null) { - fieldErrors = new ArrayList<>(); - } - fieldErrors.add(new FieldErrorVM(objectName, field, message)); - } - - public String getMessage() { - return message; - } - - public String getDescription() { - return description; - } - - public List getFieldErrors() { - return fieldErrors; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.kt b/src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.kt new file mode 100644 index 000000000..39ae5c5cd --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/ErrorVM.kt @@ -0,0 +1,31 @@ +package org.radarbase.management.web.rest.errors + +import java.io.Serializable + +/** + * View Model for transferring error message with a list of field errors. + */ +class ErrorVM @JvmOverloads constructor(val message: String?, val description: String? = null) : Serializable { + private var fieldErrors: MutableList? = null + + /** + * Add a field error. + * @param objectName the object name + * @param field the field name + * @param message the error message + */ + fun add(objectName: String?, field: String?, message: String?) { + if (fieldErrors == null) { + fieldErrors = ArrayList() + } + fieldErrors!!.add(FieldErrorVM(objectName, field, message)) + } + + fun getFieldErrors(): List? { + return fieldErrors + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.java b/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.java deleted file mode 100644 index 795beb9af..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.java +++ /dev/null @@ -1,209 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.web.rest.util.HeaderUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.dao.ConcurrencyFailureException; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.http.ResponseEntity.BodyBuilder; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.oauth2.provider.NoSuchClientException; -import org.springframework.transaction.TransactionSystemException; -import org.springframework.validation.BindingResult; -import org.springframework.validation.FieldError; -import org.springframework.web.HttpRequestMethodNotSupportedException; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.ResponseStatus; -import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; -import org.springframework.web.server.ResponseStatusException; - -import java.util.List; - -/** - * Controller advice to translate the server side exceptions to client-friendly json structures. - */ -@ControllerAdvice -@SuppressWarnings("PMD.CouplingBetweenObjects") -public class ExceptionTranslator { - - private static final Logger logger = LoggerFactory.getLogger(ExceptionTranslator.class); - - /** - * Translate a {@link ConcurrencyFailureException}. - * @param ex the exception - * @return the view-model for the translated exception - */ - @ExceptionHandler(ConcurrencyFailureException.class) - @ResponseStatus(HttpStatus.CONFLICT) - @ResponseBody - public ErrorVM processConcurrencyError(ConcurrencyFailureException ex) { - return new ErrorVM(ErrorConstants.ERR_CONCURRENCY_FAILURE); - } - - /** - * Translate a {@link TransactionSystemException}. - * @param ex the exception - * @return the view-model for the translated exception - */ - @ExceptionHandler(TransactionSystemException.class) - @ResponseStatus(HttpStatus.BAD_REQUEST) - @ResponseBody - public ErrorVM processValidationError(TransactionSystemException ex) { - // TODO: this is the top level exception that is thrown when e.g. a - // ConstraintValidationException occurs. Need to investigate what other exceptions result - // in this one and probably add a check for it. - return new ErrorVM(ErrorConstants.ERR_VALIDATION, ex.getMessage()); - } - - /** - * Translate a {@link MethodArgumentNotValidException}. - * @param ex the exception - * @return the view-model for the translated exception - */ - @ExceptionHandler(MethodArgumentNotValidException.class) - @ResponseStatus(HttpStatus.BAD_REQUEST) - @ResponseBody - public ErrorVM processValidationError(MethodArgumentNotValidException ex) { - BindingResult result = ex.getBindingResult(); - List fieldErrors = result.getFieldErrors(); - ErrorVM dto = new ErrorVM(ErrorConstants.ERR_VALIDATION); - for (FieldError fieldError : fieldErrors) { - dto.add(fieldError.getObjectName(), fieldError.getField(), - fieldError.getCode() + ": " + fieldError.getDefaultMessage()); - } - return dto; - } - - @ExceptionHandler(MethodArgumentTypeMismatchException.class) - @ResponseBody - public ErrorVM processValidationError(MethodArgumentTypeMismatchException ex) { - return new ErrorVM(ErrorConstants.ERR_VALIDATION, - ex.getName() + ": " + ex.getMessage()); - } - - @ExceptionHandler(RadarWebApplicationException.class) - public ResponseEntity processParameterizedValidationError( - RadarWebApplicationException ex) { - return processRadarWebApplicationException(ex); - } - - @ExceptionHandler(NotFoundException.class) - public ResponseEntity processNotFound(NotFoundException ex) { - return processRadarWebApplicationException(ex); - } - - @ExceptionHandler(InvalidStateException.class) - public ResponseEntity processNotFound( - InvalidStateException ex) { - return processRadarWebApplicationException(ex); - } - - @ExceptionHandler(RequestGoneException.class) - public ResponseEntity processNotFound(RequestGoneException ex) { - return processRadarWebApplicationException(ex); - } - - @ExceptionHandler(BadRequestException.class) - public ResponseEntity processNotFound(BadRequestException ex) { - return processRadarWebApplicationException(ex); - } - - @ExceptionHandler(InvalidRequestException.class) - public ResponseEntity processNotFound( - InvalidRequestException ex) { - return processRadarWebApplicationException(ex); - } - - - /** - * Translate a {@link ConflictException}. - * @param ex the exception - * @return the view-model for the translated exception - */ - @ExceptionHandler(ConflictException.class) - public ResponseEntity processConflict( - ConflictException ex) { - return processRadarWebApplicationException(ex); - } - - private ResponseEntity processRadarWebApplicationException( - RadarWebApplicationException exception) { - return ResponseEntity - .status(exception.getStatus()) - .headers(HeaderUtil.createExceptionAlert(exception.getEntityName(), - exception.getErrorCode(), exception.getMessage())) - .body(exception.getExceptionVM()); - } - - @ExceptionHandler(AccessDeniedException.class) - @ResponseStatus(HttpStatus.FORBIDDEN) - @ResponseBody - public ErrorVM processAccessDeniedException(AccessDeniedException e) { - return new ErrorVM(ErrorConstants.ERR_ACCESS_DENIED, e.getMessage()); - } - - @ExceptionHandler(NotAuthorizedException.class) - @ResponseStatus(HttpStatus.FORBIDDEN) - @ResponseBody - public ErrorVM processRadarNotAuthorizedException(NotAuthorizedException e) { - return new ErrorVM(ErrorConstants.ERR_ACCESS_DENIED, e.getMessage()); - } - - @ExceptionHandler(HttpRequestMethodNotSupportedException.class) - @ResponseBody - @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) - public ErrorVM processMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) { - return new ErrorVM(ErrorConstants.ERR_METHOD_NOT_SUPPORTED, ex.getMessage()); - } - - /** - * If a client tries to initiate an OAuth flow with a non-existing client, this will - * translate the error into a bad request status. Otherwise we return an internal server - * error status, but it is not a server error. - * - * @param ex the exception - * @return the view-model for the translated exception - */ - @ExceptionHandler(NoSuchClientException.class) - @ResponseBody - @ResponseStatus(HttpStatus.BAD_REQUEST) - public ErrorVM processNoSuchClientException(NoSuchClientException ex) { - return new ErrorVM(ErrorConstants.ERR_NO_SUCH_CLIENT, ex.getMessage()); - } - - @ExceptionHandler(ResponseStatusException.class) - public ResponseEntity responseStatusResponse(ResponseStatusException ex) { - return ResponseEntity.status(ex.getStatus()) - .body(new ErrorVM(null, ex.getMessage())); - } - - /** - * Generic exception translator. - * @param ex the exception - * @return the view-model for the translated exception - */ - @ExceptionHandler(Exception.class) - public ResponseEntity processRuntimeException(Exception ex) { - BodyBuilder builder; - ErrorVM errorVm; - logger.error("Failed to process message", ex); - ResponseStatus responseStatus = AnnotationUtils.findAnnotation(ex.getClass(), - ResponseStatus.class); - if (responseStatus != null) { - builder = ResponseEntity.status(responseStatus.value()); - errorVm = new ErrorVM("error." + responseStatus.value().value(), - responseStatus.reason()); - } else { - builder = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR); - errorVm = new ErrorVM(ErrorConstants.ERR_INTERNAL_SERVER_ERROR, - "Internal server error"); - } - return builder.body(errorVm); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt b/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt new file mode 100644 index 000000000..c405793cf --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt @@ -0,0 +1,224 @@ +package org.radarbase.management.web.rest.errors + +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.web.rest.errors.InvalidStateException +import org.radarbase.management.web.rest.errors.RadarWebApplicationException +import org.radarbase.management.web.rest.errors.RequestGoneException +import org.radarbase.management.web.rest.util.HeaderUtil +import org.slf4j.LoggerFactory +import org.springframework.core.annotation.AnnotationUtils +import org.springframework.dao.ConcurrencyFailureException +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.security.access.AccessDeniedException +import org.springframework.security.oauth2.provider.NoSuchClientException +import org.springframework.transaction.TransactionSystemException +import org.springframework.web.HttpRequestMethodNotSupportedException +import org.springframework.web.bind.MethodArgumentNotValidException +import org.springframework.web.bind.annotation.ControllerAdvice +import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.ResponseBody +import org.springframework.web.bind.annotation.ResponseStatus +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException +import org.springframework.web.server.ResponseStatusException + +/** + * Controller advice to translate the server side exceptions to client-friendly json structures. + */ +@ControllerAdvice +class ExceptionTranslator { + /** + * Translate a [ConcurrencyFailureException]. + * @param ex the exception + * @return the view-model for the translated exception + */ + @ExceptionHandler(ConcurrencyFailureException::class) + @ResponseStatus(HttpStatus.CONFLICT) + @ResponseBody + fun processConcurrencyError(ex: ConcurrencyFailureException?): ErrorVM { + return ErrorVM(ErrorConstants.ERR_CONCURRENCY_FAILURE) + } + + /** + * Translate a [TransactionSystemException]. + * @param ex the exception + * @return the view-model for the translated exception + */ + @ExceptionHandler(TransactionSystemException::class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ResponseBody + fun processValidationError(ex: TransactionSystemException): ErrorVM { + // TODO: this is the top level exception that is thrown when e.g. a + // ConstraintValidationException occurs. Need to investigate what other exceptions result + // in this one and probably add a check for it. + return ErrorVM(ErrorConstants.ERR_VALIDATION, ex.message) + } + + /** + * Translate a [MethodArgumentNotValidException]. + * @param ex the exception + * @return the view-model for the translated exception + */ + @ExceptionHandler(MethodArgumentNotValidException::class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ResponseBody + fun processValidationError(ex: MethodArgumentNotValidException): ErrorVM { + val result = ex.bindingResult + val fieldErrors = result.fieldErrors + val dto = ErrorVM(ErrorConstants.ERR_VALIDATION) + for (fieldError in fieldErrors) { + dto.add( + fieldError.objectName, fieldError.field, + fieldError.code + ": " + fieldError.defaultMessage + ) + } + return dto + } + + @ExceptionHandler(MethodArgumentTypeMismatchException::class) + @ResponseBody + fun processValidationError(ex: MethodArgumentTypeMismatchException): ErrorVM { + return ErrorVM( + ErrorConstants.ERR_VALIDATION, + ex.name + ": " + ex.message + ) + } + + @ExceptionHandler(RadarWebApplicationException::class) + fun processParameterizedValidationError( + ex: RadarWebApplicationException + ): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + @ExceptionHandler(NotFoundException::class) + fun processNotFound(ex: NotFoundException): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + @ExceptionHandler(InvalidStateException::class) + fun processNotFound( + ex: InvalidStateException + ): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + @ExceptionHandler(RequestGoneException::class) + fun processNotFound(ex: RequestGoneException): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + @ExceptionHandler(BadRequestException::class) + fun processNotFound(ex: BadRequestException): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + @ExceptionHandler(InvalidRequestException::class) + fun processNotFound( + ex: InvalidRequestException + ): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + /** + * Translate a [ConflictException]. + * @param ex the exception + * @return the view-model for the translated exception + */ + @ExceptionHandler(ConflictException::class) + fun processConflict( + ex: ConflictException + ): ResponseEntity { + return processRadarWebApplicationException(ex) + } + + private fun processRadarWebApplicationException( + exception: RadarWebApplicationException + ): ResponseEntity { + return ResponseEntity + .status(exception.status) + .headers( + HeaderUtil.createExceptionAlert( + exception.entityName, + exception.errorCode, exception.message + ) + ) + .body(exception.exceptionVM) + } + + @ExceptionHandler(AccessDeniedException::class) + @ResponseStatus(HttpStatus.FORBIDDEN) + @ResponseBody + fun processAccessDeniedException(e: AccessDeniedException): ErrorVM { + return ErrorVM(ErrorConstants.ERR_ACCESS_DENIED, e.message) + } + + @ExceptionHandler(NotAuthorizedException::class) + @ResponseStatus(HttpStatus.FORBIDDEN) + @ResponseBody + fun processRadarNotAuthorizedException(e: NotAuthorizedException): ErrorVM { + return ErrorVM(ErrorConstants.ERR_ACCESS_DENIED, e.message) + } + + @ExceptionHandler(HttpRequestMethodNotSupportedException::class) + @ResponseBody + @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) + fun processMethodNotSupportedException(ex: HttpRequestMethodNotSupportedException): ErrorVM { + return ErrorVM(ErrorConstants.ERR_METHOD_NOT_SUPPORTED, ex.message) + } + + /** + * If a client tries to initiate an OAuth flow with a non-existing client, this will + * translate the error into a bad request status. Otherwise we return an internal server + * error status, but it is not a server error. + * + * @param ex the exception + * @return the view-model for the translated exception + */ + @ExceptionHandler(NoSuchClientException::class) + @ResponseBody + @ResponseStatus(HttpStatus.BAD_REQUEST) + fun processNoSuchClientException(ex: NoSuchClientException): ErrorVM { + return ErrorVM(ErrorConstants.ERR_NO_SUCH_CLIENT, ex.message) + } + + @ExceptionHandler(ResponseStatusException::class) + fun responseStatusResponse(ex: ResponseStatusException): ResponseEntity { + return ResponseEntity.status(ex.status) + .body(ErrorVM(null, ex.message)) + } + + /** + * Generic exception translator. + * @param ex the exception + * @return the view-model for the translated exception + */ + @ExceptionHandler(Exception::class) + fun processRuntimeException(ex: Exception): ResponseEntity { + val builder: ResponseEntity.BodyBuilder + val errorVm: ErrorVM + logger.error("Failed to process message", ex) + val responseStatus = AnnotationUtils.findAnnotation( + ex.javaClass, + ResponseStatus::class.java + ) + if (responseStatus != null) { + builder = ResponseEntity.status(responseStatus.value) + errorVm = ErrorVM( + "error." + responseStatus.value.value(), + responseStatus.reason + ) + } else { + builder = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + errorVm = ErrorVM( + ErrorConstants.ERR_INTERNAL_SERVER_ERROR, + "Internal server error" + ) + } + return builder.body(errorVm) + } + + companion object { + private val logger = LoggerFactory.getLogger(ExceptionTranslator::class.java) + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.java b/src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.java deleted file mode 100644 index 81c580594..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import java.io.Serializable; - -public class FieldErrorVM implements Serializable { - - private static final long serialVersionUID = 1L; - - private final String objectName; - - private final String field; - - private final String message; - - /** - * Create a new field error view-model. - * @param dto the object name - * @param field the field name - * @param message the message - */ - public FieldErrorVM(String dto, String field, String message) { - this.objectName = dto; - this.field = field; - this.message = message; - } - - public String getObjectName() { - return objectName; - } - - public String getField() { - return field; - } - - public String getMessage() { - return message; - } - -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.kt b/src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.kt new file mode 100644 index 000000000..ca4f5cc3d --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/FieldErrorVM.kt @@ -0,0 +1,16 @@ +package org.radarbase.management.web.rest.errors + +import java.io.Serializable + +class FieldErrorVM +/** + * Create a new field error view-model. + * @param dto the object name + * @param field the field name + * @param message the message + */(val objectName: String?, val field: String?, val message: String?) : Serializable { + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.java b/src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.java deleted file mode 100644 index 75c5420be..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.springframework.http.HttpStatus; - -import java.util.Map; - -/** - * The server understood the request, but is refusing to fulfill it. - * Authorization will not help and the request SHOULD NOT be repeated. - */ -public class InvalidRequestException extends RadarWebApplicationException { - - /** - * Create a {@link InvalidRequestException} with the given message, relatedEntityName,errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - */ - public InvalidRequestException(String message, String entityName, String errorCode) { - super(HttpStatus.FORBIDDEN, message, entityName, errorCode); - } - - /** - * Create a {@link InvalidRequestException} with the given message, relatedEntityName,errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - * @param params map of additional information. - */ - public InvalidRequestException(String message, String entityName, String errorCode, - Map params) { - super(HttpStatus.FORBIDDEN, message, entityName, errorCode, params); - } - -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.kt b/src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.kt new file mode 100644 index 000000000..85e344ef4 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/InvalidRequestException.kt @@ -0,0 +1,36 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus + +/** + * The server understood the request, but is refusing to fulfill it. + * Authorization will not help and the request SHOULD NOT be repeated. + */ +class InvalidRequestException : RadarWebApplicationException { + /** + * Create a [InvalidRequestException] with the given message, relatedEntityName,errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + */ + constructor(message: String?, entityName: String, errorCode: String?) : super( + HttpStatus.FORBIDDEN, + message, + entityName, + errorCode + ) + + /** + * Create a [InvalidRequestException] with the given message, relatedEntityName,errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + * @param params map of additional information. + */ + constructor( + message: String?, entityName: String, errorCode: String?, + params: Map? + ) : super(HttpStatus.FORBIDDEN, message, entityName, errorCode, params) +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.java b/src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.java deleted file mode 100644 index f547e1d06..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.radarbase.management.web.rest.errors; - - -import org.springframework.http.HttpStatus; - -import java.util.Map; - -/** - * The server encountered an unexpected condition which prevented it from fulfilling the request. - */ -public class InvalidStateException extends RadarWebApplicationException { - - /** - * Create a {@link InvalidStateException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - */ - public InvalidStateException(String message, String entityName, String errorCode) { - super(HttpStatus.INTERNAL_SERVER_ERROR, message, entityName, errorCode); - } - - /** - * Create a {@link InvalidStateException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - * @param params map of additional information. - */ - public InvalidStateException(String message, String entityName, String errorCode, - Map params) { - super(HttpStatus.INTERNAL_SERVER_ERROR, message, entityName, errorCode, params); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.kt b/src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.kt new file mode 100644 index 000000000..4bf9d316d --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/InvalidStateException.kt @@ -0,0 +1,35 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus + +/** + * The server encountered an unexpected condition which prevented it from fulfilling the request. + */ +class InvalidStateException : RadarWebApplicationException { + /** + * Create a [InvalidStateException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + */ + constructor(message: String?, entityName: String, errorCode: String?) : super( + HttpStatus.INTERNAL_SERVER_ERROR, + message, + entityName, + errorCode + ) + + /** + * Create a [InvalidStateException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + * @param params map of additional information. + */ + constructor( + message: String?, entityName: String, errorCode: String?, + params: Map? + ) : super(HttpStatus.INTERNAL_SERVER_ERROR, message, entityName, errorCode, params) +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.java b/src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.java deleted file mode 100644 index 0c2330b24..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.springframework.http.HttpStatus; - -import java.util.Map; - -/** - * Created by dverbeec on 7/09/2017. - * Modified by nivethika on 2/08/2018. - *

The server has not found anything matching the Request-URI. - * No indication is given of whether the condition is temporary or permanent. - *

- */ -public class NotFoundException extends RadarWebApplicationException { - - /** - * Create a {@link NotFoundException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - */ - public NotFoundException(String message, String entityName, String errorCode) { - super(HttpStatus.NOT_FOUND, message, entityName, errorCode); - } - - /** - * Create a {@link NotFoundException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - * @param paramMap map of additional information. - */ - public NotFoundException(String message, String entityName, String errorCode, - Map paramMap) { - super(HttpStatus.NOT_FOUND, message, entityName, errorCode, paramMap); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.kt b/src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.kt new file mode 100644 index 000000000..4e071e791 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/NotFoundException.kt @@ -0,0 +1,40 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus + +/** + * Created by dverbeec on 7/09/2017. + * Modified by nivethika on 2/08/2018. + * + * The server has not found anything matching the Request-URI. + * No indication is given of whether the condition is temporary or permanent. + * + */ +class NotFoundException : RadarWebApplicationException { + /** + * Create a [NotFoundException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + */ + constructor(message: String?, entityName: String, errorCode: String?) : super( + HttpStatus.NOT_FOUND, + message, + entityName, + errorCode + ) + + /** + * Create a [NotFoundException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + * @param paramMap map of additional information. + */ + constructor( + message: String, entityName: String, errorCode: String, + paramMap: Map? + ) : super(HttpStatus.NOT_FOUND, message, entityName, errorCode, paramMap) +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.java b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.java deleted file mode 100644 index 9c2ac3a87..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.springframework.http.HttpStatus; -import org.springframework.web.server.ResponseStatusException; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -import static java.util.Collections.emptyMap; - -/** - * A base parameterized exception, which can be translated on the client side. - * - *

For example:

- * - *

{@code throw new RadarWebApplicationException("Message to client", "entity", - * "error.errorCode")}

- * - *

can be translated with:

- * - *

{@code "error.myCustomError" : "The server says {{param0}} to {{param1}}"}

- */ -public class RadarWebApplicationException extends ResponseStatusException { - - private final String message; - - private final String entityName; - - private final String errorCode; - - private final Map paramMap = new HashMap<>(); - - /** - * Create an exception with the given parameters. This will be used to to create response - * body of the request. - * - * @param message Error message to the client - * @param entityName Entity related to the exception - * @param errorCode error code defined in MP if relevant. - */ - public RadarWebApplicationException(HttpStatus status, String message, String entityName, - String errorCode) { - this(status, message, entityName, errorCode, emptyMap()); - } - - - /** - * A base parameterized exception, which can be translated on the client side. - * @param status {@link HttpStatus} code. - * @param message message to client. - * @param entityName entityRelated from {@link EntityName} - * @param errorCode errorCode from {@link ErrorConstants} - * @param params map of optional information. - */ - public RadarWebApplicationException(HttpStatus status, String message, String entityName, - String errorCode, Map params) { - super(status, message, null); - // add default timestamp first, so a timestamp key in the paramMap will overwrite it - this.paramMap.put("timestamp", - new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US) - .format(new Date())); - this.paramMap.putAll(params); - this.message = message; - this.entityName = entityName; - this.errorCode = errorCode; - } - - @Override - public String getMessage() { - return message; - } - - public String getEntityName() { - return entityName; - } - - public String getErrorCode() { - return errorCode; - } - - protected RadarWebApplicationExceptionVM getExceptionVM() { - return new RadarWebApplicationExceptionVM(message, entityName, errorCode, paramMap); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.kt b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.kt new file mode 100644 index 000000000..088340c08 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationException.kt @@ -0,0 +1,60 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus +import org.springframework.web.server.ResponseStatusException +import java.text.SimpleDateFormat +import java.util.* + +/** + * A base parameterized exception, which can be translated on the client side. + * + * + * For example: + * + * + * `throw new RadarWebApplicationException("Message to client", "entity", + * "error.errorCode")` + * + * + * can be translated with: + * + * + * `"error.myCustomError" : "The server says {{param0}} to {{param1}}"` + */ +open class RadarWebApplicationException @JvmOverloads constructor( + status: HttpStatus?, message: String?, entityName: String, + errorCode: String?, params: Map? = emptyMap() +) : ResponseStatusException(status, message, null) { + override val message: String? + val entityName: String + val errorCode: String? + private val paramMap: MutableMap = HashMap() + /** + * A base parameterized exception, which can be translated on the client side. + * @param status [HttpStatus] code. + * @param message message to client. + * @param entityName entityRelated from [EntityName] + * @param errorCode errorCode from [ErrorConstants] + * @param params map of optional information. + */ + /** + * Create an exception with the given parameters. This will be used to to create response + * body of the request. + * + * @param message Error message to the client + * @param entityName Entity related to the exception + * @param errorCode error code defined in MP if relevant. + */ + init { + // add default timestamp first, so a timestamp key in the paramMap will overwrite it + paramMap["timestamp"] = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US) + .format(Date()) + paramMap.putAll(params!!) + this.message = message + this.entityName = entityName + this.errorCode = errorCode + } + + val exceptionVM: RadarWebApplicationExceptionVM + get() = RadarWebApplicationExceptionVM(message, entityName, errorCode, paramMap) +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.java b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.java deleted file mode 100644 index dfc438d55..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import java.io.Serializable; -import java.util.Collections; -import java.util.Map; -import java.util.Objects; - -import com.fasterxml.jackson.annotation.JsonProperty; - -/** - * View Model for sending a {@link RadarWebApplicationException}. - */ -public class RadarWebApplicationExceptionVM implements Serializable { - - private static final long serialVersionUID = 1L; - - @JsonProperty - private final String entityName; - - @JsonProperty - private final String errorCode; - - @JsonProperty - private final String message; - - @JsonProperty - private Map params; - - /** - * Creates an error view model with message, entityName and errorCode. - * - * @param message message to client. - * @param entityName entityRelated from {@link EntityName} - * @param errorCode errorCode from {@link ErrorConstants} - */ - protected RadarWebApplicationExceptionVM(String message, String entityName, String errorCode) { - this(message, entityName, errorCode, Collections.emptyMap()); - } - - /** - * Creates an error view model with message, entityName and errorCode. - * - * @param message message to client. - * @param entityName entityRelated from {@link EntityName} - * @param errorCode errorCode from {@link ErrorConstants} - * @param params map of optional information. - */ - protected RadarWebApplicationExceptionVM(String message, String entityName, String errorCode, - Map params) { - this.message = message; - this.entityName = entityName; - this.errorCode = errorCode; - this.params = params; - } - - public Map getParams() { - return params; - } - - public String getEntityName() { - return entityName; - } - - public String getErrorCode() { - return errorCode; - } - - public String getMessage() { - return message; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - RadarWebApplicationExceptionVM that = (RadarWebApplicationExceptionVM) o; - return Objects.equals(entityName, that.entityName) && Objects - .equals(errorCode, that.errorCode) && Objects.equals(message, that.message) && Objects - .equals(params, that.params); - } - - @Override - public int hashCode() { - - return Objects.hash(entityName, errorCode, message, params); - } - - @Override - public String toString() { - return "RadarWebApplicationExceptionVM{" + "entityName='" + entityName + '\'' - + ", errorCode='" + errorCode + '\'' + ", message='" + message + '\'' + ", params=" - + params + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt new file mode 100644 index 000000000..51d44586a --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt @@ -0,0 +1,63 @@ +package org.radarbase.management.web.rest.errors + +import com.fasterxml.jackson.annotation.JsonProperty +import java.io.Serializable +import java.util.* + +/** + * View Model for sending a [RadarWebApplicationException]. + */ +class RadarWebApplicationExceptionVM +/** + * Creates an error view model with message, entityName and errorCode. + * + * @param message message to client. + * @param entityName entityRelated from [EntityName] + * @param errorCode errorCode from [ErrorConstants] + * @param params map of optional information. + */( + @field:JsonProperty val message: String?, + @field:JsonProperty val entityName: String, + @field:JsonProperty val errorCode: String?, + @field:JsonProperty val params: Map +) : Serializable { + + /** + * Creates an error view model with message, entityName and errorCode. + * + * @param message message to client. + * @param entityName entityRelated from [EntityName] + * @param errorCode errorCode from [ErrorConstants] + */ + protected constructor(message: String?, entityName: String, errorCode: String?) : this( + message, + entityName, + errorCode, + emptyMap() + ) + + override fun equals(o: Any?): Boolean { + if (this === o) { + return true + } + if (o == null || javaClass != o.javaClass) { + return false + } + val that = o as RadarWebApplicationExceptionVM + return entityName == that.entityName && errorCode == that.errorCode && message == that.message && params == that.params + } + + override fun hashCode(): Int { + return Objects.hash(entityName, errorCode, message, params) + } + + override fun toString(): String { + return ("RadarWebApplicationExceptionVM{" + "entityName='" + entityName + '\'' + + ", errorCode='" + errorCode + '\'' + ", message='" + message + '\'' + ", params=" + + params + '}') + } + + companion object { + private const val serialVersionUID = 1L + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.java b/src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.java deleted file mode 100644 index c9cf2aa39..000000000 --- a/src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.radarbase.management.web.rest.errors; - -import org.springframework.http.HttpStatus; - -import java.util.Map; - -/** - * Throw when the requested resource is no longer available at the server and no forwarding - * address is known. This condition is expected to be considered permanent. Clients with - * link editing capabilities SHOULD delete references to the Request-URI after user approval. - */ -public class RequestGoneException extends RadarWebApplicationException { - - /** - * Create a {@link RequestGoneException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - */ - public RequestGoneException(String message, String entityName, String errorCode) { - super(HttpStatus.GONE, message, entityName, errorCode); - } - - - /** - * Create a {@link RequestGoneException} with the given message, relatedEntityName, errorCode. - * - * @param message the message. - * @param entityName relatedEntityName from {@link EntityName}. - * @param errorCode errorCode from {@link ErrorConstants} - * @param paramMap map of additional information. - */ - public RequestGoneException(String message, String entityName, String errorCode, - Map paramMap) { - super(HttpStatus.GONE, message, entityName, errorCode, paramMap); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.kt b/src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.kt new file mode 100644 index 000000000..622aff31c --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/errors/RequestGoneException.kt @@ -0,0 +1,37 @@ +package org.radarbase.management.web.rest.errors + +import org.springframework.http.HttpStatus + +/** + * Throw when the requested resource is no longer available at the server and no forwarding + * address is known. This condition is expected to be considered permanent. Clients with + * link editing capabilities SHOULD delete references to the Request-URI after user approval. + */ +class RequestGoneException : RadarWebApplicationException { + /** + * Create a [RequestGoneException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + */ + constructor(message: String?, entityName: String, errorCode: String?) : super( + HttpStatus.GONE, + message, + entityName, + errorCode + ) + + /** + * Create a [RequestGoneException] with the given message, relatedEntityName, errorCode. + * + * @param message the message. + * @param entityName relatedEntityName from [EntityName]. + * @param errorCode errorCode from [ErrorConstants] + * @param paramMap map of additional information. + */ + constructor( + message: String?, entityName: String, errorCode: String?, + paramMap: Map? + ) : super(HttpStatus.GONE, message, entityName, errorCode, paramMap) +} diff --git a/src/main/java/org/radarbase/management/web/rest/package-info.java b/src/main/java/org/radarbase/management/web/rest/package-info.java deleted file mode 100644 index 6ae57b9cf..000000000 --- a/src/main/java/org/radarbase/management/web/rest/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Spring MVC REST controllers. - */ -package org.radarbase.management.web.rest; diff --git a/src/main/java/org/radarbase/management/web/rest/package-info.kt b/src/main/java/org/radarbase/management/web/rest/package-info.kt new file mode 100644 index 000000000..3dfc41d29 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/package-info.kt @@ -0,0 +1,5 @@ +/** + * Spring MVC REST controllers. + */ +package org.radarbase.management.web.rest + diff --git a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.java b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.java deleted file mode 100644 index e3855681e..000000000 --- a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.java +++ /dev/null @@ -1,105 +0,0 @@ -package org.radarbase.management.web.rest.util; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.Arrays; -import java.util.Objects; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpHeaders; - -/** - * Utility class for HTTP headers creation. - */ -public final class HeaderUtil { - - private static final Logger log = LoggerFactory.getLogger(HeaderUtil.class); - - private static final String APPLICATION_NAME = "managementPortalApp"; - - private HeaderUtil() { - } - - /** - * Create the headers for displaying an alert in the frontend. - * @param message the message - * @param param the message parameters - * @return the {@link HttpHeaders} - */ - public static HttpHeaders createAlert(String message, String param) { - HttpHeaders headers = new HttpHeaders(); - headers.add("X-managementPortalApp-alert", message); - headers.add("X-managementPortalApp-params", param); - return headers; - } - - public static HttpHeaders createEntityCreationAlert(String entityName, String param) { - return createAlert(APPLICATION_NAME + "." + entityName + ".created", param); - } - - public static HttpHeaders createEntityUpdateAlert(String entityName, String param) { - return createAlert(APPLICATION_NAME + "." + entityName + ".updated", param); - } - - public static HttpHeaders createEntityDeletionAlert(String entityName, String param) { - return createAlert(APPLICATION_NAME + "." + entityName + ".deleted", param); - } - - /** - * Create headers to display a failure alert in the frontend. - * @param entityName the entity on which the failure occurred - * @param errorKey the error key in the translation dictionary - * @param defaultMessage the default message - * @return the {@link HttpHeaders} - */ - public static HttpHeaders createFailureAlert(String entityName, String errorKey, - String defaultMessage) { - log.error("Entity creation failed, {}", defaultMessage); - HttpHeaders headers = new HttpHeaders(); - headers.add("X-managementPortalApp-error", "error." + errorKey); - headers.add("X-managementPortalApp-params", entityName); - return headers; - } - - /** - * Create headers to display a failure alert in the frontend. - * @param entityName the entity on which the failure occurred - * @param errorKey the error key in the translation dictionary - * @param defaultMessage the default message - * @return the {@link HttpHeaders} - */ - public static HttpHeaders createExceptionAlert(String entityName, String errorKey, - String defaultMessage) { - //TODO: Replace createFailureAlert with error. addition - log.error("Entity creation failed, {}", defaultMessage); - HttpHeaders headers = new HttpHeaders(); - headers.add("X-managementPortalApp-error", errorKey); - headers.add("X-managementPortalApp-params", entityName); - return headers; - } - - /** - * URLEncode each component, prefix and join them by forward slashes. - * - *

E.g. buildPath("api", "projects", "radar/1") results in the string - * /api/projects/radar%2F1.

- * - * @param components The components of the path. - * @return A String where the components are URLEncoded and joined by forward slashes. - */ - public static String buildPath(String... components) { - return Arrays.stream(components) - .filter(Objects::nonNull) - .filter(c -> !c.isEmpty()) - .map(c -> { - // try-catch needs to be inside the lambda - try { - return URLEncoder.encode(c, "UTF-8"); - } catch (UnsupportedEncodingException ex) { - log.error(ex.getMessage()); - return ""; - } - }) - .reduce("", (a, b) -> String.join("/", a, b)); - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt new file mode 100644 index 000000000..9fc6f8f50 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt @@ -0,0 +1,103 @@ +package org.radarbase.management.web.rest.util + +import org.slf4j.LoggerFactory +import org.springframework.http.HttpHeaders +import java.io.UnsupportedEncodingException +import java.net.URLEncoder +import java.util.* + +/** + * Utility class for HTTP headers creation. + */ +object HeaderUtil { + private val log = LoggerFactory.getLogger(HeaderUtil::class.java) + private const val APPLICATION_NAME = "managementPortalApp" + + /** + * Create the headers for displaying an alert in the frontend. + * @param message the message + * @param param the message parameters + * @return the [HttpHeaders] + */ + fun createAlert(message: String?, param: String?): HttpHeaders { + val headers = HttpHeaders() + headers.add("X-managementPortalApp-alert", message) + headers.add("X-managementPortalApp-params", param) + return headers + } + + fun createEntityCreationAlert(entityName: String, param: String?): HttpHeaders { + return createAlert(APPLICATION_NAME + "." + entityName + ".created", param) + } + + fun createEntityUpdateAlert(entityName: String, param: String?): HttpHeaders { + return createAlert(APPLICATION_NAME + "." + entityName + ".updated", param) + } + + fun createEntityDeletionAlert(entityName: String, param: String?): HttpHeaders { + return createAlert(APPLICATION_NAME + "." + entityName + ".deleted", param) + } + + /** + * Create headers to display a failure alert in the frontend. + * @param entityName the entity on which the failure occurred + * @param errorKey the error key in the translation dictionary + * @param defaultMessage the default message + * @return the [HttpHeaders] + */ + fun createFailureAlert( + entityName: String, errorKey: String, + defaultMessage: String? + ): HttpHeaders { + log.error("Entity creation failed, {}", defaultMessage) + val headers = HttpHeaders() + headers.add("X-managementPortalApp-error", "error.$errorKey") + headers.add("X-managementPortalApp-params", entityName) + return headers + } + + /** + * Create headers to display a failure alert in the frontend. + * @param entityName the entity on which the failure occurred + * @param errorKey the error key in the translation dictionary + * @param defaultMessage the default message + * @return the [HttpHeaders] + */ + fun createExceptionAlert( + entityName: String?, errorKey: String?, + defaultMessage: String? + ): HttpHeaders { + //TODO: Replace createFailureAlert with error. addition + log.error("Entity creation failed, {}", defaultMessage) + val headers = HttpHeaders() + headers.add("X-managementPortalApp-error", errorKey) + headers.add("X-managementPortalApp-params", entityName) + return headers + } + + /** + * URLEncode each component, prefix and join them by forward slashes. + * + * + * E.g. `buildPath("api", "projects", "radar/1")` results in the string + * `/api/projects/radar%2F1`. + * + * @param components The components of the path. + * @return A String where the components are URLEncoded and joined by forward slashes. + */ + fun buildPath(vararg components: String): String { + return Arrays.stream(components) + .filter { obj: String? -> Objects.nonNull(obj) } + .filter { c: String -> !c.isEmpty() } + .map { c: String? -> + // try-catch needs to be inside the lambda + try { + return@map URLEncoder.encode(c, "UTF-8") + } catch (ex: UnsupportedEncodingException) { + log.error(ex.message) + return@map "" + } + } + .reduce("") { a: String?, b: String? -> java.lang.String.join("/", a, b) } + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.java b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.java deleted file mode 100644 index ec5db882c..000000000 --- a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.radarbase.management.web.rest.util; - -import org.radarbase.management.service.dto.SubjectDTO; -import org.radarbase.management.web.rest.criteria.CriteriaRange; -import org.radarbase.management.web.rest.criteria.SubjectCriteria; -import org.springframework.data.domain.Page; -import org.springframework.http.HttpHeaders; -import org.springframework.web.util.UriComponentsBuilder; - -import javax.annotation.Nullable; -import java.util.Locale; - -/** - * Utility class for handling pagination. - * - *

- * Pagination uses the same principles as the - * GithubAPI, - * and follow RFC 5988 (Link header). - *

- */ -public final class PaginationUtil { - - private PaginationUtil() { - } - - /** - * Generate headers for pagination. - * @param page the page - * @param baseUrl the base URL - * @return the {@link HttpHeaders} - */ - public static HttpHeaders generatePaginationHttpHeaders(Page page, String baseUrl) { - HttpHeaders headers = new HttpHeaders(); - headers.add("X-Total-Count", Long.toString(page.getTotalElements())); - - StringBuilder link = new StringBuilder(256); - if ((page.getNumber() + 1) < page.getTotalPages()) { - link.append('<') - .append(generateUri(baseUrl, page.getNumber() + 1, page.getSize())) - .append(">; rel=\"next\","); - } - // prev link - if ((page.getNumber()) > 0) { - link.append('<') - .append(generateUri(baseUrl, page.getNumber() - 1, page.getSize())) - .append(">; rel=\"prev\","); - } - // last and first link - int lastPage = 0; - if (page.getTotalPages() > 0) { - lastPage = page.getTotalPages() - 1; - } - link.append('<') - .append(generateUri(baseUrl, lastPage, page.getSize())) - .append(">; rel=\"last\",<") - .append(generateUri(baseUrl, 0, page.getSize())) - .append(">; rel=\"first\""); - headers.add(HttpHeaders.LINK, link.toString()); - return headers; - } - - /** - * Generate pagination HTTP headers for subjects given a subject filter. - * @param page the page - * @param baseUrl the base URL - * @param criteria subject criteria - * @return the {@link HttpHeaders} - */ - public static HttpHeaders generateSubjectPaginationHttpHeaders( - Page page, String baseUrl, SubjectCriteria criteria - ) { - HttpHeaders headers = new HttpHeaders(); - headers.add("X-Total-Count", Long.toString(page.getTotalElements())); - if (!page.isEmpty()) { - String link = '<' - + generateUri(page, baseUrl, criteria) - + ">; rel=\"next\""; - headers.add(HttpHeaders.LINK, link); - } - return headers; - } - - private static String generateUri(String baseUrl, int page, int size) { - return UriComponentsBuilder.fromUriString(baseUrl) - .queryParam("page", page) - .queryParam("size", size) - .toUriString(); - } - - private static String generateUri(Page page, String baseUrl, - SubjectCriteria criteria) { - UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(baseUrl); - generateUriCriteriaRange(builder, "dateOfBirth", criteria.getDateOfBirth()); - generateUriCriteriaRange(builder, "enrollmentDate", criteria.getEnrollmentDate()); - generateUriParam(builder, "externalId", criteria.getExternalId()); - generateUriParam(builder, "groupId", criteria.getGroupId()); - generateUriParam(builder, "personName", criteria.getPersonName()); - generateUriParam(builder, "humanReadableIdentifier", - criteria.getHumanReadableIdentifier()); - generateUriParam(builder, "projectName", criteria.getProjectName()); - generateUriParam(builder, "login", criteria.getLogin()); - if (criteria.getAuthority() != null) { - criteria.getAuthority().forEach(a -> generateUriParam(builder, - "authority", a)); - } - generateUriParam(builder, "size", criteria.getSize()); - generateUriParam(builder, "page", criteria.getPage()); - if (criteria.getSort() != null) { - criteria.getParsedSort().forEach(order -> generateUriParam(builder, "sort", - order.getSortBy().getQueryParam() + ',' - + order.getDirection().name().toLowerCase(Locale.ROOT))); - } - SubjectDTO lastSubject = page.getContent().get(page.getNumberOfElements() - 1); - generateUriParam(builder, "last.id", lastSubject.getId()); - generateUriParam(builder, "last.login", lastSubject.getLogin()); - if (lastSubject.getExternalId() != null && !lastSubject.getExternalId().isEmpty()) { - generateUriParam(builder, "last.externalId", lastSubject.getExternalId()); - } - return builder.toUriString(); - } - - private static void generateUriCriteriaRange(UriComponentsBuilder builder, String prefix, - CriteriaRange range) { - if (range == null) { - return; - } - generateUriParam(builder, prefix + ".is", range.getIs()); - generateUriParam(builder, prefix + ".from", range.getFrom()); - generateUriParam(builder, prefix + ".to", range.getTo()); - } - - private static void generateUriParam(UriComponentsBuilder builder, String name, - @Nullable Object value) { - if (value != null) { - builder.queryParam(name, value); - } - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt new file mode 100644 index 000000000..bc27cdb8d --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt @@ -0,0 +1,151 @@ +package org.radarbase.management.web.rest.util + +import org.radarbase.management.service.dto.SubjectDTO +import org.radarbase.management.web.rest.criteria.CriteriaRange +import org.radarbase.management.web.rest.criteria.SubjectAuthority +import org.radarbase.management.web.rest.criteria.SubjectCriteria +import org.radarbase.management.web.rest.criteria.SubjectSortOrder +import org.springframework.data.domain.Page +import org.springframework.http.HttpHeaders +import org.springframework.web.util.UriComponentsBuilder +import java.util.function.Consumer + +/** + * Utility class for handling pagination. + * + * + * + * Pagination uses the same principles as the + * [GithubAPI](https://developer.github.com/v3/#pagination), + * and follow [RFC 5988 (Link header)](http://tools.ietf.org/html/rfc5988). + * + */ +object PaginationUtil { + /** + * Generate headers for pagination. + * @param page the page + * @param baseUrl the base URL + * @return the [HttpHeaders] + */ + fun generatePaginationHttpHeaders(page: Page<*>?, baseUrl: String): HttpHeaders { + val headers = HttpHeaders() + headers.add("X-Total-Count", page!!.totalElements.toString()) + val link = StringBuilder(256) + if (page.number + 1 < page.totalPages) { + link.append('<') + .append(generateUri(baseUrl, page.number + 1, page.size)) + .append(">; rel=\"next\",") + } + // prev link + if (page.number > 0) { + link.append('<') + .append(generateUri(baseUrl, page.number - 1, page.size)) + .append(">; rel=\"prev\",") + } + // last and first link + var lastPage = 0 + if (page.totalPages > 0) { + lastPage = page.totalPages - 1 + } + link.append('<') + .append(generateUri(baseUrl, lastPage, page.size)) + .append(">; rel=\"last\",<") + .append(generateUri(baseUrl, 0, page.size)) + .append(">; rel=\"first\"") + headers.add(HttpHeaders.LINK, link.toString()) + return headers + } + + /** + * Generate pagination HTTP headers for subjects given a subject filter. + * @param page the page + * @param baseUrl the base URL + * @param criteria subject criteria + * @return the [HttpHeaders] + */ + fun generateSubjectPaginationHttpHeaders( + page: Page, baseUrl: String, criteria: SubjectCriteria + ): HttpHeaders { + val headers = HttpHeaders() + headers.add("X-Total-Count", page.totalElements.toString()) + if (!page.isEmpty) { + val link = ('<' + .toString() + generateUri(page, baseUrl, criteria) + + ">; rel=\"next\"") + headers.add(HttpHeaders.LINK, link) + } + return headers + } + + private fun generateUri(baseUrl: String, page: Int, size: Int): String { + return UriComponentsBuilder.fromUriString(baseUrl) + .queryParam("page", page) + .queryParam("size", size) + .toUriString() + } + + private fun generateUri( + page: Page, baseUrl: String, + criteria: SubjectCriteria + ): String { + val builder = UriComponentsBuilder.fromUriString(baseUrl) + generateUriCriteriaRange(builder, "dateOfBirth", criteria.dateOfBirth) + generateUriCriteriaRange(builder, "enrollmentDate", criteria.enrollmentDate) + generateUriParam(builder, "externalId", criteria.externalId) + generateUriParam(builder, "groupId", criteria.groupId) + generateUriParam(builder, "personName", criteria.personName) + generateUriParam( + builder, "humanReadableIdentifier", + criteria.humanReadableIdentifier + ) + generateUriParam(builder, "projectName", criteria.projectName) + generateUriParam(builder, "login", criteria.login) + if (criteria.authority != null) { + criteria.authority!!.forEach(Consumer { a: SubjectAuthority? -> + generateUriParam( + builder, + "authority", a + ) + }) + } + generateUriParam(builder, "size", criteria.size) + generateUriParam(builder, "page", criteria.page) + if (criteria.getSort() != null) { + criteria.getParsedSort()!!.forEach(Consumer { order: SubjectSortOrder? -> + generateUriParam( + builder, "sort", + order?.sortBy?.queryParam + ',' + + order?.direction?.name?.lowercase() + ) + }) + } + val lastSubject = page.content[page.numberOfElements - 1] + generateUriParam(builder, "last.id", lastSubject?.id) + generateUriParam(builder, "last.login", lastSubject?.login) + if (lastSubject?.externalId != null && !lastSubject.externalId.isNullOrEmpty()) { + generateUriParam(builder, "last.externalId", lastSubject.externalId) + } + return builder.toUriString() + } + + private fun generateUriCriteriaRange( + builder: UriComponentsBuilder, prefix: String, + range: CriteriaRange<*>? + ) { + if (range == null) { + return + } + generateUriParam(builder, "$prefix.is", range.iss) + generateUriParam(builder, "$prefix.from", range.from) + generateUriParam(builder, "$prefix.to", range.to) + } + + private fun generateUriParam( + builder: UriComponentsBuilder, name: String, + value: Any? + ) { + if (value != null) { + builder.queryParam(name, value) + } + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.kt b/src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.kt new file mode 100644 index 000000000..e39d1b04d --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.kt @@ -0,0 +1,19 @@ +package org.radarbase.management.web.rest.vm + +/** + * A POJO for PATCH .../groups/{groupName}/subjects + * [ + * {"op": "add", "value": [{"login": "sub1"}, {"id": 2}]}, + * {"op": "remove", "value": [{"login": "sub3"}]} + * ] + * request. + */ +class GroupPatchOperation { + var op: String? = null + var value: List? = null + + class SubjectPatchValue { + var id: Long? = null + var login: String? = null + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.kt b/src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.kt new file mode 100644 index 000000000..005cd097c --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.kt @@ -0,0 +1,9 @@ +package org.radarbase.management.web.rest.vm + +/** + * View Model object for storing the user's key and password. + */ +class KeyAndPasswordVM { + lateinit var key: String + lateinit var newPassword: String +} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.kt b/src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.kt new file mode 100644 index 000000000..596752026 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.kt @@ -0,0 +1,27 @@ +package org.radarbase.management.web.rest.vm + +import ch.qos.logback.classic.Logger +import com.fasterxml.jackson.annotation.JsonCreator + +/** + * View Model object for storing a Logback logger. + */ +class LoggerVM { + var name: String? = null + var level: String? = null + + constructor(logger: Logger) { + name = logger.name + level = logger.effectiveLevel.toString() + } + + @JsonCreator + constructor() + + override fun toString(): String { + return ("LoggerVM{" + + "name='" + name + '\'' + + ", level='" + level + '\'' + + '}') + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.kt b/src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.kt new file mode 100644 index 000000000..831165595 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.kt @@ -0,0 +1,19 @@ +package org.radarbase.management.web.rest.vm + +import org.radarbase.management.service.dto.UserDTO +import javax.validation.constraints.Size + +/** + * View Model extending the UserDTO, which is meant to be used in the user management UI. + */ +class ManagedUserVM : UserDTO() { + var password: @Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH) String? = null + override fun toString(): String { + return "ManagedUserVM{} " + super.toString() + } + + companion object { + const val PASSWORD_MIN_LENGTH = 4 + const val PASSWORD_MAX_LENGTH = 100 + } +} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/package-info.kt b/src/main/java/org/radarbase/management/web/rest/vm/package-info.kt new file mode 100644 index 000000000..52bd63ff5 --- /dev/null +++ b/src/main/java/org/radarbase/management/web/rest/vm/package-info.kt @@ -0,0 +1,5 @@ +/** + * View Models used by Spring MVC REST controllers. + */ +package org.radarbase.management.web.rest.vm + From 210c53ce3ff51ca07ec172a47b88391e02f1bfd4 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 30 Oct 2023 22:38:01 +0100 Subject: [PATCH 098/158] test compiles, not passing yet --- .../management/service/PasswordService.kt | 2 +- .../management/service/RoleService.kt | 12 +- .../management/service/UserService.kt | 11 +- .../service/dto/ClientDetailsDTO.kt | 2 +- .../management/service/dto/SourceTypeDTO.kt | 2 +- .../mapper/decorator/RoleMapperDecorator.kt | 14 +- .../management/web/rest/ProjectResource.kt | 8 +- .../management/web/rest/util/HeaderUtil.kt | 10 +- .../auth/authentication/OAuthHelper.kt | 6 +- .../security/SecurityUtilsUnitTest.kt | 2 +- .../service/MetaTokenServiceTest.kt | 2 +- ...apIntegrationWorkFlowOnServiceLevelTest.kt | 10 +- .../management/service/SubjectServiceTest.kt | 17 +- .../management/service/UserServiceIntTest.kt | 37 +-- .../web/rest/AccountResourceIntTest.kt | 43 ++-- .../web/rest/AuditResourceIntTest.kt | 61 ++--- .../web/rest/GroupResourceIntTest.kt | 209 ++++++--------- .../web/rest/OAuthClientsResourceIntTest.kt | 20 +- .../web/rest/OrganizationResourceIntTest.kt | 238 +++++++++--------- .../web/rest/ProfileInfoResourceIntTest.kt | 2 +- .../web/rest/SourceDataResourceIntTest.kt | 144 +++++------ .../web/rest/SourceTypeResourceIntTest.kt | 14 +- .../web/rest/SubjectResourceIntTest.kt | 34 +-- .../web/rest/UserResourceIntTest.kt | 10 +- 24 files changed, 417 insertions(+), 493 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/PasswordService.kt b/src/main/java/org/radarbase/management/service/PasswordService.kt index 9245e110e..abda1038f 100644 --- a/src/main/java/org/radarbase/management/service/PasswordService.kt +++ b/src/main/java/org/radarbase/management/service/PasswordService.kt @@ -17,7 +17,7 @@ import java.security.SecureRandom import java.util.* @Service -class PasswordService(private val passwordEncoder: PasswordEncoder) { +open class PasswordService(private val passwordEncoder: PasswordEncoder) { private val random: Random = SecureRandom() /** diff --git a/src/main/java/org/radarbase/management/service/RoleService.kt b/src/main/java/org/radarbase/management/service/RoleService.kt index 7bc960bd1..9074ceaf3 100644 --- a/src/main/java/org/radarbase/management/service/RoleService.kt +++ b/src/main/java/org/radarbase/management/service/RoleService.kt @@ -19,7 +19,6 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import java.util.* -import java.util.Map import java.util.function.Consumer /** @@ -144,8 +143,9 @@ open class RoleService( "Cannot find organization for authority", EntityName.USER, ErrorConstants.ERR_INVALID_AUTHORITY, - Map.of( - "authorityName", role.authority, "projectId", organizationId.toString() + mapOf( + Pair("authorityName", role.authority), + Pair("projectId", organizationId.toString()) ) ) } @@ -164,8 +164,10 @@ open class RoleService( ) ?: createNewRole(role) { r: Role -> r.project = projectRepository.findByIdWithOrganization(projectId) ?: throw NotFoundException( - "Cannot find project for authority", EntityName.USER, ErrorConstants.ERR_INVALID_AUTHORITY, Map.of( - "authorityName", role.authority, "projectId", projectId.toString() + "Cannot find project for authority", EntityName.USER, ErrorConstants.ERR_INVALID_AUTHORITY, + mapOf( + Pair("authorityName", role.authority), + Pair("projectId", projectId.toString()) ) ) } diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt index 3adcb8c2f..3f0dc91d6 100644 --- a/src/main/java/org/radarbase/management/service/UserService.kt +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -31,13 +31,10 @@ import org.springframework.transaction.annotation.Transactional import java.time.Period import java.time.ZonedDateTime import java.util.* -import java.util.Map import java.util.function.Function -import java.util.stream.Collectors import kotlin.collections.HashSet import kotlin.collections.MutableSet import kotlin.collections.Set -import kotlin.collections.setOf /** * Service class for managing users. @@ -72,7 +69,7 @@ open class UserService( "User with activation key $key not found", EntityName.USER, ErrorConstants.ERR_ENTITY_NOT_FOUND, - Map.of("activationKey", key) + mapOf(Pair("activationKey", key)) ) } @@ -235,7 +232,7 @@ open class UserService( "Email address $email already in use", EntityName.USER, ErrorConstants.ERR_EMAIL_EXISTS, - Map.of("email", email) + mapOf(Pair("email", email)) ) } } else { @@ -243,7 +240,7 @@ open class UserService( "User with login $userName not found", EntityName.USER, ErrorConstants.ERR_ENTITY_NOT_FOUND, - Map.of("user", userName) + mapOf(Pair("user", userName)) ) } user.firstName = firstName @@ -420,7 +417,7 @@ open class UserService( "User with login $login not found", EntityName.USER, ErrorConstants.ERR_ENTITY_NOT_FOUND, - Map.of("user", login) + mapOf(Pair("user", login)) ) val managedRoles = user.roles diff --git a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt index b2a19c2f6..98f7da1a6 100644 --- a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt @@ -16,5 +16,5 @@ class ClientDetailsDTO { var refreshTokenValiditySeconds: Long? = null var authorities: Set? = null var registeredRedirectUri: Set? = null - var additionalInformation: Map? = null + var additionalInformation: MutableMap? = null } diff --git a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt index 1eb8c3b85..ff5fe709e 100644 --- a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt @@ -25,7 +25,7 @@ class SourceTypeDTO : Serializable { @set:JsonSetter(nulls = Nulls.AS_EMPTY) @JsonInclude(JsonInclude.Include.NON_EMPTY) - var sourceData: Set = HashSet() + var sourceData: MutableSet = HashSet() override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt index 0fb761825..244965c2d 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt @@ -10,13 +10,9 @@ import org.springframework.beans.factory.annotation.Qualifier /** * Created by nivethika on 03-8-18. */ -abstract class RoleMapperDecorator : RoleMapper { - @Autowired - @Qualifier("delegate") - private val delegate: RoleMapper? = null - - @Autowired - private val authorityRepository: AuthorityRepository? = null +abstract class RoleMapperDecorator(@Autowired @Qualifier("delegate") private val delegate: RoleMapper, + @Autowired private val authorityRepository: AuthorityRepository +) : RoleMapper { /** * Overrides standard RoleMapperImpl and loads authority from repository if not specified. @@ -27,9 +23,9 @@ abstract class RoleMapperDecorator : RoleMapper { if (roleDto == null) { return null } - val role = delegate!!.roleDTOToRole(roleDto) + val role = delegate.roleDTOToRole(roleDto) if (role!!.authority == null) { - role.authority = roleDto.authorityName?.let { authorityRepository!!.getById(it) } + role.authority = roleDto.authorityName?.let { authorityRepository.getById(it) } } return role } diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index 842c51558..af751ea30 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -77,7 +77,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, fun createProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity { log.debug("REST request to save Project : {}", projectDto) val org = projectDto!!.organization - if (org == null || org.name == null) { + if (org?.name == null) { throw BadRequestException( "Organization must be provided", ENTITY_NAME, ErrorConstants.ERR_VALIDATION @@ -109,7 +109,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, .headers( createEntityCreationAlert( ENTITY_NAME, - result?.projectName + result.projectName ) ) .body(result) @@ -135,7 +135,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, // When a client wants to link the project to the default organization, // this must be done explicitly. val org = projectDto.organization - if (org == null || org.name == null) { + if (org?.name == null) { throw BadRequestException( "Organization must be provided", ENTITY_NAME, ErrorConstants.ERR_VALIDATION @@ -309,7 +309,7 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, ): ResponseEntity<*> { authService.checkScope(Permission.SOURCE_READ) log.debug("REST request to get all Sources") - val projectDto = projectService.findOneByName(projectName) ?: throw NoSuchElementException() + val projectDto = projectService.findOneByName(projectName) //?: throw NoSuchElementException() authService.checkPermission(Permission.SOURCE_READ, { e: EntityDetails -> e.organization(projectDto.organization?.name) diff --git a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt index 9fc6f8f50..888626811 100644 --- a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt +++ b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt @@ -4,7 +4,6 @@ import org.slf4j.LoggerFactory import org.springframework.http.HttpHeaders import java.io.UnsupportedEncodingException import java.net.URLEncoder -import java.util.* /** * Utility class for HTTP headers creation. @@ -85,10 +84,9 @@ object HeaderUtil { * @param components The components of the path. * @return A String where the components are URLEncoded and joined by forward slashes. */ - fun buildPath(vararg components: String): String { - return Arrays.stream(components) - .filter { obj: String? -> Objects.nonNull(obj) } - .filter { c: String -> !c.isEmpty() } + fun buildPath(vararg components: String?): String { + return components + .filterNotNull() .map { c: String? -> // try-catch needs to be inside the lambda try { @@ -98,6 +96,6 @@ object HeaderUtil { return@map "" } } - .reduce("") { a: String?, b: String? -> java.lang.String.join("/", a, b) } + .reduce { a: String, b: String -> java.lang.String.join("/", a, b) } } } diff --git a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt index 3c18fd705..e4779a75a 100644 --- a/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt +++ b/src/test/java/org/radarbase/auth/authentication/OAuthHelper.kt @@ -109,7 +109,7 @@ object OAuthHelper { val rsa = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey) validRsaToken = createValidToken(rsa) val verifierList = listOf(ecdsa, rsa) - .map{ alg: Algorithm? -> + .map { alg: Algorithm? -> alg?.toTokenVerifier(ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL) } .requireNoNulls() @@ -126,9 +126,7 @@ object OAuthHelper { fun createAuthenticationFilter(): JwtAuthenticationFilter { val userRepository = Mockito.mock(UserRepository::class.java) Mockito.`when`(userRepository.findOneByLogin(ArgumentMatchers.anyString())).thenReturn( - Optional.of( - createAdminUser() - ) + createAdminUser() ) return JwtAuthenticationFilter(createTokenValidator(), { auth: Authentication? -> auth }, userRepository) } diff --git a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt index 6bfdb36ce..e414e8506 100644 --- a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt +++ b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt @@ -19,7 +19,7 @@ internal class SecurityUtilsUnitTest { "admin" ) SecurityContextHolder.setContext(securityContext) - val login = SecurityUtils.getCurrentUserLogin().orElse(null) + val login = SecurityUtils.currentUserLogin Assertions.assertThat(login).isEqualTo("admin") } } diff --git a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt index b4f3f447d..5e167e471 100644 --- a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt @@ -42,7 +42,7 @@ internal open class MetaTokenServiceTest( fun setUp() { subjectDto = SubjectServiceTest.createEntityDTO() subjectDto = subjectService.createSubject(subjectDto)!! - clientDetails = oAuthClientService.createClientDetail(OAuthClientServiceTestUtil.createClient())!! + clientDetails = oAuthClientService.createClientDetail(OAuthClientServiceTestUtil.createClient()) } @Test diff --git a/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt b/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt index a4461d7cb..69a4efc1c 100644 --- a/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt +++ b/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt @@ -19,7 +19,7 @@ import java.util.* @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -internal class RedcapIntegrationWorkFlowOnServiceLevelTest { +internal open class RedcapIntegrationWorkFlowOnServiceLevelTest { @Autowired private val projectService: ProjectService? = null @@ -46,13 +46,13 @@ internal class RedcapIntegrationWorkFlowOnServiceLevelTest { // manually save val saved = projectService!!.save(projectDto) - val storedProjectId = saved.id + val storedProjectId = saved.id!! Assertions.assertTrue(storedProjectId > 0) // Use ROLE_EXTERNAL_ERF_INTEGRATOR authority in your oauth2 client config // GET api/projects/{storedProjectId} val retrievedById = projectService.findOne(storedProjectId) - Assertions.assertEquals(retrievedById.id, storedProjectId) + Assertions.assertEquals(retrievedById?.id, storedProjectId) // retrieve required details // location is part of project property @@ -64,7 +64,7 @@ internal class RedcapIntegrationWorkFlowOnServiceLevelTest { // redcap-id from trigger val redcapRecordId = "1" - for ((key, value) in retrievedById.attributes) { + for ((key, value) in retrievedById!!.attributes!!) { when (key) { ProjectDTO.WORK_PACKAGE_KEY -> workPackageRetrieved = value ProjectDTO.PHASE_KEY -> phaseRetrieved = value @@ -98,7 +98,7 @@ internal class RedcapIntegrationWorkFlowOnServiceLevelTest { // create/save a subject // PUT api/subjects/ val savedSubject = subjectService!!.createSubject(newSubject) - Assertions.assertTrue(savedSubject!!.id > 0) + Assertions.assertTrue(savedSubject!!.id!! > 0) // asset human-readable-id for ((key, value) in savedSubject.attributes) { diff --git a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt index 895b8ef2c..d1200bb68 100644 --- a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt @@ -21,19 +21,18 @@ import java.util.* @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -class SubjectServiceTest { - @Autowired - private val subjectService: SubjectService? = null +open class SubjectServiceTest( + @Autowired private val subjectService: SubjectService, + @Autowired private val projectService: ProjectService +) { - @Autowired - private val projectService: ProjectService? = null @Test @Transactional - fun testGetPrivacyPolicyUrl() { - projectService!!.save(createEntityDTO().project) - val created = subjectService!!.createSubject(createEntityDTO()) + open fun testGetPrivacyPolicyUrl() { + projectService.save(createEntityDTO().project!!) + val created = subjectService.createSubject(createEntityDTO()) Assertions.assertNotNull(created!!.id) - val subject = subjectService.findOneByLogin(created.getLogin()) + val subject = subjectService.findOneByLogin(created.login) Assertions.assertNotNull(subject) val privacyPolicyUrl = subjectService.getPrivacyPolicyUrl(subject) Assertions.assertNotNull(privacyPolicyUrl) diff --git a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt index 3fd29977a..eae6e9804 100644 --- a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt +++ b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt @@ -66,19 +66,20 @@ open class UserServiceIntTest( ReflectionTestUtils.setField(revisionService, "entityManager", entityManager) ReflectionTestUtils.setField(userService, "userMapper", userMapper) ReflectionTestUtils.setField(userService, "userRepository", userRepository) - userRepository.findOneByLogin(userDto!!.login) - .ifPresent { entity: User -> userRepository.delete(entity) } + + + userRepository.delete(userRepository.findOneByLogin(userDto!!.login)!!) } @Test fun assertThatUserMustExistToResetPassword() { var maybeUser = userService.requestPasswordReset("john.doe@localhost") - Assertions.assertThat(maybeUser).isNotPresent() + Assertions.assertThat(maybeUser).isNull() maybeUser = userService.requestPasswordReset("admin@localhost") - Assertions.assertThat(maybeUser).isPresent() - Assertions.assertThat(maybeUser.get().email).isEqualTo("admin@localhost") - Assertions.assertThat(maybeUser.get().resetDate).isNotNull() - Assertions.assertThat(maybeUser.get().resetKey).isNotNull() + Assertions.assertThat(maybeUser).isNotNull() + Assertions.assertThat(maybeUser?.email).isEqualTo("admin@localhost") + Assertions.assertThat(maybeUser?.resetDate).isNotNull() + Assertions.assertThat(maybeUser?.resetKey).isNotNull() } @Test @@ -86,9 +87,9 @@ open class UserServiceIntTest( fun assertThatOnlyActivatedUserCanRequestPasswordReset() { val user = userService.createUser(userDto!!) val maybeUser = userService.requestPasswordReset( - userDto?.email + userDto?.email!! ) - Assertions.assertThat(maybeUser).isNotPresent() + Assertions.assertThat(maybeUser).isNull() userRepository.delete(user) } @@ -104,9 +105,9 @@ open class UserServiceIntTest( userRepository.save(user) val maybeUser = userService.completePasswordReset( "johndoe2", - user.resetKey + user.resetKey!! ) - Assertions.assertThat(maybeUser).isNotPresent() + Assertions.assertThat(maybeUser).isNull() userRepository.delete(user) } @@ -121,9 +122,9 @@ open class UserServiceIntTest( userRepository.save(user) val maybeUser = userService.completePasswordReset( "johndoe2", - user.resetKey + user.resetKey!! ) - Assertions.assertThat(maybeUser).isNotPresent() + Assertions.assertThat(maybeUser).isNull() userRepository.delete(user) } @@ -140,12 +141,12 @@ open class UserServiceIntTest( userRepository.save(user) val maybeUser = userService.completePasswordReset( "johndoe2", - user.resetKey + user.resetKey!! ) - Assertions.assertThat(maybeUser).isPresent() - Assertions.assertThat(maybeUser.get().resetDate).isNull() - Assertions.assertThat(maybeUser.get().resetKey).isNull() - Assertions.assertThat(maybeUser.get().password).isNotEqualTo(oldPassword) + Assertions.assertThat(maybeUser).isNotNull() + Assertions.assertThat(maybeUser?.resetDate).isNull() + Assertions.assertThat(maybeUser?.resetKey).isNull() + Assertions.assertThat(maybeUser?.password).isNotEqualTo(oldPassword) userRepository.delete(user) } diff --git a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt index 1b8092117..d90d5bc7d 100644 --- a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt @@ -21,6 +21,7 @@ import org.radarbase.management.security.JwtAuthenticationFilter.Companion.radar import org.radarbase.management.security.RadarAuthentication import org.radarbase.management.service.AuthService import org.radarbase.management.service.MailService +import org.radarbase.management.service.PasswordService import org.radarbase.management.service.UserService import org.radarbase.management.service.dto.RoleDTO import org.radarbase.management.service.dto.UserDTO @@ -50,6 +51,7 @@ internal open class AccountResourceIntTest( @Autowired private val userRepository: UserRepository, @Autowired private val userService: UserService, @Autowired private val userMapper: UserMapper, + @Autowired private val passwordService: PasswordService, @Mock private val mockUserService: UserService, @Mock private val mockMailService: MailService, private var restUserMockMvc: MockMvc, @@ -67,25 +69,22 @@ internal open class AccountResourceIntTest( ) ) SecurityContextHolder.getContext().authentication = RadarAuthentication(radarToken) - val accountResource = AccountResource() - ReflectionTestUtils.setField(accountResource, "userService", userService) - ReflectionTestUtils.setField(accountResource, "userMapper", userMapper) - ReflectionTestUtils.setField(accountResource, "mailService", mockMailService) - ReflectionTestUtils.setField(accountResource, "authService", authService) - ReflectionTestUtils.setField(accountResource, "token", radarToken) - ReflectionTestUtils.setField( - accountResource, "managementPortalProperties", - managementPortalProperties + val accountResource = AccountResource( + userService, + mockMailService, + userMapper, + managementPortalProperties, + authService, + passwordService ) - val accountUserMockResource = AccountResource() - ReflectionTestUtils.setField(accountUserMockResource, "userService", mockUserService) - ReflectionTestUtils.setField(accountUserMockResource, "userMapper", userMapper) - ReflectionTestUtils.setField(accountUserMockResource, "mailService", mockMailService) - ReflectionTestUtils.setField(accountUserMockResource, "authService", authService) - ReflectionTestUtils.setField(accountUserMockResource, "token", radarToken) - ReflectionTestUtils.setField( - accountUserMockResource, "managementPortalProperties", - managementPortalProperties + ReflectionTestUtils.setField(accountResource, "token", radarToken) + val accountUserMockResource = AccountResource( + userService, + mockMailService, + userMapper, + managementPortalProperties, + authService, + passwordService ) restUserMockMvc = MockMvcBuilders.standaloneSetup(accountUserMockResource).build() } @@ -122,7 +121,7 @@ internal open class AccountResourceIntTest( user.email = "john.doe@jhipster.com" user.langKey = "en" user.roles = roles - Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(Optional.of(user)) + Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(user) restUserMockMvc.perform(MockMvcRequestBuilders.post("/api/login") .with { request: MockHttpServletRequest -> request.radarToken = token @@ -160,7 +159,7 @@ internal open class AccountResourceIntTest( user.email = "john.doe@jhipster.com" user.langKey = "en" user.roles = roles - Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(Optional.of(user)) + Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(user) restUserMockMvc.perform( MockMvcRequestBuilders.get("/api/account") .accept(MediaType.APPLICATION_JSON) @@ -182,7 +181,7 @@ internal open class AccountResourceIntTest( @Test @Throws(Exception::class) fun testGetUnknownAccount() { - Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(Optional.empty()) + Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(null) restUserMockMvc.perform( MockMvcRequestBuilders.get("/api/account") .accept(MediaType.APPLICATION_JSON) @@ -213,6 +212,6 @@ internal open class AccountResourceIntTest( ) .andExpect(MockMvcResultMatchers.status().isBadRequest()) val user = userRepository.findOneByEmail("funky@example.com") - Assertions.assertThat(user).isNotPresent() + Assertions.assertThat(user).isNull() } } diff --git a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt index 0c35a35e0..58f6f4b0e 100644 --- a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt @@ -38,37 +38,28 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -internal class AuditResourceIntTest { - @Autowired - private val auditEventRepository: PersistenceAuditEventRepository? = null +internal open class AuditResourceIntTest( + @Autowired private val auditEventRepository: PersistenceAuditEventRepository, + @Autowired private val auditEventConverter: AuditEventConverter, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val formattingConversionService: FormattingConversionService, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + private var auditEvent: PersistentAuditEvent, + private var restAuditMockMvc: MockMvc, + @Autowired private val authService: AuthService +) { - @Autowired - private val auditEventConverter: AuditEventConverter? = null - - @Autowired - private val jacksonMessageConverter: MappingJackson2HttpMessageConverter? = null - - @Autowired - private val formattingConversionService: FormattingConversionService? = null - - @Autowired - private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver? = null - private var auditEvent: PersistentAuditEvent? = null - private var restAuditMockMvc: MockMvc? = null - - @Autowired - private val authService: AuthService? = null @BeforeEach @Throws(ServletException::class) fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) val auditEventService = AuditEventService( auditEventRepository, auditEventConverter ) val auditResource = AuditResource(auditEventService, authService) val filter = OAuthHelper.createAuthenticationFilter() - filter!!.init(MockFilterConfig()) + filter.init(MockFilterConfig()) restAuditMockMvc = MockMvcBuilders.standaloneSetup(auditResource) .setCustomArgumentResolvers(pageableArgumentResolver) .setConversionService(formattingConversionService) @@ -80,11 +71,11 @@ internal class AuditResourceIntTest { @BeforeEach fun initTest() { - auditEventRepository!!.deleteAll() + auditEventRepository.deleteAll() auditEvent = PersistentAuditEvent() - auditEvent!!.auditEventType = SAMPLE_TYPE - auditEvent!!.principal = SAMPLE_PRINCIPAL - auditEvent!!.auditEventDate = SAMPLE_TIMESTAMP + auditEvent.auditEventType = SAMPLE_TYPE + auditEvent.principal = SAMPLE_PRINCIPAL + auditEvent.auditEventDate = SAMPLE_TIMESTAMP } @get:Throws(Exception::class) @@ -92,10 +83,10 @@ internal class AuditResourceIntTest { val allAudits: Unit get() { // Initialize the database - auditEventRepository!!.save(auditEvent) + auditEventRepository.save(auditEvent) // Get all the audits - restAuditMockMvc!!.perform(MockMvcRequestBuilders.get("/management/audits")) + restAuditMockMvc.perform(MockMvcRequestBuilders.get("/management/audits")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect( @@ -112,10 +103,10 @@ internal class AuditResourceIntTest { val audit: Unit get() { // Initialize the database - auditEventRepository!!.save(auditEvent) + auditEventRepository.save(auditEvent) // Get the audit - restAuditMockMvc!!.perform(MockMvcRequestBuilders.get("/management/audits/{id}", auditEvent!!.id)) + restAuditMockMvc.perform(MockMvcRequestBuilders.get("/management/audits/{id}", auditEvent.id)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$.principal").value(SAMPLE_PRINCIPAL)) @@ -123,17 +114,17 @@ internal class AuditResourceIntTest { @get:Throws(Exception::class) @get:Test - val auditsByDate: Unit + open val auditsByDate: Unit get() { // Initialize the database - auditEventRepository!!.save(auditEvent) + auditEventRepository.save(auditEvent) // Generate dates for selecting audits by date, making sure the period contains the audit val fromDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER) val toDate = SAMPLE_TIMESTAMP.plusDays(1).format(FORMATTER) // Get the audit - restAuditMockMvc!!.perform( + restAuditMockMvc.perform( MockMvcRequestBuilders.get( "/management/audits?fromDate=" + fromDate + "&toDate=" + toDate @@ -155,7 +146,7 @@ internal class AuditResourceIntTest { val nonExistingAuditsByDate: Unit get() { // Initialize the database - auditEventRepository!!.save(auditEvent) + auditEventRepository.save(auditEvent) // Generate dates for selecting audits by date, making sure the period will not contain the // sample audit @@ -163,7 +154,7 @@ internal class AuditResourceIntTest { val toDate = SAMPLE_TIMESTAMP.minusDays(1).format(FORMATTER) // Query audits but expect no results - restAuditMockMvc!!.perform( + restAuditMockMvc.perform( MockMvcRequestBuilders.get( "/management/audits?fromDate=" + fromDate + "&toDate=" + toDate @@ -179,7 +170,7 @@ internal class AuditResourceIntTest { val nonExistingAudit: Unit get() { // Get the audit - restAuditMockMvc!!.perform(MockMvcRequestBuilders.get("/management/audits/{id}", Long.MAX_VALUE)) + restAuditMockMvc.perform(MockMvcRequestBuilders.get("/management/audits/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) } diff --git a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt index ca21e70f4..882b0afc1 100644 --- a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt @@ -53,39 +53,41 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal class GroupResourceIntTest(@Autowired private val groupService: GroupService, - @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, - @Autowired private val projectMapper: ProjectMapper, - @Autowired private val projectRepository: ProjectRepository, - @Autowired private val roleRepository: RoleRepository, - @Autowired private val subjectRepository: SubjectRepository, - @Autowired private val subjectService: SubjectService, - @Autowired private val groupMapper: GroupMapper, - @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, - @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val groupRepository: GroupRepository, - private var restGroupMockMvc: MockMvc, private var group: Group, - private var project: Project +internal class GroupResourceIntTest( + @Autowired private val groupService: GroupService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val roleRepository: RoleRepository, + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val subjectService: SubjectService, + @Autowired private val groupMapper: GroupMapper, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val groupRepository: GroupRepository, + private var restGroupMockMvc: MockMvc, + private var group: Group, + private var project: Project ) { @Autowired private val authService: AuthService? = null + @BeforeEach @Throws(ServletException::class) fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) val groupResource = GroupResource() ReflectionTestUtils.setField(groupResource, "groupService", groupService) ReflectionTestUtils.setField(groupResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) - restGroupMockMvc = MockMvcBuilders.standaloneSetup(groupResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) - .build() + restGroupMockMvc = + MockMvcBuilders.standaloneSetup(groupResource).setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator).setMessageConverters(jacksonMessageConverter) + .addFilter(filter).defaultRequest( + MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken()) + ).build() project = ProjectResourceIntTest.Companion.createEntity() projectRepository.save(project) group = createEntity() @@ -95,7 +97,7 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe fun tearDown() { groupRepository.delete(group) val roles = roleRepository.findAllRolesByProjectName( - project.projectName + project.projectName!! ) roleRepository.deleteAll(roles) projectRepository.delete(project) @@ -118,13 +120,9 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe val groupDto = groupMapper.groupToGroupDTO(group) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + "/api/projects/{projectName}/groups", project.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(groupDto)) + ).andExpect(MockMvcResultMatchers.status().isCreated()) val savedGroup: Group? = groupRepository.findByProjectNameAndName( project.projectName, groupDto.name ) @@ -143,13 +141,9 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe val groupDto = groupMapper.groupToGroupDTO(group) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto)) - ) - .andExpect(MockMvcResultMatchers.status().isNotFound()) + "/api/projects/{projectName}/groups", project.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(groupDto)) + ).andExpect(MockMvcResultMatchers.status().isNotFound()) } @Test @@ -159,29 +153,20 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe val groupDto = groupMapper.groupToGroupDTO(group) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + "/api/projects/{projectName}/groups", project.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(groupDto)) + ).andExpect(MockMvcResultMatchers.status().isCreated()) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto)) - ) - .andExpect(MockMvcResultMatchers.status().isConflict()) + "/api/projects/{projectName}/groups", project.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(groupDto)) + ).andExpect(MockMvcResultMatchers.status().isConflict()) } @Test @Throws(Exception::class) fun createGroupWithExistingNameInDifferentProject() { - val project2: Project = ProjectResourceIntTest.Companion.createEntity() - .projectName(project.projectName + "2") + val project2: Project = ProjectResourceIntTest.Companion.createEntity().projectName(project.projectName + "2") projectRepository.saveAndFlush(project2) val group2 = Group() group2.name = group.name @@ -191,23 +176,15 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe val groupDto = groupMapper.groupToGroupDTO(group) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + "/api/projects/{projectName}/groups", project.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(groupDto)) + ).andExpect(MockMvcResultMatchers.status().isCreated()) val group2Dto = groupMapper.groupToGroupDTO(group2) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project2.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(group2Dto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + "/api/projects/{projectName}/groups", project2.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(group2Dto)) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate groups are saved for both projects val savedGroup1: Group? = groupRepository.findByProjectNameAndName( @@ -241,13 +218,9 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe val groupDto = groupMapper.groupToGroupDTO(group) restGroupMockMvc.perform( MockMvcRequestBuilders.post( - "/api/projects/{projectName}/groups", - project.projectName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(groupDto)) - ) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) + "/api/projects/{projectName}/groups", project.projectName + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(groupDto)) + ).andExpect(MockMvcResultMatchers.status().isBadRequest()) } @get:Throws(Exception::class) @@ -260,18 +233,14 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get all the groups restGroupMockMvc.perform( MockMvcRequestBuilders.get( - "/api/projects/{projectName}/groups", - project.projectName + "/api/projects/{projectName}/groups", project.projectName ) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect( + ).andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)).andExpect( MockMvcResultMatchers.jsonPath("$.[*].projectId").value>( Matchers.hasItem(project.id!!.toInt()) ) - ) - .andExpect( + ).andExpect( MockMvcResultMatchers.jsonPath("$.[*].name").value>(Matchers.hasItem("group1")) ) } @@ -285,11 +254,9 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.get( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name + "/api/projects/{projectName}/groups/{groupName}", project.projectName, group.name ) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("group1")) .andExpect(MockMvcResultMatchers.jsonPath("$.projectId").value(project.id!!.toInt())) @@ -302,11 +269,9 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.get( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name + "/api/projects/{projectName}/groups/{groupName}", project.projectName, group.name ) - ) - .andExpect(MockMvcResultMatchers.status().isNotFound()) + ).andExpect(MockMvcResultMatchers.status().isNotFound()) } @Test @@ -318,12 +283,9 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name - ) - .accept(TestUtil.APPLICATION_JSON_UTF8) - ) - .andExpect(MockMvcResultMatchers.status().isNoContent()) + "/api/projects/{projectName}/groups/{groupName}", project.projectName, group.name + ).accept(TestUtil.APPLICATION_JSON_UTF8) + ).andExpect(MockMvcResultMatchers.status().isNoContent()) // Validate the Group is not present in the database val savedGroup = groupRepository.findByProjectNameAndName( @@ -349,30 +311,23 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Try to delete the Group (and fail) restGroupMockMvc.perform( MockMvcRequestBuilders.delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name - ) - .accept(TestUtil.APPLICATION_JSON_UTF8) - ) - .andExpect(MockMvcResultMatchers.status().isConflict()) + "/api/projects/{projectName}/groups/{groupName}", project.projectName, group.name + ).accept(TestUtil.APPLICATION_JSON_UTF8) + ).andExpect(MockMvcResultMatchers.status().isConflict()) // Delete the Group (and unlink the subjects) restGroupMockMvc.perform( MockMvcRequestBuilders.delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name - ) - .param("unlinkSubjects", "true") - .accept(TestUtil.APPLICATION_JSON_UTF8) - ) - .andExpect(MockMvcResultMatchers.status().isNoContent()) + "/api/projects/{projectName}/groups/{groupName}", project.projectName, group.name + ).param("unlinkSubjects", "true").accept(TestUtil.APPLICATION_JSON_UTF8) + ).andExpect(MockMvcResultMatchers.status().isNoContent()) // Validate the Group is not present in the database val savedGroup = groupRepository.findByProjectNameAndName( project.projectName, group.name ) Assertions.assertThat(savedGroup).isNull() - val storedSubject = subjectRepository.getOne(savedSubject!!.id) + val storedSubject = subjectRepository.getOne(savedSubject!!.id!!) subjectRepository.delete(storedSubject) } @@ -385,17 +340,14 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName, group.name + "2" - ) - .accept(TestUtil.APPLICATION_JSON_UTF8) - ) - .andExpect(MockMvcResultMatchers.status().isNotFound()) + "/api/projects/{projectName}/groups/{groupName}", project.projectName, group.name + "2" + ).accept(TestUtil.APPLICATION_JSON_UTF8) + ).andExpect(MockMvcResultMatchers.status().isNotFound()) // Validate the database still contains the group Assertions.assertThat( groupRepository.findById( - group.id + group.id!! ) ).isNotEmpty() } @@ -409,17 +361,14 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.delete( - "/api/projects/{projectName}/groups/{groupName}", - project.projectName + "2", group.name - ) - .accept(TestUtil.APPLICATION_JSON_UTF8) - ) - .andExpect(MockMvcResultMatchers.status().isNotFound()) + "/api/projects/{projectName}/groups/{groupName}", project.projectName + "2", group.name + ).accept(TestUtil.APPLICATION_JSON_UTF8) + ).andExpect(MockMvcResultMatchers.status().isNotFound()) // Validate the database still contains the group Assertions.assertThat( groupRepository.findById( - group.id + group.id!! ) ).isNotEmpty() } @@ -445,7 +394,7 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe val sub1Patch = SubjectPatchValue() sub1Patch.id = savedSub1!!.id val sub2Patch = SubjectPatchValue() - sub2Patch.login = savedSub2!!.getLogin() + sub2Patch.login = savedSub2!!.login val patchOp = GroupPatchOperation() patchOp.op = "add" val patchValue = ArrayList() @@ -458,16 +407,12 @@ internal class GroupResourceIntTest(@Autowired private val groupService: GroupSe // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.patch( - "/api/projects/{projectName}/groups/{groupName}/subjects", - project.projectName, group.name - ) - .contentType(TestUtil.APPLICATION_JSON_PATCH) - .content(TestUtil.convertObjectToJsonBytes(body)) - ) - .andExpect(MockMvcResultMatchers.status().isNoContent()) + "/api/projects/{projectName}/groups/{groupName}/subjects", project.projectName, group.name + ).contentType(TestUtil.APPLICATION_JSON_PATCH).content(TestUtil.convertObjectToJsonBytes(body)) + ).andExpect(MockMvcResultMatchers.status().isNoContent()) // Validate that the group was set for both subjects - val subjectLogins = listOf(savedSub1.getLogin(), savedSub2.getLogin()) + val subjectLogins = listOf(savedSub1.login!!, savedSub2.login!!) val subjects = subjectRepository.findAllBySubjectLogins(subjectLogins) Assertions.assertThat(subjects).hasSize(2) Assertions.assertThat(subjects).allSatisfy { s: Subject -> diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt index d319aeeee..16b8952af 100644 --- a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt @@ -131,7 +131,7 @@ internal open class OAuthClientsResourceIntTest( MockMvcResultMatchers.jsonPath("$.accessTokenValiditySeconds").value( Matchers.equalTo( details - .getAccessTokenValiditySeconds().toInt() + .accessTokenValiditySeconds?.toInt() ) ) ) @@ -139,34 +139,34 @@ internal open class OAuthClientsResourceIntTest( MockMvcResultMatchers.jsonPath("$.refreshTokenValiditySeconds").value( Matchers.equalTo( details - .refreshTokenValiditySeconds.toInt() + .refreshTokenValiditySeconds?.toInt() ) ) ) .andExpect( MockMvcResultMatchers.jsonPath("$.scope").value( Matchers.containsInAnyOrder( - *details.scope.toTypedArray() + details.scope?.toTypedArray() ) ) ) .andExpect( MockMvcResultMatchers.jsonPath("$.autoApproveScopes").value( Matchers.containsInAnyOrder( - *details.autoApproveScopes.toTypedArray() + details.autoApproveScopes?.toTypedArray() ) ) ) .andExpect( MockMvcResultMatchers.jsonPath("$.authorizedGrantTypes").value( Matchers.containsInAnyOrder( - *details.authorizedGrantTypes.toTypedArray() + details.authorizedGrantTypes?.toTypedArray() ) ) ) .andExpect( MockMvcResultMatchers.jsonPath("$.authorities").value( - Matchers.containsInAnyOrder(*details.authorities.toTypedArray()) + Matchers.containsInAnyOrder(details.authorities?.toTypedArray()) ) ) val testDetails = clientDetailsList.stream() @@ -183,7 +183,7 @@ internal open class OAuthClientsResourceIntTest( Assertions.assertThat(testDetails.authorizedGrantTypes).containsExactlyInAnyOrderElementsOf( details.authorizedGrantTypes ) - details.autoApproveScopes.forEach(Consumer { scope: String? -> + details.autoApproveScopes?.forEach(Consumer { scope: String? -> Assertions.assertThat( testDetails.isAutoApprove( scope @@ -191,10 +191,10 @@ internal open class OAuthClientsResourceIntTest( ).isTrue() }) Assertions.assertThat(testDetails.accessTokenValiditySeconds).isEqualTo( - details.accessTokenValiditySeconds.toInt() + details.accessTokenValiditySeconds?.toInt() ) Assertions.assertThat(testDetails.refreshTokenValiditySeconds).isEqualTo( - details.refreshTokenValiditySeconds.toInt() + details.refreshTokenValiditySeconds?.toInt() ) Assertions.assertThat(testDetails.authorities.stream().map { obj: GrantedAuthority -> obj.authority }) .containsExactlyInAnyOrderElementsOf(details.authorities) @@ -257,7 +257,7 @@ internal open class OAuthClientsResourceIntTest( @Throws(Exception::class) open fun cannotModifyProtected() { // first change our test client to be protected - details.additionalInformation["protected"] = "true" + details.additionalInformation!!["protected"] = "true" restOauthClientMvc.perform( MockMvcRequestBuilders.put("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index e650e923b..f1bc651d1 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -41,7 +41,7 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal class OrganizationResourceIntTest( +internal open class OrganizationResourceIntTest( @Autowired private val organizationMapper: OrganizationMapper, @Autowired private val organizationRepository: OrganizationRepository, @Autowired private val organizationService: OrganizationService, @@ -71,15 +71,7 @@ internal class OrganizationResourceIntTest( .addFilter(filter) .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) .build() - organization = createEntity() - } - - @AfterEach - fun tearDown() { - val testOrg = organizationRepository.findOneByName( - organization.name - ) - testOrg.ifPresent { entity: Organization -> organizationRepository.delete(entity) } + organization = this.createEntity() } /** @@ -93,54 +85,20 @@ internal class OrganizationResourceIntTest( return org } - @Test - @Throws(Exception::class) - fun createOrganization() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) - - // Validate the Organization in the database - val savedOrg = organizationRepository.findOneByName(orgDto.name) - Assertions.assertThat(savedOrg).isNotEmpty() - } - - @Test - @Throws(Exception::class) - fun createOrganizationWithExistingName() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) - - // Second request should fail - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isConflict()) - } - @Test - @Throws(Exception::class) - fun checkGroupNameIsRequired() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - orgDto.name = null - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - } + @get:Throws(Exception::class) + @get:Test + val nonExistingOrganization: Unit + get() { + // Get the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}", + organization.name + ) + ) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @get:Throws(Exception::class) @get:Test @@ -158,57 +116,97 @@ internal class OrganizationResourceIntTest( ) } - @Test - @Throws(Exception::class) - fun getOrganization() { - // Initialize the database - organizationRepository.saveAndFlush(organization) - - // Get the organization - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/organizations/{name}", - organization.name + @get:Throws(Exception::class) + @get:Test + val projectsByOrganizationName: Unit + get() { + // Initialize the database + organizationRepository.saveAndFlush(organization) + val project: Project = ProjectResourceIntTest.Companion.createEntity() + .organization(organization) + .projectName("organization_project") + projectRepository.saveAndFlush(project) + + // Get projects of the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}/projects", + organization.name + ) ) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("org1")) - } + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].projectName").value("organization_project")) + projectRepository.delete(project) + } - @Test - @Throws(Exception::class) - fun editOrganization() { - // Initialize the database - organizationRepository.saveAndFlush(organization) - val updatedOrgDto = organizationMapper - .organizationToOrganizationDTO(organization) - updatedOrgDto?.location = "Other location" - - // Update the organization - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.put("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(updatedOrgDto)) + @AfterEach + fun tearDown() { + val testOrg = organizationRepository.findOneByName( + organization.name!! ) - .andExpect(MockMvcResultMatchers.status().isOk()) + if (testOrg != null) + organizationRepository.delete(testOrg) + - // Get the organization - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/organizations/{name}", - organization.name + @Test + @Throws(Exception::class) + fun createOrganization() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) ) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.location").value("Other location")) - } + .andExpect(MockMvcResultMatchers.status().isCreated()) + + // Validate the Organization in the database + val savedOrg = organizationRepository.findOneByName(orgDto.name) + Assertions.assertThat(savedOrg).isNotNull() + } + + @Test + @Throws(Exception::class) + fun createOrganizationWithExistingName() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) + + // Second request should fail + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isConflict()) + } + + + @Test + @Throws(Exception::class) + //TODO this is covered by not using a nullable type + fun checkGroupNameIsRequired() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + orgDto.name = "" + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + } + + + @Test + @Throws(Exception::class) + fun getOrganization() { + // Initialize the database + organizationRepository.saveAndFlush(organization) - @get:Throws(Exception::class) - @get:Test - val nonExistingOrganization: Unit - get() { // Get the organization restOrganizationMockMvc.perform( MockMvcRequestBuilders.get( @@ -216,30 +214,40 @@ internal class OrganizationResourceIntTest( organization.name ) ) - .andExpect(MockMvcResultMatchers.status().isNotFound()) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("org1")) } - @get:Throws(Exception::class) - @get:Test - val projectsByOrganizationName: Unit - get() { + @Test + @Throws(Exception::class) + fun editOrganization() { // Initialize the database organizationRepository.saveAndFlush(organization) - val project: Project = ProjectResourceIntTest.Companion.createEntity() - .organization(organization) - .projectName("organization_project") - projectRepository.saveAndFlush(project) + val updatedOrgDto = organizationMapper + .organizationToOrganizationDTO(organization) + updatedOrgDto?.location = "Other location" - // Get projects of the organization + // Update the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.put("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(updatedOrgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + + // Get the organization restOrganizationMockMvc.perform( MockMvcRequestBuilders.get( - "/api/organizations/{name}/projects", + "/api/organizations/{name}", organization.name ) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[*].projectName").value("organization_project")) - projectRepository.delete(project) + .andExpect(MockMvcResultMatchers.jsonPath("$.location").value("Other location")) } + + + } } diff --git a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt index 9851cc0ba..108c9644b 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt @@ -30,7 +30,7 @@ internal class ProfileInfoResourceIntTest { private var restProfileMockMvc: MockMvc? = null @BeforeEach fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) val activeProfiles = arrayOf("test") Mockito.`when`(environment!!.defaultProfiles).thenReturn(activeProfiles) Mockito.`when`(environment.activeProfiles).thenReturn(activeProfiles) diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt index 4db6c68a5..8ef5320d0 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt @@ -40,41 +40,31 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal class SourceDataResourceIntTest { - @Autowired - private val sourceDataRepository: SourceDataRepository? = null +internal open class SourceDataResourceIntTest( + @Autowired private val sourceDataRepository: SourceDataRepository, + @Autowired private val sourceDataMapper: SourceDataMapper, + @Autowired private val sourceDataService: SourceDataService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val em: EntityManager, + private var restSourceDataMockMvc: MockMvc, + private var sourceData: SourceData, + @Autowired private val authService: AuthService +) { - @Autowired - private val sourceDataMapper: SourceDataMapper? = null - - @Autowired - private val sourceDataService: SourceDataService? = null - - @Autowired - private val jacksonMessageConverter: MappingJackson2HttpMessageConverter? = null - - @Autowired - private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver? = null - - @Autowired - private val exceptionTranslator: ExceptionTranslator? = null - - @Autowired - private val em: EntityManager? = null - private var restSourceDataMockMvc: MockMvc? = null - private var sourceData: SourceData? = null - - @Autowired - private val authService: AuthService? = null @BeforeEach @Throws(ServletException::class) fun setUp() { - MockitoAnnotations.initMocks(this) - val sourceDataResource = SourceDataResource() + MockitoAnnotations.openMocks(this) + val sourceDataResource = SourceDataResource( + sourceDataService, + authService + ) ReflectionTestUtils.setField(sourceDataResource, "sourceDataService", sourceDataService) ReflectionTestUtils.setField(sourceDataResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() - filter!!.init(MockFilterConfig()) + filter.init(MockFilterConfig()) restSourceDataMockMvc = MockMvcBuilders.standaloneSetup(sourceDataResource) .setCustomArgumentResolvers(pageableArgumentResolver) .setControllerAdvice(exceptionTranslator) @@ -92,12 +82,12 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun createSourceData() { - val databaseSizeBeforeCreate = sourceDataRepository!!.findAll().size + open fun createSourceData() { + val databaseSizeBeforeCreate = sourceDataRepository.findAll().size // Create the SourceData - val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) - restSourceDataMockMvc!!.perform( + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) + restSourceDataMockMvc.perform( MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) @@ -121,15 +111,15 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun createSourceDataWithExistingId() { - val databaseSizeBeforeCreate = sourceDataRepository!!.findAll().size + open fun createSourceDataWithExistingId() { + val databaseSizeBeforeCreate = sourceDataRepository.findAll().size // Create the SourceData with an existing ID - sourceData!!.id = 1L - val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) + sourceData.id = 1L + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) // An entity with an existing ID cannot be created, so this API call must fail - restSourceDataMockMvc!!.perform( + restSourceDataMockMvc.perform( MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) @@ -144,14 +134,14 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun checkSourceDataTypeIsNotRequired() { - val databaseSizeBeforeTest = sourceDataRepository!!.findAll().size + open fun checkSourceDataTypeIsNotRequired() { + val databaseSizeBeforeTest = sourceDataRepository.findAll().size // set the field null - sourceData!!.sourceDataType = null + sourceData.sourceDataType = null // Create the SourceData, which fails. - val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) - restSourceDataMockMvc!!.perform( + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) + restSourceDataMockMvc.perform( MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) @@ -164,15 +154,15 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun checkSourceDataTypeOrTopicIsRequired() { - val databaseSizeBeforeTest = sourceDataRepository!!.findAll().size + open fun checkSourceDataTypeOrTopicIsRequired() { + val databaseSizeBeforeTest = sourceDataRepository.findAll().size // set the field null - sourceData!!.sourceDataType = null - sourceData!!.topic = null + sourceData.sourceDataType = null + sourceData.topic = null // Create the SourceData, which fails. - val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) - restSourceDataMockMvc!!.perform( + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) + restSourceDataMockMvc.perform( MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) @@ -185,19 +175,19 @@ internal class SourceDataResourceIntTest { @get:Throws(Exception::class) @get:Transactional @get:Test - val allSourceData: Unit + open val allSourceData: Unit get() { // Initialize the database - sourceDataRepository!!.saveAndFlush(sourceData) + sourceDataRepository.saveAndFlush(sourceData) // Get all the sourceDataList - restSourceDataMockMvc!!.perform(MockMvcRequestBuilders.get("/api/source-data?sort=id,desc")) + restSourceDataMockMvc.perform(MockMvcRequestBuilders.get("/api/source-data?sort=id,desc")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].id").value>( Matchers.hasItem( - sourceData!!.id!!.toInt() + sourceData.id!!.toInt() ) ) ) @@ -256,19 +246,19 @@ internal class SourceDataResourceIntTest { @get:Throws(Exception::class) @get:Transactional @get:Test - val allSourceDataWithPagination: Unit + open val allSourceDataWithPagination: Unit get() { // Initialize the database - sourceDataRepository!!.saveAndFlush(sourceData) + sourceDataRepository.saveAndFlush(sourceData) // Get all the sourceDataList - restSourceDataMockMvc!!.perform(MockMvcRequestBuilders.get("/api/source-data?page=0&size=5&sort=id,desc")) + restSourceDataMockMvc.perform(MockMvcRequestBuilders.get("/api/source-data?page=0&size=5&sort=id,desc")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].id").value>( Matchers.hasItem( - sourceData!!.id!!.toInt() + sourceData.id!!.toInt() ) ) ) @@ -327,20 +317,20 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun getSourceData() { + open fun getSourceData() { // Initialize the database - sourceDataRepository!!.saveAndFlush(sourceData) + sourceDataRepository.saveAndFlush(sourceData) // Get the sourceData - restSourceDataMockMvc!!.perform( + restSourceDataMockMvc.perform( MockMvcRequestBuilders.get( "/api/source-data/{sourceDataName}", - sourceData!!.sourceDataName + sourceData.sourceDataName ) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(sourceData!!.id!!.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(sourceData.id!!.toInt())) .andExpect(MockMvcResultMatchers.jsonPath("$.sourceDataType").value(DEFAULT_SOURCE_DATA_TYPE)) .andExpect(MockMvcResultMatchers.jsonPath("$.sourceDataName").value(DEFAULT_SOURCE_DATA_NAME)) .andExpect(MockMvcResultMatchers.jsonPath("$.processingState").value(DEFAULT_PROCESSING_STATE)) @@ -354,10 +344,10 @@ internal class SourceDataResourceIntTest { @get:Throws(Exception::class) @get:Transactional @get:Test - val nonExistingSourceData: Unit + open val nonExistingSourceData: Unit get() { // Get the sourceData - restSourceDataMockMvc!!.perform( + restSourceDataMockMvc.perform( MockMvcRequestBuilders.get( "/api/source-data/{sourceDataName}", DEFAULT_SOURCE_DATA_NAME + DEFAULT_SOURCE_DATA_NAME @@ -369,13 +359,13 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun updateSourceData() { + open fun updateSourceData() { // Initialize the database - sourceDataRepository!!.saveAndFlush(sourceData) + sourceDataRepository.saveAndFlush(sourceData) val databaseSizeBeforeUpdate = sourceDataRepository.findAll().size // Update the sourceData - val updatedSourceData = sourceDataRepository.findById(sourceData!!.id).get() + val updatedSourceData = sourceDataRepository.findById(sourceData.id).get() updatedSourceData .sourceDataType(UPDATED_SOURCE_DATA_TYPE) .sourceDataName(UPDATED_SOURCE_DATA_NAME) @@ -385,8 +375,8 @@ internal class SourceDataResourceIntTest { .topic(UPDATED_TOPIC) .unit(UPDATED_UNIT) .frequency(UPDATED_FREQUENCY) - val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(updatedSourceData) - restSourceDataMockMvc!!.perform( + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(updatedSourceData) + restSourceDataMockMvc.perform( MockMvcRequestBuilders.put("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) @@ -410,14 +400,14 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun updateNonExistingSourceData() { - val databaseSizeBeforeUpdate = sourceDataRepository!!.findAll().size + open fun updateNonExistingSourceData() { + val databaseSizeBeforeUpdate = sourceDataRepository.findAll().size // Create the SourceData - val sourceDataDto = sourceDataMapper!!.sourceDataToSourceDataDTO(sourceData) + val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) // If the entity doesn't have an ID, it will be created instead of just being updated - restSourceDataMockMvc!!.perform( + restSourceDataMockMvc.perform( MockMvcRequestBuilders.put("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceDataDto)) @@ -432,16 +422,16 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun deleteSourceData() { + open fun deleteSourceData() { // Initialize the database - sourceDataRepository!!.saveAndFlush(sourceData) + sourceDataRepository.saveAndFlush(sourceData) val databaseSizeBeforeDelete = sourceDataRepository.findAll().size // Get the sourceData - restSourceDataMockMvc!!.perform( + restSourceDataMockMvc.perform( MockMvcRequestBuilders.delete( "/api/source-data/{sourceDataName}", - sourceData!!.sourceDataName + sourceData.sourceDataName ) .accept(TestUtil.APPLICATION_JSON_UTF8) ) @@ -455,7 +445,7 @@ internal class SourceDataResourceIntTest { @Test @Transactional @Throws(Exception::class) - fun equalsVerifier() { + open fun equalsVerifier() { org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(SourceData::class.java)) } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt index 71ce2af6f..dc22d57e5 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt @@ -25,7 +25,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -62,13 +61,12 @@ internal open class SourceTypeResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val sourceTypeResource = SourceTypeResource() - ReflectionTestUtils.setField(sourceTypeResource, "sourceTypeService", sourceTypeService) - ReflectionTestUtils.setField( - sourceTypeResource, "sourceTypeRepository", - sourceTypeRepository + val sourceTypeResource = SourceTypeResource( + sourceTypeService, + sourceTypeRepository, + authService ) - ReflectionTestUtils.setField(sourceTypeResource, "authService", authService) + val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) restSourceTypeMockMvc = MockMvcBuilders.standaloneSetup(sourceTypeResource) @@ -97,7 +95,7 @@ internal open class SourceTypeResourceIntTest( SourceDataResourceIntTest.Companion.createEntity(em) ) val sourceData = sourceTypeDto.sourceData - sourceData.add(sourceDataDto) + sourceData.add(sourceDataDto!!) restSourceTypeMockMvc.perform( MockMvcRequestBuilders.post("/api/source-types") .contentType(TestUtil.APPLICATION_JSON_UTF8) diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index 623c78878..06c7e0d3a 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -147,7 +147,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit .andExpect( MockMvcResultMatchers.jsonPath("$.[*].id").value>( Matchers.hasItem( - subjectDto!!.id.toInt() + subjectDto!!.id!!.toInt() ) ) ) @@ -174,10 +174,10 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) // Get the subject - restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{login}", subjectDto!!.getLogin())) + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{login}", subjectDto!!.login)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(subjectDto.id.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(subjectDto.id!!.toInt())) .andExpect( MockMvcResultMatchers.jsonPath("$.externalLink") .value(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK) @@ -302,7 +302,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Get the subject restSubjectMockMvc.perform( - MockMvcRequestBuilders.delete("/api/subjects/{login}", subjectDto!!.getLogin()) + MockMvcRequestBuilders.delete("/api/subjects/{login}", subjectDto!!.login) .accept(TestUtil.APPLICATION_JSON_UTF8) ) .andExpect(MockMvcResultMatchers.status().isOk()) @@ -404,7 +404,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Get all the subjectList restSubjectMockMvc - .perform(MockMvcRequestBuilders.get("/api/subjects/{login}/sources?sort=id,desc", subjectDto.getLogin())) + .perform(MockMvcRequestBuilders.get("/api/subjects/{login}/sources?sort=id,desc", subjectDto.login)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").isNotEmpty()) @@ -455,7 +455,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit .id(createdSource.id) .sourceName(createdSource.sourceName) .sourceTypeId(createdSource.sourceType.id) - .sourceId(createdSource.sourceId) + .sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) @@ -465,12 +465,12 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit restSubjectMockMvc.perform( MockMvcRequestBuilders.get( "/api/subjects/{login}/sources", - createdSubject.getLogin() + createdSubject.login ) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[0].id").value(createdSource.id.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.[0].id").value(createdSource.id!!.toInt())) .andExpect( MockMvcResultMatchers.jsonPath("$.[0].sourceId").value(createdSource.sourceId.toString()) ) @@ -488,22 +488,22 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit .id(createdSource.id) .sourceName(createdSource.sourceName) .sourceTypeId(createdSource.sourceType.id) - .sourceId(createdSource.sourceId) + .sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) TestUtil.commitTransactionAndStartNew() - org.junit.jupiter.api.Assertions.assertNotNull(createdSubject!!.getLogin()) + org.junit.jupiter.api.Assertions.assertNotNull(createdSubject!!.login) // Get the subject restSubjectMockMvc.perform( MockMvcRequestBuilders.get( "/api/subjects/{login}/sources?withInactiveSources=true", - createdSubject.getLogin() + createdSubject.login ) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id!!.toInt())) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) ) @@ -521,7 +521,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit .id(createdSource.id) .sourceName(createdSource.sourceName) .sourceTypeId(createdSource.sourceType.id) - .sourceId(createdSource.sourceId) + .sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) @@ -529,17 +529,17 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit createdSubject!!.sources = emptySet() val updatedSubject = subjectService.updateSubject(createdSubject) TestUtil.commitTransactionAndStartNew() - org.junit.jupiter.api.Assertions.assertNotNull(updatedSubject!!.getLogin()) + org.junit.jupiter.api.Assertions.assertNotNull(updatedSubject!!.login) // Get the subject restSubjectMockMvc.perform( MockMvcRequestBuilders.get( "/api/subjects/{login}/sources?withInactiveSources=true", - updatedSubject.getLogin() + updatedSubject.login ) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id.toInt())) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id!!.toInt())) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) ) @@ -549,7 +549,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit .perform( MockMvcRequestBuilders.get( "/api/subjects/{login}/sources?withInactiveSources=false", - updatedSubject.getLogin() + updatedSubject.login ) ) .andExpect(MockMvcResultMatchers.status().isOk()) diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt index 6f84bcf65..d0bb73db5 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt @@ -107,10 +107,12 @@ internal open class UserResourceIntTest( @BeforeEach fun initTest() { user = UserServiceIntTest.createEntity(passwordService) - userRepository.findOneByLogin(UserServiceIntTest.DEFAULT_LOGIN) - .ifPresent { entity: User -> userRepository.delete(entity) } - userRepository.findOneByLogin(UserServiceIntTest.UPDATED_LOGIN) - .ifPresent { entity: User -> userRepository.delete(entity) } + val default_user = userRepository.findOneByLogin(UserServiceIntTest.DEFAULT_LOGIN) + if (default_user != null) + userRepository.delete(default_user) + val updated_user = userRepository.findOneByLogin(UserServiceIntTest.UPDATED_LOGIN) + if (updated_user != null) + userRepository.delete(updated_user) val roles = roleRepository .findRolesByAuthorityName(RoleAuthority.PARTICIPANT.authority) .stream().filter { r: Role -> r.project == null } From 4bd325120b3503f1adf949170bd0faa580e7e401 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 31 Oct 2023 09:39:14 +0100 Subject: [PATCH 099/158] Rename .java to .kt --- .../{ManagementPortalApp.java => ManagementPortalApp.kt} | 0 ...agementPortalProperties.java => ManagementPortalProperties.kt} | 0 ...yConfigLoader.java => ManagementPortalSecurityConfigLoader.kt} | 0 .../{OAuth2LoginUiWebConfig.java => OAuth2LoginUiWebConfig.kt} | 0 .../web/rest/{AuthorityResource.java => AuthorityResource.kt} | 0 .../rest/{SiteSettingsResource.java => SiteSettingsResource.kt} | 0 .../web/rest/{TokenKeyEndpoint.java => TokenKeyEndpoint.kt} | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/org/radarbase/management/{ManagementPortalApp.java => ManagementPortalApp.kt} (100%) rename src/main/java/org/radarbase/management/config/{ManagementPortalProperties.java => ManagementPortalProperties.kt} (100%) rename src/main/java/org/radarbase/management/config/{ManagementPortalSecurityConfigLoader.java => ManagementPortalSecurityConfigLoader.kt} (100%) rename src/main/java/org/radarbase/management/config/{OAuth2LoginUiWebConfig.java => OAuth2LoginUiWebConfig.kt} (100%) rename src/main/java/org/radarbase/management/web/rest/{AuthorityResource.java => AuthorityResource.kt} (100%) rename src/main/java/org/radarbase/management/web/rest/{SiteSettingsResource.java => SiteSettingsResource.kt} (100%) rename src/main/java/org/radarbase/management/web/rest/{TokenKeyEndpoint.java => TokenKeyEndpoint.kt} (100%) diff --git a/src/main/java/org/radarbase/management/ManagementPortalApp.java b/src/main/java/org/radarbase/management/ManagementPortalApp.kt similarity index 100% rename from src/main/java/org/radarbase/management/ManagementPortalApp.java rename to src/main/java/org/radarbase/management/ManagementPortalApp.kt diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalProperties.java b/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/ManagementPortalProperties.java rename to src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.java b/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.java rename to src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt diff --git a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.java b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt similarity index 100% rename from src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.java rename to src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt diff --git a/src/main/java/org/radarbase/management/web/rest/AuthorityResource.java b/src/main/java/org/radarbase/management/web/rest/AuthorityResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/AuthorityResource.java rename to src/main/java/org/radarbase/management/web/rest/AuthorityResource.kt diff --git a/src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.java b/src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.java rename to src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.kt diff --git a/src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.java b/src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.kt similarity index 100% rename from src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.java rename to src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.kt From 6cadd7894a07398349c8f1020a374a237300dd16 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 31 Oct 2023 09:39:15 +0100 Subject: [PATCH 100/158] test compiles, implemented joris' requested changes --- .../authorization/MPAuthorizationOracle.kt | 3 +- .../auth/authentication/TokenValidatorTest.kt | 10 +- .../management/ManagementPortalApp.kt | 154 +++++---- .../management/config/AsyncConfiguration.kt | 7 +- .../management/config/CacheConfiguration.kt | 2 +- .../config/DatabaseConfiguration.kt | 2 +- .../management/config/LoggingConfiguration.kt | 8 +- .../config/ManagementPortalProperties.kt | 327 +++--------------- .../ManagementPortalSecurityConfigLoader.kt | 271 +++++++-------- .../config/OAuth2LoginUiWebConfig.kt | 136 ++++---- .../radarbase/management/domain/Project.kt | 8 +- .../org/radarbase/management/domain/Source.kt | 9 +- .../management/repository/SourceRepository.kt | 4 +- .../security/JwtAuthenticationFilter.kt | 5 +- .../security/RadarAuthentication.kt | 2 +- .../management/security/SecurityUtils.kt | 34 +- .../ManagementPortalOauthKeyStoreHandler.kt | 16 +- .../algorithm/AsymmetricalJwtAlgorithm.java | 40 --- .../jwt/algorithm/EcdsaJwtAlgorithm.java | 41 --- .../security/jwt/algorithm/JwtAlgorithm.java | 26 -- .../jwt/algorithm/RsaJwtAlgorithm.java | 40 --- .../management/service/RoleService.kt | 1 - .../management/service/SiteSettingsService.kt | 8 +- .../management/service/SourceService.kt | 4 +- .../management/service/SubjectService.kt | 15 +- .../service/dto/MinimalSourceDetailsDTO.kt | 9 +- .../management/service/dto/SiteSettingsDto.kt | 8 +- .../mapper/decorator/SourceMapperDecorator.kt | 2 +- .../mapper/decorator/UserMapperDecorator.kt | 10 +- .../management/web/rest/AuthorityResource.kt | 88 ++--- .../web/rest/SiteSettingsResource.kt | 69 ++-- .../management/web/rest/SourceResource.kt | 2 +- .../management/web/rest/TokenKeyEndpoint.kt | 57 ++- .../errors/RadarWebApplicationExceptionVM.kt | 8 +- .../web/rest/OrganizationResourceIntTest.kt | 2 +- .../web/rest/SourceDataResourceIntTest.kt | 6 +- .../web/rest/SourceResourceIntTest.kt | 14 +- .../web/rest/SourceTypeResourceIntTest.kt | 4 +- .../web/rest/SubjectResourceIntTest.kt | 78 ++--- .../web/rest/UserResourceIntTest.kt | 2 +- 40 files changed, 569 insertions(+), 963 deletions(-) delete mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.java delete mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.java delete mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.java delete mode 100644 src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.java diff --git a/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt b/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt index 804470a50..ef7f0ad5d 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt @@ -26,8 +26,7 @@ class MPAuthorizationOracle( return identity.roles?.forkAny { it.hasPermission(identity, permission, entity, entityScope) - } - ?: false + } ?: false } /** diff --git a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt index 9b62292c8..9c35dc29e 100644 --- a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt +++ b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt @@ -20,7 +20,7 @@ import org.radarbase.auth.util.TokenTestUtils.WIREMOCK_PORT * Created by dverbeec on 24/04/2017. */ internal class TokenValidatorTest { - private var validator: TokenValidator? = null + private lateinit var validator: TokenValidator /** * Set up a stub public key endpoint and initialize a TokenValidator object. @@ -53,28 +53,28 @@ internal class TokenValidatorTest { @Test fun testValidToken() { - validator!!.validateBlocking(TokenTestUtils.VALID_RSA_TOKEN) + validator.validateBlocking(TokenTestUtils.VALID_RSA_TOKEN) } @Test fun testIncorrectAudienceToken() { Assertions.assertThrows( TokenValidationException::class.java - ) { validator!!.validateBlocking(TokenTestUtils.INCORRECT_AUDIENCE_TOKEN) } + ) { validator.validateBlocking(TokenTestUtils.INCORRECT_AUDIENCE_TOKEN) } } @Test fun testExpiredToken() { Assertions.assertThrows( TokenValidationException::class.java - ) { validator!!.validateBlocking(TokenTestUtils.EXPIRED_TOKEN) } + ) { validator.validateBlocking(TokenTestUtils.EXPIRED_TOKEN) } } @Test fun testIncorrectAlgorithmToken() { Assertions.assertThrows( TokenValidationException::class.java - ) { validator!!.validateBlocking(TokenTestUtils.INCORRECT_ALGORITHM_TOKEN) } + ) { validator.validateBlocking(TokenTestUtils.INCORRECT_ALGORITHM_TOKEN) } } companion object { diff --git a/src/main/java/org/radarbase/management/ManagementPortalApp.kt b/src/main/java/org/radarbase/management/ManagementPortalApp.kt index 7bfc158d2..2200a96d2 100644 --- a/src/main/java/org/radarbase/management/ManagementPortalApp.kt +++ b/src/main/java/org/radarbase/management/ManagementPortalApp.kt @@ -1,97 +1,105 @@ -package org.radarbase.management; +package org.radarbase.management -import tech.jhipster.config.DefaultProfileUtil; -import tech.jhipster.config.JHipsterConstants; -import java.net.InetAddress; -import java.net.UnknownHostException; -import javax.annotation.PostConstruct; -import org.radarbase.management.config.ApplicationProperties; -import org.radarbase.management.config.ManagementPortalProperties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.core.env.Environment; -import org.springframework.core.env.Profiles; +import org.radarbase.management.config.ApplicationProperties +import org.radarbase.management.config.ManagementPortalProperties +import org.slf4j.LoggerFactory +import org.springframework.boot.SpringApplication +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties +import org.springframework.boot.context.properties.EnableConfigurationProperties +import org.springframework.context.annotation.ComponentScan +import org.springframework.core.env.Environment +import org.springframework.core.env.Profiles +import tech.jhipster.config.DefaultProfileUtil +import tech.jhipster.config.JHipsterConstants +import java.net.InetAddress +import java.net.UnknownHostException +import javax.annotation.PostConstruct -@ComponentScan({ - "org.radarbase.management.config", - "org.radarbase.management.domain.support", - "org.radarbase.management.filters", - "org.radarbase.management.repository", - "org.radarbase.management.service", - "org.radarbase.management.security", - "org.radarbase.management.web" -}) +@ComponentScan( + "org.radarbase.management.config", + "org.radarbase.management.domain.support", + "org.radarbase.management.filters", + "org.radarbase.management.repository", + "org.radarbase.management.service", + "org.radarbase.management.security", + "org.radarbase.management.web" +) @EnableAutoConfiguration -@EnableConfigurationProperties({LiquibaseProperties.class, ApplicationProperties.class, - ManagementPortalProperties.class}) -public class ManagementPortalApp { - - private static final Logger log = LoggerFactory.getLogger(ManagementPortalApp.class); - - private final Environment env; - - public ManagementPortalApp(Environment env) { - this.env = env; - } - +@EnableConfigurationProperties( + LiquibaseProperties::class, ApplicationProperties::class, ManagementPortalProperties::class +) +class ManagementPortalApp(private val env: Environment) { /** * Initializes ManagementPortal. * - *

Spring profiles can be configured with a program arguments - * --spring.profiles.active=your-active-profile

* - *

You can find more information on how profiles work with JHipster on - * - * http://jhipster.github.io/profiles/ - *

. + * Spring profiles can be configured with a program arguments + * --spring.profiles.active=your-active-profile + * + * + * You can find more information on how profiles work with JHipster on + * [ + * http://jhipster.github.io/profiles/ +](http://jhipster.github.io/profiles/) * . */ @PostConstruct - public void initApplication() { + fun initApplication() { if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) - && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_PRODUCTION))) { - log.error("You have misconfigured your application! It should not run " - + "with both the 'dev' and 'prod' profiles at the same time."); + && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) + ) { + log.error( + "You have misconfigured your application! It should not run " + + "with both the 'dev' and 'prod' profiles at the same time." + ) } if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)) - && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_CLOUD))) { - log.error("You have misconfigured your application! It should not" - + "run with both the 'dev' and 'cloud' profiles at the same time."); + && env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_CLOUD)) + ) { + log.error( + "You have misconfigured your application! It should not" + + "run with both the 'dev' and 'cloud' profiles at the same time." + ) } } - /** - * Main method, used to run the application. - * - * @param args the command line arguments - * @throws UnknownHostException if the local host name could not be resolved into an address - */ - public static void main(String[] args) throws UnknownHostException { - SpringApplication app = new SpringApplication(ManagementPortalApp.class); - DefaultProfileUtil.addDefaultProfile(app); - Environment env = app.run(args).getEnvironment(); - String protocol = "http"; - if (env.getProperty("server.ssl.key-store") != null) { - protocol = "https"; - } - log.info(""" + companion object { + private val log = LoggerFactory.getLogger(ManagementPortalApp::class.java) + /** + * Main method, used to run the application. + * + * @param args the command line arguments + * @throws UnknownHostException if the local host name could not be resolved into an address + */ + @Throws(UnknownHostException::class) + @JvmStatic + fun main(args: Array) { + val app = SpringApplication(ManagementPortalApp::class.java) + DefaultProfileUtil.addDefaultProfile(app) + val env: Environment = app.run(*args).environment + var protocol = "http" + if (env.getProperty("server.ssl.key-store") != null) { + protocol = "https" + } + log.info( + """ + + ----------------------------------------------------- + ${'\t'}Application '{}' is running! Access URLs: + ${'\t'}Local: ${'\t'}${'\t'}{}://localhost:{} + ${'\t'}External: ${'\t'}{}://{}:{} + ${'\t'}Profile(s): ${'\t'}{} ----------------------------------------------------- - \tApplication '{}' is running! Access URLs: - \tLocal: \t\t{}://localhost:{} - \tExternal: \t{}://{}:{} - \tProfile(s): \t{} - -----------------------------------------------------""", + """.trimIndent(), env.getProperty("spring.application.name"), protocol, env.getProperty("server.port"), protocol, - InetAddress.getLocalHost().getHostAddress(), + InetAddress.getLocalHost().hostAddress, env.getProperty("server.port"), - env.getActiveProfiles()); + env.activeProfiles + ) + } } } diff --git a/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt index 51e7aaf21..bca9e4d4f 100644 --- a/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt @@ -16,14 +16,13 @@ import tech.jhipster.config.JHipsterProperties @Configuration @EnableAsync @EnableScheduling -open class AsyncConfiguration : AsyncConfigurer { - @Autowired - private val jHipsterProperties: JHipsterProperties? = null +open class AsyncConfiguration( + @Autowired private val jHipsterProperties: JHipsterProperties) : AsyncConfigurer { @Bean(name = ["taskExecutor"]) override fun getAsyncExecutor(): ExceptionHandlingAsyncTaskExecutor { log.debug("Creating Async Task Executor") val executor = ThreadPoolTaskExecutor() - executor.corePoolSize = jHipsterProperties!!.async.corePoolSize + executor.corePoolSize = jHipsterProperties.async.corePoolSize executor.maxPoolSize = jHipsterProperties.async.maxPoolSize executor.queueCapacity = jHipsterProperties.async.queueCapacity executor.setThreadNamePrefix("management-portal-Executor-") diff --git a/src/main/java/org/radarbase/management/config/CacheConfiguration.kt b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt index 57b0cd25e..dcc1adbeb 100644 --- a/src/main/java/org/radarbase/management/config/CacheConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt @@ -37,7 +37,7 @@ open class CacheConfiguration { } @Bean - open fun HazelcastInstance?.cacheManager(): CacheManager { + open fun HazelcastInstance.cacheManager(): CacheManager { log.debug("Starting HazelcastCacheManager") return HazelcastCacheManager( this diff --git a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt index 752f96662..896feab14 100644 --- a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt @@ -28,7 +28,7 @@ open class DatabaseConfiguration { private val env: Environment? = null @Bean open fun liquibase( - dataSource: DataSource?, + dataSource: DataSource, liquibaseProperties: LiquibaseProperties ): SpringLiquibase { diff --git a/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt b/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt index 6e6651e07..0ef95ad72 100644 --- a/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt @@ -18,9 +18,11 @@ open class LoggingConfiguration( /** Logging configuration for JHipster. */ init { val context = LoggerFactory.getILoggerFactory() as LoggerContext - val map: MutableMap = HashMap() - map["app_name"] = appName - map["app_port"] = serverPort + val map: MutableMap = buildMap { + put("app_name", appName) + put("app_port", serverPort) + } as MutableMap + val customFields = mapper.writeValueAsString(map) val loggingProperties = jHipsterProperties.logging val logstashProperties = loggingProperties.logstash diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt b/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt index e478a0679..c9853ddbc 100644 --- a/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt +++ b/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt @@ -1,299 +1,68 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.springframework.boot.context.properties.ConfigurationProperties; - -import java.util.List; +import org.springframework.boot.context.properties.ConfigurationProperties /** * Created by nivethika on 3-10-17. */ @ConfigurationProperties(prefix = "managementportal", ignoreUnknownFields = false) -public class ManagementPortalProperties { - - private final Mail mail = new Mail(); - - private final Frontend frontend = new Frontend(); - - private Oauth oauth = new Oauth(); - - private final Common common = new Common(); - - private final CatalogueServer catalogueServer = new CatalogueServer(); - - private final Account account = new Account(); - - private final SiteSettings siteSettings = new SiteSettings(); - - public ManagementPortalProperties.Frontend getFrontend() { - return frontend; +class ManagementPortalProperties { + val mail = Mail() + @JvmField + val frontend = Frontend() + @JvmField + var oauth = Oauth() + @JvmField + val common = Common() + val catalogueServer = CatalogueServer() + val account = Account() + val siteSettings = SiteSettings() + + class Account { + var enableExposeToken = false } - public ManagementPortalProperties.Mail getMail() { - return mail; + class Common { + var baseUrl = "" + var managementPortalBaseUrl = "" + var privacyPolicyUrl = "" + @JvmField + var adminPassword = "" + var activationKeyTimeoutInSeconds = 24 * 60 * 60 // 1 day } - public ManagementPortalProperties.Oauth getOauth() { - return oauth; + class Mail { + var from = "" } - public void setOauth(ManagementPortalProperties.Oauth oauth) { - this.oauth = oauth; + class Frontend { + @JvmField + var clientId = "" + var clientSecret = "" + @JvmField + var accessTokenValiditySeconds = 4 * 60 * 60 + @JvmField + var refreshTokenValiditySeconds = 72 * 60 * 60 + var sessionTimeout = 24 * 60 * 60 // a day } - public CatalogueServer getCatalogueServer() { - return catalogueServer; - } - - public Common getCommon() { - return common; - } - - public Account getAccount() { - return account; - } - - public SiteSettings getSiteSettings() { - return siteSettings; - } - - public static class Account { - private boolean enableExposeToken = false; - - public boolean getEnableExposeToken() { - return enableExposeToken; - } - - public void setEnableExposeToken(boolean enableExposeToken) { - this.enableExposeToken = enableExposeToken; - } - } - - public static class Common { - - private String baseUrl = ""; - - private String managementPortalBaseUrl = ""; - - private String privacyPolicyUrl = ""; - - private String adminPassword = ""; - - private Integer activationKeyTimeoutInSeconds = 24 * 60 * 60; // 1 day - - public String getBaseUrl() { - return baseUrl; - } - - public void setBaseUrl(String baseUrl) { - this.baseUrl = baseUrl; - } - - public String getPrivacyPolicyUrl() { - return privacyPolicyUrl; - } - - public void setPrivacyPolicyUrl(String privacyPolicyUrl) { - this.privacyPolicyUrl = privacyPolicyUrl; - } - - public String getAdminPassword() { - return adminPassword; - } - - public void setAdminPassword(String adminPassword) { - this.adminPassword = adminPassword; - } - - public String getManagementPortalBaseUrl() { - return managementPortalBaseUrl; - } - - public void setManagementPortalBaseUrl(String managementPortalBaseUrl) { - this.managementPortalBaseUrl = managementPortalBaseUrl; - } - - public Integer getActivationKeyTimeoutInSeconds() { - return activationKeyTimeoutInSeconds; - } - - public void setActivationKeyTimeoutInSeconds(Integer activationKeyTimeoutInSeconds) { - this.activationKeyTimeoutInSeconds = activationKeyTimeoutInSeconds; - } + class Oauth { + @JvmField + var clientsFile: String? = null + var signingKeyAlias: String? = null + var checkingKeyAliases: List? = null + lateinit var keyStorePassword: String + var metaTokenTimeout: String? = null + var persistentMetaTokenTimeout: String? = null + var enablePublicKeyVerifiers = false } - public static class Mail { - - private String from = ""; - - public String getFrom() { - return from; - } - - public void setFrom(String from) { - this.from = from; - } - + class CatalogueServer { + var isEnableAutoImport = false + var serverUrl: String? = null } - public static class Frontend { - - private String clientId = ""; - - private String clientSecret = ""; - - private Integer accessTokenValiditySeconds = 4 * 60 * 60; - - private Integer refreshTokenValiditySeconds = 72 * 60 * 60; - - private Integer sessionTimeout = 24 * 60 * 60; // a day - - public String getClientId() { - return clientId; - } - - public void setClientId(String clientId) { - this.clientId = clientId; - } - - public String getClientSecret() { - return clientSecret; - } - - public void setClientSecret(String clientSecret) { - this.clientSecret = clientSecret; - } - - public Integer getSessionTimeout() { - return sessionTimeout; - } - - public void setSessionTimeout(Integer sessionTimeout) { - this.sessionTimeout = sessionTimeout; - } - - public Integer getAccessTokenValiditySeconds() { - return accessTokenValiditySeconds; - } - - public void setAccessTokenValiditySeconds(Integer accessTokenValiditySeconds) { - this.accessTokenValiditySeconds = accessTokenValiditySeconds; - } - - public Integer getRefreshTokenValiditySeconds() { - return refreshTokenValiditySeconds; - } - - public void setRefreshTokenValiditySeconds(Integer refreshTokenValiditySeconds) { - this.refreshTokenValiditySeconds = refreshTokenValiditySeconds; - } - } - - public static class Oauth { - - private String clientsFile; - - private String signingKeyAlias; - - private List checkingKeyAliases; - - private String keyStorePassword; - - private String metaTokenTimeout; - - private String persistentMetaTokenTimeout; - - private Boolean enablePublicKeyVerifiers = false; - - public String getClientsFile() { - return clientsFile; - } - - public void setClientsFile(String clientsFile) { - this.clientsFile = clientsFile; - } - - public String getSigningKeyAlias() { - return signingKeyAlias; - } - - public void setSigningKeyAlias(String signingKeyAlias) { - this.signingKeyAlias = signingKeyAlias; - } - - public List getCheckingKeyAliases() { - return checkingKeyAliases; - } - - public void setCheckingKeyAliases(List checkingKeyAliases) { - this.checkingKeyAliases = checkingKeyAliases; - } - - public String getKeyStorePassword() { - return keyStorePassword; - } - - public void setKeyStorePassword(String keyStorePassword) { - this.keyStorePassword = keyStorePassword; - } - - public String getMetaTokenTimeout() { - return metaTokenTimeout; - } - - public void setMetaTokenTimeout(String metaTokenTimeout) { - this.metaTokenTimeout = metaTokenTimeout; - } - - public String getPersistentMetaTokenTimeout() { - return persistentMetaTokenTimeout; - } - - public void setPersistentMetaTokenTimeout(String persistentMetaTokenTimeout) { - this.persistentMetaTokenTimeout = persistentMetaTokenTimeout; - } - - public Boolean getEnablePublicKeyVerifiers() { - return enablePublicKeyVerifiers; - } - - public void setEnablePublicKeyVerifiers(Boolean enablePublicKeyVerifiers) { - this.enablePublicKeyVerifiers = enablePublicKeyVerifiers; - } - } - - public static class CatalogueServer { - - private boolean enableAutoImport = false; - - private String serverUrl; - - public String getServerUrl() { - return serverUrl; - } - - public void setServerUrl(String serverUrl) { - this.serverUrl = serverUrl; - } - - public boolean isEnableAutoImport() { - return enableAutoImport; - } - - public void setEnableAutoImport(boolean enableAutoImport) { - this.enableAutoImport = enableAutoImport; - } - } - - public static class SiteSettings { - - private List hiddenSubjectFields; - - public void setHiddenSubjectFields(List hiddenSubjectFields) { - this.hiddenSubjectFields = hiddenSubjectFields; - } - - public List getHiddenSubjectFields() { - return hiddenSubjectFields; - } + class SiteSettings { + var hiddenSubjectFields: List = listOf() } } diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt b/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt index aa1f15116..b12b7ce13 100644 --- a/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt +++ b/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt @@ -1,198 +1,199 @@ -package org.radarbase.management.config; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.MappingIterator; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.ObjectReader; -import com.fasterxml.jackson.dataformat.csv.CsvMapper; -import com.fasterxml.jackson.dataformat.csv.CsvSchema; -import org.radarbase.auth.authorization.Permission; -import org.radarbase.management.service.UserService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.context.event.EventListener; -import org.springframework.security.oauth2.provider.ClientDetails; -import org.springframework.security.oauth2.provider.NoSuchClientException; -import org.springframework.security.oauth2.provider.client.BaseClientDetails; -import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService; -import org.springframework.stereotype.Component; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; +package org.radarbase.management.config + +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.annotation.JsonSetter +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.dataformat.csv.CsvMapper +import org.radarbase.auth.authorization.Permission.Companion.scopes +import org.radarbase.management.service.UserService +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.event.ContextRefreshedEvent +import org.springframework.context.event.EventListener +import org.springframework.security.oauth2.provider.ClientDetails +import org.springframework.security.oauth2.provider.NoSuchClientException +import org.springframework.security.oauth2.provider.client.BaseClientDetails +import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService +import org.springframework.stereotype.Component +import java.lang.Boolean +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths +import java.util.* +import kotlin.Any +import kotlin.Array +import kotlin.Exception +import kotlin.String /** * Loads security configs such as oauth-clients, and overriding admin password if specified. * Created by dverbeec on 20/11/2017. */ @Component -public class ManagementPortalSecurityConfigLoader { - +class ManagementPortalSecurityConfigLoader { @Autowired - private JdbcClientDetailsService clientDetailsService; + private val clientDetailsService: JdbcClientDetailsService? = null @Autowired - private ManagementPortalProperties managementPortalProperties; + private val managementPortalProperties: ManagementPortalProperties? = null @Autowired - private UserService userService; - - private static final Logger logger = - LoggerFactory.getLogger(ManagementPortalSecurityConfigLoader.class); - - private static final Character SEPARATOR = ';'; + private val userService: UserService? = null /** * Resets the admin password to the value of managementportal.common.adminPassword value if * exists. */ - @EventListener(ContextRefreshedEvent.class) - public void overrideAdminPassword() { - String adminPassword = managementPortalProperties.getCommon().getAdminPassword(); - + @EventListener(ContextRefreshedEvent::class) + fun overrideAdminPassword() { + val adminPassword = managementPortalProperties!!.common.adminPassword if (adminPassword != null && !adminPassword.isEmpty()) { - logger.info("Overriding admin password to configured password"); - userService.changePassword("admin", adminPassword); + logger.info("Overriding admin password to configured password") + userService!!.changePassword("admin", adminPassword) } else { - logger.info("AdminPassword property is empty. Using default password..."); + logger.info("AdminPassword property is empty. Using default password...") } } - /** * Build the ClientDetails for the ManagementPortal frontend and load it to the database. */ - @EventListener(ContextRefreshedEvent.class) - public void loadFrontendOauthClient() { - logger.info("Loading ManagementPortal frontend client"); - ManagementPortalProperties.Frontend frontend = managementPortalProperties.getFrontend(); - BaseClientDetails details = new BaseClientDetails(); - details.setClientId(frontend.getClientId()); - details.setClientSecret(null); - details.setAccessTokenValiditySeconds(frontend.getAccessTokenValiditySeconds()); - details.setRefreshTokenValiditySeconds(frontend.getRefreshTokenValiditySeconds()); - details.setResourceIds(List.of("res_ManagementPortal", "res_appconfig", "res_upload", - "res_restAuthorizer")); - details.setAuthorizedGrantTypes(Arrays.asList("password", "refresh_token", - "authorization_code")); - details.setAdditionalInformation(Collections.singletonMap("protected", Boolean.TRUE)); - List allScopes = Arrays.asList(Permission.scopes()); - details.setScope(allScopes); - details.setAutoApproveScopes(allScopes); - loadOAuthClient(details); + @EventListener(ContextRefreshedEvent::class) + fun loadFrontendOauthClient() { + logger.info("Loading ManagementPortal frontend client") + val frontend = managementPortalProperties!!.frontend + val details = BaseClientDetails() + details.clientId = frontend.clientId + details.clientSecret = null + details.accessTokenValiditySeconds = frontend.accessTokenValiditySeconds + details.refreshTokenValiditySeconds = frontend.refreshTokenValiditySeconds + details.setResourceIds( + listOf( + "res_ManagementPortal", "res_appconfig", "res_upload", + "res_restAuthorizer" + ) + ) + details.setAuthorizedGrantTypes( + mutableListOf( + "password", "refresh_token", + "authorization_code" + ) + ) + details.setAdditionalInformation(Collections.singletonMap("protected", Boolean.TRUE)) + val allScopes = Arrays.asList(*scopes()) + details.setScope(allScopes) + details.setAutoApproveScopes(allScopes) + loadOAuthClient(details) } /** * Event listener method that loads OAuth clients from file as soon as the application * context is refreshed. This happens at least once, on application startup. */ - @EventListener(ContextRefreshedEvent.class) - public void loadOAuthClientsFromFile() { - String path = managementPortalProperties.getOauth().getClientsFile(); - if (Objects.isNull(path) || path.equals("")) { - logger.info("No OAuth clients file specified, not loading additional clients"); - return; + @EventListener(ContextRefreshedEvent::class) + fun loadOAuthClientsFromFile() { + val path = managementPortalProperties!!.oauth.clientsFile + if (Objects.isNull(path) || path == "") { + logger.info("No OAuth clients file specified, not loading additional clients") + return } - Path file = Paths.get(path); + val file = Paths.get(path) // CsvSchema uses the @JsonPropertyOrder to define column order, it does not // read the header. Let's read the header ourselves and provide that as // column order - String[] columnOrder = getCsvFileColumnOrder(file); - if (columnOrder == null) { - return; - } - CsvMapper mapper = new CsvMapper(); - CsvSchema schema = mapper.schemaFor(CustomBaseClientDetails.class) - .withColumnReordering(true) - .sortedBy(columnOrder) - .withColumnSeparator(SEPARATOR) - .withHeader(); - ObjectReader reader = mapper - .readerFor(CustomBaseClientDetails.class) - .with(schema); - try (InputStream inputStream = Files.newInputStream(file); - MappingIterator iterator = reader.readValues(inputStream)) { - logger.info("Loading OAuth clients from {}", file.toAbsolutePath()); - while (iterator.hasNext()) { - loadOAuthClient(iterator.nextValue()); + val columnOrder = getCsvFileColumnOrder(file) ?: return + val mapper = CsvMapper() + val schema = mapper.schemaFor(CustomBaseClientDetails::class.java) + .withColumnReordering(true) + .sortedBy(*columnOrder) + .withColumnSeparator(SEPARATOR) + .withHeader() + val reader = mapper + .readerFor(CustomBaseClientDetails::class.java) + .with(schema) + try { + Files.newInputStream(file).use { inputStream -> + reader.readValues(inputStream).use { iterator -> + logger.info("Loading OAuth clients from {}", file.toAbsolutePath()) + while (iterator.hasNext()) { + loadOAuthClient(iterator.nextValue()) + } + } } - } catch (Exception ex) { - logger.error("Unable to load OAuth clients from file: " + ex.getMessage(), ex); + } catch (ex: Exception) { + logger.error("Unable to load OAuth clients from file: " + ex.message, ex) } } - private void loadOAuthClient(ClientDetails details) { + private fun loadOAuthClient(details: ClientDetails) { try { - ClientDetails client = clientDetailsService.loadClientByClientId(details.getClientId()); + val client = clientDetailsService!!.loadClientByClientId(details.clientId) // we delete the existing client and reload it in the next try block - clientDetailsService.removeClientDetails(client.getClientId()); - logger.info("Removed existing OAuth client: " + details.getClientId()); - } catch (NoSuchClientException ex) { + clientDetailsService.removeClientDetails(client.clientId) + logger.info("Removed existing OAuth client: " + details.clientId) + } catch (ex: NoSuchClientException) { // the client is not in the databse yet, this is ok - } catch (Exception ex) { + } catch (ex: Exception) { // other error, e.g. database issue - logger.error(ex.getMessage(), ex); + logger.error(ex.message, ex) } try { - clientDetailsService.addClientDetails(details); - logger.info("OAuth client loaded: " + details.getClientId()); - } catch (Exception ex) { - logger.error("Unable to load OAuth client " + details.getClientId() + ": " - + ex.getMessage(), ex); + clientDetailsService!!.addClientDetails(details) + logger.info("OAuth client loaded: " + details.clientId) + } catch (ex: Exception) { + logger.error( + "Unable to load OAuth client " + details.clientId + ": " + + ex.message, ex + ) } } - private String[] getCsvFileColumnOrder(Path csvFile) { - try (BufferedReader bufferedReader = Files.newBufferedReader(csvFile)) { - return bufferedReader.readLine().split(SEPARATOR.toString()); - } catch (Exception ex) { - logger.error("Unable to read header from OAuth clients file: " + ex.getMessage(), ex); - return null; + private fun getCsvFileColumnOrder(csvFile: Path): Array? { + try { + Files.newBufferedReader(csvFile).use { bufferedReader -> + return bufferedReader.readLine().split(SEPARATOR.toString().toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray() + } + } catch (ex: Exception) { + logger.error("Unable to read header from OAuth clients file: " + ex.message, ex) + return null } } /** * Custom class that will also deserialize the additional_information field. This field holds a - * JSON structure that needs to be converted to a {@code Map}. This field is - * {@link com.fasterxml.jackson.annotation.JsonIgnore}d in BaseClientDetails but we need it. + * JSON structure that needs to be converted to a `Map`. This field is + * [com.fasterxml.jackson.annotation.JsonIgnore]d in BaseClientDetails but we need it. */ - private static class CustomBaseClientDetails extends BaseClientDetails { - + private class CustomBaseClientDetails : BaseClientDetails() { @JsonProperty("additional_information") - private Map additionalInformation = new LinkedHashMap<>(); - - @Override - public Map getAdditionalInformation() { - return additionalInformation; + private var additionalInformation: Map = LinkedHashMap() + override fun getAdditionalInformation(): Map { + return additionalInformation } @JsonSetter("additional_information") - public void setAdditionalInformation(String additionalInformation) { - if (Objects.isNull(additionalInformation) || additionalInformation.equals("")) { - this.additionalInformation = Collections.emptyMap(); - return; + fun setAdditionalInformation(additionalInformation: String) { + if (Objects.isNull(additionalInformation) || additionalInformation == "") { + this.additionalInformation = emptyMap() + return } - ObjectMapper mapper = new ObjectMapper(); + val mapper = ObjectMapper() try { - this.additionalInformation = mapper.readValue(additionalInformation, - new TypeReference>() { - }); - } catch (Exception ex) { - logger.error("Unable to parse additional_information field for client " - + getClientId() + ": " + ex.getMessage(), ex); + this.additionalInformation = mapper.readValue>(additionalInformation, + object : TypeReference>() {}) + } catch (ex: Exception) { + logger.error( + "Unable to parse additional_information field for client " + + clientId + ": " + ex.message, ex + ) } } } + + companion object { + private val logger = LoggerFactory.getLogger(ManagementPortalSecurityConfigLoader::class.java) + private const val SEPARATOR = ';' + } } diff --git a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt index dae7d135d..741e9d882 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt @@ -1,39 +1,34 @@ -package org.radarbase.management.config; +package org.radarbase.management.config -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; -import org.springframework.security.oauth2.common.util.OAuth2Utils; -import org.springframework.security.oauth2.provider.AuthorizationRequest; -import org.springframework.security.oauth2.provider.ClientDetailsService; -import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.SessionAttributes; -import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.util.HtmlUtils; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.text.SimpleDateFormat; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.TreeMap; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception +import org.springframework.security.oauth2.common.util.OAuth2Utils +import org.springframework.security.oauth2.provider.ClientDetailsService +import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory +import org.springframework.stereotype.Controller +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.SessionAttributes +import org.springframework.web.servlet.ModelAndView +import org.springframework.web.util.HtmlUtils +import java.lang.Boolean +import java.text.SimpleDateFormat +import java.util.* +import java.util.function.Function +import java.util.stream.Collectors +import java.util.stream.Stream +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse +import kotlin.Any +import kotlin.String /** * Created by dverbeec on 6/07/2017. */ @Controller @SessionAttributes("authorizationRequest") -public class OAuth2LoginUiWebConfig { - +class OAuth2LoginUiWebConfig { @Autowired - private ClientDetailsService clientDetailsService; + private val clientDetailsService: ClientDetailsService? = null /** * Login form for OAuth2 auhorization flows. @@ -42,12 +37,12 @@ public class OAuth2LoginUiWebConfig { * @return a ModelAndView to render the form */ @RequestMapping("/login") - public ModelAndView getLogin(HttpServletRequest request, HttpServletResponse response) { - TreeMap model = new TreeMap<>(); - if (request.getParameterMap().containsKey("error")) { - model.put("loginError", Boolean.TRUE); + fun getLogin(request: HttpServletRequest, response: HttpServletResponse?): ModelAndView { + val model = TreeMap() + if (request.parameterMap.containsKey("error")) { + model["loginError"] = Boolean.TRUE } - return new ModelAndView("login", model); + return ModelAndView("login", model) } /** @@ -57,23 +52,25 @@ public class OAuth2LoginUiWebConfig { * @return a ModelAndView to render the form */ @RequestMapping("/oauth/confirm_access") - public ModelAndView getAccessConfirmation(HttpServletRequest request, - HttpServletResponse response) { - - Map params = request.getParameterMap(); - - Map authorizationParameters = Stream.of( - OAuth2Utils.CLIENT_ID, OAuth2Utils.REDIRECT_URI, OAuth2Utils.STATE, - OAuth2Utils.SCOPE, OAuth2Utils.RESPONSE_TYPE) - .filter(params::containsKey) - .collect(Collectors.toMap(Function.identity(), p -> params.get(p)[0])); - - AuthorizationRequest authorizationRequest = new DefaultOAuth2RequestFactory( - clientDetailsService).createAuthorizationRequest(authorizationParameters); - - Map model = Collections.singletonMap("authorizationRequest", - authorizationRequest); - return new ModelAndView("authorize", model); + fun getAccessConfirmation( + request: HttpServletRequest, + response: HttpServletResponse? + ): ModelAndView { + val params = request.parameterMap + val authorizationParameters = Stream.of( + OAuth2Utils.CLIENT_ID, OAuth2Utils.REDIRECT_URI, OAuth2Utils.STATE, + OAuth2Utils.SCOPE, OAuth2Utils.RESPONSE_TYPE + ) + .filter { key: String -> params.containsKey(key) } + .collect(Collectors.toMap(Function.identity(), Function { p: String -> params[p]!![0] })) + val authorizationRequest = DefaultOAuth2RequestFactory( + clientDetailsService + ).createAuthorizationRequest(authorizationParameters) + val model = Collections.singletonMap( + "authorizationRequest", + authorizationRequest + ) + return ModelAndView("authorize", model) } /** @@ -82,34 +79,33 @@ public class OAuth2LoginUiWebConfig { * @return a ModelAndView to render the page */ @RequestMapping("/oauth/error") - public ModelAndView handleOAuthClientError(HttpServletRequest req) { - TreeMap model = new TreeMap<>(); - Object error = req.getAttribute("error"); + fun handleOAuthClientError(req: HttpServletRequest): ModelAndView { + val model = TreeMap() + val error = req.getAttribute("error") // The error summary may contain malicious user input, // it needs to be escaped to prevent XSS - Map errorParams = new HashMap<>(); - errorParams.put("date", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US) - .format(new Date())); - if (error instanceof OAuth2Exception) { - OAuth2Exception oauthError = (OAuth2Exception) error; - errorParams.put("status", String.format("%d", oauthError.getHttpErrorCode())); - errorParams.put("code", oauthError.getOAuth2ErrorCode()); - errorParams.put("message", HtmlUtils.htmlEscape(oauthError.getMessage())); + val errorParams: MutableMap = HashMap() + errorParams["date"] = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US) + .format(Date()) + if (error is OAuth2Exception) { + val oauthError = error + errorParams["status"] = String.format("%d", oauthError.httpErrorCode) + errorParams["code"] = oauthError.oAuth2ErrorCode + errorParams["message"] = HtmlUtils.htmlEscape(oauthError.message) // transform the additionalInfo map to a comma seperated list of key: value pairs - if (oauthError.getAdditionalInformation() != null) { - errorParams.put("additionalInfo", HtmlUtils.htmlEscape( - oauthError.getAdditionalInformation().entrySet().stream() - .map(entry -> entry.getKey() + ": " + entry.getValue()) - .collect(Collectors.joining(", ")))); + if (oauthError.additionalInformation != null) { + errorParams["additionalInfo"] = HtmlUtils.htmlEscape( + oauthError.additionalInformation.entries.joinToString(", ") { entry -> entry.key + ": " + entry.value } + ) } } // Copy non-empty entries to the model. Empty entries will not be present in the model, // so the default value will be rendered in the view. - for (Map.Entry entry : errorParams.entrySet()) { - if (!entry.getValue().equals("")) { - model.put(entry.getKey(), entry.getValue()); + for ((key, value) in errorParams) { + if (value != "") { + model[key] = value } } - return new ModelAndView("error", model); + return ModelAndView("error", model) } } diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index bc36271a5..faa6b7cbd 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -169,14 +169,14 @@ class Project : AbstractEntity(), Serializable { return this } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val project = o as Project + val project = other as Project return if (project.id == null || id == null) { false } else id == project.id diff --git a/src/main/java/org/radarbase/management/domain/Source.kt b/src/main/java/org/radarbase/management/domain/Source.kt index 241f4a5b4..53d1287c3 100644 --- a/src/main/java/org/radarbase/management/domain/Source.kt +++ b/src/main/java/org/radarbase/management/domain/Source.kt @@ -58,7 +58,7 @@ class Source : AbstractEntity, Serializable { var expectedSourceName: String? = null @Column(name = "assigned", nullable = false) - var isAssigned: @NotNull Boolean? = false + var assigned: @NotNull Boolean? = false @Column(name = "deleted", nullable = false) var isDeleted: @NotNull Boolean = false @@ -125,11 +125,6 @@ class Source : AbstractEntity, Serializable { } } - fun assigned(assigned: Boolean): Source { - isAssigned = assigned - return this - } - fun deleted(deleted: Boolean): Source { isDeleted = deleted return this @@ -177,7 +172,7 @@ class Source : AbstractEntity, Serializable { + "id=" + id + ", sourceId='" + sourceId + '\'' + ", sourceName='" + sourceName + '\'' - + ", assigned=" + isAssigned + + ", assigned=" + assigned + ", sourceType=" + sourceType + ", project=" + project + '}') diff --git a/src/main/java/org/radarbase/management/repository/SourceRepository.kt b/src/main/java/org/radarbase/management/repository/SourceRepository.kt index a11861da6..094d95d46 100644 --- a/src/main/java/org/radarbase/management/repository/SourceRepository.kt +++ b/src/main/java/org/radarbase/management/repository/SourceRepository.kt @@ -35,10 +35,10 @@ interface SourceRepository : JpaRepository, RevisionRepository? + val User.authorityReferences: Set get() = roles?.mapTo(HashSet()) { role: Role? -> val auth = role?.role val referent = when (auth?.scope) { @@ -195,7 +195,8 @@ class JwtAuthenticationFilter @JvmOverloads constructor( null -> null } AuthorityReference(auth!!, referent) - } + } ?: setOf() + @get:JvmStatic diff --git a/src/main/java/org/radarbase/management/security/RadarAuthentication.kt b/src/main/java/org/radarbase/management/security/RadarAuthentication.kt index 26df1809d..3f6be9708 100644 --- a/src/main/java/org/radarbase/management/security/RadarAuthentication.kt +++ b/src/main/java/org/radarbase/management/security/RadarAuthentication.kt @@ -79,7 +79,7 @@ class RadarAuthentication(@param:Nonnull private val token: RadarToken) : Authen } override fun hashCode(): Int { - var result = token?.hashCode() ?: 0 + var result = token.hashCode() result = 31 * result + if (isAuthenticated) 1 else 0 return result } diff --git a/src/main/java/org/radarbase/management/security/SecurityUtils.kt b/src/main/java/org/radarbase/management/security/SecurityUtils.kt index 0b6b66f42..309c52ecc 100644 --- a/src/main/java/org/radarbase/management/security/SecurityUtils.kt +++ b/src/main/java/org/radarbase/management/security/SecurityUtils.kt @@ -25,27 +25,25 @@ object SecurityUtils { * @param authentication context authentication * @return user name if present */ - fun getUserName(authentication: Authentication): String? { - return authentication - .let { obj: Authentication -> obj.principal } - .let { principal: Any? -> - when (principal) { - is UserDetails -> { - return (authentication.principal as UserDetails).username - } + fun getUserName(authentication: Authentication): String? = authentication + .let { obj: Authentication -> obj.principal } + .let { principal: Any? -> + when (principal) { + is UserDetails -> { + return (authentication.principal as UserDetails).username + } - is String -> { - return authentication.principal as String - } + is String -> { + return authentication.principal as String + } - is Authentication -> { - return principal.name - } + is Authentication -> { + return principal.name + } - else -> { - return null - } + else -> { + return null } } - } + } } diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt index 7fae1aed9..57625c3f4 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt @@ -112,9 +112,9 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( private fun loadVerifiersPublicKeyAliasList(): List { val publicKeyAliases: MutableList = ArrayList() - publicKeyAliases.add(oauthConfig.signingKeyAlias) + oauthConfig.signingKeyAlias?.let { publicKeyAliases.add(it) } if (oauthConfig.checkingKeyAliases != null) { - publicKeyAliases.addAll(oauthConfig.checkingKeyAliases) + publicKeyAliases.addAll(oauthConfig.checkingKeyAliases!!) } return publicKeyAliases } @@ -230,23 +230,17 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( private val logger = LoggerFactory.getLogger( ManagementPortalOauthKeyStoreHandler::class.java ) - private val KEYSTORE_PATHS = Arrays.asList( + private val KEYSTORE_PATHS = listOf( ClassPathResource("/config/keystore.p12"), ClassPathResource("/config/keystore.jks") ) private fun checkOAuthConfig(managementPortalProperties: ManagementPortalProperties) { val oauthConfig = managementPortalProperties.oauth - if (oauthConfig == null) { - logger.error( - "Could not find valid Oauth Config. Please configure compulsary " + "properties of Oauth configs of Management Portal" - ) - throw IllegalArgumentException("OauthConfig is not provided") - } - if (oauthConfig.keyStorePassword == null || oauthConfig.keyStorePassword.isEmpty()) { + if (oauthConfig.keyStorePassword.isEmpty()) { logger.error("oauth.keyStorePassword is empty") throw IllegalArgumentException("oauth.keyStorePassword is empty") } - if (oauthConfig.signingKeyAlias == null || oauthConfig.signingKeyAlias.isEmpty()) { + if (oauthConfig.signingKeyAlias == null || oauthConfig.signingKeyAlias!!.isEmpty()) { logger.error("oauth.signingKeyAlias is empty") throw IllegalArgumentException("OauthConfig is not provided") } diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.java b/src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.java deleted file mode 100644 index a0145c422..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/algorithm/AsymmetricalJwtAlgorithm.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.radarbase.management.security.jwt.algorithm; - -import java.security.KeyPair; -import java.util.Base64; - -import org.radarbase.auth.jwks.JsonWebKey; -import org.radarbase.auth.jwks.MPJsonWebKey; - -public abstract class AsymmetricalJwtAlgorithm implements JwtAlgorithm { - - protected final KeyPair keyPair; - - protected AsymmetricalJwtAlgorithm(KeyPair keyPair) { - this.keyPair = keyPair; - } - - /** Header used for encoding public keys. */ - protected abstract String getEncodedStringHeader(); - - /** Footer used for encoding public keys. */ - protected abstract String getEncodedStringFooter(); - - /** The family of cryptographic algorithms used with the key. */ - protected abstract String getKeyType(); - - @Override - public String getVerifierKeyEncodedString() { - return getEncodedStringHeader() + '\n' - + new String(Base64.getEncoder().encode(keyPair.getPublic().getEncoded())) - + '\n' + getEncodedStringFooter(); - } - - @Override - public JsonWebKey getJwk() { - return new MPJsonWebKey( - this.getAlgorithm().getName(), - this.getKeyType(), - this.getVerifierKeyEncodedString()); - } -} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.java b/src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.java deleted file mode 100644 index 2ab3931e1..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/algorithm/EcdsaJwtAlgorithm.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.radarbase.management.security.jwt.algorithm; - -import com.auth0.jwt.algorithms.Algorithm; - -import java.security.KeyPair; -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; - -public class EcdsaJwtAlgorithm extends AsymmetricalJwtAlgorithm { - /** ECDSA JWT algorithm. */ - public EcdsaJwtAlgorithm(KeyPair keyPair) { - super(keyPair); - if (!(keyPair.getPrivate() instanceof ECPrivateKey)) { - throw new IllegalArgumentException( - "Cannot make EcdsaJwtAlgorithm with " + keyPair.getPrivate().getClass()); - } - } - - @Override - public Algorithm getAlgorithm() { - return Algorithm.ECDSA256( - (ECPublicKey)keyPair.getPublic(), - (ECPrivateKey)keyPair.getPrivate()); - } - - @Override - public String getEncodedStringHeader() { - return "-----BEGIN EC PUBLIC KEY-----"; - } - - @Override - public String getEncodedStringFooter() { - return "-----END EC PUBLIC KEY-----"; - } - - @Override - public String getKeyType() { - return "EC"; - } - -} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.java b/src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.java deleted file mode 100644 index d7d026371..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/algorithm/JwtAlgorithm.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.radarbase.management.security.jwt.algorithm; - -import com.auth0.jwt.algorithms.Algorithm; -import org.radarbase.auth.jwks.JsonWebKey; - -/** - * Encodes a signing and verification algorithm for JWT. - */ -public interface JwtAlgorithm { - - /** - * Auth0 Algorithm used in JWTs. - */ - Algorithm getAlgorithm(); - - /** - * Encoded public key for storage or transmission. - */ - String getVerifierKeyEncodedString(); - - /** - * JavaWebKey for given algorithm for token verification. - * @return instance of {@link JsonWebKey} - */ - JsonWebKey getJwk(); -} diff --git a/src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.java b/src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.java deleted file mode 100644 index 10d1aedde..000000000 --- a/src/main/java/org/radarbase/management/security/jwt/algorithm/RsaJwtAlgorithm.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.radarbase.management.security.jwt.algorithm; - -import com.auth0.jwt.algorithms.Algorithm; - -import java.security.KeyPair; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; - -public class RsaJwtAlgorithm extends AsymmetricalJwtAlgorithm { - /** RSA JWT algorithm. */ - public RsaJwtAlgorithm(KeyPair keyPair) { - super(keyPair); - if (!(keyPair.getPrivate() instanceof RSAPrivateKey)) { - throw new IllegalArgumentException( - "Cannot make RsaJwtAlgorithm with " + keyPair.getPrivate().getClass()); - } - } - - @Override - public Algorithm getAlgorithm() { - return Algorithm.RSA256( - (RSAPublicKey)keyPair.getPublic(), - (RSAPrivateKey)keyPair.getPrivate()); - } - - @Override - public String getEncodedStringHeader() { - return "-----BEGIN PUBLIC KEY-----"; - } - - @Override - public String getEncodedStringFooter() { - return "-----END PUBLIC KEY-----"; - } - - @Override - public String getKeyType() { - return "RSA"; - } -} diff --git a/src/main/java/org/radarbase/management/service/RoleService.kt b/src/main/java/org/radarbase/management/service/RoleService.kt index 9074ceaf3..239dcf59a 100644 --- a/src/main/java/org/radarbase/management/service/RoleService.kt +++ b/src/main/java/org/radarbase/management/service/RoleService.kt @@ -35,7 +35,6 @@ open class RoleService( @Autowired private val userService: UserService ) { - private val log = LoggerFactory.getLogger(RoleService::class.java) /** * Save a role. diff --git a/src/main/java/org/radarbase/management/service/SiteSettingsService.kt b/src/main/java/org/radarbase/management/service/SiteSettingsService.kt index 9226f49a1..cabb2e47e 100644 --- a/src/main/java/org/radarbase/management/service/SiteSettingsService.kt +++ b/src/main/java/org/radarbase/management/service/SiteSettingsService.kt @@ -12,9 +12,8 @@ import org.springframework.transaction.annotation.Transactional */ @Service @Transactional -class SiteSettingsService { - @Autowired - private val managementPortalProperties: ManagementPortalProperties? = null +open class SiteSettingsService( + @Autowired private val managementPortalProperties: ManagementPortalProperties) { /** * Convert a [SiteSettings] to a [SiteSettingsDto] object. @@ -28,6 +27,5 @@ class SiteSettingsService { } val siteSettingsDto: SiteSettingsDto - // NAMING! - get() = createSiteSettingsDto(managementPortalProperties!!.siteSettings) + get() = createSiteSettingsDto(managementPortalProperties.siteSettings) } diff --git a/src/main/java/org/radarbase/management/service/SourceService.kt b/src/main/java/org/radarbase/management/service/SourceService.kt index ccf937a07..eb21d13e9 100644 --- a/src/main/java/org/radarbase/management/service/SourceService.kt +++ b/src/main/java/org/radarbase/management/service/SourceService.kt @@ -117,7 +117,7 @@ open class SourceService( val sourceHistory = sourceRepository.findRevisions(id) val sources = sourceHistory.content .mapNotNull { obj -> obj.entity } - .filter{ it.isAssigned + .filter{ it.assigned ?: false } .toList() if (sources.isEmpty()) { @@ -228,7 +228,7 @@ open class SourceService( // if the source is being transferred to another project. if (existingSource.project?.id != sourceDto.project?.id) { - if (existingSource.isAssigned!!) { + if (existingSource.assigned!!) { throw InvalidRequestException( "Cannot transfer an assigned source", EntityName.SOURCE, "error.sourceIsAssigned" diff --git a/src/main/java/org/radarbase/management/service/SubjectService.kt b/src/main/java/org/radarbase/management/service/SubjectService.kt index 84dcd8ec1..2a2bec776 100644 --- a/src/main/java/org/radarbase/management/service/SubjectService.kt +++ b/src/main/java/org/radarbase/management/service/SubjectService.kt @@ -98,7 +98,10 @@ open class SubjectService( user.activated = true //set if any devices are set as assigned if (subject.sources.isNotEmpty()) { - subject.sources.forEach(Consumer { s: Source -> s.assigned(true).subject(subject) }) + subject.sources.forEach(Consumer { s: Source -> + s.assigned = true + s.subject(subject) + }) } if (subject.enrollmentDate == null) { subject.enrollmentDate = ZonedDateTime.now() @@ -157,7 +160,8 @@ open class SubjectService( //set only the devices assigned to a subject as assigned subjectMapper.safeUpdateSubjectFromDTO(newSubjectDto, subjectFromDb) sourcesToUpdate.addAll(subjectFromDb.sources) - subjectFromDb.sources.forEach(Consumer { s: Source -> s.subject(subjectFromDb).assigned(true) }) + subjectFromDb.sources.forEach(Consumer { s: Source -> + s.subject(subjectFromDb).assigned = true }) sourceRepository.saveAll(sourcesToUpdate) // update participant role subjectFromDb.user!!.roles = updateParticipantRoles(subjectFromDb, newSubjectDto) @@ -233,7 +237,7 @@ open class SubjectService( */ private fun unassignAllSources(subject: Subject) { subject.sources.forEach(Consumer { source: Source -> - source.isAssigned = false + source.assigned = false source.subject = null source.isDeleted = true sourceRepository.save(source) @@ -262,7 +266,8 @@ open class SubjectService( // create a source and register metadata // we allow only one source of a source-type per subject if (sources.isNullOrEmpty()) { - var source = Source(sourceType).project(project).assigned(true).sourceType(sourceType).subject(subject) + var source = Source(sourceType).project(project).sourceType(sourceType).subject(subject) + source.assigned = true source.attributes += sourceRegistrationDto.attributes // if source name is provided update source name if (sourceRegistrationDto.sourceName != null) { @@ -332,7 +337,7 @@ open class SubjectService( source.sourceName = sourceRegistrationDto.sourceName } source.attributes += sourceRegistrationDto.attributes - source.isAssigned = true + source.assigned = true source.subject = subject return sourceRepository.save(source) } diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt index fe111ae5b..56eb19894 100644 --- a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt @@ -16,7 +16,7 @@ class MinimalSourceDetailsDTO { lateinit var sourceId: UUID var sourceName: String? = null var isAssigned: Boolean? = null - var attributes: Map = HashMap() + var attributes: MutableMap = HashMap() fun id(id: Long?): MinimalSourceDetailsDTO { this.id = id return this @@ -27,11 +27,6 @@ class MinimalSourceDetailsDTO { return this } - fun setExpectedSourceName(expectedSourceName: String?): MinimalSourceDetailsDTO { - this.expectedSourceName = expectedSourceName - return this - } - fun sourceId(sourceId: UUID): MinimalSourceDetailsDTO { this.sourceId = sourceId return this @@ -47,7 +42,7 @@ class MinimalSourceDetailsDTO { return this } - fun attributes(attributes: Map): MinimalSourceDetailsDTO { + fun attributes(attributes: MutableMap): MinimalSourceDetailsDTO { this.attributes = attributes return this } diff --git a/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt b/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt index b45250e80..b4fba3a0d 100644 --- a/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt +++ b/src/main/java/org/radarbase/management/service/dto/SiteSettingsDto.kt @@ -9,14 +9,14 @@ import java.util.* */ class SiteSettingsDto : Serializable { var hiddenSubjectFields = listOf() - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val that = o as SiteSettingsDto + val that = other as SiteSettingsDto return hiddenSubjectFields == that.hiddenSubjectFields } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt index eb418185c..518f91360 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt @@ -31,7 +31,7 @@ abstract class SourceMapperDecorator( EntityName.Companion.SOURCE, ErrorConstants.ERR_SOURCE_NOT_FOUND, Map.of("sourceId", minimalSourceDetailsDto.sourceId.toString()) ) - source.isAssigned = minimalSourceDetailsDto.isAssigned + source.assigned = minimalSourceDetailsDto.isAssigned return source } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt index 02f4fa2eb..163eda4ee 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt @@ -7,13 +7,11 @@ import org.radarbase.management.service.mapper.UserMapper import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Qualifier -abstract class UserMapperDecorator : UserMapper { - @Autowired - @Qualifier("delegate") - private val delegate: UserMapper? = null +abstract class UserMapperDecorator( + @Autowired @Qualifier("delegate") private val delegate: UserMapper? = null, + @Autowired private val revisionService: RevisionService? = null +) : UserMapper { - @Autowired - private val revisionService: RevisionService? = null override fun userToUserDTO(user: User?): UserDTO? { if (user == null) { return null diff --git a/src/main/java/org/radarbase/management/web/rest/AuthorityResource.kt b/src/main/java/org/radarbase/management/web/rest/AuthorityResource.kt index e47911788..231e4395b 100644 --- a/src/main/java/org/radarbase/management/web/rest/AuthorityResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/AuthorityResource.kt @@ -1,53 +1,57 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.auth.authorization.RoleAuthority; -import org.radarbase.management.security.NotAuthorizedException; -import org.radarbase.management.service.AuthService; -import org.radarbase.management.service.dto.AuthorityDTO; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; -import java.util.stream.Stream; - -import static org.radarbase.auth.authorization.Permission.AUTHORITY_READ; +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.authorization.Permission +import org.radarbase.auth.authorization.RoleAuthority +import org.radarbase.management.security.NotAuthorizedException +import org.radarbase.management.service.AuthService +import org.radarbase.management.service.dto.AuthorityDTO +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import java.util.stream.Stream /** * REST controller for managing Authority. */ @RestController @RequestMapping("/api") -public class AuthorityResource { - private static final Logger log = LoggerFactory.getLogger(AuthorityResource.class); - - private static final List ALL_AUTHORITIES = Stream.of( - RoleAuthority.SYS_ADMIN, - RoleAuthority.ORGANIZATION_ADMIN, - RoleAuthority.PROJECT_ADMIN, - RoleAuthority.PROJECT_OWNER, - RoleAuthority.PROJECT_AFFILIATE, - RoleAuthority.PROJECT_ANALYST) - .map(AuthorityDTO::new) - .toList(); - +class AuthorityResource { @Autowired - private AuthService authService; + private val authService: AuthService? = null + + @get:Throws(NotAuthorizedException::class) + @get:Timed + @get:GetMapping("/authorities") + val allAuthorities: List + /** + * GET /authorities : get all the authorities. + * + * @return the ResponseEntity with status 200 (OK) and the list of authorities in body + */ + get() { + log.debug("REST request to get all Authorities") + authService!!.checkScope(Permission.AUTHORITY_READ) + return ALL_AUTHORITIES + } - /** - * GET /authorities : get all the authorities. - * - * @return the ResponseEntity with status 200 (OK) and the list of authorities in body - */ - @GetMapping("/authorities") - @Timed - public List getAllAuthorities() throws NotAuthorizedException { - log.debug("REST request to get all Authorities"); - authService.checkScope(AUTHORITY_READ); - return ALL_AUTHORITIES; + companion object { + private val log = LoggerFactory.getLogger(AuthorityResource::class.java) + private val ALL_AUTHORITIES = Stream.of( + RoleAuthority.SYS_ADMIN, + RoleAuthority.ORGANIZATION_ADMIN, + RoleAuthority.PROJECT_ADMIN, + RoleAuthority.PROJECT_OWNER, + RoleAuthority.PROJECT_AFFILIATE, + RoleAuthority.PROJECT_ANALYST + ) + .map { role: RoleAuthority? -> + AuthorityDTO( + role!! + ) + } + .toList() } } diff --git a/src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.kt b/src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.kt index a4ba51d05..71d872714 100644 --- a/src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SiteSettingsResource.kt @@ -1,49 +1,44 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.management.service.SiteSettingsService; -import org.radarbase.management.service.dto.SiteSettingsDto; -import org.radarbase.management.config.ManagementPortalProperties.SiteSettings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import io.micrometer.core.annotation.Timed +import org.radarbase.management.service.SiteSettingsService +import org.radarbase.management.service.dto.SiteSettingsDto +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController /** * REST controller for managing site settings. * - *

This class accesses {@link SiteSettings} entity as a means of defining configurations - * before authentication.

+ * + * This class accesses [SiteSettings] entity as a means of defining configurations + * before authentication. * */ @RestController @RequestMapping("/api") -public class SiteSettingsResource { - - private static final Logger log = LoggerFactory.getLogger(SiteSettingsResource.class); - - private final SiteSettingsService siteSettingsService; - - public SiteSettingsResource( - @Autowired SiteSettingsService siteSettingsService) { - this.siteSettingsService = siteSettingsService; - } - - /** - * GET /SiteSettings : Gets the current SiteSettings as a DTO. - * - * @return the ResponseEntity with status 200 (Ok) and with body {@link SiteSettingsDto}. - */ - @GetMapping("/sitesettings") - @Timed - public ResponseEntity getDisabledSubjectFields() { - log.debug("REST request to get sitesettings"); - - return ResponseEntity +class SiteSettingsResource( + @param:Autowired private val siteSettingsService: SiteSettingsService +) { + @get:Timed + @get:GetMapping("/sitesettings") + val disabledSubjectFields: ResponseEntity + /** + * GET /SiteSettings : Gets the current SiteSettings as a DTO. + * + * @return the ResponseEntity with status 200 (Ok) and with body [SiteSettingsDto]. + */ + get() { + log.debug("REST request to get sitesettings") + return ResponseEntity .ok() - .body(siteSettingsService.getSiteSettingsDto()); + .body(siteSettingsService.siteSettingsDto) + } + + companion object { + private val log = LoggerFactory.getLogger(SiteSettingsResource::class.java) } } diff --git a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt index 3e14ca0a5..856c3b61b 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt @@ -207,7 +207,7 @@ class SourceResource( val sourceId = sourceDto.id val sourceHistory = sourceId?.let { sourceRepository.findRevisions(it) } val sources = - sourceHistory?.mapNotNull { obj: Revision -> obj.entity }?.filter { it.isAssigned == true } + sourceHistory?.mapNotNull { obj: Revision -> obj.entity }?.filter { it.assigned == true } ?.toList() if (sources?.isNotEmpty() == true) { val failureAlert = HeaderUtil.createFailureAlert( diff --git a/src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.kt b/src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.kt index fed32de5c..c4fc357ee 100644 --- a/src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.kt +++ b/src/main/java/org/radarbase/management/web/rest/TokenKeyEndpoint.kt @@ -1,37 +1,32 @@ -package org.radarbase.management.web.rest; +package org.radarbase.management.web.rest -import io.micrometer.core.annotation.Timed; -import org.radarbase.auth.jwks.JsonWebKeySet; -import org.radarbase.management.security.jwt.ManagementPortalOauthKeyStoreHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; +import io.micrometer.core.annotation.Timed +import org.radarbase.auth.jwks.JsonWebKeySet +import org.radarbase.management.security.jwt.ManagementPortalOauthKeyStoreHandler +import org.slf4j.LoggerFactory +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController @RestController -public class TokenKeyEndpoint { - private static final Logger logger = LoggerFactory.getLogger(TokenKeyEndpoint.class); +class TokenKeyEndpoint @Autowired constructor( + private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler +) { + @get:Timed + @get:GetMapping("/oauth/token_key") + val key: JsonWebKeySet + /** + * Get the verification key for the token signatures. The principal has to + * be provided only if the key is secret + * + * @return the key used to verify tokens + */ + get() { + logger.debug("Requesting verifier public keys...") + return keyStoreHandler.loadJwks() + } - private final ManagementPortalOauthKeyStoreHandler keyStoreHandler; - - @Autowired - public TokenKeyEndpoint( - ManagementPortalOauthKeyStoreHandler keyStoreHandler - ) { - this.keyStoreHandler = keyStoreHandler; - } - - /** - * Get the verification key for the token signatures. The principal has to - * be provided only if the key is secret - * - * @return the key used to verify tokens - */ - @GetMapping("/oauth/token_key") - @Timed - public JsonWebKeySet getKey() { - logger.debug("Requesting verifier public keys..."); - return keyStoreHandler.loadJwks(); + companion object { + private val logger = LoggerFactory.getLogger(TokenKeyEndpoint::class.java) } } diff --git a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt index 51d44586a..6fc2c2404 100644 --- a/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt +++ b/src/main/java/org/radarbase/management/web/rest/errors/RadarWebApplicationExceptionVM.kt @@ -36,14 +36,14 @@ class RadarWebApplicationExceptionVM emptyMap() ) - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val that = o as RadarWebApplicationExceptionVM + val that = other as RadarWebApplicationExceptionVM return entityName == that.entityName && errorCode == that.errorCode && message == that.message && params == that.params } diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index f1bc651d1..78ec5fa9a 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -226,7 +226,7 @@ internal open class OrganizationResourceIntTest( organizationRepository.saveAndFlush(organization) val updatedOrgDto = organizationMapper .organizationToOrganizationDTO(organization) - updatedOrgDto?.location = "Other location" + updatedOrgDto.location = "Other location" // Update the organization restOrganizationMockMvc.perform( diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt index 8ef5320d0..804292021 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt @@ -76,7 +76,7 @@ internal open class SourceDataResourceIntTest( @BeforeEach fun initTest() { - sourceData = createEntity(em) + sourceData = createEntity() } @Test @@ -365,7 +365,7 @@ internal open class SourceDataResourceIntTest( val databaseSizeBeforeUpdate = sourceDataRepository.findAll().size // Update the sourceData - val updatedSourceData = sourceDataRepository.findById(sourceData.id).get() + val updatedSourceData = sourceDataRepository.findById(sourceData.id!!).get() updatedSourceData .sourceDataType(UPDATED_SOURCE_DATA_TYPE) .sourceDataName(UPDATED_SOURCE_DATA_NAME) @@ -474,7 +474,7 @@ internal open class SourceDataResourceIntTest( * This is a static method, as tests for other entities might also need it, * if they test an entity which requires the current entity. */ - fun createEntity(em: EntityManager?): SourceData { + fun createEntity(): SourceData { return SourceData() .sourceDataType(DEFAULT_SOURCE_DATA_TYPE) .sourceDataName(DEFAULT_SOURCE_DATA_NAME) diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt index 04f5133ef..80033e65a 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt @@ -109,7 +109,7 @@ internal open class SourceResourceIntTest( val sourceList = sourceRepository.findAll() Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeCreate + 1) val testSource = sourceList[sourceList.size - 1] - Assertions.assertThat(testSource.isAssigned).isEqualTo(DEFAULT_ASSIGNED) + Assertions.assertThat(testSource.assigned).isEqualTo(DEFAULT_ASSIGNED) Assertions.assertThat(testSource.sourceName).isEqualTo(DEFAULT_SOURCE_NAME) Assertions.assertThat(testSource.project!!.projectName).isEqualTo(project.projectName) } @@ -173,7 +173,7 @@ internal open class SourceResourceIntTest( open fun checkAssignedIsRequired() { val databaseSizeBeforeTest = sourceRepository.findAll().size // set the field null - source.isAssigned = null + source.assigned = null // Create the Source, which fails. val sourceDto = sourceMapper.sourceToSourceDTO(source) @@ -254,7 +254,7 @@ internal open class SourceResourceIntTest( val updatedSource = sourceRepository.findById(source.id!!).get() updatedSource .sourceId(UPDATED_SOURCE_PHYSICAL_ID) - .assigned(UPDATED_ASSIGNED) + .assigned = UPDATED_ASSIGNED val sourceDto = sourceMapper.sourceToSourceDTO(updatedSource) restDeviceMockMvc.perform( MockMvcRequestBuilders.put("/api/sources") @@ -268,7 +268,7 @@ internal open class SourceResourceIntTest( Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeUpdate) val testSource = sourceList[sourceList.size - 1] Assertions.assertThat(testSource.sourceId).isEqualTo(UPDATED_SOURCE_PHYSICAL_ID) - Assertions.assertThat(testSource.isAssigned).isEqualTo(UPDATED_ASSIGNED) + Assertions.assertThat(testSource.assigned).isEqualTo(UPDATED_ASSIGNED) } @Test @@ -335,9 +335,11 @@ internal open class SourceResourceIntTest( * if they test an entity which requires the current entity. */ fun createEntity(): Source { - return Source() - .assigned(DEFAULT_ASSIGNED) + val s = Source() .sourceName(DEFAULT_SOURCE_NAME) + + s.assigned = DEFAULT_ASSIGNED + return s } } } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt index dc22d57e5..2981eb2ad 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt @@ -92,7 +92,7 @@ internal open class SourceTypeResourceIntTest( // Create the SourceType val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO( - SourceDataResourceIntTest.Companion.createEntity(em) + SourceDataResourceIntTest.Companion.createEntity() ) val sourceData = sourceTypeDto.sourceData sourceData.add(sourceDataDto!!) @@ -431,7 +431,7 @@ internal open class SourceTypeResourceIntTest( open fun idempotentPutWithoutId() { val databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size val sensorsSizeBeforeUpdate = sourceDataRepository.findAll().size - sourceType.sourceData = setOf(SourceDataResourceIntTest.Companion.createEntity(em)) + sourceType.sourceData = setOf(SourceDataResourceIntTest.Companion.createEntity()) // Create the SourceType val sourceTypeDto = sourceTypeMapper.sourceTypeToSourceTypeDTO(sourceType) diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index 06c7e0d3a..e93558545 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -93,7 +93,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -105,9 +105,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val subjectList = subjectRepository.findAll() Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) val testSubject = subjectList[subjectList.size - 1] - Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK) - Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.Companion.DEFAULT_ENTERNAL_ID) - Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.Companion.DEFAULT_REMOVED) + Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) + Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.DEFAULT_ENTERNAL_ID) + Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.DEFAULT_REMOVED) org.junit.jupiter.api.Assertions.assertEquals(1, testSubject.user!!.roles!!.size) } @@ -116,7 +116,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit @Throws(Exception::class) open fun createSubjectWithExistingId() { // Create a Subject - val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeCreate = subjectRepository.findAll().size // An entity with an existing ID cannot be created, so this API call must fail @@ -138,7 +138,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit open val allSubjects: Unit get() { // Initialize the database - val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) // Get all the subjectList restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects?sort=id,desc")) @@ -153,15 +153,15 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit ) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].externalLink") - .value>(Matchers.hasItem(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK)) + .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_EXTERNAL_LINK)) ) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].externalId") - .value>(Matchers.hasItem(SubjectServiceTest.Companion.DEFAULT_ENTERNAL_ID)) + .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_ENTERNAL_ID)) ) .andExpect( MockMvcResultMatchers.jsonPath("$.[*].status") - .value>(Matchers.hasItem(SubjectServiceTest.Companion.DEFAULT_STATUS.toString())) + .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_STATUS.toString())) ) } @@ -171,7 +171,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit open val subject: Unit get() { // Initialize the database - val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) // Get the subject restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{login}", subjectDto!!.login)) @@ -180,15 +180,15 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(subjectDto.id!!.toInt())) .andExpect( MockMvcResultMatchers.jsonPath("$.externalLink") - .value(SubjectServiceTest.Companion.DEFAULT_EXTERNAL_LINK) + .value(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) ) .andExpect( MockMvcResultMatchers.jsonPath("$.externalId") - .value(SubjectServiceTest.Companion.DEFAULT_ENTERNAL_ID) + .value(SubjectServiceTest.DEFAULT_ENTERNAL_ID) ) .andExpect( MockMvcResultMatchers.jsonPath("$.status") - .value(SubjectServiceTest.Companion.DEFAULT_STATUS.toString()) + .value(SubjectServiceTest.DEFAULT_STATUS.toString()) ) } @@ -207,15 +207,15 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit @Throws(Exception::class) open fun updateSubject() { // Initialize the database - var subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + var subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Update the subject - val updatedSubject = subjectRepository.findById(subjectDto!!.id).get() + val updatedSubject = subjectRepository.findById(subjectDto!!.id!!).get() updatedSubject - .externalLink(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) - .externalId(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) - .removed(SubjectServiceTest.Companion.UPDATED_REMOVED) + .externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) + .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID) + .removed(SubjectServiceTest.UPDATED_REMOVED) subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) restSubjectMockMvc.perform( MockMvcRequestBuilders.put("/api/subjects") @@ -228,9 +228,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val subjectList = subjectRepository.findAll() Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeUpdate) val testSubject = subjectList[subjectList.size - 1] - Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) - Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) - Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.Companion.UPDATED_REMOVED) + Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.UPDATED_EXTERNAL_LINK) + Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.UPDATED_ENTERNAL_ID) + Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) } @Test @@ -238,15 +238,15 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit @Throws(Exception::class) open fun updateSubjectWithNewProject() { // Initialize the database - var subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + var subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Update the subject - val updatedSubject = subjectRepository.findById(subjectDto!!.id).get() + val updatedSubject = subjectRepository.findById(subjectDto!!.id!!).get() updatedSubject - .externalLink(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) - .externalId(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) - .removed(SubjectServiceTest.Companion.UPDATED_REMOVED) + .externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) + .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID) + .removed(SubjectServiceTest.UPDATED_REMOVED) subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) val newProject = ProjectDTO() newProject.id = 2L @@ -264,9 +264,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val subjectList = subjectRepository.findAll() Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeUpdate) val testSubject = subjectList[subjectList.size - 1] - Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.Companion.UPDATED_EXTERNAL_LINK) - Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.Companion.UPDATED_ENTERNAL_ID) - Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.Companion.UPDATED_REMOVED) + Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.UPDATED_EXTERNAL_LINK) + Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.UPDATED_ENTERNAL_ID) + Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) Assertions.assertThat(testSubject.user!!.roles!!.size).isEqualTo(2) } @@ -277,7 +277,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Create the Subject - val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() // If the entity doesn't have an ID, it will be created instead of just being updated restSubjectMockMvc.perform( @@ -297,7 +297,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit @Throws(Exception::class) open fun deleteSubject() { // Initialize the database - val subjectDto = subjectService.createSubject(SubjectServiceTest.Companion.createEntityDTO()) + val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeDelete = subjectRepository.findAll().size // Get the subject @@ -326,7 +326,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -368,7 +368,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -417,7 +417,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -449,7 +449,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit open val subjectSources: Unit get() { // Initialize the database - val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) val sourceDto = MinimalSourceDetailsDTO() .id(createdSource.id) @@ -482,7 +482,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit open val subjectSourcesWithQueryParam: Unit get() { // Initialize the database - val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) val sourceDto = MinimalSourceDetailsDTO() .id(createdSource.id) @@ -515,7 +515,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit open val inactiveSubjectSourcesWithQueryParam: Unit get() { // Initialize the database - val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) val sourceDto = MinimalSourceDetailsDTO() .id(createdSource.id) @@ -602,7 +602,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit private val source: MinimalSourceDetailsDTO get() { val sourceRegistrationDto = MinimalSourceDetailsDTO() - .sourceName(SubjectServiceTest.Companion.PRODUCER + "-" + SubjectServiceTest.Companion.MODEL) + .sourceName(SubjectServiceTest.PRODUCER + "-" + SubjectServiceTest.MODEL) .attributes(Collections.singletonMap("something", "value")) Assertions.assertThat(sourceRegistrationDto.sourceId).isNull() return sourceRegistrationDto @@ -615,7 +615,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject - val subjectDto: SubjectDTO = SubjectServiceTest.Companion.createEntityDTO() + val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( MockMvcRequestBuilders.post("/api/subjects") .contentType(TestUtil.APPLICATION_JSON_UTF8) diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt index d0bb73db5..9d0a54a50 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt @@ -100,7 +100,7 @@ internal open class UserResourceIntTest( @AfterEach fun tearDown() { if (project != null) { - projectRepository.delete(project) + projectRepository.delete(project!!) } } From dce265e61a30b8d8b5aeff5b9302e9c28ff13596 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 31 Oct 2023 10:12:58 +0100 Subject: [PATCH 101/158] properties back to java class for simplicities' sake --- .../config/ManagementPortalProperties.java | 299 ++++++++++++++++++ .../config/ManagementPortalProperties.kt | 68 ---- 2 files changed, 299 insertions(+), 68 deletions(-) create mode 100644 src/main/java/org/radarbase/management/config/ManagementPortalProperties.java delete mode 100644 src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalProperties.java b/src/main/java/org/radarbase/management/config/ManagementPortalProperties.java new file mode 100644 index 000000000..e478a0679 --- /dev/null +++ b/src/main/java/org/radarbase/management/config/ManagementPortalProperties.java @@ -0,0 +1,299 @@ +package org.radarbase.management.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.List; + +/** + * Created by nivethika on 3-10-17. + */ +@ConfigurationProperties(prefix = "managementportal", ignoreUnknownFields = false) +public class ManagementPortalProperties { + + private final Mail mail = new Mail(); + + private final Frontend frontend = new Frontend(); + + private Oauth oauth = new Oauth(); + + private final Common common = new Common(); + + private final CatalogueServer catalogueServer = new CatalogueServer(); + + private final Account account = new Account(); + + private final SiteSettings siteSettings = new SiteSettings(); + + public ManagementPortalProperties.Frontend getFrontend() { + return frontend; + } + + public ManagementPortalProperties.Mail getMail() { + return mail; + } + + public ManagementPortalProperties.Oauth getOauth() { + return oauth; + } + + public void setOauth(ManagementPortalProperties.Oauth oauth) { + this.oauth = oauth; + } + + public CatalogueServer getCatalogueServer() { + return catalogueServer; + } + + public Common getCommon() { + return common; + } + + public Account getAccount() { + return account; + } + + public SiteSettings getSiteSettings() { + return siteSettings; + } + + public static class Account { + private boolean enableExposeToken = false; + + public boolean getEnableExposeToken() { + return enableExposeToken; + } + + public void setEnableExposeToken(boolean enableExposeToken) { + this.enableExposeToken = enableExposeToken; + } + } + + public static class Common { + + private String baseUrl = ""; + + private String managementPortalBaseUrl = ""; + + private String privacyPolicyUrl = ""; + + private String adminPassword = ""; + + private Integer activationKeyTimeoutInSeconds = 24 * 60 * 60; // 1 day + + public String getBaseUrl() { + return baseUrl; + } + + public void setBaseUrl(String baseUrl) { + this.baseUrl = baseUrl; + } + + public String getPrivacyPolicyUrl() { + return privacyPolicyUrl; + } + + public void setPrivacyPolicyUrl(String privacyPolicyUrl) { + this.privacyPolicyUrl = privacyPolicyUrl; + } + + public String getAdminPassword() { + return adminPassword; + } + + public void setAdminPassword(String adminPassword) { + this.adminPassword = adminPassword; + } + + public String getManagementPortalBaseUrl() { + return managementPortalBaseUrl; + } + + public void setManagementPortalBaseUrl(String managementPortalBaseUrl) { + this.managementPortalBaseUrl = managementPortalBaseUrl; + } + + public Integer getActivationKeyTimeoutInSeconds() { + return activationKeyTimeoutInSeconds; + } + + public void setActivationKeyTimeoutInSeconds(Integer activationKeyTimeoutInSeconds) { + this.activationKeyTimeoutInSeconds = activationKeyTimeoutInSeconds; + } + } + + public static class Mail { + + private String from = ""; + + public String getFrom() { + return from; + } + + public void setFrom(String from) { + this.from = from; + } + + } + + public static class Frontend { + + private String clientId = ""; + + private String clientSecret = ""; + + private Integer accessTokenValiditySeconds = 4 * 60 * 60; + + private Integer refreshTokenValiditySeconds = 72 * 60 * 60; + + private Integer sessionTimeout = 24 * 60 * 60; // a day + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + public Integer getSessionTimeout() { + return sessionTimeout; + } + + public void setSessionTimeout(Integer sessionTimeout) { + this.sessionTimeout = sessionTimeout; + } + + public Integer getAccessTokenValiditySeconds() { + return accessTokenValiditySeconds; + } + + public void setAccessTokenValiditySeconds(Integer accessTokenValiditySeconds) { + this.accessTokenValiditySeconds = accessTokenValiditySeconds; + } + + public Integer getRefreshTokenValiditySeconds() { + return refreshTokenValiditySeconds; + } + + public void setRefreshTokenValiditySeconds(Integer refreshTokenValiditySeconds) { + this.refreshTokenValiditySeconds = refreshTokenValiditySeconds; + } + } + + public static class Oauth { + + private String clientsFile; + + private String signingKeyAlias; + + private List checkingKeyAliases; + + private String keyStorePassword; + + private String metaTokenTimeout; + + private String persistentMetaTokenTimeout; + + private Boolean enablePublicKeyVerifiers = false; + + public String getClientsFile() { + return clientsFile; + } + + public void setClientsFile(String clientsFile) { + this.clientsFile = clientsFile; + } + + public String getSigningKeyAlias() { + return signingKeyAlias; + } + + public void setSigningKeyAlias(String signingKeyAlias) { + this.signingKeyAlias = signingKeyAlias; + } + + public List getCheckingKeyAliases() { + return checkingKeyAliases; + } + + public void setCheckingKeyAliases(List checkingKeyAliases) { + this.checkingKeyAliases = checkingKeyAliases; + } + + public String getKeyStorePassword() { + return keyStorePassword; + } + + public void setKeyStorePassword(String keyStorePassword) { + this.keyStorePassword = keyStorePassword; + } + + public String getMetaTokenTimeout() { + return metaTokenTimeout; + } + + public void setMetaTokenTimeout(String metaTokenTimeout) { + this.metaTokenTimeout = metaTokenTimeout; + } + + public String getPersistentMetaTokenTimeout() { + return persistentMetaTokenTimeout; + } + + public void setPersistentMetaTokenTimeout(String persistentMetaTokenTimeout) { + this.persistentMetaTokenTimeout = persistentMetaTokenTimeout; + } + + public Boolean getEnablePublicKeyVerifiers() { + return enablePublicKeyVerifiers; + } + + public void setEnablePublicKeyVerifiers(Boolean enablePublicKeyVerifiers) { + this.enablePublicKeyVerifiers = enablePublicKeyVerifiers; + } + } + + public static class CatalogueServer { + + private boolean enableAutoImport = false; + + private String serverUrl; + + public String getServerUrl() { + return serverUrl; + } + + public void setServerUrl(String serverUrl) { + this.serverUrl = serverUrl; + } + + public boolean isEnableAutoImport() { + return enableAutoImport; + } + + public void setEnableAutoImport(boolean enableAutoImport) { + this.enableAutoImport = enableAutoImport; + } + } + + public static class SiteSettings { + + private List hiddenSubjectFields; + + public void setHiddenSubjectFields(List hiddenSubjectFields) { + this.hiddenSubjectFields = hiddenSubjectFields; + } + + public List getHiddenSubjectFields() { + return hiddenSubjectFields; + } + } +} diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt b/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt deleted file mode 100644 index c9853ddbc..000000000 --- a/src/main/java/org/radarbase/management/config/ManagementPortalProperties.kt +++ /dev/null @@ -1,68 +0,0 @@ -package org.radarbase.management.config - -import org.springframework.boot.context.properties.ConfigurationProperties - -/** - * Created by nivethika on 3-10-17. - */ -@ConfigurationProperties(prefix = "managementportal", ignoreUnknownFields = false) -class ManagementPortalProperties { - val mail = Mail() - @JvmField - val frontend = Frontend() - @JvmField - var oauth = Oauth() - @JvmField - val common = Common() - val catalogueServer = CatalogueServer() - val account = Account() - val siteSettings = SiteSettings() - - class Account { - var enableExposeToken = false - } - - class Common { - var baseUrl = "" - var managementPortalBaseUrl = "" - var privacyPolicyUrl = "" - @JvmField - var adminPassword = "" - var activationKeyTimeoutInSeconds = 24 * 60 * 60 // 1 day - } - - class Mail { - var from = "" - } - - class Frontend { - @JvmField - var clientId = "" - var clientSecret = "" - @JvmField - var accessTokenValiditySeconds = 4 * 60 * 60 - @JvmField - var refreshTokenValiditySeconds = 72 * 60 * 60 - var sessionTimeout = 24 * 60 * 60 // a day - } - - class Oauth { - @JvmField - var clientsFile: String? = null - var signingKeyAlias: String? = null - var checkingKeyAliases: List? = null - lateinit var keyStorePassword: String - var metaTokenTimeout: String? = null - var persistentMetaTokenTimeout: String? = null - var enablePublicKeyVerifiers = false - } - - class CatalogueServer { - var isEnableAutoImport = false - var serverUrl: String? = null - } - - class SiteSettings { - var hiddenSubjectFields: List = listOf() - } -} From d9b6b719d6557188eb7af793e72e789faf793c22 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 31 Oct 2023 10:13:27 +0100 Subject: [PATCH 102/158] change the renamed boolean properties back so hibernate plays nice --- .../org/radarbase/management/domain/Source.kt | 8 +------- .../radarbase/management/domain/SourceData.kt | 12 +++++------ .../radarbase/management/domain/Subject.kt | 9 ++------- .../management/repository/SourceRepository.kt | 20 +++++++++---------- .../management/service/SubjectService.kt | 4 ++-- .../management/service/dto/SourceDataDTO.kt | 8 ++++---- .../decorator/SubjectMapperDecorator.kt | 14 ++++++------- .../management/web/rest/UserResource.kt | 2 +- .../web/rest/SubjectResourceIntTest.kt | 10 +++++----- 9 files changed, 38 insertions(+), 49 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Source.kt b/src/main/java/org/radarbase/management/domain/Source.kt index 53d1287c3..c409cca9e 100644 --- a/src/main/java/org/radarbase/management/domain/Source.kt +++ b/src/main/java/org/radarbase/management/domain/Source.kt @@ -61,7 +61,7 @@ class Source : AbstractEntity, Serializable { var assigned: @NotNull Boolean? = false @Column(name = "deleted", nullable = false) - var isDeleted: @NotNull Boolean = false + var deleted: @NotNull Boolean = false @JvmField @ManyToOne(fetch = FetchType.EAGER) @@ -124,12 +124,6 @@ class Source : AbstractEntity, Serializable { ) } } - - fun deleted(deleted: Boolean): Source { - isDeleted = deleted - return this - } - fun sourceType(sourceType: SourceType?): Source { this.sourceType = sourceType return this diff --git a/src/main/java/org/radarbase/management/domain/SourceData.kt b/src/main/java/org/radarbase/management/domain/SourceData.kt index 28a8805b3..ce73c1df6 100644 --- a/src/main/java/org/radarbase/management/domain/SourceData.kt +++ b/src/main/java/org/radarbase/management/domain/SourceData.kt @@ -86,7 +86,7 @@ class SourceData : AbstractEntity(), Serializable { var provider: String? = null @Column(name = "enabled") - var isEnabled = true + var enabled = true @JvmField @ManyToOne(fetch = FetchType.LAZY) @@ -137,14 +137,14 @@ class SourceData : AbstractEntity(), Serializable { return this } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val sourceData = o as SourceData + val sourceData = other as SourceData return if (sourceData.id == null || id == null) { false } else id == sourceData.id @@ -162,7 +162,7 @@ class SourceData : AbstractEntity(), Serializable { + ", dataClass='" + dataClass + '\'' + ", keySchema='" + keySchema + '\'' + ", valueSchema='" + valueSchema + '\'' + ", topic='" + topic + '\'' + ", provider='" - + provider + '\'' + ", enabled=" + isEnabled + '}') + + provider + '\'' + ", enabled=" + enabled + '}') } companion object { diff --git a/src/main/java/org/radarbase/management/domain/Subject.kt b/src/main/java/org/radarbase/management/domain/Subject.kt index e5e1217e7..4fecfdce7 100644 --- a/src/main/java/org/radarbase/management/domain/Subject.kt +++ b/src/main/java/org/radarbase/management/domain/Subject.kt @@ -64,7 +64,7 @@ class Subject( var externalId: String? = null @Column(name = "removed", nullable = false) - var isRemoved: @NotNull Boolean? = false + var removed: @NotNull Boolean = false @JvmField @OneToOne @@ -124,11 +124,6 @@ class Subject( return this } - fun removed(removed: Boolean?): Subject { - isRemoved = removed - return this - } - fun user(usr: User?): Subject { user = usr return this @@ -189,7 +184,7 @@ class Subject( + "id=" + id + ", externalLink='" + externalLink + '\'' + ", externalId='" + externalId + '\'' - + ", removed=" + isRemoved + + ", removed=" + removed + ", user=" + user + ", sources=" + sources + ", attributes=" + attributes diff --git a/src/main/java/org/radarbase/management/repository/SourceRepository.kt b/src/main/java/org/radarbase/management/repository/SourceRepository.kt index 094d95d46..4b5946480 100644 --- a/src/main/java/org/radarbase/management/repository/SourceRepository.kt +++ b/src/main/java/org/radarbase/management/repository/SourceRepository.kt @@ -17,26 +17,26 @@ import java.util.* interface SourceRepository : JpaRepository, RevisionRepository { @Query( value = "select source from Source source " - + "WHERE source.isDeleted = false", countQuery = "select count(source) from Source source " - + "WHERE source.isDeleted = false" + + "WHERE source.deleted = false", countQuery = "select count(source) from Source source " + + "WHERE source.deleted = false" ) override fun findAll(pageable: Pageable): Page @Query( value = "select source from Source source " - + "WHERE source.isDeleted = false " + + "WHERE source.deleted = false " + "AND source.project.id = :projectId", countQuery = "select count(source) from Source source " - + "WHERE source.isDeleted = false " + + "WHERE source.deleted = false " + "AND source.project.id = :projectId" ) fun findAllSourcesByProjectId(pageable: Pageable, @Param("projectId") projectId: Long): Page @Query( value = "select source from Source source " - + "WHERE source.isDeleted = false " + + "WHERE source.deleted = false " + "AND source.project.id = :projectId " + "AND source.assigned = :assigned", countQuery = "select count(source) from Source source " - + "WHERE source.isDeleted = false " + + "WHERE source.deleted = false " + "AND source.project.id = :projectId " + "AND source.assigned = :assigned" ) @@ -47,18 +47,18 @@ interface SourceRepository : JpaRepository, RevisionRepository source.assigned = false source.subject = null - source.isDeleted = true + source.deleted = true sourceRepository.save(source) }) subject.sources.clear() diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt index 187af33bd..0bf175343 100644 --- a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt @@ -34,14 +34,14 @@ class SourceDataDTO : Serializable { @JsonInclude(JsonInclude.Include.NON_NULL) var sourceType: MinimalSourceTypeDTO? = null - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val sourceDataDto = o as SourceDataDTO + val sourceDataDto = other as SourceDataDTO return if (sourceDataDto.id == null || id == null) { false } else id == sourceDataDto.id diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt index 19ece43e4..94face2c9 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt @@ -108,11 +108,11 @@ abstract class SubjectMapperDecorator( } private fun getSubjectStatus(subject: Subject): SubjectStatus { - if (!subject.user!!.activated && !subject.isRemoved!!) { + if (!subject.user!!.activated && !subject.removed!!) { return SubjectStatus.DEACTIVATED - } else if (subject.user!!.activated && !subject.isRemoved!!) { + } else if (subject.user!!.activated && !subject.removed!!) { return SubjectStatus.ACTIVATED - } else if (!subject.user!!.activated && subject.isRemoved!!) { + } else if (!subject.user!!.activated && subject.removed!!) { return SubjectStatus.DISCONTINUED } return SubjectStatus.INVALID @@ -122,22 +122,22 @@ abstract class SubjectMapperDecorator( when (subjectDto!!.status) { SubjectStatus.DEACTIVATED -> { subject!!.user!!.activated = false - subject.isRemoved = false + subject.removed = false } SubjectStatus.ACTIVATED -> { subject!!.user!!.activated = true - subject.isRemoved = false + subject.removed = false } SubjectStatus.DISCONTINUED -> { subject!!.user!!.activated = false - subject.isRemoved = true + subject.removed = true } SubjectStatus.INVALID -> { subject!!.user!!.activated = true - subject.isRemoved = true + subject.removed = true } else -> {} diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.kt b/src/main/java/org/radarbase/management/web/rest/UserResource.kt index 0c49f4aa1..39fdbcc49 100644 --- a/src/main/java/org/radarbase/management/web/rest/UserResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/UserResource.kt @@ -158,7 +158,7 @@ class UserResource( throw BadRequestException("Login already in use", EntityName.USER, "emailexists") } val subject = subjectRepository.findOneWithEagerBySubjectLogin(managedUserVm.login) - if (subject != null && managedUserVm.isActivated && subject.isRemoved!!) { + if (subject != null && managedUserVm.isActivated && subject.removed!!) { // if the subject is also a user, check if the removed/activated states are valid throw InvalidRequestException( "Subject cannot be the user to request " + "this changes", EntityName.USER, "error.invalidsubjectstate" diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index e93558545..c024bcd1a 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -107,7 +107,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val testSubject = subjectList[subjectList.size - 1] Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.DEFAULT_ENTERNAL_ID) - Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.DEFAULT_REMOVED) + Assertions.assertThat(testSubject.removed).isEqualTo(SubjectServiceTest.DEFAULT_REMOVED) org.junit.jupiter.api.Assertions.assertEquals(1, testSubject.user!!.roles!!.size) } @@ -215,7 +215,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit updatedSubject .externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID) - .removed(SubjectServiceTest.UPDATED_REMOVED) + .removed = SubjectServiceTest.UPDATED_REMOVED subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) restSubjectMockMvc.perform( MockMvcRequestBuilders.put("/api/subjects") @@ -230,7 +230,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val testSubject = subjectList[subjectList.size - 1] Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.UPDATED_EXTERNAL_LINK) Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.UPDATED_ENTERNAL_ID) - Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) + Assertions.assertThat(testSubject.removed).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) } @Test @@ -246,7 +246,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit updatedSubject .externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID) - .removed(SubjectServiceTest.UPDATED_REMOVED) + .removed = SubjectServiceTest.UPDATED_REMOVED subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) val newProject = ProjectDTO() newProject.id = 2L @@ -266,7 +266,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val testSubject = subjectList[subjectList.size - 1] Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.UPDATED_EXTERNAL_LINK) Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.UPDATED_ENTERNAL_ID) - Assertions.assertThat(testSubject.isRemoved).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) + Assertions.assertThat(testSubject.removed).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) Assertions.assertThat(testSubject.user!!.roles!!.size).isEqualTo(2) } From d655726d4f99dd1fe115c3aa1fcab9c0ff8a7cce Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 31 Oct 2023 14:59:22 +0100 Subject: [PATCH 103/158] structmap issues solved by reverting back to some java classes and using kapt --- build.gradle | 1 + gradle/mapstruct.gradle | 2 +- .../management/service/OAuthClientService.kt | 31 ++++--- .../service/mapper/ClientDetailsMapper.java | 80 +++++++++++++++++++ .../service/mapper/ClientDetailsMapper.kt | 72 ----------------- .../management/service/mapper/UserMapper.kt | 10 ++- .../ClientDetailsMapperDecorator.java | 44 ++++++++++ .../decorator/ClientDetailsMapperDecorator.kt | 36 --------- .../decorator/ProjectMapperDecorator.kt | 24 +++--- .../mapper/decorator/RoleMapperDecorator.kt | 12 +-- .../mapper/decorator/SourceMapperDecorator.kt | 26 +++--- .../decorator/SubjectMapperDecorator.kt | 47 +++++------ .../web/rest/vm/GroupPatchOperation.java | 53 ------------ .../web/rest/vm/KeyAndPasswordVM.java | 27 ------- .../management/web/rest/vm/LoggerVM.java | 48 ----------- .../management/web/rest/vm/ManagedUserVM.java | 31 ------- 16 files changed, 201 insertions(+), 343 deletions(-) create mode 100644 src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java delete mode 100644 src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt create mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java delete mode 100644 src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt delete mode 100644 src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.java delete mode 100644 src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.java delete mode 100644 src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.java delete mode 100644 src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.java diff --git a/build.gradle b/build.gradle index 24c364e83..2b480b1a6 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,7 @@ plugins { id "io.github.gradle-nexus.publish-plugin" version "1.3.0" id("com.github.ben-manes.versions") version "0.47.0" id 'org.jetbrains.kotlin.jvm' version "1.9.10" + id "org.jetbrains.kotlin.kapt" version "1.9.10" id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.10' apply false id 'org.jetbrains.dokka' version "1.8.20" } diff --git a/gradle/mapstruct.gradle b/gradle/mapstruct.gradle index b267a55f5..10a398198 100644 --- a/gradle/mapstruct.gradle +++ b/gradle/mapstruct.gradle @@ -1,5 +1,5 @@ dependencies { implementation group: 'org.mapstruct', name: 'mapstruct', version: mapstruct_version - annotationProcessor group: 'org.mapstruct', name: 'mapstruct-processor', version: mapstruct_version + kapt group: 'org.mapstruct', name: 'mapstruct-processor', version: mapstruct_version } diff --git a/src/main/java/org/radarbase/management/service/OAuthClientService.kt b/src/main/java/org/radarbase/management/service/OAuthClientService.kt index a0d6fd53f..9268d5d5e 100644 --- a/src/main/java/org/radarbase/management/service/OAuthClientService.kt +++ b/src/main/java/org/radarbase/management/service/OAuthClientService.kt @@ -30,17 +30,14 @@ import java.util.* * Created by nivethika on 03/08/2018. */ @Service -class OAuthClientService { - @Autowired - private val clientDetailsService: JdbcClientDetailsService? = null +class OAuthClientService( + @Autowired private val clientDetailsService: JdbcClientDetailsService, + @Autowired private val clientDetailsMapper: ClientDetailsMapper, + @Autowired private val authorizationServerEndpointsConfiguration: AuthorizationServerEndpointsConfiguration +) { - @Autowired - private val clientDetailsMapper: ClientDetailsMapper? = null - - @Autowired - private val authorizationServerEndpointsConfiguration: AuthorizationServerEndpointsConfiguration? = null fun findAllOAuthClients(): List { - return clientDetailsService!!.listClientDetails() + return clientDetailsService.listClientDetails() } /** @@ -52,7 +49,7 @@ class OAuthClientService { */ fun findOneByClientId(clientId: String?): ClientDetails { return try { - clientDetailsService!!.loadClientByClientId(clientId) + clientDetailsService.loadClientByClientId(clientId) } catch (e: NoSuchClientException) { log.error("Pair client request for unknown client id: {}", clientId) val errorParams: MutableMap = HashMap() @@ -71,9 +68,9 @@ class OAuthClientService { * @return Updated [ClientDetails] instance. */ fun updateOauthClient(clientDetailsDto: ClientDetailsDTO): ClientDetails { - val details: ClientDetails? = clientDetailsMapper!!.clientDetailsDTOToClientDetails(clientDetailsDto) + val details: ClientDetails? = clientDetailsMapper.clientDetailsDTOToClientDetails(clientDetailsDto) // update client. - clientDetailsService!!.updateClientDetails(details) + clientDetailsService.updateClientDetails(details) val updated = findOneByClientId(clientDetailsDto.clientId) // updateClientDetails does not update secret, so check for it separately if (clientDetailsDto.clientSecret != null && clientDetailsDto.clientSecret != updated.clientSecret) { @@ -90,7 +87,7 @@ class OAuthClientService { * @param clientId of the auth-client to delete. */ fun deleteClientDetails(clientId: String?) { - clientDetailsService!!.removeClientDetails(clientId) + clientDetailsService.removeClientDetails(clientId) } /** @@ -102,7 +99,7 @@ class OAuthClientService { fun createClientDetail(clientDetailsDto: ClientDetailsDTO): ClientDetails { // check if the client id exists try { - val existingClient = clientDetailsService!!.loadClientByClientId(clientDetailsDto.clientId) + val existingClient = clientDetailsService.loadClientByClientId(clientDetailsDto.clientId) if (existingClient != null) { throw ConflictException( "OAuth client already exists with this id", @@ -117,9 +114,9 @@ class OAuthClientService { clientDetailsDto.clientId ) } - val details: ClientDetails? = clientDetailsMapper!!.clientDetailsDTOToClientDetails(clientDetailsDto) + val details: ClientDetails? = clientDetailsMapper.clientDetailsDTOToClientDetails(clientDetailsDto) // create oauth client. - clientDetailsService!!.addClientDetails(details) + clientDetailsService.addClientDetails(details) return findOneByClientId(clientDetailsDto.clientId) } @@ -149,7 +146,7 @@ class OAuthClientService { val authenticationToken: Authentication = UsernamePasswordAuthenticationToken( user.login, null, authorities ) - return authorizationServerEndpointsConfiguration!!.getEndpointsConfigurer() + return authorizationServerEndpointsConfiguration.getEndpointsConfigurer() .tokenServices .createAccessToken(OAuth2Authentication(oAuth2Request, authenticationToken)) } diff --git a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java new file mode 100644 index 000000000..10c1b1ad8 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java @@ -0,0 +1,80 @@ +package org.radarbase.management.service.mapper; + +import org.mapstruct.DecoratedWith; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.radarbase.management.service.dto.ClientDetailsDTO; +import org.radarbase.management.service.mapper.decorator.ClientDetailsMapperDecorator; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.provider.ClientDetails; +import org.springframework.security.oauth2.provider.client.BaseClientDetails; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * Created by dverbeec on 7/09/2017. + */ +@Mapper(componentModel = "spring", uses = {BaseClientDetails.class}) +@DecoratedWith(ClientDetailsMapperDecorator.class) + public interface ClientDetailsMapper { + + @Mapping(target = "clientSecret", ignore = true) + @Mapping(target = "autoApproveScopes", ignore = true) + ClientDetailsDTO clientDetailsToClientDetailsDTO(ClientDetails details); + + List clientDetailsToClientDetailsDTO(List detailsList); + + BaseClientDetails clientDetailsDTOToClientDetails(ClientDetailsDTO detailsDto); + + List clientDetailsDTOToClientDetails(List detailsDtoList); + + /** + * Map a set of authorities represented as strings to a collection of {@link GrantedAuthority}s. + * @param authorities the set of authorities to be mapped + * @return a collection of {@link GrantedAuthority}s + */ + default Collection map(Set authorities) { + if (Objects.isNull(authorities)) { + return Collections.emptySet(); + } + return authorities.stream() + .map(SimpleGrantedAuthority::new) + .collect(Collectors.toList()); + } + + /** + * Map a collection of authorities represented as {@link GrantedAuthority}s to a set of strings. + * @param authorities the collection of {@link GrantedAuthority}s to be mapped + * @return the set of strings + */ + default Set map(Collection authorities) { + if (Objects.isNull(authorities)) { + return Collections.emptySet(); + } + return authorities.stream() + .map(GrantedAuthority::getAuthority) + .collect(Collectors.toSet()); + } + + /** + * Transforms the values in the input map to strings so the result is a + * {@link Map}. + * @param additionalInformation a {@link Map} to be transformed + * @return a new map with the same keys as the input map, but the values are transformed to + * strings using their {@link Object#toString()} method + */ + default Map map(Map additionalInformation) { + if (Objects.isNull(additionalInformation)) { + return Collections.emptyMap(); + } + return additionalInformation.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString())); + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt deleted file mode 100644 index 7d4258077..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.kt +++ /dev/null @@ -1,72 +0,0 @@ -package org.radarbase.management.service.mapper - -import org.mapstruct.DecoratedWith -import org.mapstruct.Mapper -import org.mapstruct.Mapping -import org.radarbase.management.service.dto.ClientDetailsDTO -import org.radarbase.management.service.mapper.decorator.ClientDetailsMapperDecorator -import org.springframework.security.core.GrantedAuthority -import org.springframework.security.core.authority.SimpleGrantedAuthority -import org.springframework.security.oauth2.provider.ClientDetails -import org.springframework.security.oauth2.provider.client.BaseClientDetails -import java.util.* -import java.util.stream.Collectors - -/** - * Created by dverbeec on 7/09/2017. - */ -@Mapper(componentModel = "spring", uses = [BaseClientDetails::class]) -@DecoratedWith( - ClientDetailsMapperDecorator::class -) -interface ClientDetailsMapper { - @Mapping(target = "clientSecret", ignore = true) - @Mapping(target = "autoApproveScopes", ignore = true) - fun clientDetailsToClientDetailsDTO(details: ClientDetails): ClientDetailsDTO - fun clientDetailsToClientDetailsDTO(detailsList: List): List? - fun clientDetailsDTOToClientDetails(detailsDto: ClientDetailsDTO?): BaseClientDetails - fun clientDetailsDTOToClientDetails(detailsDtoList: List): List - - /** - * Map a set of authorities represented as strings to a collection of [GrantedAuthority]s. - * @param authorities the set of authorities to be mapped - * @return a collection of [GrantedAuthority]s - */ - fun map(authorities: Set): Collection? { - return if (Objects.isNull(authorities)) { - emptySet() - } else authorities.stream() - .map { role: String? -> SimpleGrantedAuthority(role) } - .collect(Collectors.toList()) - } - - /** - * Map a collection of authorities represented as [GrantedAuthority]s to a set of strings. - * @param authorities the collection of [GrantedAuthority]s to be mapped - * @return the set of strings - */ - fun map(authorities: Collection): Set? { - return if (Objects.isNull(authorities)) { - emptySet() - } else authorities.stream() - .map { obj: GrantedAuthority -> obj.authority } - .collect(Collectors.toSet()) - } - - /** - * Transforms the values in the input map to strings so the result is a - * [Map]. - * @param additionalInformation a [Map] to be transformed - * @return a new map with the same keys as the input map, but the values are transformed to - * strings using their [Object.toString] method - */ - fun map(additionalInformation: Map): Map? { - return if (Objects.isNull(additionalInformation)) { - emptyMap() - } else additionalInformation.entries - .associateBy( - { it.key }, - { e -> e.value.toString() } - ) - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt index affe9f120..d5e652f2d 100644 --- a/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt +++ b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt @@ -46,10 +46,14 @@ interface UserMapper { * @param authorities the authorities to map * @return the set of strings if authorities is not null, null otherwise */ - fun stringsFromAuthorities(authorities: Set?): Set<@NotNull @Size( + fun map(authorities: Set): Set<@NotNull @Size( max = 50, min = 0 - ) @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") String?>? { - return authorities?.map{ it?.name }?.toSet() + ) @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") String> { + return authorities.mapNotNull { it.name }.toSet() + } + + fun map(authority: Authority): String { + return authority.name!! } } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java new file mode 100644 index 000000000..119bdea64 --- /dev/null +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java @@ -0,0 +1,44 @@ +package org.radarbase.management.service.mapper.decorator; + + +import org.radarbase.management.service.dto.ClientDetailsDTO; +import org.radarbase.management.service.mapper.ClientDetailsMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.security.oauth2.provider.ClientDetails; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Decorator for ClientDetailsMapper. The ClientDetails interface does not expose a method to get + * all auto-approve scopes, instead it only has a method to check if a given scope is auto-approve. + * This decorator adds the subset of scopes for which isAutoApprove returns true to the DTO. + */ +public abstract class ClientDetailsMapperDecorator implements ClientDetailsMapper { + + @Autowired + @Qualifier("delegate") + private ClientDetailsMapper delegate; + + @Override + public ClientDetailsDTO clientDetailsToClientDetailsDTO(ClientDetails details) { + ClientDetailsDTO clientDetailsDto = delegate.clientDetailsToClientDetailsDTO(details); + // collect the scopes that are auto-approve and set them in our DTO + clientDetailsDto.setAutoApproveScopes(details.getScope().stream() + .filter(details::isAutoApprove) + .collect(Collectors.toSet())); + return clientDetailsDto; + } + + @Override + public List clientDetailsToClientDetailsDTO(List details) { + if (Objects.isNull(details)) { + return null; + } + return details.stream() + .map(this::clientDetailsToClientDetailsDTO) + .toList(); + } +} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt deleted file mode 100644 index e0e6217cf..000000000 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.radarbase.management.service.mapper.decorator - -import org.radarbase.management.service.dto.ClientDetailsDTO -import org.radarbase.management.service.mapper.ClientDetailsMapper -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Qualifier -import org.springframework.security.oauth2.provider.ClientDetails -import java.util.* -import java.util.stream.Collectors - -/** - * Decorator for ClientDetailsMapper. The ClientDetails interface does not expose a method to get - * all auto-approve scopes, instead it only has a method to check if a given scope is auto-approve. - * This decorator adds the subset of scopes for which isAutoApprove returns true to the DTO. - */ -abstract class ClientDetailsMapperDecorator : ClientDetailsMapper { - @Autowired - @Qualifier("delegate") - private val delegate: ClientDetailsMapper? = null - override fun clientDetailsToClientDetailsDTO(details: ClientDetails): ClientDetailsDTO { - val clientDetailsDto = delegate!!.clientDetailsToClientDetailsDTO(details) - // collect the scopes that are auto-approve and set them in our DTO - clientDetailsDto.autoApproveScopes = details.scope.stream() - .filter { scope: String? -> details.isAutoApprove(scope) } - .collect(Collectors.toSet()) - return clientDetailsDto - } - - override fun clientDetailsToClientDetailsDTO(detailsList: List): List? { - return if (Objects.isNull(detailsList)) { - null - } else detailsList.stream() - .map { details: ClientDetails -> this.clientDetailsToClientDetailsDTO(details) } - .toList() - } -} diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt index 48d862398..a023f87d1 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt @@ -18,18 +18,18 @@ import java.util.* /** * Created by nivethika on 30-8-17. */ -abstract class ProjectMapperDecorator( - @Autowired @Qualifier("delegate") private val delegate: ProjectMapper, - @Autowired private val organizationRepository: OrganizationRepository, - @Autowired private val projectRepository: ProjectRepository, - @Autowired private val metaTokenService: MetaTokenService -) : ProjectMapper { +abstract class ProjectMapperDecorator() : ProjectMapper { + + @Autowired @Qualifier("delegate") private val delegate: ProjectMapper? = null + private val organizationRepository: OrganizationRepository? = null + private val projectRepository: ProjectRepository? = null + private val metaTokenService: MetaTokenService? = null override fun projectToProjectDTO(project: Project?): ProjectDTO? { - val dto = delegate.projectToProjectDTO(project) + val dto = delegate?.projectToProjectDTO(project) dto?.humanReadableProjectName = project?.attributes?.get(ProjectDTO.HUMAN_READABLE_PROJECT_NAME) try { - dto?.persistentTokenTimeout = metaTokenService.getMetaTokenTimeout(true, project).toMillis() + dto?.persistentTokenTimeout = metaTokenService?.getMetaTokenTimeout(true, project)?.toMillis() } catch (ex: BadRequestException) { dto?.persistentTokenTimeout = null } @@ -40,7 +40,7 @@ abstract class ProjectMapperDecorator( if (project == null) { return null } - val dto = delegate.projectToProjectDTOReduced(project) + val dto = delegate?.projectToProjectDTOReduced(project) dto?.humanReadableProjectName = project.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] dto?.sourceTypes = null return dto @@ -50,14 +50,14 @@ abstract class ProjectMapperDecorator( if (projectDto == null) { return null } - val project = delegate.projectDTOToProject(projectDto) + val project = delegate?.projectDTOToProject(projectDto) val projectName = projectDto.humanReadableProjectName if (!projectName.isNullOrEmpty()) { project!!.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] = projectName } val orgDto = projectDto.organization if (orgDto?.name != null) { - val org = organizationRepository.findOneByName(orgDto.name) + val org = organizationRepository?.findOneByName(orgDto.name) ?: throw NotFoundException( "Organization not found with name", EntityName.Companion.ORGANIZATION, @@ -72,6 +72,6 @@ abstract class ProjectMapperDecorator( override fun descriptiveDTOToProject(minimalProjectDetailsDto: MinimalProjectDetailsDTO?): Project? { return if (minimalProjectDetailsDto == null) { null - } else minimalProjectDetailsDto.id?.let { projectRepository.getById(it) } + } else minimalProjectDetailsDto.id?.let { projectRepository?.getById(it) } } } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt index 244965c2d..6ea4a059c 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt @@ -10,9 +10,11 @@ import org.springframework.beans.factory.annotation.Qualifier /** * Created by nivethika on 03-8-18. */ -abstract class RoleMapperDecorator(@Autowired @Qualifier("delegate") private val delegate: RoleMapper, - @Autowired private val authorityRepository: AuthorityRepository -) : RoleMapper { +abstract class RoleMapperDecorator() : RoleMapper { + +// constructor(roleMapper: RoleMapper, authorityRepository: AuthorityRepository?) : this(roleMapper) + @Autowired @Qualifier("delegate") private val delegate: RoleMapper? = null + private var authorityRepository: AuthorityRepository? = null; /** * Overrides standard RoleMapperImpl and loads authority from repository if not specified. @@ -23,9 +25,9 @@ abstract class RoleMapperDecorator(@Autowired @Qualifier("delegate") private val if (roleDto == null) { return null } - val role = delegate.roleDTOToRole(roleDto) + val role = delegate?.roleDTOToRole(roleDto) if (role!!.authority == null) { - role.authority = roleDto.authorityName?.let { authorityRepository.getById(it) } + role.authority = roleDto.authorityName?.let { authorityRepository?.getById(it) } } return role } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt index 518f91360..6a1136560 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt @@ -16,15 +16,15 @@ import java.util.Map /** * Created by nivethika on 13-6-17. */ -abstract class SourceMapperDecorator( - @Autowired @Qualifier("delegate") private val delegate: SourceMapper, - @Autowired private val sourceRepository: SourceRepository, - @Autowired private val subjectRepository: SubjectRepository -) : SourceMapper { +abstract class SourceMapperDecorator() : SourceMapper { + + @Autowired @Qualifier("delegate") private val delegate: SourceMapper? = null + private val sourceRepository: SourceRepository? = null + private val subjectRepository: SubjectRepository? = null override fun minimalSourceDTOToSource(minimalSourceDetailsDto: MinimalSourceDetailsDTO): Source? { val source = sourceRepository - .findOneBySourceId(minimalSourceDetailsDto.sourceId) + ?.findOneBySourceId(minimalSourceDetailsDto.sourceId) ?: throw NotFoundException( "Source ID " + minimalSourceDetailsDto.sourceId + " not found", @@ -36,11 +36,11 @@ abstract class SourceMapperDecorator( } override fun sourceDTOToSource(sourceDto: SourceDTO): Source { - val source = delegate.sourceDTOToSource(sourceDto) + val source = delegate?.sourceDTOToSource(sourceDto) if (sourceDto.id != null) { val existingSource = sourceDto.id?.let { - sourceRepository.findById(it) - .orElseThrow { + sourceRepository?.findById(it) + ?.orElseThrow { NotFoundException( "Source ID " + sourceDto.id + " not found", EntityName.Companion.SOURCE, ErrorConstants.ERR_SOURCE_NOT_FOUND, @@ -49,13 +49,13 @@ abstract class SourceMapperDecorator( } }!! if (sourceDto.subjectLogin == null) { - source.subject = existingSource.subject + source?.subject = existingSource.subject } else { - source.subject = subjectRepository - .findOneWithEagerBySubjectLogin(sourceDto.subjectLogin) + source?.subject = subjectRepository + ?.findOneWithEagerBySubjectLogin(sourceDto.subjectLogin) ?: throw NoSuchElementException() } } - return source + return source!! } } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt index 94face2c9..6396b670a 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt @@ -19,22 +19,21 @@ import org.springframework.beans.factory.annotation.Qualifier /** * Created by nivethika on 30-8-17. */ -abstract class SubjectMapperDecorator( - @Autowired @Qualifier("delegate") private val delegate: SubjectMapper, - @Autowired private val projectMapper: ProjectMapper, - @Autowired private val revisionService: RevisionService, - @Autowired private val projectRepository: ProjectRepository, - @Autowired private val groupRepository: GroupRepository -) : SubjectMapper { +abstract class SubjectMapperDecorator() : SubjectMapper { + @Autowired @Qualifier("delegate") private val delegate: SubjectMapper? = null + private var groupRepository: GroupRepository? = null + private var projectRepository: ProjectRepository? = null + private var revisionService: RevisionService? = null + private var projectMapper: ProjectMapper? = null override fun subjectToSubjectDTO(subject: Subject?): SubjectDTO? { if (subject == null) { return null } val dto = subjectToSubjectWithoutProjectDTO(subject) val project = subject.activeProject - .let { p -> projectRepository.findOneWithEagerRelationships(p?.id!!) } - dto?.project = projectMapper.projectToProjectDTO(project) + .let { p -> projectRepository?.findOneWithEagerRelationships(p?.id!!) } + dto?.project = projectMapper?.projectToProjectDTO(project) addAuditInfo(subject, dto) return dto } @@ -44,24 +43,24 @@ abstract class SubjectMapperDecorator( return null } val dto = subjectToSubjectWithoutProjectDTO(subject) - subject.activeProject?.let { project -> dto?.project = projectMapper.projectToProjectDTOReduced(project) } + subject.activeProject?.let { project -> dto?.project = projectMapper?.projectToProjectDTOReduced(project) } addAuditInfo(subject, dto) return dto } private fun addAuditInfo(subject: Subject, dto: SubjectDTO?) { - val auditInfo = revisionService.getAuditInfo(subject) - dto!!.createdDate = auditInfo.createdAt - dto.createdBy = auditInfo.createdBy - dto.lastModifiedDate = auditInfo.lastModifiedAt - dto.lastModifiedBy = auditInfo.lastModifiedBy + val auditInfo = revisionService?.getAuditInfo(subject) + dto!!.createdDate = auditInfo?.createdAt + dto.createdBy = auditInfo?.createdBy + dto.lastModifiedDate = auditInfo?.lastModifiedAt + dto.lastModifiedBy = auditInfo?.lastModifiedBy } override fun subjectToSubjectWithoutProjectDTO(subject: Subject?): SubjectDTO? { if (subject == null) { return null } - val dto = delegate.subjectToSubjectWithoutProjectDTO(subject) + val dto = delegate?.subjectToSubjectWithoutProjectDTO(subject) dto?.status = getSubjectStatus(subject) return dto } @@ -70,7 +69,7 @@ abstract class SubjectMapperDecorator( if (subjectDto == null) { return null } - val subject = delegate.subjectDTOToSubject(subjectDto) + val subject = delegate?.subjectDTOToSubject(subjectDto) setSubjectStatus(subjectDto, subject) subject?.group = getGroup(subjectDto) return subject @@ -80,13 +79,13 @@ abstract class SubjectMapperDecorator( return if (subjectDto!!.group == null) { null } else if (subjectDto.project?.id != null) { - groupRepository.findByProjectIdAndName(subjectDto.project?.id, subjectDto.group) + groupRepository?.findByProjectIdAndName(subjectDto.project?.id, subjectDto.group) ?: throw BadRequestException( "Group " + subjectDto.group + " not found in project " + subjectDto.project?.id, EntityName.SUBJECT, ErrorConstants.ERR_GROUP_NOT_FOUND) } else if (subjectDto.project?.projectName != null) { - groupRepository.findByProjectNameAndName(subjectDto.project?.projectName, subjectDto.group) + groupRepository?.findByProjectNameAndName(subjectDto.project?.projectName, subjectDto.group) ?: throw BadRequestException( "Group " + subjectDto.group + " not found in project " + subjectDto.project?.projectName, @@ -101,18 +100,18 @@ abstract class SubjectMapperDecorator( } override fun safeUpdateSubjectFromDTO(subjectDto: SubjectDTO?, @MappingTarget subject: Subject?): Subject? { - val subjectRetrieved = delegate.safeUpdateSubjectFromDTO(subjectDto, subject) + val subjectRetrieved = delegate?.safeUpdateSubjectFromDTO(subjectDto, subject) setSubjectStatus(subjectDto, subjectRetrieved) subject!!.group = getGroup(subjectDto) return subjectRetrieved } private fun getSubjectStatus(subject: Subject): SubjectStatus { - if (!subject.user!!.activated && !subject.removed!!) { + if (!subject.user!!.activated && !subject.removed) { return SubjectStatus.DEACTIVATED - } else if (subject.user!!.activated && !subject.removed!!) { + } else if (subject.user!!.activated && !subject.removed) { return SubjectStatus.ACTIVATED - } else if (!subject.user!!.activated && subject.removed!!) { + } else if (!subject.user!!.activated && subject.removed) { return SubjectStatus.DISCONTINUED } return SubjectStatus.INVALID @@ -139,8 +138,6 @@ abstract class SubjectMapperDecorator( subject!!.user!!.activated = true subject.removed = true } - - else -> {} } } } diff --git a/src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.java b/src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.java deleted file mode 100644 index 9e8614504..000000000 --- a/src/main/java/org/radarbase/management/web/rest/vm/GroupPatchOperation.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.radarbase.management.web.rest.vm; - -import java.util.List; - -/** - * A POJO for PATCH .../groups/{groupName}/subjects - * [ - * {"op": "add", "value": [{"login": "sub1"}, {"id": 2}]}, - * {"op": "remove", "value": [{"login": "sub3"}]} - * ] - * request. - */ -public class GroupPatchOperation { - private String op; - private List value; - - public String getOp() { - return op; - } - - public void setOp(String op) { - this.op = op; - } - - public List getValue() { - return value; - } - - public void setValue(List value) { - this.value = value; - } - - public static class SubjectPatchValue { - private Long id; - private String login; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getLogin() { - return login; - } - - public void setLogin(String login) { - this.login = login; - } - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.java b/src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.java deleted file mode 100644 index 5625aea90..000000000 --- a/src/main/java/org/radarbase/management/web/rest/vm/KeyAndPasswordVM.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.radarbase.management.web.rest.vm; - -/** - * View Model object for storing the user's key and password. - */ -public class KeyAndPasswordVM { - - private String key; - - private String newPassword; - - public String getKey() { - return key; - } - - public void setKey(String key) { - this.key = key; - } - - public String getNewPassword() { - return newPassword; - } - - public void setNewPassword(String newPassword) { - this.newPassword = newPassword; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.java b/src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.java deleted file mode 100644 index 11e736fe7..000000000 --- a/src/main/java/org/radarbase/management/web/rest/vm/LoggerVM.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.radarbase.management.web.rest.vm; - -import ch.qos.logback.classic.Logger; -import com.fasterxml.jackson.annotation.JsonCreator; - -/** - * View Model object for storing a Logback logger. - */ -public class LoggerVM { - - private String name; - - private String level; - - public LoggerVM(Logger logger) { - this.name = logger.getName(); - this.level = logger.getEffectiveLevel().toString(); - } - - @JsonCreator - public LoggerVM() { - // Empty public constructor used by Jackson. - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getLevel() { - return level; - } - - public void setLevel(String level) { - this.level = level; - } - - @Override - public String toString() { - return "LoggerVM{" - + "name='" + name + '\'' - + ", level='" + level + '\'' - + '}'; - } -} diff --git a/src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.java b/src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.java deleted file mode 100644 index 21a4f299a..000000000 --- a/src/main/java/org/radarbase/management/web/rest/vm/ManagedUserVM.java +++ /dev/null @@ -1,31 +0,0 @@ -package org.radarbase.management.web.rest.vm; - -import org.radarbase.management.service.dto.UserDTO; - -import javax.validation.constraints.Size; - -/** - * View Model extending the UserDTO, which is meant to be used in the user management UI. - */ -public class ManagedUserVM extends UserDTO { - - public static final int PASSWORD_MIN_LENGTH = 4; - - public static final int PASSWORD_MAX_LENGTH = 100; - - @Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH) - private String password; - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - @Override - public String toString() { - return "ManagedUserVM{} " + super.toString(); - } -} From 0dd9e78af736ad6923f2e68d9e31f14f18180506 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 31 Oct 2023 22:40:29 +0100 Subject: [PATCH 104/158] fixed updateproject test --- build.gradle | 8 + .../radarbase/management/domain/Project.kt | 9 +- .../management/service/ProjectService.kt | 2 +- .../management/service/RoleService.kt | 5 +- .../management/service/UserService.kt | 21 +- .../management/service/dto/GroupDTO.kt | 8 +- .../management/service/dto/OrganizationDTO.kt | 3 +- .../management/service/dto/ProjectDTO.kt | 12 +- .../decorator/ProjectMapperDecorator.kt | 12 +- .../management/web/rest/ProjectResource.kt | 21 +- .../management/web/rest/util/HeaderUtil.kt | 3 +- .../web/rest/AccountResourceIntTest.kt | 3 +- .../web/rest/AuditResourceIntTest.kt | 40 +- .../web/rest/GroupResourceIntTest.kt | 24 +- .../web/rest/LogsResourceIntTest.kt | 9 +- .../web/rest/OAuthClientsResourceIntTest.kt | 29 +- .../web/rest/OrganizationResourceIntTest.kt | 25 +- .../web/rest/ProfileInfoResourceIntTest.kt | 14 +- .../web/rest/ProjectResourceIntTest.kt | 79 ++- .../web/rest/SourceDataResourceIntTest.kt | 33 +- .../web/rest/SourceResourceIntTest.kt | 24 +- .../web/rest/SourceTypeResourceIntTest.kt | 33 +- .../web/rest/SubjectResourceIntTest.kt | 511 ++++++++---------- .../web/rest/UserResourceIntTest.kt | 6 +- 24 files changed, 420 insertions(+), 514 deletions(-) diff --git a/build.gradle b/build.gradle index 2b480b1a6..e03b2b71a 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,7 @@ plugins { id "org.jetbrains.kotlin.kapt" version "1.9.10" id 'org.jetbrains.kotlin.plugin.serialization' version '1.9.10' apply false id 'org.jetbrains.dokka' version "1.8.20" + id "org.jetbrains.kotlin.plugin.allopen" version "1.9.10" } apply plugin: 'org.springframework.boot' @@ -172,6 +173,7 @@ dependencies { exclude group: 'org.hibernate', module: 'hibernate-entitymanager' } implementation "org.hibernate:hibernate-core" + implementation "org.hibernate:hibernate-core" implementation "org.hibernate:hibernate-envers" implementation 'org.hibernate:hibernate-validator:8.0.0.Final' @@ -227,6 +229,12 @@ dependencies { annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") } +allOpen { + annotation("org.springframework.stereotype.Component") + annotation("org.springframework.boot.test.context.SpringBootTest") + annotation("org.springframework.web.bind.annotation.RestController") +} + dependencyManagement { imports { mavenBom "com.fasterxml.jackson:jackson-bom:$jackson_version" diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index faa6b7cbd..b6c57b4f7 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -12,7 +12,6 @@ import org.hibernate.envers.Audited import org.hibernate.envers.NotAudited import org.radarbase.management.domain.enumeration.ProjectStatus import org.radarbase.management.domain.support.AbstractEntityListener -import org.radarbase.management.security.Constants import java.io.Serializable import java.time.ZonedDateTime import java.util.* @@ -57,7 +56,7 @@ class Project : AbstractEntity(), Serializable { override var id: Long? = null @Column(name = "project_name", nullable = false, unique = true) - var projectName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + var projectName: @NotNull @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") String? = null @Column(name = "description", nullable = false) var description: @NotNull String? = null @@ -124,17 +123,17 @@ class Project : AbstractEntity(), Serializable { ) @OrderBy("name ASC") var groups: MutableSet = HashSet() - fun projectName(projectName: String?): Project { + fun projectName(projectName: String): Project { this.projectName = projectName return this } - fun description(description: String?): Project { + fun description(description: String): Project { this.description = description return this } - fun organizationName(organizationName: String?): Project { + fun organizationName(organizationName: String): Project { this.organizationName = organizationName return this } diff --git a/src/main/java/org/radarbase/management/service/ProjectService.kt b/src/main/java/org/radarbase/management/service/ProjectService.kt index 5856587f0..adaaaa547 100644 --- a/src/main/java/org/radarbase/management/service/ProjectService.kt +++ b/src/main/java/org/radarbase/management/service/ProjectService.kt @@ -39,7 +39,7 @@ open class ProjectService( */ fun save(projectDto: ProjectDTO): ProjectDTO { log.debug("Request to save Project : {}", projectDto) - var project = projectMapper.projectDTOToProject(projectDto) + var project: Project? = projectMapper.projectDTOToProject(projectDto) project = project?.let { projectRepository.save(it) } return projectMapper.projectToProjectDTO(project)!! } diff --git a/src/main/java/org/radarbase/management/service/RoleService.kt b/src/main/java/org/radarbase/management/service/RoleService.kt index 239dcf59a..6f167e446 100644 --- a/src/main/java/org/radarbase/management/service/RoleService.kt +++ b/src/main/java/org/radarbase/management/service/RoleService.kt @@ -31,10 +31,9 @@ open class RoleService( @Autowired private val authorityRepository: AuthorityRepository, @Autowired private val organizationRepository: OrganizationRepository, @Autowired private val projectRepository: ProjectRepository, - @Autowired private val roleMapper: RoleMapper, - @Autowired private val userService: UserService + @Autowired private val roleMapper: RoleMapper ) { - + @Autowired lateinit private var userService: UserService /** * Save a role. diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt index 3f0dc91d6..7f332f726 100644 --- a/src/main/java/org/radarbase/management/service/UserService.kt +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -32,24 +32,21 @@ import java.time.Period import java.time.ZonedDateTime import java.util.* import java.util.function.Function -import kotlin.collections.HashSet -import kotlin.collections.MutableSet -import kotlin.collections.Set /** * Service class for managing users. */ @Service @Transactional -open class UserService( - @Autowired private val userRepository: UserRepository, - @Autowired private val passwordService: PasswordService, - @Autowired private val roleService: RoleService, - @Autowired private val userMapper: UserMapper, - @Autowired private val revisionService: RevisionService, - @Autowired private val managementPortalProperties: ManagementPortalProperties, - @Autowired private val authService: AuthService +open class UserService @Autowired constructor( + private val userRepository: UserRepository, + private val passwordService: PasswordService, + private val userMapper: UserMapper, + private val revisionService: RevisionService, + private val managementPortalProperties: ManagementPortalProperties, + private val authService: AuthService ) { + @Autowired lateinit var roleService: RoleService /** * Activate a user with the given activation key. @@ -312,7 +309,7 @@ open class UserService( * @param password the new password * @param login of the user to change password */ - fun changePassword(login: String, password: String) { + open fun changePassword(login: String, password: String) { val user = userRepository.findOneByLogin(login) if (user != null) diff --git a/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt b/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt index 7daa3ba88..02463bb31 100644 --- a/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt @@ -12,14 +12,14 @@ class GroupDTO { var id: Long? = null var projectId: Long? = null var name: @NotNull String? = null - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val groupDto = o as GroupDTO + val groupDto = other as GroupDTO return if (id == null || groupDto.id == null) { false } else id == groupDto.id diff --git a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt index 00aab1319..44a5e8ada 100644 --- a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt @@ -14,7 +14,8 @@ class OrganizationDTO : Serializable { lateinit var name: @NotNull String lateinit var description: @NotNull String lateinit var location: @NotNull String - var projects: List? = null + + var projects: List = emptyList() override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt index 3d4655f89..c5f9b7421 100644 --- a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt @@ -18,26 +18,26 @@ class ProjectDTO : Serializable { var description: @NotNull String? = null var organization: OrganizationDTO? = null var organizationName: String? = null - var location: @NotNull String? = null + lateinit var location: @NotNull String var startDate: ZonedDateTime? = null var projectStatus: ProjectStatus? = null var endDate: ZonedDateTime? = null @JsonInclude(JsonInclude.Include.NON_EMPTY) - var sourceTypes: Set? = null + var sourceTypes: Set = emptySet() var attributes: Map? = null @JsonInclude(JsonInclude.Include.NON_EMPTY) var groups: Set? = null var persistentTokenTimeout: Long? = null - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val projectDto = o as ProjectDTO + val projectDto = other as ProjectDTO return if (id == null || projectDto.id == null) { false } else id == projectDto.id diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt index a023f87d1..41e988a82 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt @@ -21,9 +21,9 @@ import java.util.* abstract class ProjectMapperDecorator() : ProjectMapper { @Autowired @Qualifier("delegate") private val delegate: ProjectMapper? = null - private val organizationRepository: OrganizationRepository? = null - private val projectRepository: ProjectRepository? = null - private val metaTokenService: MetaTokenService? = null + @Autowired private lateinit var organizationRepository: OrganizationRepository + @Autowired private lateinit var projectRepository: ProjectRepository + @Autowired private lateinit var metaTokenService: MetaTokenService override fun projectToProjectDTO(project: Project?): ProjectDTO? { val dto = delegate?.projectToProjectDTO(project) @@ -41,8 +41,8 @@ abstract class ProjectMapperDecorator() : ProjectMapper { return null } val dto = delegate?.projectToProjectDTOReduced(project) - dto?.humanReadableProjectName = project.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] - dto?.sourceTypes = null + dto?.humanReadableProjectName = project.attributes[ProjectDTO.HUMAN_READABLE_PROJECT_NAME] + dto?.sourceTypes = emptySet() return dto } @@ -57,7 +57,7 @@ abstract class ProjectMapperDecorator() : ProjectMapper { } val orgDto = projectDto.organization if (orgDto?.name != null) { - val org = organizationRepository?.findOneByName(orgDto.name) + val org = organizationRepository.findOneByName(orgDto.name) ?: throw NotFoundException( "Organization not found with name", EntityName.Companion.ORGANIZATION, diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index af751ea30..2f9b0a775 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -46,7 +46,6 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController import java.net.URISyntaxException -import java.util.NoSuchElementException import javax.validation.Valid /** @@ -54,13 +53,14 @@ import javax.validation.Valid */ @RestController @RequestMapping("/api") -class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, - @Autowired private val projectRepository: ProjectRepository, - @Autowired private val projectService: ProjectService, - @Autowired private val roleService: RoleService, - @Autowired private val subjectService: SubjectService, - @Autowired private val sourceService: SourceService, - @Autowired private val authService: AuthService +class ProjectResource( + @Autowired private val subjectMapper: SubjectMapper, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val projectService: ProjectService, + @Autowired private val roleService: RoleService, + @Autowired private val subjectService: SubjectService, + @Autowired private val sourceService: SourceService, + @Autowired private val authService: AuthService ) { /** @@ -127,9 +127,8 @@ class ProjectResource(@Autowired private val subjectMapper: SubjectMapper, @PutMapping("/projects") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun updateProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity { - log.debug("REST request to update Project : {}", projectDto) - if (projectDto!!.id == null) { + fun updateProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity {log.debug("REST request to update Project : {}", projectDto) + if (projectDto?.id == null) { return createProject(projectDto) } // When a client wants to link the project to the default organization, diff --git a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt index 888626811..a6104569c 100644 --- a/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt +++ b/src/main/java/org/radarbase/management/web/rest/util/HeaderUtil.kt @@ -85,8 +85,9 @@ object HeaderUtil { * @return A String where the components are URLEncoded and joined by forward slashes. */ fun buildPath(vararg components: String?): String { - return components + return "/" + components .filterNotNull() + .filter { it != "" } .map { c: String? -> // try-catch needs to be inside the lambda try { diff --git a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt index d90d5bc7d..442093261 100644 --- a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt @@ -54,12 +54,11 @@ internal open class AccountResourceIntTest( @Autowired private val passwordService: PasswordService, @Mock private val mockUserService: UserService, @Mock private val mockMailService: MailService, - private var restUserMockMvc: MockMvc, @Autowired private val radarToken: RadarToken, @Autowired private val authService: AuthService, @Autowired private val managementPortalProperties: ManagementPortalProperties ) { - + private lateinit var restUserMockMvc: MockMvc @BeforeEach fun setUp() { MockitoAnnotations.openMocks(this) diff --git a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt index 58f6f4b0e..3924e62f3 100644 --- a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt @@ -44,11 +44,10 @@ internal open class AuditResourceIntTest( @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val formattingConversionService: FormattingConversionService, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, - private var auditEvent: PersistentAuditEvent, - private var restAuditMockMvc: MockMvc, @Autowired private val authService: AuthService ) { - + private lateinit var auditEvent: PersistentAuditEvent + private lateinit var restAuditMockMvc: MockMvc @BeforeEach @Throws(ServletException::class) fun setUp() { @@ -78,10 +77,9 @@ internal open class AuditResourceIntTest( auditEvent.auditEventDate = SAMPLE_TIMESTAMP } - @get:Throws(Exception::class) - @get:Test - val allAudits: Unit - get() { + @Throws(Exception::class) + @Test + fun allAudits() { // Initialize the database auditEventRepository.save(auditEvent) @@ -98,10 +96,9 @@ internal open class AuditResourceIntTest( ) } - @get:Throws(Exception::class) - @get:Test - val audit: Unit - get() { + @Throws(Exception::class) + @Test + fun audit() { // Initialize the database auditEventRepository.save(auditEvent) @@ -112,10 +109,9 @@ internal open class AuditResourceIntTest( .andExpect(MockMvcResultMatchers.jsonPath("$.principal").value(SAMPLE_PRINCIPAL)) } - @get:Throws(Exception::class) - @get:Test - open val auditsByDate: Unit - get() { + @Throws(Exception::class) + @Test + fun auditsByDate() { // Initialize the database auditEventRepository.save(auditEvent) @@ -141,10 +137,9 @@ internal open class AuditResourceIntTest( ) } - @get:Throws(Exception::class) - @get:Test - val nonExistingAuditsByDate: Unit - get() { + @Throws(Exception::class) + @Test + fun nonExistingAuditsByDate() { // Initialize the database auditEventRepository.save(auditEvent) @@ -165,10 +160,9 @@ internal open class AuditResourceIntTest( .andExpect(MockMvcResultMatchers.header().string("X-Total-Count", "0")) } - @get:Throws(Exception::class) - @get:Test - val nonExistingAudit: Unit - get() { + @Throws(Exception::class) + @Test + fun nonExistingAudit() { // Get the audit restAuditMockMvc.perform(MockMvcRequestBuilders.get("/management/audits/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) diff --git a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt index 882b0afc1..113b59f30 100644 --- a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt @@ -65,13 +65,13 @@ internal class GroupResourceIntTest( @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, @Autowired private val groupRepository: GroupRepository, - private var restGroupMockMvc: MockMvc, - private var group: Group, - private var project: Project + @Autowired private val authService: AuthService ) { + private lateinit var restGroupMockMvc: MockMvc + private lateinit var group: Group + private lateinit var project: Project + - @Autowired - private val authService: AuthService? = null @BeforeEach @Throws(ServletException::class) @@ -223,10 +223,9 @@ internal class GroupResourceIntTest( ).andExpect(MockMvcResultMatchers.status().isBadRequest()) } - @get:Throws(Exception::class) - @get:Test - val allGroups: Unit - get() { + @Throws(Exception::class) + @Test + fun allGroups() { // Initialize the database groupRepository.saveAndFlush(group) @@ -262,10 +261,9 @@ internal class GroupResourceIntTest( .andExpect(MockMvcResultMatchers.jsonPath("$.projectId").value(project.id!!.toInt())) } - @get:Throws(Exception::class) - @get:Test - val nonExistingGroup: Unit - get() { + @Throws(Exception::class) + @Test + fun nonExistingGroup() { // Get the Group restGroupMockMvc.perform( MockMvcRequestBuilders.get( diff --git a/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt index 65a4f2fa8..bf268ac6a 100644 --- a/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/LogsResourceIntTest.kt @@ -25,17 +25,16 @@ internal class LogsResourceIntTest { private var restLogsMockMvc: MockMvc? = null @BeforeEach fun setUp() { - MockitoAnnotations.initMocks(this) + MockitoAnnotations.openMocks(this) val logsResource = LogsResource() restLogsMockMvc = MockMvcBuilders .standaloneSetup(logsResource) .build() } - @get:Throws(Exception::class) - @get:Test - val allLogs: Unit - get() { + @Throws(Exception::class) + @Test + fun allLogs() { restLogsMockMvc!!.perform(MockMvcRequestBuilders.get("/management/logs")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt index 16b8952af..7d196a709 100644 --- a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt @@ -42,22 +42,21 @@ import java.util.function.Consumer */ @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalApp::class]) -internal open class OAuthClientsResourceIntTest( - @Autowired private val clientDetailsService: JdbcClientDetailsService, - @Autowired private val clientDetailsMapper: ClientDetailsMapper, - @Autowired private val subjectService: SubjectService, - @Autowired private val userService: UserService, - @Autowired private val oAuthClientService: OAuthClientService, - @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, - @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, - @Autowired private val exceptionTranslator: ExceptionTranslator, - private var restOauthClientMvc: MockMvc, - private var details: ClientDetailsDTO, - private var clientDetailsList: List, - private var databaseSizeBeforeCreate: Int = 0, - @Autowired private val authService: AuthService +internal open class OAuthClientsResourceIntTest @Autowired constructor ( + private val clientDetailsService: JdbcClientDetailsService, + private val clientDetailsMapper: ClientDetailsMapper, + private val subjectService: SubjectService, + private val userService: UserService, + private val oAuthClientService: OAuthClientService, + private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + private val exceptionTranslator: ExceptionTranslator, + private val authService: AuthService ) { - + private lateinit var restOauthClientMvc: MockMvc + private lateinit var details: ClientDetailsDTO + private var databaseSizeBeforeCreate: Int = 0 + private lateinit var clientDetailsList: List @BeforeEach @Throws(Exception::class) diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index 78ec5fa9a..63870f3e9 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -49,10 +49,10 @@ internal open class OrganizationResourceIntTest( @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - private var restOrganizationMockMvc: MockMvc, - private var organization: Organization, @Autowired private val authService: AuthService ) { + private lateinit var restOrganizationMockMvc: MockMvc + private lateinit var organization: Organization @BeforeEach @Throws(ServletException::class) @@ -86,10 +86,9 @@ internal open class OrganizationResourceIntTest( } - @get:Throws(Exception::class) - @get:Test - val nonExistingOrganization: Unit - get() { + @Throws(Exception::class) + @Test + fun nonExistingOrganization() { // Get the organization restOrganizationMockMvc.perform( MockMvcRequestBuilders.get( @@ -100,10 +99,9 @@ internal open class OrganizationResourceIntTest( .andExpect(MockMvcResultMatchers.status().isNotFound()) } - @get:Throws(Exception::class) - @get:Test - val allOrganizations: Unit - get() { + @Throws(Exception::class) + @Test + fun allOrganizations() { // Initialize the database organizationRepository.saveAndFlush(organization) @@ -116,10 +114,9 @@ internal open class OrganizationResourceIntTest( ) } - @get:Throws(Exception::class) - @get:Test - val projectsByOrganizationName: Unit - get() { + @Throws(Exception::class) + @Test + fun projectsByOrganizationName() { // Initialize the database organizationRepository.saveAndFlush(organization) val project: Project = ProjectResourceIntTest.Companion.createEntity() diff --git a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt index 108c9644b..ba9b4e2fa 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt @@ -41,19 +41,17 @@ internal class ProfileInfoResourceIntTest { .build() } - @get:Throws(Exception::class) - @get:Test - val profileInfo: Unit - get() { + @Throws(Exception::class) + @Test + fun profileInfo() { restProfileMockMvc!!.perform(MockMvcRequestBuilders.get("/api/profile-info")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) } - @get:Throws(Exception::class) - @get:Test - val profileInfoWithoutActiveProfiles: Unit - get() { + @Throws(Exception::class) + @Test + fun profileInfoWithoutActiveProfiles() { val emptyProfile = arrayOf() Mockito.`when`(environment!!.defaultProfiles).thenReturn(emptyProfile) Mockito.`when`(environment.activeProfiles).thenReturn(emptyProfile) diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt index b75f57972..9a1decae5 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt @@ -1,6 +1,5 @@ package org.radarbase.management.web.rest -import org.assertj.core.api.Assertions import org.assertj.core.api.Assertions.assertThat import org.hamcrest.Matchers import org.junit.jupiter.api.BeforeEach @@ -14,8 +13,6 @@ import org.radarbase.management.domain.Project import org.radarbase.management.domain.enumeration.ProjectStatus import org.radarbase.management.repository.OrganizationRepository import org.radarbase.management.repository.ProjectRepository -import org.radarbase.management.service.AuthService -import org.radarbase.management.service.ProjectService import org.radarbase.management.service.mapper.ProjectMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired @@ -26,7 +23,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -48,26 +44,30 @@ import javax.servlet.ServletException @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser internal open class ProjectResourceIntTest( - @Autowired private val organizationRepository: OrganizationRepository, + @Autowired private val projectResource: ProjectResource, + +// @Autowired private val subjectMapper: SubjectMapper, @Autowired private val projectRepository: ProjectRepository, - @Autowired private val projectMapper: ProjectMapper, - @Autowired private val projectService: ProjectService, - @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, +// @Autowired private val projectService: ProjectService, +// @Autowired private val roleService: RoleService, +// @Autowired private val subjectService: SubjectService, +// @Autowired private val sourceService: SourceService, +// @Autowired private val authService: AuthService, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val exceptionTranslator: ExceptionTranslator, - private var restProjectMockMvc: MockMvc, - private var project: Project, - @Autowired private val authService: AuthService + + @Autowired private val projectMapper: ProjectMapper, + @Autowired private val organizationRepository: OrganizationRepository, ) { + private lateinit var restProjectMockMvc: MockMvc + private lateinit var project: Project @BeforeEach @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val projectResource = ProjectResource - ReflectionTestUtils.setField(projectResource, "projectRepository", projectRepository) - ReflectionTestUtils.setField(projectResource, "projectService", projectService) - ReflectionTestUtils.setField(projectResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) restProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) @@ -101,15 +101,15 @@ internal open class ProjectResourceIntTest( // Validate the Project in the database val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeCreate + 1) + assertThat(projectList).hasSize(databaseSizeBeforeCreate + 1) val testProject = projectList[projectList.size - 1] - Assertions.assertThat(testProject!!.projectName).isEqualTo(DEFAULT_PROJECT_NAME) - Assertions.assertThat(testProject.description).isEqualTo(DEFAULT_DESCRIPTION) - Assertions.assertThat(testProject.organizationName).isEqualTo(DEFAULT_ORGANIZATION) - Assertions.assertThat(testProject.location).isEqualTo(DEFAULT_LOCATION) - Assertions.assertThat(testProject.startDate).isEqualTo(DEFAULT_START_DATE) - Assertions.assertThat(testProject.projectStatus).isEqualTo(DEFAULT_PROJECT_STATUS) - Assertions.assertThat(testProject.endDate).isEqualTo(DEFAULT_END_DATE) + assertThat(testProject!!.projectName).isEqualTo(DEFAULT_PROJECT_NAME) + assertThat(testProject.description).isEqualTo(DEFAULT_DESCRIPTION) + assertThat(testProject.organizationName).isEqualTo(DEFAULT_ORGANIZATION) + assertThat(testProject.location).isEqualTo(DEFAULT_LOCATION) + assertThat(testProject.startDate).isEqualTo(DEFAULT_START_DATE) + assertThat(testProject.projectStatus).isEqualTo(DEFAULT_PROJECT_STATUS) + assertThat(testProject.endDate).isEqualTo(DEFAULT_END_DATE) } @Test @@ -132,7 +132,7 @@ internal open class ProjectResourceIntTest( // Validate the Alice in the database val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeCreate) + assertThat(projectList).hasSize(databaseSizeBeforeCreate) } @Test @@ -152,7 +152,7 @@ internal open class ProjectResourceIntTest( ) .andExpect(MockMvcResultMatchers.status().isBadRequest()) val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeTest) + assertThat(projectList).hasSize(databaseSizeBeforeTest) } @Test @@ -172,7 +172,7 @@ internal open class ProjectResourceIntTest( ) .andExpect(MockMvcResultMatchers.status().isBadRequest()) val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeTest) + assertThat(projectList).hasSize(databaseSizeBeforeTest) } @Test @@ -192,14 +192,13 @@ internal open class ProjectResourceIntTest( ) .andExpect(MockMvcResultMatchers.status().isBadRequest()) val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeTest) + assertThat(projectList).hasSize(databaseSizeBeforeTest) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allProjects: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun allProjects() { // Initialize the database projectRepository.saveAndFlush(project) @@ -284,11 +283,10 @@ internal open class ProjectResourceIntTest( .andExpect(MockMvcResultMatchers.jsonPath("$.endDate").value(TestUtil.sameInstant(DEFAULT_END_DATE))) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val nonExistingProject: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun nonExistingProject() { // Get the project restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) @@ -324,8 +322,7 @@ internal open class ProjectResourceIntTest( MockMvcRequestBuilders.put("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(projectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Project in the database val projectList = projectRepository.findAll() @@ -363,7 +360,7 @@ internal open class ProjectResourceIntTest( // Validate the Project in the database val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeUpdate + 1) + assertThat(projectList).hasSize(databaseSizeBeforeUpdate + 1) } @Test @@ -383,7 +380,7 @@ internal open class ProjectResourceIntTest( // Validate the database is empty val projectList = projectRepository.findAll() - Assertions.assertThat(projectList).hasSize(databaseSizeBeforeDelete - 1) + assertThat(projectList).hasSize(databaseSizeBeforeDelete - 1) } @Test diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt index 804292021..87bd2cff6 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt @@ -29,7 +29,6 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers import org.springframework.test.web.servlet.setup.MockMvcBuilders import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder import org.springframework.transaction.annotation.Transactional -import javax.persistence.EntityManager import javax.servlet.ServletException /** @@ -47,11 +46,10 @@ internal open class SourceDataResourceIntTest( @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val em: EntityManager, - private var restSourceDataMockMvc: MockMvc, - private var sourceData: SourceData, @Autowired private val authService: AuthService ) { + private lateinit var restSourceDataMockMvc: MockMvc + private lateinit var sourceData: SourceData @BeforeEach @Throws(ServletException::class) @@ -172,11 +170,10 @@ internal open class SourceDataResourceIntTest( Assertions.assertThat(sourceDataList).hasSize(databaseSizeBeforeTest) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allSourceData: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun allSourceData() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) @@ -243,11 +240,10 @@ internal open class SourceDataResourceIntTest( ) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allSourceDataWithPagination: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun allSourceDataWithPagination() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) @@ -341,11 +337,10 @@ internal open class SourceDataResourceIntTest( .andExpect(MockMvcResultMatchers.jsonPath("$.frequency").value(DEFAULT_FREQUENCY)) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val nonExistingSourceData: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun nonExistingSourceData() { // Get the sourceData restSourceDataMockMvc.perform( MockMvcRequestBuilders.get( diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt index 80033e65a..6c4ed5696 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt @@ -55,11 +55,11 @@ internal open class SourceResourceIntTest( @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, @Autowired private val projectRepository: ProjectRepository, - private var restDeviceMockMvc: MockMvc, - private var source: Source, - private var project: Project, @Autowired private val authService: AuthService ) { + private lateinit var restDeviceMockMvc: MockMvc + private lateinit var source: Source + private lateinit var project: Project @BeforeEach @Throws(ServletException::class) @@ -187,11 +187,10 @@ internal open class SourceResourceIntTest( Assertions.assertThat(sourceList).hasSize(databaseSizeBeforeTest) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allSources: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun allSources() { // Initialize the database sourceRepository.saveAndFlush(source) @@ -232,11 +231,10 @@ internal open class SourceResourceIntTest( .andExpect(MockMvcResultMatchers.jsonPath("$.assigned").value(DEFAULT_ASSIGNED)) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val nonExistingSource: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun nonExistingSource() { // Get the source restDeviceMockMvc.perform(MockMvcRequestBuilders.get("/api/sources/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt index 2981eb2ad..ad2dbf537 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt @@ -31,7 +31,6 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers import org.springframework.test.web.servlet.setup.MockMvcBuilders import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder import org.springframework.transaction.annotation.Transactional -import javax.persistence.EntityManager import javax.servlet.ServletException /** @@ -51,11 +50,10 @@ internal open class SourceTypeResourceIntTest( @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val em: EntityManager, - private var restSourceTypeMockMvc: MockMvc, - private var sourceType: SourceType, @Autowired private val authService: AuthService ) { + private lateinit var restSourceTypeMockMvc: MockMvc + private lateinit var sourceType: SourceType @BeforeEach @Throws(ServletException::class) @@ -205,11 +203,10 @@ internal open class SourceTypeResourceIntTest( Assertions.assertThat(sourceTypeList).hasSize(databaseSizeBeforeTest) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allSourceTypes: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun allSourceTypes() { // Initialize the database sourceTypeRepository.saveAndFlush(sourceType) @@ -252,11 +249,10 @@ internal open class SourceTypeResourceIntTest( ) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allSourceTypesWithPagination: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun allSourceTypesWithPagination() { // Initialize the database sourceTypeRepository.saveAndFlush(sourceType) @@ -325,11 +321,10 @@ internal open class SourceTypeResourceIntTest( ) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val nonExistingSourceType: Unit - get() { + @Throws(Exception::class) + @Transactional + @Test + open fun nonExistingSourceType() { // Get the sourceType restSourceTypeMockMvc.perform( MockMvcRequestBuilders.get( diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index c024bcd1a..4b48e9a80 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -12,6 +12,7 @@ import org.radarbase.management.domain.Subject import org.radarbase.management.repository.ProjectRepository import org.radarbase.management.repository.SubjectRepository import org.radarbase.management.service.AuthService +import org.radarbase.management.service.RevisionService import org.radarbase.management.service.SourceService import org.radarbase.management.service.SourceTypeService import org.radarbase.management.service.SubjectService @@ -24,6 +25,7 @@ import org.radarbase.management.service.dto.SubjectDTO import org.radarbase.management.service.mapper.SubjectMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.actuate.audit.AuditEventRepository import org.springframework.boot.test.context.SpringBootTest import org.springframework.data.web.PageableHandlerMethodArgumentResolver import org.springframework.http.MediaType @@ -31,7 +33,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -50,40 +51,47 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class SubjectResourceIntTest(@Autowired private val subjectRepository: SubjectRepository, - @Autowired private val subjectMapper: SubjectMapper, - @Autowired private val subjectService: SubjectService, - @Autowired private val sourceService: SourceService, - @Autowired private val sourceTypeService: SourceTypeService, - @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, - @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, - @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val projectRepository: ProjectRepository, - private var restSubjectMockMvc: MockMvc, - @Autowired private val authService: AuthService +internal open class SubjectResourceIntTest( + @Autowired private val subjectRepository: SubjectRepository, + @Autowired private val subjectMapper: SubjectMapper, + @Autowired private val subjectService: SubjectService, + @Autowired private val sourceService: SourceService, + @Autowired private val sourceTypeService: SourceTypeService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, + @Autowired private val projectRepository: ProjectRepository, + @Autowired private val authService: AuthService, + @Autowired private val revisionService: RevisionService, + @Autowired private val eventRepository: AuditEventRepository ) { + private lateinit var restSubjectMockMvc: MockMvc @BeforeEach @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val subjectResource = SubjectResource - ReflectionTestUtils.setField(subjectResource, "subjectService", subjectService) - ReflectionTestUtils.setField(subjectResource, "subjectRepository", subjectRepository) - ReflectionTestUtils.setField(subjectResource, "subjectMapper", subjectMapper) - ReflectionTestUtils.setField(subjectResource, "projectRepository", projectRepository) - ReflectionTestUtils.setField(subjectResource, "sourceTypeService", sourceTypeService) - ReflectionTestUtils.setField(subjectResource, "authService", authService) - ReflectionTestUtils.setField(subjectResource, "sourceService", sourceService) + val subjectResource = SubjectResource( + subjectService, + subjectRepository, + subjectMapper, + projectRepository, + sourceTypeService, + eventRepository, + revisionService, + sourceService, + authService + ) + val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) - restSubjectMockMvc = MockMvcBuilders.standaloneSetup(subjectResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) // add the oauth token by default to all requests for this mockMvc - .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) - .build() + restSubjectMockMvc = + MockMvcBuilders.standaloneSetup(subjectResource).setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator).setMessageConverters(jacksonMessageConverter) + .addFilter(filter) // add the oauth token by default to all requests for this mockMvc + .defaultRequest( + MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken()) + ).build() } @Test @@ -95,11 +103,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Create the Subject val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( - MockMvcRequestBuilders.post("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -121,86 +127,71 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // An entity with an existing ID cannot be created, so this API call must fail restSubjectMockMvc.perform( - MockMvcRequestBuilders.post("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) + ).andExpect(MockMvcResultMatchers.status().isBadRequest()) // Validate the Alice in the database val subjectList = subjectRepository.findAll() Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val allSubjects: Unit - get() { - // Initialize the database - val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) - - // Get all the subjectList - restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects?sort=id,desc")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[*].id").value>( - Matchers.hasItem( - subjectDto!!.id!!.toInt() - ) + @Throws(Exception::class) + @Transactional + @Test + open fun allSubjects() { + // Initialize the database + val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) + + // Get all the subjectList + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects?sort=id,desc")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)).andExpect( + MockMvcResultMatchers.jsonPath("$.[*].id").value>( + Matchers.hasItem( + subjectDto!!.id!!.toInt() ) ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[*].externalLink") - .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_EXTERNAL_LINK)) - ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[*].externalId") - .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_ENTERNAL_ID)) - ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[*].status") - .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_STATUS.toString())) - ) - } + ).andExpect( + MockMvcResultMatchers.jsonPath("$.[*].externalLink") + .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_EXTERNAL_LINK)) + ).andExpect( + MockMvcResultMatchers.jsonPath("$.[*].externalId") + .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_ENTERNAL_ID)) + ).andExpect( + MockMvcResultMatchers.jsonPath("$.[*].status") + .value>(Matchers.hasItem(SubjectServiceTest.DEFAULT_STATUS.toString())) + ) + } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val subject: Unit - get() { - // Initialize the database - val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) - - // Get the subject - restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{login}", subjectDto!!.login)) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(subjectDto.id!!.toInt())) - .andExpect( - MockMvcResultMatchers.jsonPath("$.externalLink") - .value(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) - ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.externalId") - .value(SubjectServiceTest.DEFAULT_ENTERNAL_ID) - ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.status") - .value(SubjectServiceTest.DEFAULT_STATUS.toString()) - ) - } + @Throws(Exception::class) + @Transactional + @Test + open fun subject() { + // Initialize the database + val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val nonExistingSubject: Unit - get() { - // Get the subject - restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{id}", Long.MAX_VALUE)) - .andExpect(MockMvcResultMatchers.status().isNotFound()) - } + // Get the subject + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{login}", subjectDto!!.login)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(subjectDto.id!!.toInt())).andExpect( + MockMvcResultMatchers.jsonPath("$.externalLink").value(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) + ).andExpect( + MockMvcResultMatchers.jsonPath("$.externalId").value(SubjectServiceTest.DEFAULT_ENTERNAL_ID) + ).andExpect( + MockMvcResultMatchers.jsonPath("$.status").value(SubjectServiceTest.DEFAULT_STATUS.toString()) + ) + } + + @Throws(Exception::class) + @Transactional + @Test + open fun nonExistingSubject() { + // Get the subject + restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{id}", Long.MAX_VALUE)) + .andExpect(MockMvcResultMatchers.status().isNotFound()) + } @Test @Transactional @@ -212,17 +203,13 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Update the subject val updatedSubject = subjectRepository.findById(subjectDto!!.id!!).get() - updatedSubject - .externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) - .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID) - .removed = SubjectServiceTest.UPDATED_REMOVED + updatedSubject.externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) + .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID).removed = SubjectServiceTest.UPDATED_REMOVED subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) restSubjectMockMvc.perform( - MockMvcRequestBuilders.put("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.put("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -243,10 +230,8 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Update the subject val updatedSubject = subjectRepository.findById(subjectDto!!.id!!).get() - updatedSubject - .externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) - .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID) - .removed = SubjectServiceTest.UPDATED_REMOVED + updatedSubject.externalLink(SubjectServiceTest.UPDATED_EXTERNAL_LINK) + .externalId(SubjectServiceTest.UPDATED_ENTERNAL_ID).removed = SubjectServiceTest.UPDATED_REMOVED subjectDto = subjectMapper.subjectToSubjectDTO(updatedSubject) val newProject = ProjectDTO() newProject.id = 2L @@ -254,11 +239,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit newProject.location = "new location" subjectDto!!.project = newProject restSubjectMockMvc.perform( - MockMvcRequestBuilders.put("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.put("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -281,11 +264,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // If the entity doesn't have an ID, it will be created instead of just being updated restSubjectMockMvc.perform( - MockMvcRequestBuilders.put("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.put("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -304,8 +285,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit restSubjectMockMvc.perform( MockMvcRequestBuilders.delete("/api/subjects/{login}", subjectDto!!.login) .accept(TestUtil.APPLICATION_JSON_UTF8) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) // Validate the database is empty val subjectList = subjectRepository.findAll() @@ -328,11 +308,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Create the Subject val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( - MockMvcRequestBuilders.post("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -347,8 +325,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.sourceId").isNotEmpty()) // A source can not be assigned twice to a subject, so this call must fail @@ -357,8 +334,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) - ) - .andExpect(MockMvcResultMatchers.status().is4xxClientError()) + ).andExpect(MockMvcResultMatchers.status().is4xxClientError()) } @Test @@ -370,11 +346,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Create the Subject val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( - MockMvcRequestBuilders.post("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -389,8 +363,7 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.sourceId").isNotEmpty()) // A source can not be assigned twice to a subject, so this call must fail @@ -399,13 +372,15 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) - ) - .andExpect(MockMvcResultMatchers.status().is4xxClientError()) + ).andExpect(MockMvcResultMatchers.status().is4xxClientError()) // Get all the subjectList - restSubjectMockMvc - .perform(MockMvcRequestBuilders.get("/api/subjects/{login}/sources?sort=id,desc", subjectDto.login)) - .andExpect(MockMvcResultMatchers.status().isOk()) + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?sort=id,desc", + subjectDto.login + ) + ).andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").isNotEmpty()) } @@ -419,11 +394,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Create the Subject val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( - MockMvcRequestBuilders.post("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -438,124 +411,98 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit MockMvcRequestBuilders.post("/api/subjects/{login}/sources", subjectLogin) .contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) - ) - .andExpect(MockMvcResultMatchers.status().is4xxClientError()) + ).andExpect(MockMvcResultMatchers.status().is4xxClientError()) .andExpect(MockMvcResultMatchers.jsonPath("$.message").isNotEmpty()) } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val subjectSources: Unit - get() { - // Initialize the database - val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() - val createdSource = sourceService.save(createSource()) - val sourceDto = MinimalSourceDetailsDTO() - .id(createdSource.id) - .sourceName(createdSource.sourceName) - .sourceTypeId(createdSource.sourceType.id) - .sourceId(createdSource.sourceId!!) - subjectDtoToCreate.sources = setOf(sourceDto) - org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) - val createdSubject = subjectService.createSubject(subjectDtoToCreate) - org.junit.jupiter.api.Assertions.assertFalse(createdSubject!!.sources.isEmpty()) - - // Get the subject - restSubjectMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/subjects/{login}/sources", - createdSubject.login - ) + @Throws(Exception::class) + @Transactional + @Test + open fun subjectSources() { + // Initialize the database + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() + val createdSource = sourceService.save(createSource()) + val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) + .sourceTypeId(createdSource.sourceType.id).sourceId(createdSource.sourceId!!) + subjectDtoToCreate.sources = setOf(sourceDto) + org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + val createdSubject = subjectService.createSubject(subjectDtoToCreate) + org.junit.jupiter.api.Assertions.assertFalse(createdSubject!!.sources.isEmpty()) + + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources", createdSubject.login ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[0].id").value(createdSource.id!!.toInt())) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[0].sourceId").value(createdSource.sourceId.toString()) - ) - } + ).andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[0].id").value(createdSource.id!!.toInt())).andExpect( + MockMvcResultMatchers.jsonPath("$.[0].sourceId").value(createdSource.sourceId.toString()) + ) + } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val subjectSourcesWithQueryParam: Unit - get() { - // Initialize the database - val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() - val createdSource = sourceService.save(createSource()) - val sourceDto = MinimalSourceDetailsDTO() - .id(createdSource.id) - .sourceName(createdSource.sourceName) - .sourceTypeId(createdSource.sourceType.id) - .sourceId(createdSource.sourceId!!) - subjectDtoToCreate.sources = setOf(sourceDto) - org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) - val createdSubject = subjectService.createSubject(subjectDtoToCreate) - TestUtil.commitTransactionAndStartNew() - org.junit.jupiter.api.Assertions.assertNotNull(createdSubject!!.login) - // Get the subject - restSubjectMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/subjects/{login}/sources?withInactiveSources=true", - createdSubject.login - ) + @Throws(Exception::class) + @Transactional + @Test + open fun subjectSourcesWithQueryParam() { + // Initialize the database + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() + val createdSource = sourceService.save(createSource()) + val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) + .sourceTypeId(createdSource.sourceType.id).sourceId(createdSource.sourceId!!) + subjectDtoToCreate.sources = setOf(sourceDto) + org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + val createdSubject = subjectService.createSubject(subjectDtoToCreate) + TestUtil.commitTransactionAndStartNew() + org.junit.jupiter.api.Assertions.assertNotNull(createdSubject!!.login) + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?withInactiveSources=true", createdSubject.login ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id!!.toInt())) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) - ) - } + ).andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id!!.toInt())).andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) + ) + } - @get:Throws(Exception::class) - @get:Transactional - @get:Test - open val inactiveSubjectSourcesWithQueryParam: Unit - get() { - // Initialize the database - val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() - val createdSource = sourceService.save(createSource()) - val sourceDto = MinimalSourceDetailsDTO() - .id(createdSource.id) - .sourceName(createdSource.sourceName) - .sourceTypeId(createdSource.sourceType.id) - .sourceId(createdSource.sourceId!!) - subjectDtoToCreate.sources = setOf(sourceDto) - org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) - val createdSubject = subjectService.createSubject(subjectDtoToCreate) - TestUtil.commitTransactionAndStartNew() - createdSubject!!.sources = emptySet() - val updatedSubject = subjectService.updateSubject(createdSubject) - TestUtil.commitTransactionAndStartNew() - org.junit.jupiter.api.Assertions.assertNotNull(updatedSubject!!.login) - // Get the subject - restSubjectMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/subjects/{login}/sources?withInactiveSources=true", - updatedSubject.login - ) + @Throws(Exception::class) + @Transactional + @Test + open fun inactiveSubjectSourcesWithQueryParam() { + // Initialize the database + val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() + val createdSource = sourceService.save(createSource()) + val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) + .sourceTypeId(createdSource.sourceType.id).sourceId(createdSource.sourceId!!) + subjectDtoToCreate.sources = setOf(sourceDto) + org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + val createdSubject = subjectService.createSubject(subjectDtoToCreate) + TestUtil.commitTransactionAndStartNew() + createdSubject!!.sources = emptySet() + val updatedSubject = subjectService.updateSubject(createdSubject) + TestUtil.commitTransactionAndStartNew() + org.junit.jupiter.api.Assertions.assertNotNull(updatedSubject!!.login) + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?withInactiveSources=true", updatedSubject.login + ) + ).andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id!!.toInt())).andExpect( + MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.[*].id").value(createdSource.id!!.toInt())) - .andExpect( - MockMvcResultMatchers.jsonPath("$.[*].sourceId").value(createdSource.sourceId.toString()) - ) - // Get the subject - restSubjectMockMvc - .perform( - MockMvcRequestBuilders.get( - "/api/subjects/{login}/sources?withInactiveSources=false", - updatedSubject.login - ) + // Get the subject + restSubjectMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/subjects/{login}/sources?withInactiveSources=false", updatedSubject.login ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andReturn() - } + ).andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)).andReturn() + } private fun createSource(): SourceDTO { val sourceDto = SourceDTO() @@ -567,43 +514,39 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit } private fun createSourceWithSourceTypeId(): MinimalSourceDetailsDTO { - val sourceTypes = sourceTypeService.findAll().stream() - .filter { obj: SourceTypeDTO -> obj.canRegisterDynamically } - .collect(Collectors.toList()) + val sourceTypes = + sourceTypeService.findAll().stream().filter { obj: SourceTypeDTO -> obj.canRegisterDynamically } + .collect(Collectors.toList()) Assertions.assertThat(sourceTypes.size).isPositive() val sourceType = sourceTypes[0] return source.sourceTypeId(sourceType.id) } private fun createSourceWithoutSourceTypeId(): MinimalSourceDetailsDTO { - val sourceTypes = sourceTypeService.findAll().stream() - .filter { obj: SourceTypeDTO -> obj.canRegisterDynamically } - .collect(Collectors.toList()) + val sourceTypes = + sourceTypeService.findAll().stream().filter { obj: SourceTypeDTO -> obj.canRegisterDynamically } + .collect(Collectors.toList()) Assertions.assertThat(sourceTypes.size).isPositive() val sourceType = sourceTypes[0] - return source - .sourceTypeCatalogVersion(sourceType.catalogVersion) - .sourceTypeModel(sourceType.model) + return source.sourceTypeCatalogVersion(sourceType.catalogVersion).sourceTypeModel(sourceType.model) .sourceTypeProducer(sourceType.producer) } private fun createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration(): MinimalSourceDetailsDTO { - val sourceTypes = sourceTypeService.findAll().stream() - .filter { it: SourceTypeDTO -> !it.canRegisterDynamically } - .collect(Collectors.toList()) + val sourceTypes = + sourceTypeService.findAll().stream().filter { it: SourceTypeDTO -> !it.canRegisterDynamically } + .collect(Collectors.toList()) Assertions.assertThat(sourceTypes.size).isPositive() val sourceType = sourceTypes[0] - return source - .sourceTypeCatalogVersion(sourceType.catalogVersion) - .sourceTypeModel(sourceType.model) + return source.sourceTypeCatalogVersion(sourceType.catalogVersion).sourceTypeModel(sourceType.model) .sourceTypeProducer(sourceType.producer) } private val source: MinimalSourceDetailsDTO get() { - val sourceRegistrationDto = MinimalSourceDetailsDTO() - .sourceName(SubjectServiceTest.PRODUCER + "-" + SubjectServiceTest.MODEL) - .attributes(Collections.singletonMap("something", "value")) + val sourceRegistrationDto = + MinimalSourceDetailsDTO().sourceName(SubjectServiceTest.PRODUCER + "-" + SubjectServiceTest.MODEL) + .attributes(Collections.singletonMap("something", "value")) Assertions.assertThat(sourceRegistrationDto.sourceId).isNull() return sourceRegistrationDto } @@ -617,11 +560,9 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit // Create the Subject val subjectDto: SubjectDTO = SubjectServiceTest.createEntityDTO() restSubjectMockMvc.perform( - MockMvcRequestBuilders.post("/api/subjects") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/subjects").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(subjectDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Subject in the database val subjectList = subjectRepository.findAll() @@ -634,17 +575,12 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit val sourceRegistrationDto = createSourceWithoutSourceTypeId() val result = restSubjectMockMvc.perform( MockMvcRequestBuilders.post( - "/api/subjects/{login}/sources", - subjectLogin - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) + "/api/subjects/{login}/sources", subjectLogin + ).contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(sourceRegistrationDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andReturn() + ).andExpect(MockMvcResultMatchers.status().isOk()).andReturn() val value = TestUtil.convertJsonStringToObject( - result - .response.contentAsString, MinimalSourceDetailsDTO::class.java + result.response.contentAsString, MinimalSourceDetailsDTO::class.java ) as MinimalSourceDetailsDTO org.junit.jupiter.api.Assertions.assertNotNull(value.sourceName) val attributes: MutableMap = HashMap() @@ -654,11 +590,8 @@ internal open class SubjectResourceIntTest(@Autowired private val subjectReposit restSubjectMockMvc.perform( MockMvcRequestBuilders.post( "/api/subjects/{login}/sources/{sourceName}", subjectLogin, value.sourceName - ) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(attributes)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(attributes)) + ).andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.attributes").isNotEmpty()) } } diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt index 9d0a54a50..5949207d7 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt @@ -66,10 +66,10 @@ internal open class UserResourceIntTest( @Autowired private val authService: AuthService, @Autowired private val passwordService: PasswordService, @Autowired private val projectRepository: ProjectRepository, - private var restUserMockMvc: MockMvc, - private var user: User, - private var project: Project? ) { + private lateinit var restUserMockMvc: MockMvc + private lateinit var user: User + private var project: Project? = null @BeforeEach @Throws(ServletException::class) From bdfc5ddc3229b849fae2462f59a9940d34472fb4 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 11:30:12 +0100 Subject: [PATCH 105/158] misc fixes --- .../management/domain/Organization.kt | 8 ++--- .../org/radarbase/management/domain/Role.kt | 8 ++--- .../web/rest/OrganizationResource.kt | 30 +++++++++---------- 3 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Organization.kt b/src/main/java/org/radarbase/management/domain/Organization.kt index 479a0f708..44b94d2d4 100644 --- a/src/main/java/org/radarbase/management/domain/Organization.kt +++ b/src/main/java/org/radarbase/management/domain/Organization.kt @@ -49,14 +49,14 @@ class Organization : AbstractEntity() { @JvmField @OneToMany(mappedBy = "organization") var projects: List? = null - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val org = o as Organization + val org = other as Organization return if (org.id == null || id == null) { false } else id == org.id diff --git a/src/main/java/org/radarbase/management/domain/Role.kt b/src/main/java/org/radarbase/management/domain/Role.kt index b71751401..010af8aca 100644 --- a/src/main/java/org/radarbase/management/domain/Role.kt +++ b/src/main/java/org/radarbase/management/domain/Role.kt @@ -99,14 +99,14 @@ class Role : AbstractEntity, Serializable { return this } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val role = o as Role + val role = other as Role return authority == role.authority && project == role.project && organization == role.organization } diff --git a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt index ad99b72e5..53071da24 100644 --- a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt @@ -35,12 +35,10 @@ import javax.validation.Valid */ @RestController @RequestMapping("/api") -class OrganizationResource { - @Autowired - private val organizationService: OrganizationService? = null - - @Autowired - private val authService: AuthService? = null +class OrganizationResource( + @Autowired private val organizationService: OrganizationService, + @Autowired private val authService: AuthService +) { /** * POST /organizations : Create a new organization. @@ -58,13 +56,13 @@ class OrganizationResource { @RequestBody organizationDto: @Valid OrganizationDTO? ): ResponseEntity { log.debug("REST request to save Organization : {}", organizationDto) - authService!!.checkPermission(Permission.ORGANIZATION_CREATE) + authService.checkPermission(Permission.ORGANIZATION_CREATE) if (organizationDto!!.id != null) { val msg = "A new organization cannot already have an ID" val headers = createFailureAlert(ENTITY_NAME, "idexists", msg) return ResponseEntity.badRequest().headers(headers).body(null) } - val existingOrg = organizationService!!.findByName(organizationDto.name) + val existingOrg = organizationDto.name?.let { organizationService.findByName(it) } if (existingOrg != null) { val msg = "An organization with this name already exists" val headers = createFailureAlert(ENTITY_NAME, "nameexists", msg) @@ -88,8 +86,8 @@ class OrganizationResource { */ get() { log.debug("REST request to get Organizations") - authService!!.checkScope(Permission.ORGANIZATION_READ) - val orgs = organizationService!!.findAll() + authService.checkScope(Permission.ORGANIZATION_READ) + val orgs = organizationService.findAll() return ResponseEntity(orgs, HttpStatus.OK) } @@ -114,8 +112,8 @@ class OrganizationResource { return createOrganization(organizationDto) } val name = organizationDto.name - authService!!.checkPermission(Permission.ORGANIZATION_UPDATE, { (organization): EntityDetails -> organization }) - val result = organizationService!!.save(organizationDto) + authService.checkPermission(Permission.ORGANIZATION_UPDATE, { (organization): EntityDetails -> organization }) + val result = organizationService.save(organizationDto) return ResponseEntity.ok() .headers(createEntityCreationAlert(ENTITY_NAME, result.name)) .body(result) @@ -138,8 +136,8 @@ class OrganizationResource { @PathVariable name: String ): ResponseEntity { log.debug("REST request to get Organization : {}", name) - authService!!.checkPermission(Permission.ORGANIZATION_READ, { (organization): EntityDetails -> organization }) - val org = organizationService!!.findByName(name) + authService.checkPermission(Permission.ORGANIZATION_READ, { (organization): EntityDetails -> organization }) + val org = organizationService.findByName(name) val dto = org ?: throw NotFoundException( "Organization not found with name $name", EntityName.ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, @@ -166,8 +164,8 @@ class OrganizationResource { @PathVariable name: String? ): ResponseEntity> { log.debug("REST request to get Projects of the Organization : {}", name) - authService!!.checkPermission(Permission.PROJECT_READ, { (organization): EntityDetails -> organization }) - val projects = organizationService!!.findAllProjectsByOrganizationName(name!!) + authService.checkPermission(Permission.PROJECT_READ, { (organization): EntityDetails -> organization }) + val projects = organizationService.findAllProjectsByOrganizationName(name!!) return ResponseEntity.ok(projects) } From 3cd8a84fc21556216b368fd5d073c97926892536 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 11:33:17 +0100 Subject: [PATCH 106/158] all tests in ProjectResourceIntTest.kt passing. --- .../radarbase/management/domain/Project.kt | 6 +- .../repository/ProjectRepository.kt | 4 +- .../management/service/dto/OrganizationDTO.kt | 6 +- .../management/service/dto/ProjectDTO.kt | 6 +- .../decorator/ProjectMapperDecorator.kt | 23 +- .../management/web/rest/ProjectResource.kt | 14 +- .../web/rest/OrganizationResourceIntTest.kt | 201 +++++++++--------- .../web/rest/ProjectResourceIntTest.kt | 7 +- 8 files changed, 136 insertions(+), 131 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index b6c57b4f7..f9c607091 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -123,17 +123,17 @@ class Project : AbstractEntity(), Serializable { ) @OrderBy("name ASC") var groups: MutableSet = HashSet() - fun projectName(projectName: String): Project { + fun projectName(projectName: String?): Project { this.projectName = projectName return this } - fun description(description: String): Project { + fun description(description: String?): Project { this.description = description return this } - fun organizationName(organizationName: String): Project { + fun organizationName(organizationName: String?): Project { this.organizationName = organizationName return this } diff --git a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt index 9dfd6b7be..2eb10938f 100644 --- a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt +++ b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt @@ -15,7 +15,7 @@ import org.springframework.data.repository.query.Param */ @Suppress("unused") @RepositoryDefinition(domainClass = Project::class, idClass = Long::class) -interface ProjectRepository : JpaRepository, RevisionRepository { +interface ProjectRepository : JpaRepository, RevisionRepository { @Query( value = "select distinct project from Project project " + "left join fetch project.sourceTypes", @@ -53,7 +53,7 @@ interface ProjectRepository : JpaRepository, RevisionRepository

= emptyList() override fun equals(other: Any?): Boolean { diff --git a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt index c5f9b7421..0955cec77 100644 --- a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt @@ -13,12 +13,12 @@ import javax.validation.constraints.NotNull @JsonInclude(JsonInclude.Include.NON_NULL) class ProjectDTO : Serializable { var id: Long? = null - var projectName: @NotNull String? = null + @NotNull var projectName: String? = null var humanReadableProjectName: String? = null - var description: @NotNull String? = null + @NotNull var description: String? = null var organization: OrganizationDTO? = null var organizationName: String? = null - lateinit var location: @NotNull String + @NotNull var location: String? = null var startDate: ZonedDateTime? = null var projectStatus: ProjectStatus? = null var endDate: ZonedDateTime? = null diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt index 41e988a82..9f7811647 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt @@ -18,18 +18,18 @@ import java.util.* /** * Created by nivethika on 30-8-17. */ -abstract class ProjectMapperDecorator() : ProjectMapper { +abstract class ProjectMapperDecorator : ProjectMapper { - @Autowired @Qualifier("delegate") private val delegate: ProjectMapper? = null + @Autowired @Qualifier("delegate") private lateinit var delegate: ProjectMapper @Autowired private lateinit var organizationRepository: OrganizationRepository @Autowired private lateinit var projectRepository: ProjectRepository @Autowired private lateinit var metaTokenService: MetaTokenService override fun projectToProjectDTO(project: Project?): ProjectDTO? { - val dto = delegate?.projectToProjectDTO(project) + val dto = delegate.projectToProjectDTO(project) dto?.humanReadableProjectName = project?.attributes?.get(ProjectDTO.HUMAN_READABLE_PROJECT_NAME) try { - dto?.persistentTokenTimeout = metaTokenService?.getMetaTokenTimeout(true, project)?.toMillis() + dto?.persistentTokenTimeout = metaTokenService.getMetaTokenTimeout(true, project).toMillis() } catch (ex: BadRequestException) { dto?.persistentTokenTimeout = null } @@ -40,7 +40,7 @@ abstract class ProjectMapperDecorator() : ProjectMapper { if (project == null) { return null } - val dto = delegate?.projectToProjectDTOReduced(project) + val dto = delegate.projectToProjectDTOReduced(project) dto?.humanReadableProjectName = project.attributes[ProjectDTO.HUMAN_READABLE_PROJECT_NAME] dto?.sourceTypes = emptySet() return dto @@ -50,19 +50,20 @@ abstract class ProjectMapperDecorator() : ProjectMapper { if (projectDto == null) { return null } - val project = delegate?.projectDTOToProject(projectDto) + val project = delegate.projectDTOToProject(projectDto) val projectName = projectDto.humanReadableProjectName if (!projectName.isNullOrEmpty()) { project!!.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] = projectName } - val orgDto = projectDto.organization - if (orgDto?.name != null) { - val org = organizationRepository.findOneByName(orgDto.name) + + val name = projectDto.organization?.name + if (name != null) { + val org = organizationRepository.findOneByName(name) ?: throw NotFoundException( "Organization not found with name", EntityName.Companion.ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, - Collections.singletonMap("name", orgDto.name) + Collections.singletonMap("name", name) ) project!!.organization = org } @@ -72,6 +73,6 @@ abstract class ProjectMapperDecorator() : ProjectMapper { override fun descriptiveDTOToProject(minimalProjectDetailsDto: MinimalProjectDetailsDTO?): Project? { return if (minimalProjectDetailsDto == null) { null - } else minimalProjectDetailsDto.id?.let { projectRepository?.getById(it) } + } else minimalProjectDetailsDto.id?.let { projectRepository.getById(it) } } } diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index 2f9b0a775..2a0dd330f 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -74,9 +74,9 @@ class ProjectResource( @PostMapping("/projects") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity { + fun createProject(@RequestBody @Valid projectDto: ProjectDTO?): ResponseEntity { log.debug("REST request to save Project : {}", projectDto) - val org = projectDto!!.organization + val org = projectDto?.organization if (org?.name == null) { throw BadRequestException( "Organization must be provided", @@ -93,7 +93,7 @@ class ProjectResource( ENTITY_NAME, "idexists", "A new project cannot already have an ID" ) ) - .body(null) + .body(null) } if (projectRepository.findOneWithEagerRelationshipsByName(projectDto.projectName) != null) { return ResponseEntity.badRequest() @@ -102,7 +102,7 @@ class ProjectResource( ENTITY_NAME, "nameexists", "A project with this name already exists" ) ) - .body(null) + .body(null) } val result = projectService.save(projectDto) return ResponseEntity.created(ResourceUriService.getUri(result)) @@ -112,7 +112,7 @@ class ProjectResource( result.projectName ) ) - .body(result) + .body(result) } /** @@ -127,7 +127,7 @@ class ProjectResource( @PutMapping("/projects") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun updateProject(@RequestBody projectDto: @Valid ProjectDTO?): ResponseEntity {log.debug("REST request to update Project : {}", projectDto) + fun updateProject(@RequestBody @Valid projectDto: ProjectDTO?): ResponseEntity {log.debug("REST request to update Project : {}", projectDto) if (projectDto?.id == null) { return createProject(projectDto) } @@ -366,7 +366,7 @@ class ProjectResource( NotAuthorizedException::class ) fun getAllSubjects( - subjectCriteria: @Valid SubjectCriteria? + @Valid subjectCriteria: SubjectCriteria? ): ResponseEntity> { authService.checkScope(Permission.SUBJECT_READ) diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index 63870f3e9..6a3815e9b 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -25,7 +25,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -42,14 +41,17 @@ import javax.servlet.ServletException @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser internal open class OrganizationResourceIntTest( + @Autowired private val organizationResource: OrganizationResource, + + @Autowired private val organizationService: OrganizationService, + @Autowired private val authService: AuthService, + @Autowired private val organizationMapper: OrganizationMapper, @Autowired private val organizationRepository: OrganizationRepository, - @Autowired private val organizationService: OrganizationService, @Autowired private val projectRepository: ProjectRepository, @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val authService: AuthService ) { private lateinit var restOrganizationMockMvc: MockMvc private lateinit var organization: Organization @@ -58,19 +60,16 @@ internal open class OrganizationResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val orgResource = OrganizationResource() - ReflectionTestUtils - .setField(orgResource, "organizationService", organizationService) - ReflectionTestUtils.setField(orgResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) - restOrganizationMockMvc = MockMvcBuilders.standaloneSetup(orgResource) + restOrganizationMockMvc = MockMvcBuilders.standaloneSetup(organizationResource) .setCustomArgumentResolvers(pageableArgumentResolver) .setControllerAdvice(exceptionTranslator) .setMessageConverters(jacksonMessageConverter) .addFilter(filter) .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) .build() + organization = this.createEntity() } @@ -137,113 +136,115 @@ internal open class OrganizationResourceIntTest( projectRepository.delete(project) } - @AfterEach - fun tearDown() { - val testOrg = organizationRepository.findOneByName( - organization.name!! + @Test + @Throws(Exception::class) + fun createOrganization() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) ) - if (testOrg != null) - organizationRepository.delete(testOrg) + .andExpect(MockMvcResultMatchers.status().isCreated()) + // Validate the Organization in the database + val savedOrg = orgDto.name?.let { organizationRepository.findOneByName(it) } + Assertions.assertThat(savedOrg).isNotNull() + } - @Test - @Throws(Exception::class) - fun createOrganization() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + @Test + @Throws(Exception::class) + fun createOrganizationWithExistingName() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isCreated()) - // Validate the Organization in the database - val savedOrg = organizationRepository.findOneByName(orgDto.name) - Assertions.assertThat(savedOrg).isNotNull() - } + // Second request should fail + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isConflict()) + } - @Test - @Throws(Exception::class) - fun createOrganizationWithExistingName() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) - // Second request should fail - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isConflict()) - } + @Test + @Throws(Exception::class) + //TODO this is covered by not using a nullable type + fun checkGroupNameIsRequired() { + val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + orgDto.name = "" + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.post("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(orgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + } - @Test - @Throws(Exception::class) - //TODO this is covered by not using a nullable type - fun checkGroupNameIsRequired() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - orgDto.name = "" - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.post("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(orgDto)) + @Test + @Throws(Exception::class) + fun getOrganization() { + // Initialize the database + organizationRepository.saveAndFlush(organization) + + // Get the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}", + organization.name ) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - } - + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("org1")) + } - @Test - @Throws(Exception::class) - fun getOrganization() { - // Initialize the database - organizationRepository.saveAndFlush(organization) + @Test + @Throws(Exception::class) + fun editOrganization() { + // Initialize the database + organizationRepository.saveAndFlush(organization) + val updatedOrgDto = organizationMapper + .organizationToOrganizationDTO(organization) + updatedOrgDto.location = "Other location" + + // Update the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.put("/api/organizations") + .contentType(TestUtil.APPLICATION_JSON_UTF8) + .content(TestUtil.convertObjectToJsonBytes(updatedOrgDto)) + ) + .andExpect(MockMvcResultMatchers.status().isOk()) - // Get the organization - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/organizations/{name}", - organization.name - ) + // Get the organization + restOrganizationMockMvc.perform( + MockMvcRequestBuilders.get( + "/api/organizations/{name}", + organization.name ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("org1")) - } + ) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.jsonPath("$.location").value("Other location")) + } + + @AfterEach + fun tearDown() { + val testOrg = organizationRepository.findOneByName( + organization.name!! + ) + if (testOrg != null) + organizationRepository.delete(testOrg) - @Test - @Throws(Exception::class) - fun editOrganization() { - // Initialize the database - organizationRepository.saveAndFlush(organization) - val updatedOrgDto = organizationMapper - .organizationToOrganizationDTO(organization) - updatedOrgDto.location = "Other location" - // Update the organization - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.put("/api/organizations") - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(updatedOrgDto)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - // Get the organization - restOrganizationMockMvc.perform( - MockMvcRequestBuilders.get( - "/api/organizations/{name}", - organization.name - ) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.jsonPath("$.location").value("Other location")) - } } diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt index 9a1decae5..a2d835205 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt @@ -13,6 +13,7 @@ import org.radarbase.management.domain.Project import org.radarbase.management.domain.enumeration.ProjectStatus import org.radarbase.management.repository.OrganizationRepository import org.radarbase.management.repository.ProjectRepository +import org.radarbase.management.service.dto.ProjectDTO import org.radarbase.management.service.mapper.ProjectMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired @@ -144,7 +145,8 @@ internal open class ProjectResourceIntTest( project.projectName = null // Create the Project, which fails. - val projectDto = projectMapper.projectToProjectDTO(project) + val projectDto: ProjectDTO? = projectMapper.projectToProjectDTO(project) + val projectt: Project? = projectMapper.projectDTOToProject(projectDto) restProjectMockMvc.perform( MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -184,7 +186,7 @@ internal open class ProjectResourceIntTest( project.location = null // Create the Project, which fails. - val projectDto = projectMapper.projectToProjectDTO(project) + val projectDto: ProjectDTO? = projectMapper.projectToProjectDTO(project) restProjectMockMvc.perform( MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -425,6 +427,7 @@ internal open class ProjectResourceIntTest( val organization = Organization() organization.id = 1L organization.name = "main" + organization.description = "test" return Project() .projectName(DEFAULT_PROJECT_NAME) .description(DEFAULT_DESCRIPTION) From 06f2aa7845c5f03bc491ac76bf0b84b4676063a0 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 12:01:54 +0100 Subject: [PATCH 107/158] move validation annotations and constraint annotations so that they actually annotate the fields/parameters rather than the types (?) --- .../radarbase/management/domain/Authority.kt | 10 +++--- .../org/radarbase/management/domain/Group.kt | 2 +- .../radarbase/management/domain/MetaToken.kt | 10 +++--- .../management/domain/Organization.kt | 6 ++-- .../management/domain/PersistentAuditEvent.kt | 2 +- .../radarbase/management/domain/Project.kt | 6 ++-- .../org/radarbase/management/domain/Source.kt | 8 ++--- .../radarbase/management/domain/SourceData.kt | 4 +-- .../radarbase/management/domain/SourceType.kt | 10 +++--- .../radarbase/management/domain/Subject.kt | 2 +- .../org/radarbase/management/domain/User.kt | 18 +++++----- .../management/repository/SourceRepository.kt | 2 +- .../management/service/RevisionService.kt | 2 +- .../management/service/SourceTypeService.kt | 4 +-- .../management/service/dto/AttributeMapDTO.kt | 8 ++--- .../service/dto/ClientDetailsDTO.kt | 2 +- .../management/service/dto/GroupDTO.kt | 2 +- .../management/service/dto/OrganizationDTO.kt | 6 ++-- .../management/service/dto/SourceDTO.kt | 6 ++-- .../management/service/dto/SourceTypeDTO.kt | 10 +++--- .../management/service/mapper/UserMapper.kt | 4 +-- .../management/web/rest/AccountResource.kt | 2 +- .../management/web/rest/GroupResource.kt | 2 +- .../web/rest/OAuthClientsResource.kt | 2 +- .../web/rest/OrganizationResource.kt | 4 +-- .../management/web/rest/ProjectResource.kt | 4 +-- .../management/web/rest/RoleResource.kt | 4 +-- .../management/web/rest/SourceDataResource.kt | 4 +-- .../management/web/rest/SourceResource.kt | 4 +-- .../management/web/rest/SourceTypeResource.kt | 36 +++++++++---------- .../management/web/rest/SubjectResource.kt | 2 +- .../web/rest/criteria/SubjectCriteria.kt | 3 +- .../web/rest/criteria/SubjectSortOrder.kt | 12 +++---- .../web/rest/ProjectResourceIntTest.kt | 10 +++--- .../web/rest/SubjectResourceIntTest.kt | 6 ++-- 35 files changed, 110 insertions(+), 109 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Authority.kt b/src/main/java/org/radarbase/management/domain/Authority.kt index 773957f64..a98a1b664 100644 --- a/src/main/java/org/radarbase/management/domain/Authority.kt +++ b/src/main/java/org/radarbase/management/domain/Authority.kt @@ -25,7 +25,7 @@ class Authority : Serializable { @JvmField @Id @Column(length = 50) - var name: @NotNull @Size(min = 0, max = 50) @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Size(min = 0, max = 50) @Pattern(regexp = Constants.ENTITY_ID_REGEX) var name: String? = null constructor() @@ -36,14 +36,14 @@ class Authority : Serializable { constructor(role: RoleAuthority) : this(role.authority) - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val authority = o as Authority + val authority = other as Authority return if (name == null || authority.name == null) { false } else name == authority.name diff --git a/src/main/java/org/radarbase/management/domain/Group.kt b/src/main/java/org/radarbase/management/domain/Group.kt index 1f527bdf9..71d2810e3 100644 --- a/src/main/java/org/radarbase/management/domain/Group.kt +++ b/src/main/java/org/radarbase/management/domain/Group.kt @@ -40,7 +40,7 @@ class Group : AbstractEntity(), Serializable { @JvmField @Column(name = "name", length = 50, nullable = false) - var name: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) var name: String? = null @JvmField @JsonIgnore diff --git a/src/main/java/org/radarbase/management/domain/MetaToken.kt b/src/main/java/org/radarbase/management/domain/MetaToken.kt index 5980d8329..8cc4e0e45 100644 --- a/src/main/java/org/radarbase/management/domain/MetaToken.kt +++ b/src/main/java/org/radarbase/management/domain/MetaToken.kt @@ -36,7 +36,7 @@ class MetaToken : AbstractEntity() { override var id: Long? = null @Column(name = "token_name", nullable = false, unique = true) - var tokenName: @NotNull @Pattern(regexp = Constants.TOKEN_NAME_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.TOKEN_NAME_REGEX) var tokenName: String? = null private set @Column(name = "fetched", nullable = false) @@ -109,14 +109,14 @@ class MetaToken : AbstractEntity() { val isValid: Boolean get() = (persistent!! || !fetched!!) && Instant.now().isBefore(expiryDate) - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val metaToken = o as MetaToken + val metaToken = other as MetaToken return id == metaToken.id && tokenName == metaToken.tokenName && fetched == metaToken.fetched && expiryDate == metaToken.expiryDate && clientId == metaToken.clientId && subject == metaToken.subject && persistent == metaToken.persistent } diff --git a/src/main/java/org/radarbase/management/domain/Organization.kt b/src/main/java/org/radarbase/management/domain/Organization.kt index 44b94d2d4..283450a18 100644 --- a/src/main/java/org/radarbase/management/domain/Organization.kt +++ b/src/main/java/org/radarbase/management/domain/Organization.kt @@ -36,15 +36,15 @@ class Organization : AbstractEntity() { @JvmField @Column(name = "name", nullable = false, unique = true) - var name: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) var name: String? = null @JvmField @Column(name = "description", nullable = false) - var description: @NotNull String? = null + @NotNull var description: String? = null @JvmField @Column(name = "location", nullable = false) - var location: @NotNull String? = null + @NotNull var location: String? = null @JvmField @OneToMany(mappedBy = "organization") diff --git a/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt b/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt index 9f04a713f..7f58cfab1 100644 --- a/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt +++ b/src/main/java/org/radarbase/management/domain/PersistentAuditEvent.kt @@ -34,7 +34,7 @@ class PersistentAuditEvent : Serializable { @JvmField @Column(nullable = false) - var principal: @NotNull String? = null + @NotNull var principal: String? = null @JvmField @Column(name = "event_date") diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index f9c607091..3c142bc38 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -56,10 +56,10 @@ class Project : AbstractEntity(), Serializable { override var id: Long? = null @Column(name = "project_name", nullable = false, unique = true) - var projectName: @NotNull @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") String? = null + @NotNull @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") var projectName: String? = null @Column(name = "description", nullable = false) - var description: @NotNull String? = null + @NotNull var description: String? = null @JvmField @Column(name = "jhi_organization") @@ -72,7 +72,7 @@ class Project : AbstractEntity(), Serializable { @JvmField @Column(name = "location", nullable = false) - var location: @NotNull String? = null + @NotNull var location: String? = null @JvmField @Column(name = "start_date") diff --git a/src/main/java/org/radarbase/management/domain/Source.kt b/src/main/java/org/radarbase/management/domain/Source.kt index c409cca9e..15ea02d99 100644 --- a/src/main/java/org/radarbase/management/domain/Source.kt +++ b/src/main/java/org/radarbase/management/domain/Source.kt @@ -47,21 +47,21 @@ class Source : AbstractEntity, Serializable { // pass @JvmField @Column(name = "source_id", nullable = false, unique = true) - var sourceId: @NotNull UUID? = null + @NotNull var sourceId: UUID? = null @JvmField @Column(name = "source_name", nullable = false, unique = true) - var sourceName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) var sourceName: String? = null @JvmField @Column(name = "expected_source_name") var expectedSourceName: String? = null @Column(name = "assigned", nullable = false) - var assigned: @NotNull Boolean? = false + @NotNull var assigned: Boolean? = false @Column(name = "deleted", nullable = false) - var deleted: @NotNull Boolean = false + @NotNull var deleted: Boolean = false @JvmField @ManyToOne(fetch = FetchType.EAGER) diff --git a/src/main/java/org/radarbase/management/domain/SourceData.kt b/src/main/java/org/radarbase/management/domain/SourceData.kt index ce73c1df6..7ff379940 100644 --- a/src/main/java/org/radarbase/management/domain/SourceData.kt +++ b/src/main/java/org/radarbase/management/domain/SourceData.kt @@ -40,12 +40,12 @@ class SourceData : AbstractEntity(), Serializable { //SourceData type e.g. ACCELEROMETER, TEMPERATURE. @JvmField @Column(name = "source_data_type", nullable = false) - var sourceDataType: @NotNull String? = null + @NotNull var sourceDataType: String? = null // this will be the unique human readable identifier of @JvmField @Column(name = "source_data_name", nullable = false, unique = true) - var sourceDataName: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) var sourceDataName: String? = null //Default data frequency @JvmField diff --git a/src/main/java/org/radarbase/management/domain/SourceType.kt b/src/main/java/org/radarbase/management/domain/SourceType.kt index cb89cefd7..5e64cbfd4 100644 --- a/src/main/java/org/radarbase/management/domain/SourceType.kt +++ b/src/main/java/org/radarbase/management/domain/SourceType.kt @@ -44,7 +44,7 @@ class SourceType : AbstractEntity(), Serializable { @JvmField @Column(name = "producer") - var producer: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) var producer: String? = null @JvmField @Column(name = "name") @@ -64,19 +64,19 @@ class SourceType : AbstractEntity(), Serializable { @JvmField @Column(name = "model", nullable = false) - var model: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) var model: String? = null @JvmField @Column(name = "catalog_version", nullable = false) - var catalogVersion: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) String? = null + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) var catalogVersion: String? = null @JvmField @Column(name = "source_type_scope", nullable = false) - var sourceTypeScope: @NotNull String? = null + @NotNull var sourceTypeScope: String? = null @JvmField @Column(name = "dynamic_registration", nullable = false) - var canRegisterDynamically: @NotNull Boolean? = false + @NotNull var canRegisterDynamically: Boolean? = false @JvmField @set:JsonSetter(nulls = Nulls.AS_EMPTY) diff --git a/src/main/java/org/radarbase/management/domain/Subject.kt b/src/main/java/org/radarbase/management/domain/Subject.kt index 4fecfdce7..a86d547e7 100644 --- a/src/main/java/org/radarbase/management/domain/Subject.kt +++ b/src/main/java/org/radarbase/management/domain/Subject.kt @@ -64,7 +64,7 @@ class Subject( var externalId: String? = null @Column(name = "removed", nullable = false) - var removed: @NotNull Boolean = false + @NotNull var removed: Boolean = false @JvmField @OneToOne diff --git a/src/main/java/org/radarbase/management/domain/User.kt b/src/main/java/org/radarbase/management/domain/User.kt index a0bcd307b..a09bff588 100644 --- a/src/main/java/org/radarbase/management/domain/User.kt +++ b/src/main/java/org/radarbase/management/domain/User.kt @@ -47,42 +47,42 @@ class User : AbstractEntity(), Serializable { override var id: Long? = null @Column(length = 50, unique = true, nullable = false) - lateinit var login: @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) String + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) lateinit var login: String private set @JvmField @JsonIgnore @Column(name = "password_hash", length = 60) - var password: @NotNull @Size(min = 60, max = 60) String? = null + @NotNull @Size(min = 60, max = 60) var password: String? = null @JvmField @Column(name = "first_name", length = 50) - var firstName: @Size(max = 50) String? = null + @Size(max = 50) var firstName: String? = null @JvmField @Column(name = "last_name", length = 50) - var lastName: @Size(max = 50) String? = null + @Size(max = 50) var lastName: String? = null @JvmField @Column(length = 100, unique = true, nullable = true) - var email: @Email @Size(min = 5, max = 100) String? = null + @Email @Size(min = 5, max = 100) var email: String? = null @JvmField @Column(nullable = false) - var activated: @NotNull Boolean = false + @NotNull var activated: Boolean = false @JvmField @Column(name = "lang_key", length = 5) - var langKey: @Size(min = 2, max = 5) String? = null + @Size(min = 2, max = 5) var langKey: String? = null @JvmField @Column(name = "activation_key", length = 20) @JsonIgnore - var activationKey: @Size(max = 20) String? = null + @Size(max = 20) var activationKey: String? = null @JvmField @Column(name = "reset_key", length = 20) - var resetKey: @Size(max = 20) String? = null + @Size(max = 20) var resetKey: String? = null @JvmField @Column(name = "reset_date") diff --git a/src/main/java/org/radarbase/management/repository/SourceRepository.kt b/src/main/java/org/radarbase/management/repository/SourceRepository.kt index 4b5946480..fa23af0b9 100644 --- a/src/main/java/org/radarbase/management/repository/SourceRepository.kt +++ b/src/main/java/org/radarbase/management/repository/SourceRepository.kt @@ -61,5 +61,5 @@ interface SourceRepository : JpaRepository, RevisionRepository?): Function { + private fun getDtoMapper(@NotNull entity: Class<*>?): Function { return dtoMapperMap.computeIfAbsent(entity) { clazz: Class<*>? -> addMapperForClass(clazz) } } diff --git a/src/main/java/org/radarbase/management/service/SourceTypeService.kt b/src/main/java/org/radarbase/management/service/SourceTypeService.kt index f0025ff43..bc2c42ed6 100644 --- a/src/main/java/org/radarbase/management/service/SourceTypeService.kt +++ b/src/main/java/org/radarbase/management/service/SourceTypeService.kt @@ -95,8 +95,8 @@ open class SourceTypeService( * Fetch SourceType by producer and model. */ fun findByProducerAndModelAndVersion( - producer: @NotNull String, - model: @NotNull String, version: @NotNull String + @NotNull producer: String, + @NotNull model: String, @NotNull version: String ): SourceTypeDTO { log.debug( "Request to get SourceType by producer and model and version: {}, {}, {}", diff --git a/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt b/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt index 7f54176ee..1d8a01441 100644 --- a/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/AttributeMapDTO.kt @@ -7,14 +7,14 @@ import java.util.* */ class AttributeMapDTO @JvmOverloads constructor(var key: String? = null, var value: String? = null) { - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val attributeMapDto = o as AttributeMapDTO + val attributeMapDto = other as AttributeMapDTO return key == attributeMapDto.key && value == attributeMapDto.value } diff --git a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt index 98f7da1a6..1992b14e4 100644 --- a/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/ClientDetailsDTO.kt @@ -6,7 +6,7 @@ import javax.validation.constraints.NotNull * Created by dverbeec on 7/09/2017. */ class ClientDetailsDTO { - lateinit var clientId: @NotNull String + @NotNull var clientId: String? = null var clientSecret: String? = null var scope: Set? = null var resourceIds: Set? = null diff --git a/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt b/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt index 02463bb31..ca53db0a4 100644 --- a/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/GroupDTO.kt @@ -11,7 +11,7 @@ import javax.validation.constraints.NotNull class GroupDTO { var id: Long? = null var projectId: Long? = null - var name: @NotNull String? = null + @NotNull var name: String? = null override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt index 849448f77..06d2ef19e 100644 --- a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt @@ -11,9 +11,9 @@ import javax.validation.constraints.NotNull @JsonInclude(JsonInclude.Include.NON_NULL) class OrganizationDTO : Serializable { var id: Long? = null - var name: @NotNull String? = null - var description: @NotNull String? = null - var location: @NotNull String? = null + @NotNull var name: String? = null + @NotNull var description: String? = null + @NotNull var location: String? = null var projects: List = emptyList() override fun equals(other: Any?): Boolean { diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt index b7ff95330..c54f245d5 100644 --- a/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/SourceDTO.kt @@ -11,10 +11,10 @@ import javax.validation.constraints.NotNull class SourceDTO : Serializable { var id: Long? = null var sourceId: UUID? = null - lateinit var sourceName: @NotNull String + @NotNull var sourceName: String? = null var expectedSourceName: String? = null - var assigned: @NotNull Boolean? = null - lateinit var sourceType: @NotNull SourceTypeDTO + @NotNull var assigned: Boolean? = null + @NotNull var sourceType: SourceTypeDTO? = null var subjectLogin: String? = null @JsonInclude(JsonInclude.Include.NON_NULL) diff --git a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt index ff5fe709e..0168170e2 100644 --- a/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/SourceTypeDTO.kt @@ -13,11 +13,11 @@ import javax.validation.constraints.NotNull @JsonInclude(JsonInclude.Include.NON_NULL) class SourceTypeDTO : Serializable { var id: Long? = null - lateinit var producer: @NotNull String - lateinit var model: @NotNull String - lateinit var catalogVersion: @NotNull String - lateinit var sourceTypeScope: @NotNull String - var canRegisterDynamically: @NotNull Boolean = false + @NotNull var producer: String? = null + @NotNull var model: String? = null + @NotNull var catalogVersion: String? = null + @NotNull var sourceTypeScope: String? = null + @NotNull var canRegisterDynamically: Boolean = false var name: String? = null var description: String? = null var assessmentType: String? = null diff --git a/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt index d5e652f2d..8296a076f 100644 --- a/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt +++ b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt @@ -46,10 +46,10 @@ interface UserMapper { * @param authorities the authorities to map * @return the set of strings if authorities is not null, null otherwise */ - fun map(authorities: Set): Set<@NotNull @Size( + fun map(authorities: Set): @NotNull @Size( max = 50, min = 0 - ) @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") String> { + ) @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") Set { return authorities.mapNotNull { it.name }.toSet() } diff --git a/src/main/java/org/radarbase/management/web/rest/AccountResource.kt b/src/main/java/org/radarbase/management/web/rest/AccountResource.kt index 852d433a1..d747595c6 100644 --- a/src/main/java/org/radarbase/management/web/rest/AccountResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/AccountResource.kt @@ -139,7 +139,7 @@ class AccountResource( @Timed @Throws(NotAuthorizedException::class) fun saveAccount( - @RequestBody userDto: @Valid UserDTO, + @RequestBody @Valid userDto: UserDTO, authentication: Authentication ): ResponseEntity { authService.checkPermission(Permission.USER_UPDATE, { e: EntityDetails -> diff --git a/src/main/java/org/radarbase/management/web/rest/GroupResource.kt b/src/main/java/org/radarbase/management/web/rest/GroupResource.kt index 22ab46839..dbd0ef7df 100644 --- a/src/main/java/org/radarbase/management/web/rest/GroupResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/GroupResource.kt @@ -54,7 +54,7 @@ class GroupResource { @Throws(NotAuthorizedException::class) fun createGroup( @PathVariable projectName: String?, - @RequestBody groupDto: @Valid GroupDTO? + @RequestBody @Valid groupDto: GroupDTO? ): ResponseEntity { authService!!.checkPermission(Permission.PROJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) val groupDtoResult = groupService!!.createGroup(projectName!!, groupDto!!) diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt index 71bdf0406..600db7e5f 100644 --- a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt @@ -120,7 +120,7 @@ class OAuthClientsResource { @PutMapping("/oauth-clients") @Timed @Throws(NotAuthorizedException::class) - fun updateOAuthClient(@RequestBody clientDetailsDto: @Valid ClientDetailsDTO?): ResponseEntity { + fun updateOAuthClient(@RequestBody @Valid clientDetailsDto: ClientDetailsDTO?): ResponseEntity { authService!!.checkPermission(Permission.OAUTHCLIENTS_UPDATE) // getOAuthClient checks if the id exists OAuthClientService.checkProtected(oAuthClientService!!.findOneByClientId(clientDetailsDto!!.clientId)) diff --git a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt index 53071da24..7f87ab0cc 100644 --- a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt @@ -53,7 +53,7 @@ class OrganizationResource( @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) fun createOrganization( - @RequestBody organizationDto: @Valid OrganizationDTO? + @RequestBody @Valid organizationDto: OrganizationDTO? ): ResponseEntity { log.debug("REST request to save Organization : {}", organizationDto) authService.checkPermission(Permission.ORGANIZATION_CREATE) @@ -105,7 +105,7 @@ class OrganizationResource( @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) fun updateOrganization( - @RequestBody organizationDto: @Valid OrganizationDTO? + @RequestBody @Valid organizationDto: OrganizationDTO? ): ResponseEntity { log.debug("REST request to update Organization : {}", organizationDto) if (organizationDto!!.id == null) { diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index 2a0dd330f..725e15a88 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -367,7 +367,7 @@ class ProjectResource( ) fun getAllSubjects( @Valid subjectCriteria: SubjectCriteria? - ): ResponseEntity> { + ): ResponseEntity> { authService.checkScope(Permission.SUBJECT_READ) @@ -394,7 +394,7 @@ class ProjectResource( val headers = PaginationUtil.generateSubjectPaginationHttpHeaders( page, baseUri, subjectCriteria ) - return ResponseEntity(page.content, headers, HttpStatus.OK) + return ResponseEntity(page.content.filterNotNull(), headers, HttpStatus.OK) } companion object { diff --git a/src/main/java/org/radarbase/management/web/rest/RoleResource.kt b/src/main/java/org/radarbase/management/web/rest/RoleResource.kt index ed4cb384a..930f5dcf1 100644 --- a/src/main/java/org/radarbase/management/web/rest/RoleResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/RoleResource.kt @@ -51,7 +51,7 @@ class RoleResource( @Throws( URISyntaxException::class, NotAuthorizedException::class ) - fun createRole(@RequestBody roleDto: @Valid RoleDTO): ResponseEntity { + fun createRole(@RequestBody @Valid roleDto: RoleDTO): ResponseEntity { log.debug("REST request to save Role : {}", roleDto) authService.checkPermission(Permission.ROLE_CREATE, { e: EntityDetails -> e.project = roleDto.projectName @@ -85,7 +85,7 @@ class RoleResource( @Throws( URISyntaxException::class, NotAuthorizedException::class ) - fun updateRole(@RequestBody roleDto: @Valid RoleDTO): ResponseEntity { + fun updateRole(@RequestBody @Valid roleDto: RoleDTO): ResponseEntity { log.debug("REST request to update Role : {}", roleDto) if (roleDto.id == null) { return createRole(roleDto) diff --git a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt index 10a99b4ff..cbbbc6090 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt @@ -55,7 +55,7 @@ class SourceDataResource( @PostMapping("/source-data") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createSourceData(@RequestBody sourceDataDto: @Valid SourceDataDTO?): ResponseEntity { + fun createSourceData(@RequestBody @Valid sourceDataDto: SourceDataDTO?): ResponseEntity { log.debug("REST request to save SourceData : {}", sourceDataDto) authService.checkPermission(Permission.SOURCEDATA_CREATE) if (sourceDataDto!!.id != null) { @@ -92,7 +92,7 @@ class SourceDataResource( @PutMapping("/source-data") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun updateSourceData(@RequestBody sourceDataDto: @Valid SourceDataDTO?): ResponseEntity { + fun updateSourceData(@RequestBody @Valid sourceDataDto: SourceDataDTO?): ResponseEntity { log.debug("REST request to update SourceData : {}", sourceDataDto) if (sourceDataDto!!.id == null) { return createSourceData(sourceDataDto) diff --git a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt index 856c3b61b..bcfcad5d0 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceResource.kt @@ -55,7 +55,7 @@ class SourceResource( @PostMapping("/sources") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createSource(@RequestBody sourceDto: @Valid SourceDTO?): ResponseEntity { + fun createSource(@RequestBody @Valid sourceDto: SourceDTO?): ResponseEntity { log.debug("REST request to save Source : {}", sourceDto) val project = sourceDto!!.project authService.checkPermission(Permission.SOURCE_CREATE, { e: EntityDetails -> @@ -110,7 +110,7 @@ class SourceResource( @PutMapping("/sources") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun updateSource(@RequestBody sourceDto: @Valid SourceDTO): ResponseEntity { + fun updateSource(@RequestBody @Valid sourceDto: SourceDTO): ResponseEntity { log.debug("REST request to update Source : {}", sourceDto) if (sourceDto.id == null) { return createSource(sourceDto) diff --git a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt index 5a34bac73..b94d22046 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt @@ -59,9 +59,9 @@ class SourceTypeResource( @PostMapping("/source-types") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createSourceType(@RequestBody sourceTypeDto: @Valid SourceTypeDTO?): ResponseEntity { + fun createSourceType(@RequestBody @Valid sourceTypeDto: SourceTypeDTO?): ResponseEntity { log.debug("REST request to save SourceType : {}", sourceTypeDto) - authService!!.checkPermission(Permission.SOURCETYPE_CREATE) + authService.checkPermission(Permission.SOURCETYPE_CREATE) if (sourceTypeDto!!.id != null) { return ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( @@ -72,8 +72,8 @@ class SourceTypeResource( } val existing: SourceType? = sourceTypeRepository .findOneWithEagerRelationshipsByProducerAndModelAndVersion( - sourceTypeDto.producer, sourceTypeDto.model, - sourceTypeDto.catalogVersion + sourceTypeDto.producer!!, sourceTypeDto.model!!, + sourceTypeDto.catalogVersion!! ) if (existing != null) { val errorParams: MutableMap = HashMap() @@ -88,7 +88,7 @@ class SourceTypeResource( ErrorConstants.ERR_SOURCE_TYPE_EXISTS, errorParams ) } - val result = sourceTypeService!!.save(sourceTypeDto) + val result = sourceTypeService.save(sourceTypeDto) return ResponseEntity.created(getUri(result)) .headers(HeaderUtil.createEntityCreationAlert(EntityName.SOURCE_TYPE, displayName(result))) .body(result) @@ -106,13 +106,13 @@ class SourceTypeResource( @PutMapping("/source-types") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun updateSourceType(@RequestBody sourceTypeDto: @Valid SourceTypeDTO?): ResponseEntity { + fun updateSourceType(@RequestBody @Valid sourceTypeDto: SourceTypeDTO?): ResponseEntity { log.debug("REST request to update SourceType : {}", sourceTypeDto) if (sourceTypeDto!!.id == null) { return createSourceType(sourceTypeDto) } - authService!!.checkPermission(Permission.SOURCETYPE_UPDATE) - val result = sourceTypeService!!.save(sourceTypeDto) + authService.checkPermission(Permission.SOURCETYPE_UPDATE) + val result = sourceTypeService.save(sourceTypeDto) return ResponseEntity.ok() .headers( HeaderUtil.createEntityUpdateAlert(EntityName.SOURCE_TYPE, displayName(sourceTypeDto)) @@ -132,8 +132,8 @@ class SourceTypeResource( fun getAllSourceTypes( @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable? ): ResponseEntity> { - authService!!.checkPermission(Permission.SOURCETYPE_READ) - val page = sourceTypeService!!.findAll(pageable!!) + authService.checkPermission(Permission.SOURCETYPE_READ) + val page = sourceTypeService.findAll(pageable!!) val headers = PaginationUtil .generatePaginationHttpHeaders(page, "/api/source-types") return ResponseEntity(page.content, headers, HttpStatus.OK) @@ -151,8 +151,8 @@ class SourceTypeResource( NotAuthorizedException::class ) fun getSourceTypes(@PathVariable producer: String?): ResponseEntity> { - authService!!.checkPermission(Permission.SOURCETYPE_READ) - return ResponseEntity.ok(sourceTypeService!!.findByProducer(producer!!)) + authService.checkPermission(Permission.SOURCETYPE_READ) + return ResponseEntity.ok(sourceTypeService.findByProducer(producer!!)) } /** @@ -175,9 +175,9 @@ class SourceTypeResource( @PathVariable producer: String?, @PathVariable model: String? ): ResponseEntity> { - authService!!.checkPermission(Permission.SOURCETYPE_READ) + authService.checkPermission(Permission.SOURCETYPE_READ) return ResponseEntity.ok( - sourceTypeService!!.findByProducerAndModel( + sourceTypeService.findByProducerAndModel( producer!!, model!! ) ) @@ -203,10 +203,10 @@ class SourceTypeResource( @PathVariable producer: String?, @PathVariable model: String?, @PathVariable version: String? ): ResponseEntity { - authService!!.checkPermission(Permission.SOURCETYPE_READ) + authService.checkPermission(Permission.SOURCETYPE_READ) return ResponseUtil.wrapOrNotFound( Optional.ofNullable( - sourceTypeService!!.findByProducerAndModelAndVersion(producer!!, model!!, version!!) + sourceTypeService.findByProducerAndModelAndVersion(producer!!, model!!, version!!) ) ) } @@ -232,13 +232,13 @@ class SourceTypeResource( @PathVariable producer: String?, @PathVariable model: String?, @PathVariable version: String? ): ResponseEntity { - authService!!.checkPermission(Permission.SOURCETYPE_DELETE) + authService.checkPermission(Permission.SOURCETYPE_DELETE) val sourceTypeDto = sourceTypeService .findByProducerAndModelAndVersion(producer!!, model!!, version!!) if (Objects.isNull(sourceTypeDto)) { return ResponseEntity.notFound().build() } - val projects = sourceTypeService!!.findProjectsBySourceType( + val projects = sourceTypeService.findProjectsBySourceType( producer, model, version ) diff --git a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt index e83ff61fb..13aede526 100644 --- a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt @@ -197,7 +197,7 @@ class SubjectResource( @Timed @Throws(NotAuthorizedException::class) fun getAllSubjects( - subjectCriteria: @Valid SubjectCriteria? + @Valid subjectCriteria: SubjectCriteria? ): ResponseEntity>? { val projectName = subjectCriteria!!.projectName authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> e.project(projectName) }) diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt index 1ec053778..312a35231 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt @@ -29,7 +29,8 @@ class SubjectCriteria { @Transient private var parsedSort: List? = null - val pageable: @NotNull Pageable + @get:NotNull + val pageable: Pageable /** Get the criteria paging settings, excluding sorting. */ get() = PageRequest.of(page, size) diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt index c2cad7a04..69932d4fa 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectSortOrder.kt @@ -13,22 +13,22 @@ import java.util.* import javax.validation.constraints.NotNull class SubjectSortOrder @JvmOverloads constructor( - val sortBy: @NotNull SubjectSortBy, - var direction: @NotNull Sort.Direction = Sort.Direction.ASC + @NotNull val sortBy: SubjectSortBy, + @NotNull var direction: Sort.Direction = Sort.Direction.ASC ) { override fun toString(): String { return sortBy.name + ',' + direction.name } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val that = o as SubjectSortOrder + val that = other as SubjectSortOrder return sortBy == that.sortBy && direction == that.direction } diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt index a2d835205..230042584 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt @@ -202,7 +202,7 @@ internal open class ProjectResourceIntTest( @Test open fun allProjects() { // Initialize the database - projectRepository.saveAndFlush(project) + projectRepository.saveAndFlush(project) // Get all the projectList restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects?sort=id,desc")) @@ -269,7 +269,7 @@ internal open class ProjectResourceIntTest( @Throws(Exception::class) open fun getProject() { // Initialize the database - projectRepository.saveAndFlush(project) + projectRepository.saveAndFlush(project) // Get the project restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects/{projectName}", project.projectName)) @@ -299,7 +299,7 @@ internal open class ProjectResourceIntTest( @Throws(Exception::class) open fun updateProject() { // Initialize the database - projectRepository.saveAndFlush(project) + projectRepository.saveAndFlush(project) val org = Organization() org.name = "org1" org.description = "Test Organization 1" @@ -328,7 +328,7 @@ internal open class ProjectResourceIntTest( // Validate the Project in the database val projectList = projectRepository.findAll() - assertThat(projectList).hasSize(databaseSizeBeforeUpdate) + assertThat(projectList).hasSize(databaseSizeBeforeUpdate) val testProject = projectList[projectList.size - 1] assertThat(testProject!!.projectName).isEqualTo(UPDATED_PROJECT_NAME) assertThat(testProject.description).isEqualTo(UPDATED_DESCRIPTION) @@ -370,7 +370,7 @@ internal open class ProjectResourceIntTest( @Throws(Exception::class) open fun deleteProject() { // Initialize the database - projectRepository.saveAndFlush(project) + projectRepository.saveAndFlush(project) val databaseSizeBeforeDelete = projectRepository.findAll().size // Get the project diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index 4b48e9a80..be76669ca 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -423,7 +423,7 @@ internal open class SubjectResourceIntTest( val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) - .sourceTypeId(createdSource.sourceType.id).sourceId(createdSource.sourceId!!) + .sourceTypeId(createdSource.sourceType?.id).sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) @@ -449,7 +449,7 @@ internal open class SubjectResourceIntTest( val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) - .sourceTypeId(createdSource.sourceType.id).sourceId(createdSource.sourceId!!) + .sourceTypeId(createdSource.sourceType?.id).sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) @@ -475,7 +475,7 @@ internal open class SubjectResourceIntTest( val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) - .sourceTypeId(createdSource.sourceType.id).sourceId(createdSource.sourceId!!) + .sourceTypeId(createdSource.sourceType?.id).sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) From 21c568a0c84d2ec3787f87dcda402d842343a469 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 21:57:00 +0100 Subject: [PATCH 108/158] simplification of Authority.kt. all AccountResourceIntTest.kt tests passing --- build.gradle | 5 +- gradle.properties | 1 + managementportal-client/build.gradle | 2 +- .../radarbase/management/domain/Authority.kt | 24 +++----- .../org/radarbase/management/domain/User.kt | 18 +++--- .../management/repository/UserRepository.kt | 2 +- .../security/DomainUserDetailsService.kt | 3 +- .../management/service/MailService.kt | 47 +++++++-------- .../management/service/OAuthClientService.kt | 3 +- .../management/service/RoleService.kt | 10 ++-- .../management/service/SubjectService.kt | 8 +-- .../management/service/dto/UserDTO.kt | 10 ++-- .../management/service/mapper/UserMapper.kt | 20 ------- .../mapper/decorator/UserMapperDecorator.kt | 8 +-- .../management/web/rest/AccountResource.kt | 9 +-- .../management/web/rest/UserResource.kt | 4 +- .../JwtAuthenticationFilterIntTest.kt | 13 ++--- .../security/SecurityUtilsUnitTest.kt | 8 +++ .../service/MetaTokenServiceTest.kt | 4 +- .../management/service/SubjectServiceTest.kt | 4 +- .../management/service/UserServiceIntTest.kt | 30 ++++------ .../web/rest/AccountResourceIntTest.kt | 58 ++++++++++--------- .../web/rest/OrganizationResourceIntTest.kt | 2 +- .../web/rest/ProfileInfoResourceIntTest.kt | 23 ++++---- .../web/rest/SourceResourceIntTest.kt | 32 +++++----- .../web/rest/UserResourceIntTest.kt | 44 ++++++-------- 26 files changed, 174 insertions(+), 218 deletions(-) diff --git a/build.gradle b/build.gradle index e03b2b71a..3ddc5d791 100644 --- a/build.gradle +++ b/build.gradle @@ -205,6 +205,9 @@ dependencies { implementation project(':radar-auth') implementation "org.springframework.data:spring-data-envers" + implementation "org.mockito:mockito-core:$mockito_version" + implementation "org.mockito.kotlin:mockito-kotlin:${mockito_kotlin_version}" + runtimeOnly("jakarta.xml.bind:jakarta.xml.bind-api:${javax_xml_bind_version}") runtimeOnly("org.glassfish.jaxb:jaxb-core:${javax_jaxb_core_version}") runtimeOnly("org.glassfish.jaxb:jaxb-runtime:${javax_jaxb_runtime_version}") @@ -221,7 +224,7 @@ dependencies { testImplementation "org.springframework.boot:spring-boot-test" testImplementation "org.assertj:assertj-core:${assertj_version}" testImplementation "org.junit.jupiter:junit-jupiter-api" - testImplementation "org.mockito:mockito-core:$mockito_version" + testImplementation "org.mockito.kotlin:mockito-kotlin:${mockito_kotlin_version}" testImplementation "com.mattbertolini:liquibase-slf4j:${liquibase_slf4j_version}" testImplementation "org.hamcrest:hamcrest-library" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine" diff --git a/gradle.properties b/gradle.properties index d36af40f2..cfedaf791 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,6 +22,7 @@ javax_jaxb_core_version=2.3.0.1 javax_jaxb_runtime_version=2.3.8 javax_activation=1.1.1 mockito_version=4.8.1 +mockito_kotlin_version=5.1.0 slf4j_version=2.0.7 logback_version=1.4.11 oauth_jwt_version=4.4.0 diff --git a/managementportal-client/build.gradle b/managementportal-client/build.gradle index 4e01cb691..17811d741 100644 --- a/managementportal-client/build.gradle +++ b/managementportal-client/build.gradle @@ -39,7 +39,7 @@ dependencies { testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test") testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junit_version testImplementation group: 'com.github.tomakehurst', name: 'wiremock', version: '2.27.2' - testImplementation group: 'org.mockito', name: 'mockito-core', version: mockito_version + testImplementation group: 'org.mockito.kotlin', name: 'mockito-kotlin', version: mockito_kotlin_version testImplementation group: 'org.hamcrest', name: 'hamcrest', version: '2.2' testRuntimeOnly group: 'org.slf4j', name: 'slf4j-simple', version: slf4j_version diff --git a/src/main/java/org/radarbase/management/domain/Authority.kt b/src/main/java/org/radarbase/management/domain/Authority.kt index a98a1b664..7a67aae0a 100644 --- a/src/main/java/org/radarbase/management/domain/Authority.kt +++ b/src/main/java/org/radarbase/management/domain/Authority.kt @@ -21,18 +21,10 @@ import javax.validation.constraints.Size @Audited @Table(name = "radar_authority") @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) -class Authority : Serializable { - @JvmField - @Id - @Column(length = 50) - @NotNull @Size(min = 0, max = 50) @Pattern(regexp = Constants.ENTITY_ID_REGEX) var name: String? = null - - constructor() - - constructor(authorityName: String?) { - name = authorityName - this.name = authorityName - } +data class Authority(@JvmField + @Id + @Column(length = 50) + @NotNull @Size(min = 0, max = 50) @Pattern(regexp = Constants.ENTITY_ID_REGEX) var name: String? = null) : Serializable { constructor(role: RoleAuthority) : this(role.authority) @@ -54,12 +46,14 @@ class Authority : Serializable { } override fun toString(): String { - return ("Authority{" - + "name='" + name + '\'' - + "}") + return name.toString() } companion object { private const val serialVersionUID = 1L } + + fun asString() : String? { + return name + } } diff --git a/src/main/java/org/radarbase/management/domain/User.kt b/src/main/java/org/radarbase/management/domain/User.kt index a09bff588..a780da221 100644 --- a/src/main/java/org/radarbase/management/domain/User.kt +++ b/src/main/java/org/radarbase/management/domain/User.kt @@ -47,7 +47,7 @@ class User : AbstractEntity(), Serializable { override var id: Long? = null @Column(length = 50, unique = true, nullable = false) - @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) lateinit var login: String + @NotNull @Pattern(regexp = Constants.ENTITY_ID_REGEX) @Size(min = 1, max = 50) var login: String? = null private set @JvmField @@ -88,8 +88,14 @@ class User : AbstractEntity(), Serializable { @Column(name = "reset_date") var resetDate: ZonedDateTime? = null + /** Authorities that a user has. */ + val authorities: Set? + get() { + return roles?.mapNotNull { obj: Role? -> obj?.authority?.name }?.toSet() + } + @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @ManyToMany(fetch = FetchType.EAGER) @JoinTable( name = "role_users", @@ -105,14 +111,10 @@ class User : AbstractEntity(), Serializable { var roles: MutableSet? = HashSet() //Lowercase the login before saving it in database - fun setLogin(login: String) { - this.login = login.lowercase() + fun setLogin(login: String?) { + this.login = login?.lowercase() } - val authorities: Set? - /** Authorities that a user has. */ - get() = roles?.map { obj: Role? -> obj?.authority }?.toSet() - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/src/main/java/org/radarbase/management/repository/UserRepository.kt b/src/main/java/org/radarbase/management/repository/UserRepository.kt index f1071863e..3543e5495 100644 --- a/src/main/java/org/radarbase/management/repository/UserRepository.kt +++ b/src/main/java/org/radarbase/management/repository/UserRepository.kt @@ -35,7 +35,7 @@ interface UserRepository : JpaRepository, RevisionRepository SimpleGrantedAuthority(authority?.name) } + user.authorities!!.map { authority -> SimpleGrantedAuthority(authority) } return User( lowercaseLogin, user.password, diff --git a/src/main/java/org/radarbase/management/service/MailService.kt b/src/main/java/org/radarbase/management/service/MailService.kt index 3f894424d..671ec5277 100644 --- a/src/main/java/org/radarbase/management/service/MailService.kt +++ b/src/main/java/org/radarbase/management/service/MailService.kt @@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.context.MessageSource import org.springframework.mail.javamail.JavaMailSender +import org.springframework.mail.javamail.JavaMailSenderImpl import org.springframework.mail.javamail.MimeMessageHelper import org.springframework.scheduling.annotation.Async import org.springframework.stereotype.Service @@ -21,18 +22,12 @@ import java.util.* * We use the @Async annotation to send emails asynchronously. */ @Service -class MailService { - @Autowired - private val managementPortalProperties: ManagementPortalProperties? = null - - @Autowired - private val javaMailSender: JavaMailSender? = null - - @Autowired - private val messageSource: MessageSource? = null - - @Autowired - private val templateEngine: SpringTemplateEngine? = null +class MailService( + @Autowired private val managementPortalProperties: ManagementPortalProperties, + @Autowired private val javaMailSender: JavaMailSender, + @Autowired private val messageSource: MessageSource, + @Autowired private val templateEngine: SpringTemplateEngine, +) { /** * Send an email. @@ -53,14 +48,14 @@ class MailService { ) // Prepare message using a Spring helper - val mimeMessage = javaMailSender!!.createMimeMessage() + val mimeMessage = javaMailSender.createMimeMessage() try { val message = MimeMessageHelper( mimeMessage, isMultipart, StandardCharsets.UTF_8.name() ) message.setTo(to) - message.setFrom(managementPortalProperties!!.mail.from) + message.setFrom(managementPortalProperties.mail.from) message.setSubject(subject) message.setText(content, isHtml) javaMailSender.send(mimeMessage) @@ -82,10 +77,10 @@ class MailService { context.setVariable(USER, user) context.setVariable( BASE_URL, - managementPortalProperties!!.common.managementPortalBaseUrl + managementPortalProperties.common.managementPortalBaseUrl ) - val content = templateEngine!!.process("activationEmail", context) - val subject = messageSource!!.getMessage("email.activation.title", null, locale) + val content = templateEngine.process("activationEmail", context) + val subject = messageSource.getMessage("email.activation.title", null, locale) sendEmail(user.email, subject, content, false, true) } @@ -101,11 +96,11 @@ class MailService { context.setVariable(USER, user) context.setVariable( BASE_URL, - managementPortalProperties!!.common.managementPortalBaseUrl + managementPortalProperties.common.managementPortalBaseUrl ) context.setVariable(EXPIRY, Duration.ofSeconds(duration).toHours()) - val content = templateEngine!!.process("creationEmail", context) - val subject = messageSource!!.getMessage("email.activation.title", null, locale) + val content = templateEngine.process("creationEmail", context) + val subject = messageSource.getMessage("email.activation.title", null, locale) sendEmail(user.email, subject, content, false, true) } @@ -122,10 +117,10 @@ class MailService { context.setVariable(USER, user) context.setVariable( BASE_URL, - managementPortalProperties!!.common.managementPortalBaseUrl + managementPortalProperties.common.managementPortalBaseUrl ) - val content = templateEngine!!.process("creationEmail", context) - val subject = messageSource!!.getMessage("email.activation.title", null, locale) + val content = templateEngine.process("creationEmail", context) + val subject = messageSource.getMessage("email.activation.title", null, locale) sendEmail(email, subject, content, false, true) } @@ -141,10 +136,10 @@ class MailService { context.setVariable(USER, user) context.setVariable( BASE_URL, - managementPortalProperties!!.common.managementPortalBaseUrl + managementPortalProperties.common.managementPortalBaseUrl ) - val content = templateEngine!!.process("passwordResetEmail", context) - val subject = messageSource!!.getMessage("email.reset.title", null, locale) + val content = templateEngine.process("passwordResetEmail", context) + val subject = messageSource.getMessage("email.reset.title", null, locale) sendEmail(user.email, subject, content, false, true) } diff --git a/src/main/java/org/radarbase/management/service/OAuthClientService.kt b/src/main/java/org/radarbase/management/service/OAuthClientService.kt index 9268d5d5e..7f09ce8f7 100644 --- a/src/main/java/org/radarbase/management/service/OAuthClientService.kt +++ b/src/main/java/org/radarbase/management/service/OAuthClientService.kt @@ -1,6 +1,5 @@ package org.radarbase.management.service -import org.radarbase.management.domain.Authority import org.radarbase.management.domain.User import org.radarbase.management.service.dto.ClientDetailsDTO import org.radarbase.management.service.mapper.ClientDetailsMapper @@ -131,7 +130,7 @@ class OAuthClientService( */ fun createAccessToken(user: User, clientId: String): OAuth2AccessToken { val authorities = user.authorities!! - .map { a: Authority? -> SimpleGrantedAuthority(a?.name) } + .map { a -> SimpleGrantedAuthority(a) } // lookup the OAuth client // getOAuthClient checks if the id exists val client = findOneByClientId(clientId) diff --git a/src/main/java/org/radarbase/management/service/RoleService.kt b/src/main/java/org/radarbase/management/service/RoleService.kt index 6f167e446..56a9c29e3 100644 --- a/src/main/java/org/radarbase/management/service/RoleService.kt +++ b/src/main/java/org/radarbase/management/service/RoleService.kt @@ -26,7 +26,7 @@ import java.util.function.Consumer */ @Service @Transactional -open class RoleService( +class RoleService( @Autowired private val roleRepository: RoleRepository, @Autowired private val authorityRepository: AuthorityRepository, @Autowired private val organizationRepository: OrganizationRepository, @@ -58,12 +58,12 @@ open class RoleService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(): List { + fun findAll(): List { val optUser = userService.userWithAuthorities ?: // return an empty list if we do not have a current user (e.g. with client credentials // oauth2 grant) return emptyList() - val currentUserAuthorities: List? = optUser.authorities?.map { auth -> auth?.name!! } + val currentUserAuthorities = optUser.authorities return if (currentUserAuthorities?.contains(RoleAuthority.SYS_ADMIN.authority) == true) { log.debug("Request to get all Roles") roleRepository.findAll().filterNotNull().map { role: Role -> roleMapper.roleToRoleDTO(role) }.toList() @@ -85,7 +85,7 @@ open class RoleService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findSuperAdminRoles(): List { + fun findSuperAdminRoles(): List { log.debug("Request to get admin Roles") return roleRepository.findRolesByAuthorityName(RoleAuthority.SYS_ADMIN.authority) .map { role: Role -> roleMapper.roleToRoleDTO(role) }.toList() @@ -98,7 +98,7 @@ open class RoleService( * @return the entity */ @Transactional(readOnly = true) - open fun findOne(id: Long): RoleDTO { + fun findOne(id: Long): RoleDTO { log.debug("Request to get Role : {}", id) val role = roleRepository.findById(id).get() return roleMapper.roleToRoleDTO(role) diff --git a/src/main/java/org/radarbase/management/service/SubjectService.kt b/src/main/java/org/radarbase/management/service/SubjectService.kt index 13ed472a8..f4b79a416 100644 --- a/src/main/java/org/radarbase/management/service/SubjectService.kt +++ b/src/main/java/org/radarbase/management/service/SubjectService.kt @@ -54,7 +54,7 @@ import javax.annotation.Nonnull */ @Service @Transactional -open class SubjectService( +class SubjectService( @Autowired private val subjectMapper: SubjectMapper, @Autowired private val projectMapper: ProjectMapper, @Autowired private val subjectRepository: SubjectRepository, @@ -76,7 +76,7 @@ open class SubjectService( * @return the newly created subject */ @Transactional - open fun createSubject(subjectDto: SubjectDTO): SubjectDTO? { + fun createSubject(subjectDto: SubjectDTO): SubjectDTO? { val subject = subjectMapper.subjectDTOToSubject(subjectDto) ?: throw NullPointerException() //assign roles val user = subject.user @@ -151,7 +151,7 @@ open class SubjectService( * @return the updated subject */ @Transactional - open fun updateSubject(newSubjectDto: SubjectDTO): SubjectDTO? { + fun updateSubject(newSubjectDto: SubjectDTO): SubjectDTO? { if (newSubjectDto.id == null) { return createSubject(newSubjectDto) } @@ -252,7 +252,7 @@ open class SubjectService( * updates meta-data. */ @Transactional - open fun assignOrUpdateSource( + fun assignOrUpdateSource( subject: Subject, sourceType: SourceType, project: Project?, sourceRegistrationDto: MinimalSourceDetailsDTO ): MinimalSourceDetailsDTO { val assignedSource: Source diff --git a/src/main/java/org/radarbase/management/service/dto/UserDTO.kt b/src/main/java/org/radarbase/management/service/dto/UserDTO.kt index 204bf4b4a..55f5bb1df 100644 --- a/src/main/java/org/radarbase/management/service/dto/UserDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/UserDTO.kt @@ -10,12 +10,12 @@ import javax.validation.constraints.Size */ open class UserDTO { var id: Long? = null - lateinit var login: @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") @Size(max = 50, min = 1) String - var firstName: @Size(max = 50) String? = null - var lastName: @Size(max = 50) String? = null - var email: @Email @Size(min = 5, max = 100) String? = null + @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") @Size(max = 50, min = 1) var login: String? = null + @Size(max = 50) var firstName: String? = null + @Size(max = 50) var lastName: String? = null + @Email @Size(min = 5, max = 100) var email: String? = null var isActivated = false - var langKey: @Size(min = 2, max = 5) String? = null + @Size(min = 2, max = 5) var langKey: String? = null var createdBy: String? = null var createdDate: ZonedDateTime? = null var lastModifiedBy: String? = null diff --git a/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt index 8296a076f..757c1ff1f 100644 --- a/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt +++ b/src/main/java/org/radarbase/management/service/mapper/UserMapper.kt @@ -4,13 +4,9 @@ import org.mapstruct.DecoratedWith import org.mapstruct.Mapper import org.mapstruct.Mapping import org.mapstruct.MappingConstants -import org.radarbase.management.domain.Authority import org.radarbase.management.domain.User import org.radarbase.management.service.dto.UserDTO import org.radarbase.management.service.mapper.decorator.UserMapperDecorator -import javax.validation.constraints.NotNull -import javax.validation.constraints.Pattern -import javax.validation.constraints.Size /** * Mapper for the entity User and its DTO UserDTO. @@ -40,20 +36,4 @@ interface UserMapper { @Mapping(target = "password", ignore = true) @Mapping(target = "authorities", ignore = true) fun userDTOToUser(userDto: UserDTO?): User? - - /** - * Map a set of [Authority]s to a set of strings that are the authority names. - * @param authorities the authorities to map - * @return the set of strings if authorities is not null, null otherwise - */ - fun map(authorities: Set): @NotNull @Size( - max = 50, - min = 0 - ) @Pattern(regexp = "^[_'.@A-Za-z0-9- ]*$") Set { - return authorities.mapNotNull { it.name }.toSet() - } - - fun map(authority: Authority): String { - return authority.name!! - } } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt index 163eda4ee..a6cc665ed 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/UserMapperDecorator.kt @@ -8,16 +8,16 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Qualifier abstract class UserMapperDecorator( - @Autowired @Qualifier("delegate") private val delegate: UserMapper? = null, - @Autowired private val revisionService: RevisionService? = null ) : UserMapper { + @Autowired @Qualifier("delegate") private lateinit var delegate: UserMapper + @Autowired private lateinit var revisionService: RevisionService override fun userToUserDTO(user: User?): UserDTO? { if (user == null) { return null } - val dto = delegate!!.userToUserDTO(user) - val auditInfo = revisionService!!.getAuditInfo(user) + val dto = delegate.userToUserDTO(user) + val auditInfo = revisionService.getAuditInfo(user) dto?.createdDate = auditInfo.createdAt dto?.createdBy = auditInfo.createdBy dto?.lastModifiedDate = auditInfo.lastModifiedAt diff --git a/src/main/java/org/radarbase/management/web/rest/AccountResource.kt b/src/main/java/org/radarbase/management/web/rest/AccountResource.kt index d747595c6..399ee5c80 100644 --- a/src/main/java/org/radarbase/management/web/rest/AccountResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/AccountResource.kt @@ -6,8 +6,6 @@ import org.radarbase.auth.authorization.Permission import org.radarbase.auth.token.DataRadarToken import org.radarbase.auth.token.RadarToken import org.radarbase.management.config.ManagementPortalProperties -import org.radarbase.management.domain.User -import org.radarbase.management.security.JwtAuthenticationFilter import org.radarbase.management.security.JwtAuthenticationFilter.Companion.radarToken import org.radarbase.management.security.NotAuthorizedException import org.radarbase.management.service.AuthService @@ -33,7 +31,6 @@ import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController -import java.lang.Exception import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpSession import javax.validation.Valid @@ -53,7 +50,7 @@ class AccountResource( ) { @Autowired(required = false) - private val token: RadarToken? = null + var token: RadarToken? = null /** * GET /activate : activate the registered user. @@ -86,8 +83,8 @@ class AccountResource( if (token == null) { throw NotAuthorizedException("Cannot login without credentials") } - log.debug("Logging in user to session with principal {}", token.username) - session?.radarToken = DataRadarToken(token) + log.debug("Logging in user to session with principal {}", token!!.username) + session?.radarToken = DataRadarToken(token!!) return account } diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.kt b/src/main/java/org/radarbase/management/web/rest/UserResource.kt index 39fdbcc49..268d977a9 100644 --- a/src/main/java/org/radarbase/management/web/rest/UserResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/UserResource.kt @@ -106,7 +106,7 @@ class UserResource( ) ).body(null) // Lowercase the user login before comparing with database - } else if (managedUserVm.login.lowercase().let { userRepository.findOneByLogin(it) } != null) { + } else if (managedUserVm.login?.lowercase().let { userRepository.findOneByLogin(it) } != null) { ResponseEntity.badRequest().headers( HeaderUtil.createFailureAlert( EntityName.USER, "userexists", "Login already in use" @@ -149,7 +149,7 @@ class UserResource( if (existingUser?.id != managedUserVm.id) { throw BadRequestException("Email already in use", EntityName.USER, "emailexists") } - existingUser = managedUserVm.login.lowercase()?.let { + existingUser = managedUserVm.login?.lowercase().let { userRepository.findOneByLogin( it ) diff --git a/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt b/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt index ca746c255..993433fb4 100644 --- a/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt +++ b/src/test/java/org/radarbase/management/security/JwtAuthenticationFilterIntTest.kt @@ -17,7 +17,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -34,22 +33,22 @@ import javax.servlet.ServletException @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser internal class JwtAuthenticationFilterIntTest( + @Autowired private val projectResource: ProjectResource, + @Autowired private val projectService: ProjectService, + @Autowired private val authService: AuthService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - private var rsaRestProjectMockMvc: MockMvc, - private var ecRestProjectMockMvc: MockMvc, - @Autowired private val authService: AuthService ) { + private lateinit var rsaRestProjectMockMvc: MockMvc + private lateinit var ecRestProjectMockMvc: MockMvc @BeforeEach @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val projectResource = ProjectResource - ReflectionTestUtils.setField(projectResource, "projectService", projectService) - ReflectionTestUtils.setField(projectResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) rsaRestProjectMockMvc = MockMvcBuilders.standaloneSetup(projectResource) diff --git a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt index e414e8506..8ff6ad4f0 100644 --- a/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt +++ b/src/test/java/org/radarbase/management/security/SecurityUtilsUnitTest.kt @@ -2,14 +2,22 @@ package org.radarbase.management.security import org.assertj.core.api.Assertions import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.radarbase.management.ManagementPortalTestApp +import org.springframework.boot.test.context.SpringBootTest import org.springframework.security.authentication.UsernamePasswordAuthenticationToken import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.security.test.context.support.WithMockUser +import org.springframework.test.context.junit.jupiter.SpringExtension /** * Test class for the SecurityUtils utility class. * * @see SecurityUtils */ +@ExtendWith(SpringExtension::class) +@SpringBootTest(classes = [ManagementPortalTestApp::class]) +@WithMockUser internal class SecurityUtilsUnitTest { @Test fun testGetCurrentUserLogin() { diff --git a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt index 5e167e471..5a79aae77 100644 --- a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt @@ -34,9 +34,9 @@ internal open class MetaTokenServiceTest( @Autowired private val subjectService: SubjectService, @Autowired private val subjectMapper: SubjectMapper, @Autowired private val oAuthClientService: OAuthClientService, - private var clientDetails: ClientDetails, - private var subjectDto: SubjectDTO ) { + private lateinit var clientDetails: ClientDetails + private lateinit var subjectDto: SubjectDTO @BeforeEach fun setUp() { diff --git a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt index d1200bb68..a3979786c 100644 --- a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt @@ -21,14 +21,14 @@ import java.util.* @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -open class SubjectServiceTest( +class SubjectServiceTest( @Autowired private val subjectService: SubjectService, @Autowired private val projectService: ProjectService ) { @Test @Transactional - open fun testGetPrivacyPolicyUrl() { + fun testGetPrivacyPolicyUrl() { projectService.save(createEntityDTO().project!!) val created = subjectService.createSubject(createEntityDTO()) Assertions.assertNotNull(created!!.id) diff --git a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt index eae6e9804..78fdea8f7 100644 --- a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt +++ b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt @@ -12,7 +12,6 @@ import org.radarbase.management.domain.Authority import org.radarbase.management.domain.Role import org.radarbase.management.domain.User import org.radarbase.management.domain.audit.CustomRevisionEntity -import org.radarbase.management.repository.CustomRevisionEntityRepository import org.radarbase.management.repository.UserRepository import org.radarbase.management.repository.filters.UserFilter import org.radarbase.management.security.Constants @@ -24,7 +23,6 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.data.domain.PageRequest import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.transaction.annotation.Transactional import java.time.Period import java.time.ZonedDateTime @@ -41,34 +39,26 @@ import javax.persistence.EntityManagerFactory @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -open class UserServiceIntTest( +class UserServiceIntTest( @Autowired private val userRepository: UserRepository, @Autowired private val userMapper: UserMapper, @Autowired private val userService: UserService, @Autowired private val revisionService: RevisionService, - @Autowired private val revisionEntityRepository: CustomRevisionEntityRepository, + @Autowired private val entityManagerFactory: EntityManagerFactory, @Autowired private val passwordService: PasswordService, - private var entityManager: EntityManager, - private var userDto: UserDTO? ) { + private lateinit var entityManager: EntityManager + private lateinit var userDto: UserDTO @BeforeEach fun setUp() { entityManager = entityManagerFactory.createEntityManager( entityManagerFactory.properties ) - userDto = userMapper.userToUserDTO(createEntity(passwordService)) - ReflectionTestUtils.setField( - revisionService, "revisionEntityRepository", - revisionEntityRepository - ) - ReflectionTestUtils.setField(revisionService, "entityManager", entityManager) - ReflectionTestUtils.setField(userService, "userMapper", userMapper) - ReflectionTestUtils.setField(userService, "userRepository", userRepository) - + userDto = userMapper.userToUserDTO(createEntity(passwordService))!! - userRepository.delete(userRepository.findOneByLogin(userDto!!.login)!!) + userRepository.delete(userRepository.findOneByLogin(userDto.login)!!) } @Test @@ -85,7 +75,7 @@ open class UserServiceIntTest( @Test @Throws(NotAuthorizedException::class) fun assertThatOnlyActivatedUserCanRequestPasswordReset() { - val user = userService.createUser(userDto!!) + val user = userService.createUser(userDto) val maybeUser = userService.requestPasswordReset( userDto?.email!! ) @@ -96,7 +86,7 @@ open class UserServiceIntTest( @Test @Throws(NotAuthorizedException::class) fun assertThatResetKeyMustNotBeOlderThan24Hours() { - val user = userService.createUser(userDto!!) + val user = userService.createUser(userDto) val daysAgo = ZonedDateTime.now().minusHours(25) val resetKey = passwordService.generateResetKey() user.activated = true @@ -114,7 +104,7 @@ open class UserServiceIntTest( @Test @Throws(NotAuthorizedException::class) fun assertThatResetKeyMustBeValid() { - val user = userService.createUser(userDto!!) + val user = userService.createUser(userDto) val daysAgo = ZonedDateTime.now().minusHours(25) user.activated = true user.resetDate = daysAgo @@ -131,7 +121,7 @@ open class UserServiceIntTest( @Test @Throws(NotAuthorizedException::class) fun assertThatUserCanResetPassword() { - val user = userService.createUser(userDto!!) + val user = userService.createUser(userDto) val oldPassword = user.password val daysAgo = ZonedDateTime.now().minusHours(2) val resetKey = passwordService.generateResetKey() diff --git a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt index 442093261..aaf65363b 100644 --- a/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AccountResourceIntTest.kt @@ -5,10 +5,11 @@ import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.ArgumentMatchers -import org.mockito.Mock -import org.mockito.Mockito -import org.mockito.MockitoAnnotations +import org.mockito.kotlin.anyVararg +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever import org.radarbase.auth.authorization.RoleAuthority import org.radarbase.auth.token.RadarToken import org.radarbase.management.ManagementPortalTestApp @@ -32,7 +33,6 @@ import org.springframework.http.MediaType import org.springframework.mock.web.MockHttpServletRequest import org.springframework.security.core.context.SecurityContextHolder import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -47,44 +47,46 @@ import java.util.* */ @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) -internal open class AccountResourceIntTest( +internal class AccountResourceIntTest( @Autowired private val userRepository: UserRepository, - @Autowired private val userService: UserService, - @Autowired private val userMapper: UserMapper, - @Autowired private val passwordService: PasswordService, - @Mock private val mockUserService: UserService, - @Mock private val mockMailService: MailService, @Autowired private val radarToken: RadarToken, + @Autowired private val userMapper: UserMapper, + @Autowired private val managementPortalProperties: ManagementPortalProperties, @Autowired private val authService: AuthService, - @Autowired private val managementPortalProperties: ManagementPortalProperties + @Autowired private val passwordService: PasswordService ) { + @Autowired private lateinit var mockUserService: UserService + @Autowired private lateinit var mockMailService: MailService private lateinit var restUserMockMvc: MockMvc + @BeforeEach fun setUp() { - MockitoAnnotations.openMocks(this) - Mockito.doNothing().`when`(mockMailService).sendActivationEmail( - ArgumentMatchers.any( - User::class.java - ) - ) + mockUserService = mock() + mockMailService = mock() + + whenever(mockMailService.sendActivationEmail(anyVararg())).doAnswer{ print("tried to send mail") } + SecurityContextHolder.getContext().authentication = RadarAuthentication(radarToken) val accountResource = AccountResource( - userService, + mockUserService, mockMailService, userMapper, managementPortalProperties, authService, - passwordService + passwordService, ) - ReflectionTestUtils.setField(accountResource, "token", radarToken) + accountResource.token = radarToken + val accountUserMockResource = AccountResource( - userService, + mockUserService, mockMailService, userMapper, managementPortalProperties, authService, - passwordService + passwordService, ) + accountUserMockResource.token = radarToken + restUserMockMvc = MockMvcBuilders.standaloneSetup(accountUserMockResource).build() } @@ -106,7 +108,7 @@ internal open class AccountResourceIntTest( @Test @Throws(Exception::class) fun testAuthenticatedUser() { - val token = Mockito.mock(RadarToken::class.java) + val token = mock() val roles: MutableSet = HashSet() val role = Role() val authority = Authority() @@ -120,7 +122,7 @@ internal open class AccountResourceIntTest( user.email = "john.doe@jhipster.com" user.langKey = "en" user.roles = roles - Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(user) + whenever(mockUserService.userWithAuthorities).doReturn(user) restUserMockMvc.perform(MockMvcRequestBuilders.post("/api/login") .with { request: MockHttpServletRequest -> request.radarToken = token @@ -158,7 +160,7 @@ internal open class AccountResourceIntTest( user.email = "john.doe@jhipster.com" user.langKey = "en" user.roles = roles - Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(user) + whenever(mockUserService.userWithAuthorities).doReturn(user) restUserMockMvc.perform( MockMvcRequestBuilders.get("/api/account") .accept(MediaType.APPLICATION_JSON) @@ -180,7 +182,7 @@ internal open class AccountResourceIntTest( @Test @Throws(Exception::class) fun testGetUnknownAccount() { - Mockito.`when`(mockUserService.userWithAuthorities).thenReturn(null) + whenever(mockUserService.userWithAuthorities).doReturn(null) restUserMockMvc.perform( MockMvcRequestBuilders.get("/api/account") .accept(MediaType.APPLICATION_JSON) @@ -191,7 +193,7 @@ internal open class AccountResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun testSaveInvalidLogin() { + fun testSaveInvalidLogin() { val roles: MutableSet = HashSet() val role = RoleDTO() role.authorityName = RoleAuthority.PARTICIPANT.authority diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index 6a3815e9b..0d0a86a7a 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -178,7 +178,7 @@ internal open class OrganizationResourceIntTest( //TODO this is covered by not using a nullable type fun checkGroupNameIsRequired() { val orgDto = organizationMapper.organizationToOrganizationDTO(organization) - orgDto.name = "" + orgDto.name = null restOrganizationMockMvc.perform( MockMvcRequestBuilders.post("/api/organizations") .contentType(TestUtil.APPLICATION_JSON_UTF8) diff --git a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt index ba9b4e2fa..5a66e84f9 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProfileInfoResourceIntTest.kt @@ -7,11 +7,11 @@ import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations import org.radarbase.management.ManagementPortalTestApp +import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.core.env.Environment import org.springframework.http.MediaType import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -24,18 +24,19 @@ import org.springframework.test.web.servlet.setup.MockMvcBuilders */ @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) -internal class ProfileInfoResourceIntTest { - @Mock - private val environment: Environment? = null - private var restProfileMockMvc: MockMvc? = null +internal class ProfileInfoResourceIntTest( + @Autowired private val profileInfoResource: ProfileInfoResource +) { + + @Mock private lateinit var environment: Environment + private lateinit var restProfileMockMvc: MockMvc + @BeforeEach fun setUp() { MockitoAnnotations.openMocks(this) val activeProfiles = arrayOf("test") - Mockito.`when`(environment!!.defaultProfiles).thenReturn(activeProfiles) + Mockito.`when`(environment.defaultProfiles).thenReturn(activeProfiles) Mockito.`when`(environment.activeProfiles).thenReturn(activeProfiles) - val profileInfoResource = ProfileInfoResource() - ReflectionTestUtils.setField(profileInfoResource, "env", environment) restProfileMockMvc = MockMvcBuilders .standaloneSetup(profileInfoResource) .build() @@ -44,7 +45,7 @@ internal class ProfileInfoResourceIntTest { @Throws(Exception::class) @Test fun profileInfo() { - restProfileMockMvc!!.perform(MockMvcRequestBuilders.get("/api/profile-info")) + restProfileMockMvc.perform(MockMvcRequestBuilders.get("/api/profile-info")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) } @@ -53,9 +54,9 @@ internal class ProfileInfoResourceIntTest { @Test fun profileInfoWithoutActiveProfiles() { val emptyProfile = arrayOf() - Mockito.`when`(environment!!.defaultProfiles).thenReturn(emptyProfile) + Mockito.`when`(environment.defaultProfiles).thenReturn(emptyProfile) Mockito.`when`(environment.activeProfiles).thenReturn(emptyProfile) - restProfileMockMvc!!.perform(MockMvcRequestBuilders.get("/api/profile-info")) + restProfileMockMvc.perform(MockMvcRequestBuilders.get("/api/profile-info")) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) } diff --git a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt index 6c4ed5696..e3b46d489 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceResourceIntTest.kt @@ -45,17 +45,17 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class SourceResourceIntTest( +internal class SourceResourceIntTest( + @Autowired private val sourceResource: SourceResource, + @Autowired private val sourceRepository: SourceRepository, @Autowired private val sourceMapper: SourceMapper, - @Autowired private val sourceService: SourceService, @Autowired private val sourceTypeService: SourceTypeService, @Autowired private val sourceTypeMapper: SourceTypeMapper, @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, @Autowired private val projectRepository: ProjectRepository, - @Autowired private val authService: AuthService ) { private lateinit var restDeviceMockMvc: MockMvc private lateinit var source: Source @@ -65,10 +65,6 @@ internal open class SourceResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val sourceResource = SourceResource - ReflectionTestUtils.setField(sourceResource, "authService", authService) - ReflectionTestUtils.setField(sourceResource, "sourceService", sourceService) - ReflectionTestUtils.setField(sourceResource, "sourceRepository", sourceRepository) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) restDeviceMockMvc = MockMvcBuilders.standaloneSetup(sourceResource) @@ -93,7 +89,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSource() { + fun createSource() { val databaseSizeBeforeCreate = sourceRepository.findAll().size // Create the Source @@ -117,7 +113,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSourceWithExistingId() { + fun createSourceWithExistingId() { val databaseSizeBeforeCreate = sourceRepository.findAll().size // Create the Source with an existing ID @@ -140,7 +136,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkSourcePhysicalIdIsGenerated() { + fun checkSourcePhysicalIdIsGenerated() { val databaseSizeBeforeTest = sourceRepository.findAll().size // set the field null source.sourceId = null @@ -170,7 +166,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkAssignedIsRequired() { + fun checkAssignedIsRequired() { val databaseSizeBeforeTest = sourceRepository.findAll().size // set the field null source.assigned = null @@ -190,7 +186,7 @@ internal open class SourceResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun allSources() { + fun allSources() { // Initialize the database sourceRepository.saveAndFlush(source) @@ -218,7 +214,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun getSource() { + fun getSource() { // Initialize the database sourceRepository.saveAndFlush(source) @@ -234,7 +230,7 @@ internal open class SourceResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun nonExistingSource() { + fun nonExistingSource() { // Get the source restDeviceMockMvc.perform(MockMvcRequestBuilders.get("/api/sources/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) @@ -243,7 +239,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateSource() { + fun updateSource() { // Initialize the database sourceRepository.saveAndFlush(source) val databaseSizeBeforeUpdate = sourceRepository.findAll().size @@ -272,7 +268,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateNonExistingSource() { + fun updateNonExistingSource() { val databaseSizeBeforeUpdate = sourceRepository.findAll().size // Create the Source @@ -294,7 +290,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun deleteSource() { + fun deleteSource() { // Initialize the database sourceRepository.saveAndFlush(source) val databaseSizeBeforeDelete = sourceRepository.findAll().size @@ -314,7 +310,7 @@ internal open class SourceResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun equalsVerifier() { + fun equalsVerifier() { org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Source::class.java)) } diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt index 5949207d7..fbd97c356 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt @@ -10,7 +10,6 @@ import org.mockito.MockitoAnnotations import org.radarbase.auth.authentication.OAuthHelper import org.radarbase.auth.authorization.RoleAuthority import org.radarbase.management.ManagementPortalTestApp -import org.radarbase.management.config.ManagementPortalProperties import org.radarbase.management.domain.Authority import org.radarbase.management.domain.Project import org.radarbase.management.domain.Role @@ -35,7 +34,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -53,8 +51,9 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class UserResourceIntTest( - @Autowired private val managementPortalProperties: ManagementPortalProperties, +internal class UserResourceIntTest( + @Autowired private val userResource: UserResource, + @Autowired private val roleRepository: RoleRepository, @Autowired private val userRepository: UserRepository, @Autowired private val mailService: MailService, @@ -75,16 +74,7 @@ internal open class UserResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val userResource = UserResource - ReflectionTestUtils.setField(userResource, "userService", userService) - ReflectionTestUtils.setField(userResource, "mailService", mailService) - ReflectionTestUtils.setField(userResource, "userRepository", userRepository) - ReflectionTestUtils.setField(userResource, "subjectRepository", subjectRepository) - ReflectionTestUtils.setField(userResource, "authService", authService) - ReflectionTestUtils.setField( - userResource, - "managementPortalProperties", managementPortalProperties - ) + val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) restUserMockMvc = MockMvcBuilders.standaloneSetup(userResource) @@ -123,7 +113,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createUser() { + fun createUser() { val databaseSizeBeforeCreate = userRepository.findAll().size // Create the User @@ -153,7 +143,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createUserWithExistingId() { + fun createUserWithExistingId() { val databaseSizeBeforeCreate = userRepository.findAll().size val roles: MutableSet = HashSet() val role = RoleDTO() @@ -178,7 +168,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createUserWithExistingLogin() { + fun createUserWithExistingLogin() { // Initialize the database userRepository.saveAndFlush(user) val databaseSizeBeforeCreate = userRepository.findAll().size @@ -205,7 +195,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createUserWithExistingEmail() { + fun createUserWithExistingEmail() { // Initialize the database userRepository.saveAndFlush(user) val databaseSizeBeforeCreate = userRepository.findAll().size @@ -232,7 +222,7 @@ internal open class UserResourceIntTest( @get:Throws(Exception::class) @get:Transactional @get:Test - open val allUsers: Unit + val allUsers: Unit get() { // Initialize the database val adminRole = Role() @@ -282,7 +272,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun getUser() { + fun getUser() { // Initialize the database userRepository.saveAndFlush(user) @@ -304,7 +294,7 @@ internal open class UserResourceIntTest( @get:Throws(Exception::class) @get:Transactional @get:Test - open val nonExistingUser: Unit + val nonExistingUser: Unit get() { restUserMockMvc.perform(MockMvcRequestBuilders.get("/api/users/unknown")) .andExpect(MockMvcResultMatchers.status().isNotFound()) @@ -313,7 +303,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateUser() { + fun updateUser() { // Initialize the database userRepository.saveAndFlush(user) val databaseSizeBeforeUpdate = userRepository.findAll().size @@ -356,7 +346,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateUserLogin() { + fun updateUserLogin() { // Initialize the database userRepository.saveAndFlush(user) project = ProjectResourceIntTest.createEntity() @@ -400,7 +390,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateUserExistingEmail() { + fun updateUserExistingEmail() { // Initialize the database with 2 users userRepository.saveAndFlush(user) project = ProjectResourceIntTest.createEntity() @@ -442,7 +432,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateUserExistingLogin() { + fun updateUserExistingLogin() { // Initialize the database userRepository.saveAndFlush(user) project = ProjectResourceIntTest.createEntity() @@ -484,7 +474,7 @@ internal open class UserResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun deleteUser() { + fun deleteUser() { // Initialize the database userRepository.saveAndFlush(user) val databaseSizeBeforeDelete = userRepository.findAll().size @@ -503,7 +493,7 @@ internal open class UserResourceIntTest( @Test @Transactional - open fun equalsVerifier() { + fun equalsVerifier() { val userA = User() userA.setLogin("AAA") val userB = User() From e9b988d84b88352ef9944709bfcd28af8b8681e4 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 22:02:07 +0100 Subject: [PATCH 109/158] fix login generation --- .../java/org/radarbase/management/service/dto/SubjectDTO.kt | 4 +--- .../org/radarbase/management/service/SubjectServiceTest.kt | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt b/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt index 337ec975d..d9205e33e 100644 --- a/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/SubjectDTO.kt @@ -28,14 +28,12 @@ class SubjectDTO : Serializable { var id: Long? = null private var _login: String? = null var login: String? - get() = { - if (_login == null) { + get() = if (_login == null) { _login = UUID.randomUUID().toString() _login } else { _login } - }.toString() set(value) { _login = value } diff --git a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt index a3979786c..0414c0ecc 100644 --- a/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/SubjectServiceTest.kt @@ -30,7 +30,8 @@ class SubjectServiceTest( @Transactional fun testGetPrivacyPolicyUrl() { projectService.save(createEntityDTO().project!!) - val created = subjectService.createSubject(createEntityDTO()) + val c = createEntityDTO() + val created = subjectService.createSubject(c) Assertions.assertNotNull(created!!.id) val subject = subjectService.findOneByLogin(created.login) Assertions.assertNotNull(subject) From 633e930248967e7d514949866579f85ec4ec4e55 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 22:46:17 +0100 Subject: [PATCH 110/158] user service tests passing --- .../radarbase/management/domain/Subject.kt | 2 +- .../management/service/UserService.kt | 32 +++++++++++-------- .../management/service/UserServiceIntTest.kt | 6 ++-- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Subject.kt b/src/main/java/org/radarbase/management/domain/Subject.kt index a86d547e7..e20b23dc0 100644 --- a/src/main/java/org/radarbase/management/domain/Subject.kt +++ b/src/main/java/org/radarbase/management/domain/Subject.kt @@ -145,7 +145,7 @@ class Subject( * @return [Project] currently active project of subject. */ get() = user?.roles - ?.first { r -> r.authority?.name == RoleAuthority.PARTICIPANT.authority } + ?.firstOrNull { r -> r.authority?.name == RoleAuthority.PARTICIPANT.authority } ?.project val associatedProject: Project? /** diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt index 7f332f726..b666cb90b 100644 --- a/src/main/java/org/radarbase/management/service/UserService.kt +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -46,7 +46,8 @@ open class UserService @Autowired constructor( private val managementPortalProperties: ManagementPortalProperties, private val authService: AuthService ) { - @Autowired lateinit var roleService: RoleService + @Autowired + lateinit var roleService: RoleService /** * Activate a user with the given activation key. @@ -83,12 +84,14 @@ open class UserService @Autowired constructor( val oneDayAgo = ZonedDateTime.now().minusSeconds( managementPortalProperties.common.activationKeyTimeoutInSeconds.toLong() ) - if (user?.resetDate?.isAfter(oneDayAgo) == true) user.password = passwordService.encode(newPassword) - user?.resetKey = null - user?.resetDate = null - user?.activated = true - - return user + return if (user?.resetDate?.isAfter(oneDayAgo) == true) { + user.password = passwordService.encode(newPassword) + user.resetKey = null + user.resetDate = null + user.activated = true + user + } else + null } /** @@ -118,9 +121,12 @@ open class UserService @Autowired constructor( */ fun requestPasswordReset(mail: String): User? { val user = userRepository.findOneByEmail(mail) - if (user?.activated == true) user.resetKey = passwordService.generateResetKey() - user?.resetDate = ZonedDateTime.now() - return user + return if (user?.activated == true) { + user.resetKey = passwordService.generateResetKey() + user.resetDate = ZonedDateTime.now() + user + } else + null } /** @@ -286,8 +292,7 @@ open class UserService @Autowired constructor( if (user != null) { userRepository.delete(user) log.debug("Deleted User: {}", user) - } - else { + } else { log.warn("could not delete User with login: {}", login) } } @@ -312,8 +317,7 @@ open class UserService @Autowired constructor( open fun changePassword(login: String, password: String) { val user = userRepository.findOneByLogin(login) - if (user != null) - { + if (user != null) { val encryptedPassword = passwordService.encode(password) user.password = encryptedPassword log.debug("Changed password for User: {}", user) diff --git a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt index 78fdea8f7..9353e68ac 100644 --- a/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt +++ b/src/test/java/org/radarbase/management/service/UserServiceIntTest.kt @@ -40,9 +40,9 @@ import javax.persistence.EntityManagerFactory @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional class UserServiceIntTest( + @Autowired private val userService: UserService, @Autowired private val userRepository: UserRepository, @Autowired private val userMapper: UserMapper, - @Autowired private val userService: UserService, @Autowired private val revisionService: RevisionService, @Autowired private val entityManagerFactory: EntityManagerFactory, @@ -58,7 +58,7 @@ class UserServiceIntTest( ) userDto = userMapper.userToUserDTO(createEntity(passwordService))!! - userRepository.delete(userRepository.findOneByLogin(userDto.login)!!) + userRepository.findOneByLogin(userDto.login)?.let { userRepository.delete(it)} } @Test @@ -77,7 +77,7 @@ class UserServiceIntTest( fun assertThatOnlyActivatedUserCanRequestPasswordReset() { val user = userService.createUser(userDto) val maybeUser = userService.requestPasswordReset( - userDto?.email!! + userDto.email!! ) Assertions.assertThat(maybeUser).isNull() userRepository.delete(user) From fcea1696688c6cc89d6114e28058c14692799c99 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 1 Nov 2023 23:01:55 +0100 Subject: [PATCH 111/158] autowire all decorator constructor parameters --- .../mapper/decorator/RoleMapperDecorator.kt | 2 +- .../mapper/decorator/SourceMapperDecorator.kt | 4 +-- .../decorator/SubjectMapperDecorator.kt | 8 ++--- .../web/rest/GroupResourceIntTest.kt | 33 +++++++++---------- .../web/rest/OAuthClientsResourceIntTest.kt | 12 +++---- 5 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt index 6ea4a059c..ad28dad59 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/RoleMapperDecorator.kt @@ -14,7 +14,7 @@ abstract class RoleMapperDecorator() : RoleMapper { // constructor(roleMapper: RoleMapper, authorityRepository: AuthorityRepository?) : this(roleMapper) @Autowired @Qualifier("delegate") private val delegate: RoleMapper? = null - private var authorityRepository: AuthorityRepository? = null; + @Autowired private var authorityRepository: AuthorityRepository? = null; /** * Overrides standard RoleMapperImpl and loads authority from repository if not specified. diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt index 6a1136560..9ce30725e 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt @@ -19,8 +19,8 @@ import java.util.Map abstract class SourceMapperDecorator() : SourceMapper { @Autowired @Qualifier("delegate") private val delegate: SourceMapper? = null - private val sourceRepository: SourceRepository? = null - private val subjectRepository: SubjectRepository? = null + @Autowired private val sourceRepository: SourceRepository? = null + @Autowired private val subjectRepository: SubjectRepository? = null override fun minimalSourceDTOToSource(minimalSourceDetailsDto: MinimalSourceDetailsDTO): Source? { val source = sourceRepository diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt index 6396b670a..9c8d86acb 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SubjectMapperDecorator.kt @@ -22,10 +22,10 @@ import org.springframework.beans.factory.annotation.Qualifier abstract class SubjectMapperDecorator() : SubjectMapper { @Autowired @Qualifier("delegate") private val delegate: SubjectMapper? = null - private var groupRepository: GroupRepository? = null - private var projectRepository: ProjectRepository? = null - private var revisionService: RevisionService? = null - private var projectMapper: ProjectMapper? = null + @Autowired private var groupRepository: GroupRepository? = null + @Autowired private var projectRepository: ProjectRepository? = null + @Autowired private var revisionService: RevisionService? = null + @Autowired private var projectMapper: ProjectMapper? = null override fun subjectToSubjectDTO(subject: Subject?): SubjectDTO? { if (subject == null) { return null diff --git a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt index 113b59f30..1c1a80d1a 100644 --- a/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/GroupResourceIntTest.kt @@ -18,8 +18,6 @@ import org.radarbase.management.repository.GroupRepository import org.radarbase.management.repository.ProjectRepository import org.radarbase.management.repository.RoleRepository import org.radarbase.management.repository.SubjectRepository -import org.radarbase.management.service.AuthService -import org.radarbase.management.service.GroupService import org.radarbase.management.service.SubjectService import org.radarbase.management.service.dto.SubjectDTO import org.radarbase.management.service.dto.SubjectDTO.SubjectStatus @@ -36,7 +34,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -54,18 +51,19 @@ import javax.servlet.ServletException @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser internal class GroupResourceIntTest( - @Autowired private val groupService: GroupService, + @Autowired private val groupResource: GroupResource, + + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val projectMapper: ProjectMapper, @Autowired private val projectRepository: ProjectRepository, @Autowired private val roleRepository: RoleRepository, @Autowired private val subjectRepository: SubjectRepository, @Autowired private val subjectService: SubjectService, @Autowired private val groupMapper: GroupMapper, - @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, - @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val groupRepository: GroupRepository, - @Autowired private val authService: AuthService + @Autowired private val groupRepository: GroupRepository ) { private lateinit var restGroupMockMvc: MockMvc private lateinit var group: Group @@ -77,18 +75,19 @@ internal class GroupResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val groupResource = GroupResource() - ReflectionTestUtils.setField(groupResource, "groupService", groupService) - ReflectionTestUtils.setField(groupResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) restGroupMockMvc = - MockMvcBuilders.standaloneSetup(groupResource).setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator).setMessageConverters(jacksonMessageConverter) - .addFilter(filter).defaultRequest( + MockMvcBuilders.standaloneSetup(groupResource) + .setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator) + .setMessageConverters(jacksonMessageConverter) + .addFilter(filter) + .defaultRequest( MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken()) - ).build() - project = ProjectResourceIntTest.Companion.createEntity() + ) + .build() + project = ProjectResourceIntTest.createEntity() projectRepository.save(project) group = createEntity() } @@ -166,7 +165,7 @@ internal class GroupResourceIntTest( @Test @Throws(Exception::class) fun createGroupWithExistingNameInDifferentProject() { - val project2: Project = ProjectResourceIntTest.Companion.createEntity().projectName(project.projectName + "2") + val project2: Project = ProjectResourceIntTest.createEntity().projectName(project.projectName + "2") projectRepository.saveAndFlush(project2) val group2 = Group() group2.name = group.name diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt index 7d196a709..41af322f6 100644 --- a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt @@ -42,7 +42,7 @@ import java.util.function.Consumer */ @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalApp::class]) -internal open class OAuthClientsResourceIntTest @Autowired constructor ( +internal class OAuthClientsResourceIntTest @Autowired constructor ( private val clientDetailsService: JdbcClientDetailsService, private val clientDetailsMapper: ClientDetailsMapper, private val subjectService: SubjectService, @@ -111,7 +111,7 @@ internal open class OAuthClientsResourceIntTest @Autowired constructor ( @Test @Transactional @Throws(Exception::class) - open fun createAndFetchOAuthClient() { + fun createAndFetchOAuthClient() { // fetch the created oauth client and check the json result restOauthClientMvc.perform( MockMvcRequestBuilders.get("/api/oauth-clients/" + details.clientId) @@ -205,7 +205,7 @@ internal open class OAuthClientsResourceIntTest @Autowired constructor ( @Test @Transactional @Throws(Exception::class) - open fun dupliceOAuthClient() { + fun dupliceOAuthClient() { restOauthClientMvc.perform( MockMvcRequestBuilders.post("/api/oauth-clients") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -217,7 +217,7 @@ internal open class OAuthClientsResourceIntTest @Autowired constructor ( @Test @Transactional @Throws(Exception::class) - open fun updateOAuthClient() { + fun updateOAuthClient() { // update the client details.refreshTokenValiditySeconds = 20L restOauthClientMvc.perform( @@ -240,7 +240,7 @@ internal open class OAuthClientsResourceIntTest @Autowired constructor ( @Test @Transactional @Throws(Exception::class) - open fun deleteOAuthClient() { + fun deleteOAuthClient() { restOauthClientMvc.perform( MockMvcRequestBuilders.delete("/api/oauth-clients/" + details.clientId) .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -254,7 +254,7 @@ internal open class OAuthClientsResourceIntTest @Autowired constructor ( @Test @Transactional @Throws(Exception::class) - open fun cannotModifyProtected() { + fun cannotModifyProtected() { // first change our test client to be protected details.additionalInformation!!["protected"] = "true" restOauthClientMvc.perform( From 6a080d1678333801c51e669eb5928dffef941d22 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 3 Nov 2023 13:22:16 +0100 Subject: [PATCH 112/158] fix failing tests in OAuthClientsResourceIntTest.kt, OrganizationResourceIntTest.kt and SourceDataResourceIntTest.kt --- .../management/domain/Organization.kt | 3 +- .../radarbase/management/domain/Project.kt | 7 +- .../management/service/SourceDataService.kt | 16 +- .../management/service/dto/OrganizationDTO.kt | 1 + .../management/service/dto/SourceDataDTO.kt | 4 +- .../web/rest/OAuthClientsResource.kt | 97 ++++----- .../web/rest/OrganizationResource.kt | 69 ++++--- .../management/web/rest/SourceDataResource.kt | 4 +- .../web/rest/OAuthClientsResourceIntTest.kt | 190 ++++++------------ .../web/rest/OrganizationResourceIntTest.kt | 3 +- .../web/rest/SourceDataResourceIntTest.kt | 32 ++- .../web/rest/SubjectResourceIntTest.kt | 59 ++---- 12 files changed, 191 insertions(+), 294 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Organization.kt b/src/main/java/org/radarbase/management/domain/Organization.kt index 283450a18..d0aa47a37 100644 --- a/src/main/java/org/radarbase/management/domain/Organization.kt +++ b/src/main/java/org/radarbase/management/domain/Organization.kt @@ -48,7 +48,8 @@ class Organization : AbstractEntity() { @JvmField @OneToMany(mappedBy = "organization") - var projects: List? = null + var projects: List = emptyList() + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index 3c142bc38..0713e5f72 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -87,14 +87,14 @@ class Project : AbstractEntity(), Serializable { @Column(name = "end_date") var endDate: ZonedDateTime? = null - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @JsonIgnore @OneToMany(mappedBy = "project", fetch = FetchType.LAZY) @Cascade(CascadeType.ALL) var roles: Set = HashSet() @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @ManyToMany(fetch = FetchType.LAZY) @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) @JoinTable( @@ -105,7 +105,7 @@ class Project : AbstractEntity(), Serializable { var sourceTypes: Set = HashSet() @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @ElementCollection(fetch = FetchType.EAGER) @MapKeyColumn(name = "attribute_key") @Column(name = "attribute_value") @@ -113,7 +113,6 @@ class Project : AbstractEntity(), Serializable { var attributes: MutableMap = HashMap() @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) @NotAudited @OneToMany( mappedBy = "project", diff --git a/src/main/java/org/radarbase/management/service/SourceDataService.kt b/src/main/java/org/radarbase/management/service/SourceDataService.kt index 03ab7afd0..0053f43f4 100644 --- a/src/main/java/org/radarbase/management/service/SourceDataService.kt +++ b/src/main/java/org/radarbase/management/service/SourceDataService.kt @@ -18,7 +18,7 @@ import org.springframework.transaction.annotation.Transactional */ @Service @Transactional -open class SourceDataService( +class SourceDataService( private val sourceDataRepository: SourceDataRepository, private val sourceDataMapper: SourceDataMapper ) { @@ -30,9 +30,9 @@ open class SourceDataService( */ fun save(sourceDataDto: SourceDataDTO?): SourceDataDTO? { log.debug("Request to save SourceData : {}", sourceDataDto) - if (sourceDataDto!!.sourceDataType == null) { + if (sourceDataDto?.sourceDataType == null) { throw BadRequestException( - ErrorConstants.ERR_VALIDATION, EntityName.Companion.SOURCE_DATA, + ErrorConstants.ERR_VALIDATION, EntityName.SOURCE_DATA, "Source Data must contain a type or a topic." ) } @@ -47,7 +47,7 @@ open class SourceDataService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(): List { + fun findAll(): List { log.debug("Request to get all SourceData") return sourceDataRepository.findAll().stream() .map { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } @@ -60,7 +60,7 @@ open class SourceDataService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(pageable: Pageable?): Page { + fun findAll(pageable: Pageable?): Page { log.debug("Request to get all SourceData") return sourceDataRepository.findAll(pageable) .map { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } @@ -73,7 +73,7 @@ open class SourceDataService( * @return the entity */ @Transactional(readOnly = true) - open fun findOne(id: Long): SourceDataDTO? { + fun findOne(id: Long): SourceDataDTO? { log.debug("Request to get SourceData : {}", id) val sourceData = sourceDataRepository.findById(id).get() return sourceDataMapper.sourceDataToSourceDataDTO(sourceData) @@ -86,7 +86,7 @@ open class SourceDataService( * @return the entity */ @Transactional(readOnly = true) - open fun findOneBySourceDataName(sourceDataName: String?): SourceDataDTO? { + fun findOneBySourceDataName(sourceDataName: String?): SourceDataDTO? { log.debug("Request to get SourceData : {}", sourceDataName) return sourceDataRepository.findOneBySourceDataName(sourceDataName) .let { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } @@ -98,7 +98,7 @@ open class SourceDataService( * @param id the id of the entity */ @Transactional - open fun delete(id: Long?) { + fun delete(id: Long?) { log.debug("Request to delete SourceData : {}", id) sourceDataRepository.deleteById(id) } diff --git a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt index 06d2ef19e..7fce03b43 100644 --- a/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/OrganizationDTO.kt @@ -16,6 +16,7 @@ class OrganizationDTO : Serializable { @NotNull var location: String? = null var projects: List = emptyList() + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt index 0bf175343..34a3e7dcf 100644 --- a/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/SourceDataDTO.kt @@ -10,8 +10,10 @@ import java.util.* class SourceDataDTO : Serializable { var id: Long? = null - //Source data type. + /** Source data type. Defaults to the topic of the source data. */ var sourceDataType: String? = null + get() = field ?: topic + var sourceDataName: String? = null //Default data frequency diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt index 600db7e5f..eec2b4409 100644 --- a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt @@ -43,45 +43,31 @@ import javax.validation.Valid */ @RestController @RequestMapping("/api") -class OAuthClientsResource { - @Autowired - private val oAuthClientService: OAuthClientService? = null +class OAuthClientsResource( + @Autowired private val oAuthClientService: OAuthClientService, + @Autowired private val metaTokenService: MetaTokenService, + @Autowired private val clientDetailsMapper: ClientDetailsMapper, + @Autowired private val subjectService: SubjectService, + @Autowired private val userService: UserService, + @Autowired private val eventRepository: AuditEventRepository, + @Autowired private val authService: AuthService +) { - @Autowired - private val metaTokenService: MetaTokenService? = null - - @Autowired - private val clientDetailsMapper: ClientDetailsMapper? = null - - @Autowired - private val subjectService: SubjectService? = null - - @Autowired - private val userService: UserService? = null - - @Autowired - private val eventRepository: AuditEventRepository? = null - - @Autowired - private val authService: AuthService? = null - - @get:Throws(NotAuthorizedException::class) - @get:Timed - @get:GetMapping("/oauth-clients") - val oAuthClients: ResponseEntity> - /** - * GET /api/oauth-clients. - * - * - * Retrieve a list of currently registered OAuth clients. - * - * @return the list of registered clients as a list of [ClientDetailsDTO] - */ - get() { - authService!!.checkPermission(Permission.OAUTHCLIENTS_READ) + @Throws(NotAuthorizedException::class) + @Timed + @GetMapping("/oauth-clients") + /** + * GET /api/oauth-clients. + * + * + * Retrieve a list of currently registered OAuth clients. + * + * @return the list of registered clients as a list of [ClientDetailsDTO] + */ + fun oAuthClients(): ResponseEntity> { + authService.checkPermission(Permission.OAUTHCLIENTS_READ) return ResponseEntity.ok().body( - clientDetailsMapper - ?.clientDetailsToClientDetailsDTO(oAuthClientService!!.findAllOAuthClients()) + clientDetailsMapper.clientDetailsToClientDetailsDTO(oAuthClientService.findAllOAuthClients()) ) } @@ -100,12 +86,13 @@ class OAuthClientsResource { NotAuthorizedException::class ) fun getOAuthClientById(@PathVariable("id") id: String?): ResponseEntity { - authService!!.checkPermission(Permission.OAUTHCLIENTS_READ) + authService.checkPermission(Permission.OAUTHCLIENTS_READ) + + val client = oAuthClientService.findOneByClientId(id) + val clientDTO = clientDetailsMapper.clientDetailsToClientDetailsDTO(client) + // getOAuthClient checks if the id exists - return ResponseEntity.ok().body( - clientDetailsMapper - ?.clientDetailsToClientDetailsDTO(oAuthClientService!!.findOneByClientId(id)) - ) + return ResponseEntity.ok().body(clientDTO) } /** @@ -121,9 +108,9 @@ class OAuthClientsResource { @Timed @Throws(NotAuthorizedException::class) fun updateOAuthClient(@RequestBody @Valid clientDetailsDto: ClientDetailsDTO?): ResponseEntity { - authService!!.checkPermission(Permission.OAUTHCLIENTS_UPDATE) + authService.checkPermission(Permission.OAUTHCLIENTS_UPDATE) // getOAuthClient checks if the id exists - OAuthClientService.checkProtected(oAuthClientService!!.findOneByClientId(clientDetailsDto!!.clientId)) + OAuthClientService.checkProtected(oAuthClientService.findOneByClientId(clientDetailsDto!!.clientId)) val updated = oAuthClientService.updateOauthClient(clientDetailsDto) return ResponseEntity.ok() .headers( @@ -132,7 +119,7 @@ class OAuthClientsResource { clientDetailsDto.clientId ) ) - .body(clientDetailsMapper!!.clientDetailsToClientDetailsDTO(updated)) + .body(clientDetailsMapper.clientDetailsToClientDetailsDTO(updated)) } /** @@ -150,9 +137,9 @@ class OAuthClientsResource { NotAuthorizedException::class ) fun deleteOAuthClient(@PathVariable id: String?): ResponseEntity { - authService!!.checkPermission(Permission.OAUTHCLIENTS_DELETE) + authService.checkPermission(Permission.OAUTHCLIENTS_DELETE) // getOAuthClient checks if the id exists - OAuthClientService.checkProtected(oAuthClientService!!.findOneByClientId(id)) + OAuthClientService.checkProtected(oAuthClientService.findOneByClientId(id)) oAuthClientService.deleteClientDetails(id) return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(EntityName.OAUTH_CLIENT, id)) .build() @@ -172,11 +159,11 @@ class OAuthClientsResource { @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) fun createOAuthClient(@RequestBody clientDetailsDto: @Valid ClientDetailsDTO): ResponseEntity { - authService!!.checkPermission(Permission.OAUTHCLIENTS_CREATE) - val created = oAuthClientService!!.createClientDetail(clientDetailsDto) + authService.checkPermission(Permission.OAUTHCLIENTS_CREATE) + val created = oAuthClientService.createClientDetail(clientDetailsDto) return ResponseEntity.created(ResourceUriService.getUri(clientDetailsDto)) .headers(HeaderUtil.createEntityCreationAlert(EntityName.OAUTH_CLIENT, created.clientId)) - .body(clientDetailsMapper!!.clientDetailsToClientDetailsDTO(created)) + .body(clientDetailsMapper.clientDetailsToClientDetailsDTO(created)) } /** @@ -199,15 +186,15 @@ class OAuthClientsResource { @RequestParam(value = "clientId") clientId: String, @RequestParam(value = "persistent", defaultValue = "false") persistent: Boolean? ): ResponseEntity { - authService!!.checkScope(Permission.SUBJECT_UPDATE) + authService.checkScope(Permission.SUBJECT_UPDATE) val currentUser = - userService!!.userWithAuthorities // We only allow this for actual logged in users for now, not for client_credentials + userService.userWithAuthorities // We only allow this for actual logged in users for now, not for client_credentials ?: throw AccessDeniedException( "You must be a logged in user to access this resource" ) // lookup the subject - val subject = subjectService!!.findOneByLogin(login) + val subject = subjectService.findOneByLogin(login) val projectName: String = subject.activeProject ?.projectName ?: throw NotFoundException( @@ -220,9 +207,9 @@ class OAuthClientsResource { authService.checkPermission( Permission.SUBJECT_UPDATE, { e: EntityDetails -> e.project(projectName).subject(login) }) - val cpi = metaTokenService!!.createMetaToken(subject, clientId, persistent!!) + val cpi = metaTokenService.createMetaToken(subject, clientId, persistent!!) // generate audit event - eventRepository!!.add( + eventRepository.add( AuditEvent( currentUser.login, "PAIR_CLIENT_REQUEST", "client_id=$clientId", "subject_login=$login" diff --git a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt index 7f87ab0cc..ea2acdbe1 100644 --- a/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OrganizationResource.kt @@ -36,8 +36,7 @@ import javax.validation.Valid @RestController @RequestMapping("/api") class OrganizationResource( - @Autowired private val organizationService: OrganizationService, - @Autowired private val authService: AuthService + @Autowired private val organizationService: OrganizationService, @Autowired private val authService: AuthService ) { /** @@ -57,39 +56,40 @@ class OrganizationResource( ): ResponseEntity { log.debug("REST request to save Organization : {}", organizationDto) authService.checkPermission(Permission.ORGANIZATION_CREATE) - if (organizationDto!!.id != null) { + if (organizationDto?.id != null) { val msg = "A new organization cannot already have an ID" val headers = createFailureAlert(ENTITY_NAME, "idexists", msg) return ResponseEntity.badRequest().headers(headers).body(null) } - val existingOrg = organizationDto.name?.let { organizationService.findByName(it) } + val existingOrg = organizationDto?.name?.let { organizationService.findByName(it) } if (existingOrg != null) { val msg = "An organization with this name already exists" val headers = createFailureAlert(ENTITY_NAME, "nameexists", msg) return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers).body(null) } - val result = organizationService.save(organizationDto) - return ResponseEntity.created(getUri(result)) - .headers(createEntityCreationAlert(ENTITY_NAME, result.name)) - .body(result) + val result = organizationDto?.let { organizationService.save(it) } + return result?.let { getUri(it) }?.let { + ResponseEntity.created(it).headers(createEntityCreationAlert(ENTITY_NAME, result.name)).body(result) + } + //TODO handle better + ?: ResponseEntity.badRequest().body(null) } - @get:Throws(NotAuthorizedException::class) - @get:Timed - @get:GetMapping("/organizations") - val allOrganizations: ResponseEntity<*> - /** - * GET /organizations : get all the organizations. - * - * @return the ResponseEntity with status 200 (OK) - * and the list of organizations in body - */ - get() { - log.debug("REST request to get Organizations") - authService.checkScope(Permission.ORGANIZATION_READ) - val orgs = organizationService.findAll() - return ResponseEntity(orgs, HttpStatus.OK) - } + /** + * GET /organizations : get all the organizations. + * + * @return the ResponseEntity with status 200 (OK) + * and the list of organizations in body + */ + @Throws(NotAuthorizedException::class) + @Timed + @GetMapping("/organizations") + fun allOrganizations(): ResponseEntity<*> { + log.debug("REST request to get Organizations") + authService.checkScope(Permission.ORGANIZATION_READ) + val orgs = organizationService.findAll() + return ResponseEntity(orgs, HttpStatus.OK) + } /** * PUT /organizations : Updates an existing organization. @@ -112,11 +112,9 @@ class OrganizationResource( return createOrganization(organizationDto) } val name = organizationDto.name - authService.checkPermission(Permission.ORGANIZATION_UPDATE, { (organization): EntityDetails -> organization }) + authService.checkPermission(Permission.ORGANIZATION_UPDATE, { e: EntityDetails -> e.organization(name) }) val result = organizationService.save(organizationDto) - return ResponseEntity.ok() - .headers(createEntityCreationAlert(ENTITY_NAME, result.name)) - .body(result) + return ResponseEntity.ok().headers(createEntityCreationAlert(ENTITY_NAME, result.name)).body(result) } /** @@ -136,13 +134,14 @@ class OrganizationResource( @PathVariable name: String ): ResponseEntity { log.debug("REST request to get Organization : {}", name) - authService.checkPermission(Permission.ORGANIZATION_READ, { (organization): EntityDetails -> organization }) + authService.checkPermission(Permission.ORGANIZATION_READ, { e: EntityDetails -> e.organization(name) }) val org = organizationService.findByName(name) val dto = org ?: throw NotFoundException( - "Organization not found with name $name", - EntityName.ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, - Collections.singletonMap("name", name) - ) + "Organization not found with name $name", + EntityName.ORGANIZATION, + ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, + Collections.singletonMap("name", name) + ) return ResponseEntity.ok(dto) } @@ -164,8 +163,8 @@ class OrganizationResource( @PathVariable name: String? ): ResponseEntity> { log.debug("REST request to get Projects of the Organization : {}", name) - authService.checkPermission(Permission.PROJECT_READ, { (organization): EntityDetails -> organization }) - val projects = organizationService.findAllProjectsByOrganizationName(name!!) + authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.organization(name) }) + val projects = name?.let { organizationService.findAllProjectsByOrganizationName(it) } return ResponseEntity.ok(projects) } diff --git a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt index cbbbc6090..352934caa 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt @@ -55,10 +55,10 @@ class SourceDataResource( @PostMapping("/source-data") @Timed @Throws(URISyntaxException::class, NotAuthorizedException::class) - fun createSourceData(@RequestBody @Valid sourceDataDto: SourceDataDTO?): ResponseEntity { + fun createSourceData(@RequestBody @Valid sourceDataDto: SourceDataDTO): ResponseEntity { log.debug("REST request to save SourceData : {}", sourceDataDto) authService.checkPermission(Permission.SOURCEDATA_CREATE) - if (sourceDataDto!!.id != null) { + if (sourceDataDto.id != null) { return ResponseEntity.badRequest().headers( createFailureAlert( EntityName.SOURCE_DATA, diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt index 41af322f6..513307e69 100644 --- a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt @@ -2,19 +2,15 @@ package org.radarbase.management.web.rest import org.assertj.core.api.Assertions import org.hamcrest.Matchers +import org.hamcrest.Matchers.containsInAnyOrder import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith import org.mockito.MockitoAnnotations import org.radarbase.auth.authentication.OAuthHelper import org.radarbase.management.ManagementPortalApp -import org.radarbase.management.service.AuthService -import org.radarbase.management.service.OAuthClientService import org.radarbase.management.service.OAuthClientServiceTestUtil -import org.radarbase.management.service.SubjectService -import org.radarbase.management.service.UserService import org.radarbase.management.service.dto.ClientDetailsDTO -import org.radarbase.management.service.mapper.ClientDetailsMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest @@ -26,7 +22,6 @@ import org.springframework.security.core.GrantedAuthority import org.springframework.security.oauth2.provider.ClientDetails import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -42,16 +37,12 @@ import java.util.function.Consumer */ @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalApp::class]) -internal class OAuthClientsResourceIntTest @Autowired constructor ( - private val clientDetailsService: JdbcClientDetailsService, - private val clientDetailsMapper: ClientDetailsMapper, - private val subjectService: SubjectService, - private val userService: UserService, - private val oAuthClientService: OAuthClientService, - private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, - private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, - private val exceptionTranslator: ExceptionTranslator, - private val authService: AuthService +internal class OAuthClientsResourceIntTest @Autowired constructor( + @Autowired private val oauthClientsResource: OAuthClientsResource, + @Autowired private val clientDetailsService: JdbcClientDetailsService, + @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, + @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, + @Autowired private val exceptionTranslator: ExceptionTranslator, ) { private lateinit var restOauthClientMvc: MockMvc private lateinit var details: ClientDetailsDTO @@ -62,46 +53,22 @@ internal class OAuthClientsResourceIntTest @Autowired constructor ( @Throws(Exception::class) fun setUp() { MockitoAnnotations.openMocks(this) - val oauthClientsResource = OAuthClientsResource() - ReflectionTestUtils.setField( - oauthClientsResource, "clientDetailsMapper", - clientDetailsMapper - ) - ReflectionTestUtils.setField( - oauthClientsResource, "subjectService", - subjectService - ) - ReflectionTestUtils.setField( - oauthClientsResource, "userService", - userService - ) - ReflectionTestUtils.setField( - oauthClientsResource, "authService", - authService - ) - ReflectionTestUtils.setField( - oauthClientsResource, "oAuthClientService", - oAuthClientService - ) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) - restOauthClientMvc = MockMvcBuilders.standaloneSetup(oauthClientsResource) - .setCustomArgumentResolvers(pageableArgumentResolver) - .setControllerAdvice(exceptionTranslator) - .setMessageConverters(jacksonMessageConverter) - .addFilter(filter) - .defaultRequest(MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken())) - .build() + restOauthClientMvc = + MockMvcBuilders.standaloneSetup(oauthClientsResource).setCustomArgumentResolvers(pageableArgumentResolver) + .setControllerAdvice(exceptionTranslator).setMessageConverters(jacksonMessageConverter) + .addFilter(filter).defaultRequest( + MockMvcRequestBuilders.get("/").with(OAuthHelper.bearerToken()) + ).build() databaseSizeBeforeCreate = clientDetailsService.listClientDetails().size // Create the OAuth Client details = OAuthClientServiceTestUtil.createClient() restOauthClientMvc.perform( - MockMvcRequestBuilders.post("/api/oauth-clients") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/oauth-clients").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isCreated()) + ).andExpect(MockMvcResultMatchers.status().isCreated()) // Validate the Project in the database clientDetailsList = clientDetailsService.listClientDetails() @@ -113,65 +80,39 @@ internal class OAuthClientsResourceIntTest @Autowired constructor ( @Throws(Exception::class) fun createAndFetchOAuthClient() { // fetch the created oauth client and check the json result - restOauthClientMvc.perform( - MockMvcRequestBuilders.get("/api/oauth-clients/" + details.clientId) - .accept(MediaType.APPLICATION_JSON) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect( - MockMvcResultMatchers.jsonPath("$.clientId").value( - Matchers.equalTo( - details.clientId - ) - ) - ) - .andExpect(MockMvcResultMatchers.jsonPath("$.clientSecret").value(Matchers.nullValue())) - .andExpect( - MockMvcResultMatchers.jsonPath("$.accessTokenValiditySeconds").value( - Matchers.equalTo( - details - .accessTokenValiditySeconds?.toInt() - ) + var ans = restOauthClientMvc.perform( + MockMvcRequestBuilders.get("/api/oauth-clients/" + details.clientId).accept(MediaType.APPLICATION_JSON) + ).andExpect( + MockMvcResultMatchers.status().isOk() + ).andExpect( + MockMvcResultMatchers.jsonPath("$.clientId").value(Matchers.equalTo(details.clientId)) + ).andExpect(MockMvcResultMatchers.jsonPath("$.clientSecret").value(Matchers.nullValue())).andExpect( + MockMvcResultMatchers.jsonPath("$.accessTokenValiditySeconds").value( + Matchers.equalTo( + details.accessTokenValiditySeconds?.toInt() ) ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.refreshTokenValiditySeconds").value( - Matchers.equalTo( - details - .refreshTokenValiditySeconds?.toInt() - ) + ).andExpect( + MockMvcResultMatchers.jsonPath("$.refreshTokenValiditySeconds").value( + Matchers.equalTo( + details.refreshTokenValiditySeconds?.toInt() ) ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.scope").value( - Matchers.containsInAnyOrder( - details.scope?.toTypedArray() - ) - ) + ).andExpect( + MockMvcResultMatchers.jsonPath("$.scope") + .value(containsInAnyOrder(details.scope?.map { Matchers.equalTo(it) })) + ).andExpect(MockMvcResultMatchers.jsonPath("$.autoApproveScopes") + .value(containsInAnyOrder(details.autoApproveScopes?.map { Matchers.equalTo(it) }))) + .andExpect(MockMvcResultMatchers.jsonPath("$.authorizedGrantTypes") + .value(containsInAnyOrder(details.authorizedGrantTypes?.map { Matchers.equalTo(it) }))).andExpect( + MockMvcResultMatchers.jsonPath("$.authorities").value( + containsInAnyOrder(details.authorities?.map { Matchers.equalTo(it) }) ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.autoApproveScopes").value( - Matchers.containsInAnyOrder( - details.autoApproveScopes?.toTypedArray() - ) - ) - ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.authorizedGrantTypes").value( - Matchers.containsInAnyOrder( - details.authorizedGrantTypes?.toTypedArray() - ) - ) - ) - .andExpect( - MockMvcResultMatchers.jsonPath("$.authorities").value( - Matchers.containsInAnyOrder(details.authorities?.toTypedArray()) - ) - ) - val testDetails = clientDetailsList.stream() - .filter { d: ClientDetails -> d.clientId == details.clientId } - .findFirst() - .orElseThrow() + ) + + val testDetails = + clientDetailsList.stream().filter { d: ClientDetails -> d.clientId == details.clientId }.findFirst() + .orElseThrow() Assertions.assertThat(testDetails.clientSecret).startsWith("$2a$10$") Assertions.assertThat(testDetails.scope).containsExactlyInAnyOrderElementsOf( details.scope @@ -205,13 +146,11 @@ internal class OAuthClientsResourceIntTest @Autowired constructor ( @Test @Transactional @Throws(Exception::class) - fun dupliceOAuthClient() { + fun duplicateOAuthClient() { restOauthClientMvc.perform( - MockMvcRequestBuilders.post("/api/oauth-clients") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.post("/api/oauth-clients").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isConflict()) + ).andExpect(MockMvcResultMatchers.status().isConflict()) } @Test @@ -221,19 +160,16 @@ internal class OAuthClientsResourceIntTest @Autowired constructor ( // update the client details.refreshTokenValiditySeconds = 20L restOauthClientMvc.perform( - MockMvcRequestBuilders.put("/api/oauth-clients") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.put("/api/oauth-clients").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) // fetch the client clientDetailsList = clientDetailsService.listClientDetails() Assertions.assertThat(clientDetailsList).hasSize(databaseSizeBeforeCreate + 1) - val testDetails = clientDetailsList.stream() - .filter { d: ClientDetails -> d.clientId == details.clientId } - .findFirst() - .orElseThrow() + val testDetails = + clientDetailsList.stream().filter { d: ClientDetails -> d.clientId == details.clientId }.findFirst() + .orElseThrow() Assertions.assertThat(testDetails.refreshTokenValiditySeconds).isEqualTo(20) } @@ -243,10 +179,8 @@ internal class OAuthClientsResourceIntTest @Autowired constructor ( fun deleteOAuthClient() { restOauthClientMvc.perform( MockMvcRequestBuilders.delete("/api/oauth-clients/" + details.clientId) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + .contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(details)) + ).andExpect(MockMvcResultMatchers.status().isOk()) val clientDetailsList = clientDetailsService.listClientDetails() Assertions.assertThat(clientDetailsList.size).isEqualTo(databaseSizeBeforeCreate) } @@ -258,27 +192,21 @@ internal class OAuthClientsResourceIntTest @Autowired constructor ( // first change our test client to be protected details.additionalInformation!!["protected"] = "true" restOauthClientMvc.perform( - MockMvcRequestBuilders.put("/api/oauth-clients") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.put("/api/oauth-clients").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isOk()) + ).andExpect(MockMvcResultMatchers.status().isOk()) // expect we can not delete it now restOauthClientMvc.perform( MockMvcRequestBuilders.delete("/api/oauth-clients/" + details.clientId) - .contentType(TestUtil.APPLICATION_JSON_UTF8) - .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isForbidden()) + .contentType(TestUtil.APPLICATION_JSON_UTF8).content(TestUtil.convertObjectToJsonBytes(details)) + ).andExpect(MockMvcResultMatchers.status().isForbidden()) // expect we can not update it now details.refreshTokenValiditySeconds = 20L restOauthClientMvc.perform( - MockMvcRequestBuilders.put("/api/oauth-clients") - .contentType(TestUtil.APPLICATION_JSON_UTF8) + MockMvcRequestBuilders.put("/api/oauth-clients").contentType(TestUtil.APPLICATION_JSON_UTF8) .content(TestUtil.convertObjectToJsonBytes(details)) - ) - .andExpect(MockMvcResultMatchers.status().isForbidden()) + ).andExpect(MockMvcResultMatchers.status().isForbidden()) } } diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index 0d0a86a7a..5abcf00e0 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -15,6 +15,7 @@ import org.radarbase.management.repository.OrganizationRepository import org.radarbase.management.repository.ProjectRepository import org.radarbase.management.service.AuthService import org.radarbase.management.service.OrganizationService +import org.radarbase.management.service.dto.OrganizationDTO import org.radarbase.management.service.mapper.OrganizationMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired @@ -177,7 +178,7 @@ internal open class OrganizationResourceIntTest( @Throws(Exception::class) //TODO this is covered by not using a nullable type fun checkGroupNameIsRequired() { - val orgDto = organizationMapper.organizationToOrganizationDTO(organization) + val orgDto: OrganizationDTO = organizationMapper.organizationToOrganizationDTO(organization) orgDto.name = null restOrganizationMockMvc.perform( MockMvcRequestBuilders.post("/api/organizations") diff --git a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt index 87bd2cff6..441ba818c 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceDataResourceIntTest.kt @@ -12,6 +12,7 @@ import org.radarbase.management.domain.SourceData import org.radarbase.management.repository.SourceDataRepository import org.radarbase.management.service.AuthService import org.radarbase.management.service.SourceDataService +import org.radarbase.management.service.dto.SourceDataDTO import org.radarbase.management.service.mapper.SourceDataMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired @@ -22,7 +23,6 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.mock.web.MockFilterConfig import org.springframework.security.test.context.support.WithMockUser import org.springframework.test.context.junit.jupiter.SpringExtension -import org.springframework.test.util.ReflectionTestUtils import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders import org.springframework.test.web.servlet.result.MockMvcResultMatchers @@ -39,7 +39,7 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class SourceDataResourceIntTest( +internal class SourceDataResourceIntTest( @Autowired private val sourceDataRepository: SourceDataRepository, @Autowired private val sourceDataMapper: SourceDataMapper, @Autowired private val sourceDataService: SourceDataService, @@ -59,8 +59,6 @@ internal open class SourceDataResourceIntTest( sourceDataService, authService ) - ReflectionTestUtils.setField(sourceDataResource, "sourceDataService", sourceDataService) - ReflectionTestUtils.setField(sourceDataResource, "authService", authService) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) restSourceDataMockMvc = MockMvcBuilders.standaloneSetup(sourceDataResource) @@ -80,7 +78,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSourceData() { + fun createSourceData() { val databaseSizeBeforeCreate = sourceDataRepository.findAll().size // Create the SourceData @@ -109,7 +107,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSourceDataWithExistingId() { + fun createSourceDataWithExistingId() { val databaseSizeBeforeCreate = sourceDataRepository.findAll().size // Create the SourceData with an existing ID @@ -132,13 +130,13 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkSourceDataTypeIsNotRequired() { + fun checkSourceDataTypeIsNotRequired() { val databaseSizeBeforeTest = sourceDataRepository.findAll().size // set the field null sourceData.sourceDataType = null // Create the SourceData, which fails. - val sourceDataDto = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) + val sourceDataDto: SourceDataDTO? = sourceDataMapper.sourceDataToSourceDataDTO(sourceData) restSourceDataMockMvc.perform( MockMvcRequestBuilders.post("/api/source-data") .contentType(TestUtil.APPLICATION_JSON_UTF8) @@ -152,7 +150,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkSourceDataTypeOrTopicIsRequired() { + fun checkSourceDataTypeOrTopicIsRequired() { val databaseSizeBeforeTest = sourceDataRepository.findAll().size // set the field null sourceData.sourceDataType = null @@ -173,7 +171,7 @@ internal open class SourceDataResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun allSourceData() { + fun allSourceData() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) @@ -243,7 +241,7 @@ internal open class SourceDataResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun allSourceDataWithPagination() { + fun allSourceDataWithPagination() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) @@ -313,7 +311,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun getSourceData() { + fun getSourceData() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) @@ -340,7 +338,7 @@ internal open class SourceDataResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun nonExistingSourceData() { + fun nonExistingSourceData() { // Get the sourceData restSourceDataMockMvc.perform( MockMvcRequestBuilders.get( @@ -354,7 +352,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateSourceData() { + fun updateSourceData() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) val databaseSizeBeforeUpdate = sourceDataRepository.findAll().size @@ -395,7 +393,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateNonExistingSourceData() { + fun updateNonExistingSourceData() { val databaseSizeBeforeUpdate = sourceDataRepository.findAll().size // Create the SourceData @@ -417,7 +415,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun deleteSourceData() { + fun deleteSourceData() { // Initialize the database sourceDataRepository.saveAndFlush(sourceData) val databaseSizeBeforeDelete = sourceDataRepository.findAll().size @@ -440,7 +438,7 @@ internal open class SourceDataResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun equalsVerifier() { + fun equalsVerifier() { org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(SourceData::class.java)) } diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index be76669ca..5189d05f9 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -9,10 +9,7 @@ import org.mockito.MockitoAnnotations import org.radarbase.auth.authentication.OAuthHelper import org.radarbase.management.ManagementPortalTestApp import org.radarbase.management.domain.Subject -import org.radarbase.management.repository.ProjectRepository import org.radarbase.management.repository.SubjectRepository -import org.radarbase.management.service.AuthService -import org.radarbase.management.service.RevisionService import org.radarbase.management.service.SourceService import org.radarbase.management.service.SourceTypeService import org.radarbase.management.service.SubjectService @@ -25,7 +22,6 @@ import org.radarbase.management.service.dto.SubjectDTO import org.radarbase.management.service.mapper.SubjectMapper import org.radarbase.management.web.rest.errors.ExceptionTranslator import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.actuate.audit.AuditEventRepository import org.springframework.boot.test.context.SpringBootTest import org.springframework.data.web.PageableHandlerMethodArgumentResolver import org.springframework.http.MediaType @@ -51,7 +47,8 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class SubjectResourceIntTest( +internal class SubjectResourceIntTest( + @Autowired private val subjectResource: SubjectResource, @Autowired private val subjectRepository: SubjectRepository, @Autowired private val subjectMapper: SubjectMapper, @Autowired private val subjectService: SubjectService, @@ -60,10 +57,6 @@ internal open class SubjectResourceIntTest( @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val projectRepository: ProjectRepository, - @Autowired private val authService: AuthService, - @Autowired private val revisionService: RevisionService, - @Autowired private val eventRepository: AuditEventRepository ) { private lateinit var restSubjectMockMvc: MockMvc @@ -71,17 +64,6 @@ internal open class SubjectResourceIntTest( @Throws(ServletException::class) fun setUp() { MockitoAnnotations.openMocks(this) - val subjectResource = SubjectResource( - subjectService, - subjectRepository, - subjectMapper, - projectRepository, - sourceTypeService, - eventRepository, - revisionService, - sourceService, - authService - ) val filter = OAuthHelper.createAuthenticationFilter() filter.init(MockFilterConfig()) @@ -97,7 +79,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSubject() { + fun createSubject() { val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject @@ -120,7 +102,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSubjectWithExistingId() { + fun createSubjectWithExistingId() { // Create a Subject val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeCreate = subjectRepository.findAll().size @@ -139,7 +121,7 @@ internal open class SubjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun allSubjects() { + fun allSubjects() { // Initialize the database val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) @@ -167,7 +149,7 @@ internal open class SubjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun subject() { + fun subject() { // Initialize the database val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) @@ -187,7 +169,7 @@ internal open class SubjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun nonExistingSubject() { + fun nonExistingSubject() { // Get the subject restSubjectMockMvc.perform(MockMvcRequestBuilders.get("/api/subjects/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) @@ -196,7 +178,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateSubject() { + fun updateSubject() { // Initialize the database var subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeUpdate = subjectRepository.findAll().size @@ -223,7 +205,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateSubjectWithNewProject() { + fun updateSubjectWithNewProject() { // Initialize the database var subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeUpdate = subjectRepository.findAll().size @@ -256,7 +238,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateNonExistingSubject() { + fun updateNonExistingSubject() { val databaseSizeBeforeUpdate = subjectRepository.findAll().size // Create the Subject @@ -276,7 +258,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun deleteSubject() { + fun deleteSubject() { // Initialize the database val subjectDto = subjectService.createSubject(SubjectServiceTest.createEntityDTO()) val databaseSizeBeforeDelete = subjectRepository.findAll().size @@ -295,14 +277,14 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun equalsVerifier() { + fun equalsVerifier() { org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Subject::class.java)) } @Test @Transactional @Throws(Exception::class) - open fun dynamicSourceRegistrationWithId() { + fun dynamicSourceRegistrationWithId() { val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject @@ -340,7 +322,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun dynamicSourceRegistrationWithoutId() { + fun dynamicSourceRegistrationWithoutId() { val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject @@ -388,7 +370,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun dynamicSourceRegistrationWithoutDynamicRegistrationFlag() { + fun dynamicSourceRegistrationWithoutDynamicRegistrationFlag() { val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject @@ -418,7 +400,7 @@ internal open class SubjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun subjectSources() { + fun subjectSources() { // Initialize the database val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) @@ -444,7 +426,7 @@ internal open class SubjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun subjectSourcesWithQueryParam() { + fun subjectSourcesWithQueryParam() { // Initialize the database val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) @@ -470,7 +452,7 @@ internal open class SubjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun inactiveSubjectSourcesWithQueryParam() { + fun inactiveSubjectSourcesWithQueryParam() { // Initialize the database val subjectDtoToCreate: SubjectDTO = SubjectServiceTest.createEntityDTO() val createdSource = sourceService.save(createSource()) @@ -534,8 +516,7 @@ internal open class SubjectResourceIntTest( private fun createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration(): MinimalSourceDetailsDTO { val sourceTypes = - sourceTypeService.findAll().stream().filter { it: SourceTypeDTO -> !it.canRegisterDynamically } - .collect(Collectors.toList()) + sourceTypeService.findAll().filter { it: SourceTypeDTO -> !it.canRegisterDynamically } Assertions.assertThat(sourceTypes.size).isPositive() val sourceType = sourceTypes[0] return source.sourceTypeCatalogVersion(sourceType.catalogVersion).sourceTypeModel(sourceType.model) @@ -554,7 +535,7 @@ internal open class SubjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun testDynamicRegistrationAndUpdateSourceAttributes() { + fun testDynamicRegistrationAndUpdateSourceAttributes() { val databaseSizeBeforeCreate = subjectRepository.findAll().size // Create the Subject From 28afdb707b76dfdb417cb72c0f67ea0fe3da1ff0 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 3 Nov 2023 15:56:40 +0100 Subject: [PATCH 113/158] all tests passing --- .../radarbase/management/domain/Subject.kt | 48 +++++----- .../repository/SubjectRepository.kt | 2 +- .../repository/filters/PredicateBuilder.kt | 2 +- .../filters/SubjectSpecification.kt | 26 ++--- .../service/dto/MinimalSourceDetailsDTO.kt | 2 +- .../management/web/rest/SubjectResource.kt | 4 +- .../management/web/rest/UserResource.kt | 4 +- .../web/rest/criteria/SubjectCriteria.kt | 95 ++++++++----------- .../web/rest/util/PaginationUtil.kt | 18 ++-- .../web/rest/SubjectResourceIntTest.kt | 27 +++--- .../web/rest/UserResourceIntTest.kt | 8 -- 11 files changed, 104 insertions(+), 132 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/Subject.kt b/src/main/java/org/radarbase/management/domain/Subject.kt index e20b23dc0..1d84aa5c4 100644 --- a/src/main/java/org/radarbase/management/domain/Subject.kt +++ b/src/main/java/org/radarbase/management/domain/Subject.kt @@ -81,7 +81,7 @@ class Subject( var sources: MutableSet = HashSet() @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @ElementCollection(fetch = FetchType.EAGER) @MapKeyColumn(name = "attribute_key") @Column(name = "attribute_value") @@ -114,25 +114,6 @@ class Subject( @JvmField @Column(name = "person_name") var personName: String? = null - fun externalLink(externalLink: String?): Subject { - this.externalLink = externalLink - return this - } - - fun externalId(enternalId: String?): Subject { - externalId = enternalId - return this - } - - fun user(usr: User?): Subject { - user = usr - return this - } - - fun sources(sources: MutableSet): Subject { - this.sources = sources - return this - } val activeProject: Project? /** @@ -147,6 +128,7 @@ class Subject( get() = user?.roles ?.firstOrNull { r -> r.authority?.name == RoleAuthority.PARTICIPANT.authority } ?.project + val associatedProject: Project? /** * Get the active project of a subject, and otherwise the @@ -155,13 +137,33 @@ class Subject( */ get() { val user = user ?: return null - return user.roles?.asIterable() + return user.roles ?.filter { r -> PARTICIPANT_TYPES.contains(r.authority?.name) } - ?.sortedBy { it.authority?.name }?.first() + ?.sortedBy { it.authority?.name }?.firstOrNull() .let { obj: Role? -> obj?.project } } + fun externalLink(externalLink: String?): Subject { + this.externalLink = externalLink + return this + } + + fun externalId(enternalId: String?): Subject { + externalId = enternalId + return this + } + + fun user(usr: User?): Subject { + user = usr + return this + } + + fun sources(sources: MutableSet): Subject { + this.sources = sources + return this + } + override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -194,7 +196,7 @@ class Subject( companion object { private const val serialVersionUID = 1L - private val PARTICIPANT_TYPES = java.util.Set.of( + private val PARTICIPANT_TYPES = mutableSetOf( RoleAuthority.PARTICIPANT.authority, RoleAuthority.INACTIVE_PARTICIPANT.authority ) diff --git a/src/main/java/org/radarbase/management/repository/SubjectRepository.kt b/src/main/java/org/radarbase/management/repository/SubjectRepository.kt index ac0738a87..15c6ee95f 100644 --- a/src/main/java/org/radarbase/management/repository/SubjectRepository.kt +++ b/src/main/java/org/radarbase/management/repository/SubjectRepository.kt @@ -123,6 +123,6 @@ interface SubjectRepository : JpaRepository, RevisionRepository< ) fun findSubjectSourcesBySourceId( @Param("login") login: String?, - @Param("sourceId") sourceId: UUID + @Param("sourceId") sourceId: UUID? ): Source? } diff --git a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt index aa1b5bb75..a35e4d9e0 100644 --- a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt +++ b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt @@ -43,7 +43,7 @@ class PredicateBuilder(val criteriaBuilder: CriteriaBuilder) { fun toAndPredicate(): Predicate? { return if (predicates.size == 1) { predicates[0] - } else if (!predicates.isEmpty()) { + } else if (predicates.isNotEmpty()) { criteriaBuilder.and(*predicates.toTypedArray()) } else { null diff --git a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt index 162cd032d..95c6336dd 100644 --- a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt +++ b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt @@ -15,7 +15,6 @@ import org.radarbase.management.web.rest.errors.ErrorConstants import org.springframework.data.jpa.domain.Specification import java.time.LocalDate import java.time.ZonedDateTime -import java.util.stream.Collectors import javax.persistence.criteria.CriteriaBuilder import javax.persistence.criteria.CriteriaQuery import javax.persistence.criteria.Join @@ -25,6 +24,7 @@ import javax.persistence.criteria.Path import javax.persistence.criteria.Predicate import javax.persistence.criteria.Root + class SubjectSpecification(criteria: SubjectCriteria) : Specification { private val dateOfBirth: CriteriaRange? private val enrollmentDate: CriteriaRange? @@ -44,9 +44,9 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification * @param criteria criteria to use for the specification. */ init { - authority = criteria.authority.stream() - .map { obj: SubjectAuthority? -> obj!!.name } - .collect(Collectors.toSet()) + authority = criteria.authority + .map { obj: SubjectAuthority? -> obj?.name } + .toSet() dateOfBirth = criteria.dateOfBirth enrollmentDate = criteria.enrollmentDate groupId = criteria.groupId @@ -56,22 +56,22 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification projectName = criteria.projectName externalId = criteria.externalId subjectId = criteria.login - sort = criteria.getParsedSort() - if (last != null) { - sortLastValues = sort + sort = criteria.parsedSort + sortLastValues = if (last != null) { + sort ?.map { o: SubjectSortOrder -> getLastValue(o.sortBy) } ?.toList() } else { - sortLastValues = null + null } } override fun toPredicate( - root: Root?, query: CriteriaQuery<*>?, - builder: CriteriaBuilder? + root: Root, query: CriteriaQuery<*>, + builder: CriteriaBuilder ): Predicate? { if (root == null || query == null || builder == null) { - return null + return null; } query.distinct(true) root.alias("subject") @@ -136,7 +136,7 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification root: Root, queryResult: Class<*> ) { // Don't add content for count queries. - if (queryResult == Long::class.java || queryResult == Long::class.javaPrimitiveType) { + if (Long::class.javaObjectType == queryResult) { return } root.fetch("sources", JoinType.LEFT) @@ -173,7 +173,7 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification val rolesJoin = userJoin.join("roles") rolesJoin.alias("roles") predicates.equal({ rolesJoin.get("project").get("projectName") }, projectName) - if (!authority.isEmpty() && authority.size != SubjectAuthority.values().size) { + if (authority.isNotEmpty() && authority.size != SubjectAuthority.values().size) { predicates.add(rolesJoin.get("authority").get("name").`in`(authority)) } } diff --git a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt index 56eb19894..cab15b76d 100644 --- a/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/MinimalSourceDetailsDTO.kt @@ -13,7 +13,7 @@ class MinimalSourceDetailsDTO { var sourceTypeCatalogVersion: String? = null var expectedSourceName: String? = null private set - lateinit var sourceId: UUID + var sourceId: UUID? = null var sourceName: String? = null var isAssigned: Boolean? = null var attributes: MutableMap = HashMap() diff --git a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt index 13aede526..7d92ccc7f 100644 --- a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt @@ -37,7 +37,6 @@ import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.actuate.audit.AuditEvent import org.springframework.boot.actuate.audit.AuditEventRepository -import org.springframework.data.domain.Page import org.springframework.data.domain.Pageable import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity @@ -204,8 +203,7 @@ class SubjectResource( val externalId = subjectCriteria.externalId log.debug("ProjectName {} and external {}", projectName, externalId) // if not specified do not include inactive patients - val authoritiesToInclude = subjectCriteria.authority.stream() - .filter { obj: SubjectAuthority? -> Objects.nonNull(obj) } + val authoritiesToInclude = subjectCriteria.authority .map { obj: SubjectAuthority -> obj.name } .toList() return if (projectName != null && externalId != null) { diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.kt b/src/main/java/org/radarbase/management/web/rest/UserResource.kt index 268d977a9..615930039 100644 --- a/src/main/java/org/radarbase/management/web/rest/UserResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/UserResource.kt @@ -146,7 +146,7 @@ class UserResource( log.debug("REST request to update User : {}", managedUserVm) authService.checkPermission(Permission.USER_UPDATE, { e: EntityDetails -> e.user(managedUserVm.login) }) var existingUser = managedUserVm.email?.let { userRepository.findOneByEmail(it) } - if (existingUser?.id != managedUserVm.id) { + if (existingUser != null && existingUser.id != managedUserVm.id) { throw BadRequestException("Email already in use", EntityName.USER, "emailexists") } existingUser = managedUserVm.login?.lowercase().let { @@ -158,7 +158,7 @@ class UserResource( throw BadRequestException("Login already in use", EntityName.USER, "emailexists") } val subject = subjectRepository.findOneWithEagerBySubjectLogin(managedUserVm.login) - if (subject != null && managedUserVm.isActivated && subject.removed!!) { + if (subject != null && managedUserVm.isActivated && subject.removed) { // if the subject is also a user, check if the removed/activated states are valid throw InvalidRequestException( "Subject cannot be the user to request " + "this changes", EntityName.USER, "error.invalidsubjectstate" diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt index 312a35231..29b52dbfb 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt @@ -20,70 +20,51 @@ class SubjectCriteria { var last: SubjectCriteriaLast? = null var page: @Min(0) Int = 0 var size: @Min(1) Int = 20 - private var sort: List? = null + var sort: List? = null var personName: String? = null var projectName: String? = null var externalId: String? = null var login: String? = null @Transient - private var parsedSort: List? = null + var parsedSort: List? = null + get() = field ?: parseSort() + private set - @get:NotNull - val pageable: Pageable - /** Get the criteria paging settings, excluding sorting. */ - get() = PageRequest.of(page, size) - - fun getSort(): List? { - return sort - } - - /** Parse the sort criteria. */ - fun getParsedSort(): List? { - if (parsedSort == null) { - val flatSort = if (sort != null) sort!!.stream() - .flatMap { s: String -> - Arrays.stream(s.split(",".toRegex()).dropLastWhile { it.isEmpty() } - .toTypedArray()) + private fun parseSort(): List { + val flatSort = sort?.flatMap { s: String -> + s.split(",") + }?.toList() ?: listOf() + val parsedSort: MutableList = ArrayList(flatSort.size) + var hasDirection = true + var previous: SubjectSortOrder? = null + for (part in flatSort) { + if (!hasDirection) { + val direction = Sort.Direction.fromOptionalString(part) + if (direction.isPresent) { + previous?.direction = direction.get() + hasDirection = true + continue } - .toList() else listOf() - val parsedSort: MutableList = ArrayList(flatSort.size) - var hasDirection = true - var previous: SubjectSortOrder? = null - for (part in flatSort) { - if (!hasDirection) { - val direction = Sort.Direction.fromOptionalString(part) - if (direction.isPresent) { - previous?.direction = direction.get() - hasDirection = true - continue - } - } else { - hasDirection = false - } - previous = SubjectSortOrder(getSubjectSortBy(part)) - parsedSort.add(previous) + } else { + hasDirection = false } - optimizeSortList(parsedSort) - this.parsedSort = Collections.unmodifiableList(parsedSort).filterNotNull() + previous = SubjectSortOrder(getSubjectSortBy(part)) + parsedSort.add(previous) } + optimizeSortList(parsedSort) + this.parsedSort = Collections.unmodifiableList(parsedSort) return parsedSort } + + @get:NotNull + val pageable: Pageable + /** Get the criteria paging settings, excluding sorting. */ + get() = PageRequest.of(page, size) + override fun toString(): String { - return ("SubjectCriteria{" + "authority=" + authority - + ", dateOfBirth=" + dateOfBirth - + ", enrollmentDate=" + enrollmentDate - + ", groupId='" + groupId + '\'' - + ", humanReadableIdentifier='" + humanReadableIdentifier + '\'' - + ", last=" + last - + ", page=" + page - + ", sort=" + sort - + ", personName='" + personName + '\'' - + ", projectName='" + projectName + '\'' - + ", externalId='" + externalId + '\'' - + ", login='" + login + '\'' - + '}') + return ("SubjectCriteria{" + "authority=" + authority + ", dateOfBirth=" + dateOfBirth + ", enrollmentDate=" + enrollmentDate + ", groupId='" + groupId + '\'' + ", humanReadableIdentifier='" + humanReadableIdentifier + '\'' + ", last=" + last + ", page=" + page + ", sort=" + sort + ", personName='" + personName + '\'' + ", projectName='" + projectName + '\'' + ", externalId='" + externalId + '\'' + ", login='" + login + '\'' + '}') } companion object { @@ -91,7 +72,7 @@ class SubjectCriteria { * Remove duplication and redundancy from sort list and make the result order consistent. * @param sort modifiable ordered sort collection. */ - private fun optimizeSortList(sort: MutableCollection) { + private fun optimizeSortList(sort: MutableCollection) { val seenSortBy: EnumSet? = EnumSet.noneOf( SubjectSortBy::class.java ) @@ -99,10 +80,10 @@ class SubjectCriteria { val iterator = sort.iterator() while (iterator.hasNext()) { val order = iterator.next() - if (hasUnique || seenSortBy?.add(order?.sortBy) != true) { + if (hasUnique || seenSortBy?.add(order.sortBy) != true) { iterator.remove() } - if (order?.sortBy?.isUnique == true) { + if (order.sortBy?.isUnique == true) { hasUnique = true } } @@ -113,12 +94,12 @@ class SubjectCriteria { private fun getSubjectSortBy(param: String): SubjectSortBy { return Arrays.stream(SubjectSortBy.values()) - .filter { s: SubjectSortBy -> s.queryParam.equals(param, ignoreCase = true) } - .findAny() + .filter { s: SubjectSortBy -> s.queryParam.equals(param, ignoreCase = true) }.findAny() .orElseThrow { BadRequestException( - "Cannot convert sort parameter " + param - + " to subject property", EntityName.Companion.SUBJECT, ErrorConstants.ERR_VALIDATION + "Cannot convert sort parameter " + param + " to subject property", + EntityName.Companion.SUBJECT, + ErrorConstants.ERR_VALIDATION ) } } diff --git a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt index bc27cdb8d..667c65afd 100644 --- a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt +++ b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt @@ -100,18 +100,16 @@ object PaginationUtil { ) generateUriParam(builder, "projectName", criteria.projectName) generateUriParam(builder, "login", criteria.login) - if (criteria.authority != null) { - criteria.authority!!.forEach(Consumer { a: SubjectAuthority? -> - generateUriParam( - builder, - "authority", a - ) - }) - } + criteria.authority.forEach(Consumer { a: SubjectAuthority? -> + generateUriParam( + builder, + "authority", a + ) + }) generateUriParam(builder, "size", criteria.size) generateUriParam(builder, "page", criteria.page) - if (criteria.getSort() != null) { - criteria.getParsedSort()!!.forEach(Consumer { order: SubjectSortOrder? -> + if (criteria.sort != null) { + criteria.parsedSort!!.forEach(Consumer { order: SubjectSortOrder? -> generateUriParam( builder, "sort", order?.sortBy?.queryParam + ',' diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index 5189d05f9..0fd79e5af 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -2,6 +2,7 @@ package org.radarbase.management.web.rest import org.assertj.core.api.Assertions import org.hamcrest.Matchers +import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -96,7 +97,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.DEFAULT_ENTERNAL_ID) Assertions.assertThat(testSubject.removed).isEqualTo(SubjectServiceTest.DEFAULT_REMOVED) - org.junit.jupiter.api.Assertions.assertEquals(1, testSubject.user!!.roles!!.size) + Assertions.assertThat(testSubject.user!!.roles!!.size).isEqualTo(1) } @Test @@ -278,7 +279,7 @@ internal class SubjectResourceIntTest( @Transactional @Throws(Exception::class) fun equalsVerifier() { - org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Subject::class.java)) + assertTrue(TestUtil.equalsVerifier(Subject::class.java)) } @Test @@ -299,7 +300,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) val testSubject = subjectList[subjectList.size - 1] val subjectLogin = testSubject.user!!.login - org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) + assertNotNull(subjectLogin) // Create a source description val sourceRegistrationDto = createSourceWithSourceTypeId() @@ -337,7 +338,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) val testSubject = subjectList[subjectList.size - 1] val subjectLogin = testSubject.user!!.login - org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) + assertNotNull(subjectLogin) // Create a source description val sourceRegistrationDto = createSourceWithoutSourceTypeId() @@ -385,7 +386,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) val testSubject = subjectList[subjectList.size - 1] val subjectLogin = testSubject.user!!.login - org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) + assertNotNull(subjectLogin) // Create a source description val sourceRegistrationDto = createSourceWithoutSourceTypeIdAndWithoutDynamicRegistration() @@ -407,9 +408,9 @@ internal class SubjectResourceIntTest( val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) .sourceTypeId(createdSource.sourceType?.id).sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) - org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) - org.junit.jupiter.api.Assertions.assertFalse(createdSubject!!.sources.isEmpty()) + assertFalse(createdSubject!!.sources.isEmpty()) // Get the subject restSubjectMockMvc.perform( @@ -433,10 +434,10 @@ internal class SubjectResourceIntTest( val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) .sourceTypeId(createdSource.sourceType?.id).sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) - org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) TestUtil.commitTransactionAndStartNew() - org.junit.jupiter.api.Assertions.assertNotNull(createdSubject!!.login) + assertNotNull(createdSubject!!.login) // Get the subject restSubjectMockMvc.perform( MockMvcRequestBuilders.get( @@ -459,13 +460,13 @@ internal class SubjectResourceIntTest( val sourceDto = MinimalSourceDetailsDTO().id(createdSource.id).sourceName(createdSource.sourceName) .sourceTypeId(createdSource.sourceType?.id).sourceId(createdSource.sourceId!!) subjectDtoToCreate.sources = setOf(sourceDto) - org.junit.jupiter.api.Assertions.assertNotNull(sourceDto.id) + assertNotNull(sourceDto.id) val createdSubject = subjectService.createSubject(subjectDtoToCreate) TestUtil.commitTransactionAndStartNew() createdSubject!!.sources = emptySet() val updatedSubject = subjectService.updateSubject(createdSubject) TestUtil.commitTransactionAndStartNew() - org.junit.jupiter.api.Assertions.assertNotNull(updatedSubject!!.login) + assertNotNull(updatedSubject!!.login) // Get the subject restSubjectMockMvc.perform( MockMvcRequestBuilders.get( @@ -550,7 +551,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(subjectList).hasSize(databaseSizeBeforeCreate + 1) val testSubject = subjectList[subjectList.size - 1] val subjectLogin = testSubject.user!!.login - org.junit.jupiter.api.Assertions.assertNotNull(subjectLogin) + assertNotNull(subjectLogin) // Create a source description val sourceRegistrationDto = createSourceWithoutSourceTypeId() @@ -563,7 +564,7 @@ internal class SubjectResourceIntTest( val value = TestUtil.convertJsonStringToObject( result.response.contentAsString, MinimalSourceDetailsDTO::class.java ) as MinimalSourceDetailsDTO - org.junit.jupiter.api.Assertions.assertNotNull(value.sourceName) + assertNotNull(value.sourceName) val attributes: MutableMap = HashMap() attributes["TEST_KEY"] = "Value" attributes["ANDROID_VERSION"] = "something" diff --git a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt index fbd97c356..656219368 100644 --- a/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/UserResourceIntTest.kt @@ -16,12 +16,8 @@ import org.radarbase.management.domain.Role import org.radarbase.management.domain.User import org.radarbase.management.repository.ProjectRepository import org.radarbase.management.repository.RoleRepository -import org.radarbase.management.repository.SubjectRepository import org.radarbase.management.repository.UserRepository -import org.radarbase.management.service.AuthService -import org.radarbase.management.service.MailService import org.radarbase.management.service.PasswordService -import org.radarbase.management.service.UserService import org.radarbase.management.service.UserServiceIntTest import org.radarbase.management.service.dto.RoleDTO import org.radarbase.management.web.rest.errors.ExceptionTranslator @@ -56,13 +52,9 @@ internal class UserResourceIntTest( @Autowired private val roleRepository: RoleRepository, @Autowired private val userRepository: UserRepository, - @Autowired private val mailService: MailService, - @Autowired private val userService: UserService, @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, @Autowired private val pageableArgumentResolver: PageableHandlerMethodArgumentResolver, @Autowired private val exceptionTranslator: ExceptionTranslator, - @Autowired private val subjectRepository: SubjectRepository, - @Autowired private val authService: AuthService, @Autowired private val passwordService: PasswordService, @Autowired private val projectRepository: ProjectRepository, ) { From 433c0df57693080bb65d6f1380b10b23707ce0db Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 3 Nov 2023 16:56:54 +0100 Subject: [PATCH 114/158] all but one e2e test passing --- .../management/security/JwtAuthenticationFilter.kt | 8 ++++---- .../jwt/ManagementPortalJwtAccessTokenConverter.kt | 7 ++++++- src/main/resources/logback-spring.xml | 4 ++-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt index c91c1dd38..abc8748fd 100644 --- a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt +++ b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt @@ -201,14 +201,14 @@ class JwtAuthenticationFilter @JvmOverloads constructor( @get:JvmStatic @set:JvmStatic - var HttpSession.radarToken: RadarToken - get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken + var HttpSession.radarToken: RadarToken? + get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken? set(value) = setAttribute(TOKEN_ATTRIBUTE, value) @get:JvmStatic @set:JvmStatic - var HttpServletRequest.radarToken: RadarToken - get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken + var HttpServletRequest.radarToken: RadarToken? + get() = getAttribute(TOKEN_ATTRIBUTE) as RadarToken? set(value) = setAttribute(TOKEN_ATTRIBUTE, value) val Authentication?.isAnonymous: Boolean diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt index c9d173c36..d4e7f2a96 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt @@ -83,7 +83,12 @@ open class ManagementPortalJwtAccessTokenConverter( } override fun extractAccessToken(value: String, map: Map?): OAuth2AccessToken { - return tokenConverter.extractAccessToken(value, map) + var mapCopy = map?.toMutableMap() + + if (mapCopy?.containsKey(AccessTokenConverter.EXP) == true) { + mapCopy[AccessTokenConverter.EXP] = (mapCopy[AccessTokenConverter.EXP] as Int).toLong() + } + return tokenConverter.extractAccessToken(value, mapCopy) } override fun extractAuthentication(map: Map?): OAuth2Authentication { diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index 6e7c1871b..c74746cf5 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -24,7 +24,7 @@ - + @@ -57,7 +57,7 @@ true - + From f7543f57a3027aa51c2ba103e421fb37610298a3 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 3 Nov 2023 17:23:43 +0100 Subject: [PATCH 115/158] stylefixes --- .../service/mapper/ClientDetailsMapper.java | 19 ++++---- .../ClientDetailsMapperDecorator.java | 11 +++-- .../management/web/rest/UserResource.kt | 43 ++++++++++--------- 3 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java index 10c1b1ad8..f8a1ddeaa 100644 --- a/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java +++ b/src/main/java/org/radarbase/management/service/mapper/ClientDetailsMapper.java @@ -23,7 +23,7 @@ */ @Mapper(componentModel = "spring", uses = {BaseClientDetails.class}) @DecoratedWith(ClientDetailsMapperDecorator.class) - public interface ClientDetailsMapper { +public interface ClientDetailsMapper { @Mapping(target = "clientSecret", ignore = true) @Mapping(target = "autoApproveScopes", ignore = true) @@ -37,6 +37,7 @@ public interface ClientDetailsMapper { /** * Map a set of authorities represented as strings to a collection of {@link GrantedAuthority}s. + * * @param authorities the set of authorities to be mapped * @return a collection of {@link GrantedAuthority}s */ @@ -44,13 +45,12 @@ default Collection map(Set authorities) { if (Objects.isNull(authorities)) { return Collections.emptySet(); } - return authorities.stream() - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); + return authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()); } /** * Map a collection of authorities represented as {@link GrantedAuthority}s to a set of strings. + * * @param authorities the collection of {@link GrantedAuthority}s to be mapped * @return the set of strings */ @@ -58,23 +58,20 @@ default Set map(Collection authorities) { if (Objects.isNull(authorities)) { return Collections.emptySet(); } - return authorities.stream() - .map(GrantedAuthority::getAuthority) - .collect(Collectors.toSet()); + return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet()); } /** * Transforms the values in the input map to strings so the result is a * {@link Map}. * @param additionalInformation a {@link Map} to be transformed - * @return a new map with the same keys as the input map, but the values are transformed to - * strings using their {@link Object#toString()} method + * @return a new map with the same keys as the input map, but the values are strings */ default Map map(Map additionalInformation) { if (Objects.isNull(additionalInformation)) { return Collections.emptyMap(); } - return additionalInformation.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString())); + return additionalInformation.entrySet().stream().collect(Collectors.toMap( + Map.Entry::getKey, e -> e.getValue().toString())); } } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java index 119bdea64..a74d11dab 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ClientDetailsMapperDecorator.java @@ -26,9 +26,10 @@ public abstract class ClientDetailsMapperDecorator implements ClientDetailsMappe public ClientDetailsDTO clientDetailsToClientDetailsDTO(ClientDetails details) { ClientDetailsDTO clientDetailsDto = delegate.clientDetailsToClientDetailsDTO(details); // collect the scopes that are auto-approve and set them in our DTO - clientDetailsDto.setAutoApproveScopes(details.getScope().stream() - .filter(details::isAutoApprove) - .collect(Collectors.toSet())); + clientDetailsDto.setAutoApproveScopes(details + .getScope() + .stream() + .filter(details::isAutoApprove).collect(Collectors.toSet())); return clientDetailsDto; } @@ -37,8 +38,6 @@ public List clientDetailsToClientDetailsDTO(List e.user(login) }) return ResponseUtil.wrapOrNotFound( Optional.ofNullable(userService.getUserWithAuthoritiesByLogin(login) - .let { obj: UserDTO? -> obj?.roles })) + .let { obj: UserDTO? -> obj?.roles }) + ) } /** From 825a90552c89789054699318d597808fb5477c52 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 6 Nov 2023 12:14:08 +0100 Subject: [PATCH 116/158] name CriteriaRange.iss back to `is` to fix serialization --- .../management/config/CacheConfiguration.kt | 6 +++--- .../management/config/DateTimeFormatConfiguration.kt | 2 +- .../management/config/OAuth2LoginUiWebConfig.kt | 5 +---- .../repository/CustomAuditEventRepository.kt | 8 ++++---- .../repository/filters/PredicateBuilder.kt | 4 ++-- .../repository/filters/SubjectSpecification.kt | 9 ++++----- .../management/security/PostgresApprovalStore.kt | 3 +-- .../management/web/rest/criteria/CriteriaRange.kt | 12 ++++++------ .../management/web/rest/criteria/SubjectCriteria.kt | 2 +- .../management/web/rest/util/PaginationUtil.kt | 2 +- 10 files changed, 24 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/radarbase/management/config/CacheConfiguration.kt b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt index dcc1adbeb..e254d296c 100644 --- a/src/main/java/org/radarbase/management/config/CacheConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/CacheConfiguration.kt @@ -27,7 +27,7 @@ import javax.annotation.PreDestroy @Configuration @EnableCaching @AutoConfigureBefore(value = [WebConfigurer::class, DatabaseConfiguration::class]) -open class CacheConfiguration { +class CacheConfiguration { @Autowired private val env: Environment? = null @PreDestroy @@ -37,7 +37,7 @@ open class CacheConfiguration { } @Bean - open fun HazelcastInstance.cacheManager(): CacheManager { + fun HazelcastInstance.cacheManager(): CacheManager { log.debug("Starting HazelcastCacheManager") return HazelcastCacheManager( this @@ -45,7 +45,7 @@ open class CacheConfiguration { } @Bean - open fun hazelcastConfig(jHipsterProperties: JHipsterProperties): Config { + fun hazelcastConfig(jHipsterProperties: JHipsterProperties): Config { val config = Config() config.setInstanceName("ManagementPortal") val networkConfig = config.networkConfig diff --git a/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt b/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt index 508f46ab1..16292ac6b 100644 --- a/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/DateTimeFormatConfiguration.kt @@ -12,7 +12,7 @@ import java.time.temporal.ChronoField import javax.annotation.Nonnull @Configuration -open class DateTimeFormatConfiguration : WebMvcConfigurer { +class DateTimeFormatConfiguration : WebMvcConfigurer { override fun addFormatters(@Nonnull registry: FormatterRegistry) { val registrar = DateTimeFormatterRegistrar() registrar.setUseIsoFormat(true) diff --git a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt index 741e9d882..a41ca544a 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt @@ -10,7 +10,6 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.SessionAttributes import org.springframework.web.servlet.ModelAndView import org.springframework.web.util.HtmlUtils -import java.lang.Boolean import java.text.SimpleDateFormat import java.util.* import java.util.function.Function @@ -18,8 +17,6 @@ import java.util.stream.Collectors import java.util.stream.Stream import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse -import kotlin.Any -import kotlin.String /** * Created by dverbeec on 6/07/2017. @@ -40,7 +37,7 @@ class OAuth2LoginUiWebConfig { fun getLogin(request: HttpServletRequest, response: HttpServletResponse?): ModelAndView { val model = TreeMap() if (request.parameterMap.containsKey("error")) { - model["loginError"] = Boolean.TRUE + model["loginError"] = true } return ModelAndView("login", model) } diff --git a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt index 018ae7ea4..e8b68ced7 100644 --- a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt +++ b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt @@ -25,8 +25,8 @@ open class CustomAuditEventRepository( ) : AuditEventRepository { override fun find(principal: String, after: Instant, type: String): List { - val persistentAuditEvents: Iterable? = persistenceAuditEventRepository - ?.findByPrincipalAndAuditEventDateAfterAndAuditEventType( + val persistentAuditEvents: Iterable = persistenceAuditEventRepository + .findByPrincipalAndAuditEventDateAfterAndAuditEventType( principal, LocalDateTime.from(after), type ) @@ -46,8 +46,8 @@ open class CustomAuditEventRepository( event.timestamp, ZoneId.systemDefault() ) - persistentAuditEvent.data = auditEventConverter!!.convertDataToStrings(event.data) - persistenceAuditEventRepository!!.save(persistentAuditEvent) + persistentAuditEvent.data = auditEventConverter.convertDataToStrings(event.data) + persistenceAuditEventRepository.save(persistentAuditEvent) } if (eventType != null && eventType.endsWith("_FAILURE")) { val typeObj = event.data["type"] diff --git a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt index a35e4d9e0..dcda7bba6 100644 --- a/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt +++ b/src/main/java/org/radarbase/management/repository/filters/PredicateBuilder.kt @@ -163,8 +163,8 @@ class PredicateBuilder(val criteriaBuilder: CriteriaBuilder) { return } range.validate() - if (range.iss != null) { - add(criteriaBuilder.equal(path, range.iss)) + if (range.`is` != null) { + add(criteriaBuilder.equal(path, range.`is`)) } else { val from = range.from val to = range.to diff --git a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt index 95c6336dd..312073fe2 100644 --- a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt +++ b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt @@ -3,18 +3,17 @@ package org.radarbase.management.repository.filters import org.radarbase.management.domain.Role import org.radarbase.management.domain.Subject import org.radarbase.management.domain.User -import org.radarbase.management.web.rest.criteria.CriteriaRange +import org.radarbase.management.web.rest.criteria.LocalDateCriteriaRange import org.radarbase.management.web.rest.criteria.SubjectAuthority import org.radarbase.management.web.rest.criteria.SubjectCriteria import org.radarbase.management.web.rest.criteria.SubjectCriteriaLast import org.radarbase.management.web.rest.criteria.SubjectSortBy import org.radarbase.management.web.rest.criteria.SubjectSortOrder +import org.radarbase.management.web.rest.criteria.ZonedDateTimeCriteriaRange import org.radarbase.management.web.rest.errors.BadRequestException import org.radarbase.management.web.rest.errors.EntityName import org.radarbase.management.web.rest.errors.ErrorConstants import org.springframework.data.jpa.domain.Specification -import java.time.LocalDate -import java.time.ZonedDateTime import javax.persistence.criteria.CriteriaBuilder import javax.persistence.criteria.CriteriaQuery import javax.persistence.criteria.Join @@ -26,8 +25,8 @@ import javax.persistence.criteria.Root class SubjectSpecification(criteria: SubjectCriteria) : Specification { - private val dateOfBirth: CriteriaRange? - private val enrollmentDate: CriteriaRange? + private val dateOfBirth: LocalDateCriteriaRange? + private val enrollmentDate: ZonedDateTimeCriteriaRange? private val groupId: Long? private val humanReadableIdentifier: String? private val last: SubjectCriteriaLast? diff --git a/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt b/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt index 1a5eadc0c..4ce4e6d1d 100644 --- a/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt +++ b/src/main/java/org/radarbase/management/security/PostgresApprovalStore.kt @@ -22,7 +22,6 @@ import org.springframework.jdbc.core.RowMapper import org.springframework.security.oauth2.provider.approval.Approval import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus import org.springframework.security.oauth2.provider.approval.ApprovalStore -import org.springframework.util.Assert import java.sql.PreparedStatement import java.sql.ResultSet import java.sql.SQLException @@ -48,7 +47,7 @@ class PostgresApprovalStore(dataSource: DataSource?) : ApprovalStore { private var handleRevocationsAsExpiry = false init { - Assert.notNull(dataSource) + dataSource ?: throw Exception("Data source not ready") jdbcTemplate = JdbcTemplate(dataSource) } diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt b/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt index 965f32fc0..29ee1b1fc 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt +++ b/src/main/java/org/radarbase/management/web/rest/criteria/CriteriaRange.kt @@ -9,33 +9,33 @@ package org.radarbase.management.web.rest.criteria open class CriteriaRange?>(var from: T? = null, var to: T? = null, - var iss: T? = null + var `is`: T? = null ) { fun from(): T? { - return if (this.iss == null) from else null + return if (this.`is` == null) from else null } fun to(): T? { - return if (this.iss == null) to else null + return if (this.`is` == null) to else null } val isEmpty: Boolean /** * Whether the criteria range contains any values at all. */ - get() = from == null && to == null && iss == null + get() = from == null && to == null && `is` == null /** * Validate this criteria range whether the from and to ranges are in order. */ fun validate() { - require(!(iss == null && from != null && to != null && from!!.compareTo(to!!) > 0)) { "CriteriaRange must have a from range that is smaller then the to range." } + require(!(`is` == null && from != null && to != null && from!!.compareTo(to!!) > 0)) { "CriteriaRange must have a from range that is smaller then the to range." } } override fun toString(): String { return ("CriteriaRange{" + "from=" + from() + ", to=" + to() - + ", is=" + this.iss + + ", is=" + this.`is` + '}') } } diff --git a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt index 29b52dbfb..76b0d6b08 100644 --- a/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt +++ b/src/main/java/org/radarbase/management/web/rest/criteria/SubjectCriteria.kt @@ -83,7 +83,7 @@ class SubjectCriteria { if (hasUnique || seenSortBy?.add(order.sortBy) != true) { iterator.remove() } - if (order.sortBy?.isUnique == true) { + if (order.sortBy.isUnique) { hasUnique = true } } diff --git a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt index 667c65afd..ad8ca3eb5 100644 --- a/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt +++ b/src/main/java/org/radarbase/management/web/rest/util/PaginationUtil.kt @@ -133,7 +133,7 @@ object PaginationUtil { if (range == null) { return } - generateUriParam(builder, "$prefix.is", range.iss) + generateUriParam(builder, "$prefix.is", range.`is`) generateUriParam(builder, "$prefix.from", range.from) generateUriParam(builder, "$prefix.to", range.to) } From 289d25f60d14ac059caac247c51c9f1e62f9e96d Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 6 Nov 2023 13:13:06 +0100 Subject: [PATCH 117/158] fix warnings --- .../ManagementPortalSecurityConfigLoader.kt | 9 ++--- .../config/OAuth2LoginUiWebConfig.kt | 2 +- .../config/OAuth2ServerConfiguration.kt | 2 +- .../org/radarbase/management/domain/Source.kt | 2 +- .../radarbase/management/domain/SourceType.kt | 10 +++--- .../domain/audit/CustomRevisionEntity.kt | 11 +++--- .../domain/audit/CustomRevisionMetadata.kt | 14 +------- .../domain/audit/EntityAuditInfo.kt | 8 ++--- .../domain/support/AutowireHelper.kt | 2 +- .../repository/filters/UserFilter.kt | 10 +++--- ...ManagementPortalJwtAccessTokenConverter.kt | 4 +-- .../ManagementPortalOauthKeyStoreHandler.kt | 2 +- .../management/service/AuditEventService.kt | 2 +- .../management/service/GroupService.kt | 30 +++++++++------- .../management/service/MailService.kt | 10 +++--- .../management/service/RevisionService.kt | 36 +++++++++---------- .../management/service/SourceDataService.kt | 2 +- .../management/service/SubjectService.kt | 8 +++-- .../service/dto/ClientPairInfoDTO.kt | 8 ++--- .../management/service/dto/RoleDTO.kt | 8 ++--- .../management/service/dto/TokenDTO.kt | 8 ++--- .../mapper/decorator/SourceMapperDecorator.kt | 5 ++- .../management/web/rest/AuditResource.kt | 6 ++-- .../management/web/rest/GroupResource.kt | 35 +++++++++--------- .../management/web/rest/SourceDataResource.kt | 2 +- .../web/rest/errors/ExceptionTranslator.kt | 6 +--- .../web/rest/OAuthClientsResourceIntTest.kt | 2 +- .../web/rest/ProjectResourceIntTest.kt | 1 - 28 files changed, 111 insertions(+), 134 deletions(-) diff --git a/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt b/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt index b12b7ce13..97b96ce68 100644 --- a/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt +++ b/src/main/java/org/radarbase/management/config/ManagementPortalSecurityConfigLoader.kt @@ -16,15 +16,10 @@ import org.springframework.security.oauth2.provider.NoSuchClientException import org.springframework.security.oauth2.provider.client.BaseClientDetails import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService import org.springframework.stereotype.Component -import java.lang.Boolean import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths import java.util.* -import kotlin.Any -import kotlin.Array -import kotlin.Exception -import kotlin.String /** * Loads security configs such as oauth-clients, and overriding admin password if specified. @@ -80,8 +75,8 @@ class ManagementPortalSecurityConfigLoader { "authorization_code" ) ) - details.setAdditionalInformation(Collections.singletonMap("protected", Boolean.TRUE)) - val allScopes = Arrays.asList(*scopes()) + details.setAdditionalInformation(Collections.singletonMap("protected", true)) + val allScopes = listOf(*scopes()) details.setScope(allScopes) details.setAutoApproveScopes(allScopes) loadOAuthClient(details) diff --git a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt index a41ca544a..625540bbd 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2LoginUiWebConfig.kt @@ -88,7 +88,7 @@ class OAuth2LoginUiWebConfig { val oauthError = error errorParams["status"] = String.format("%d", oauthError.httpErrorCode) errorParams["code"] = oauthError.oAuth2ErrorCode - errorParams["message"] = HtmlUtils.htmlEscape(oauthError.message) + errorParams["message"] = oauthError.message?.let { HtmlUtils.htmlEscape(it) } ?: "No error message found" // transform the additionalInfo map to a comma seperated list of key: value pairs if (oauthError.additionalInformation != null) { errorParams["additionalInfo"] = HtmlUtils.htmlEscape( diff --git a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt index ce5b0ecc8..ca7cc87a8 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt @@ -215,7 +215,7 @@ open class OAuth2ServerConfiguration { @Bean open fun approvalStore(): ApprovalStore { - return if (jpaProperties!!.database == Database.POSTGRESQL) { + return if (jpaProperties.database == Database.POSTGRESQL) { PostgresApprovalStore(dataSource) } else { // to have compatibility for other databases including H2 diff --git a/src/main/java/org/radarbase/management/domain/Source.kt b/src/main/java/org/radarbase/management/domain/Source.kt index 15ea02d99..770d5233a 100644 --- a/src/main/java/org/radarbase/management/domain/Source.kt +++ b/src/main/java/org/radarbase/management/domain/Source.kt @@ -79,7 +79,7 @@ class Source : AbstractEntity, Serializable { var project: Project? = null @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @ElementCollection(fetch = FetchType.EAGER) @MapKeyColumn(name = "attribute_key") @Column(name = "attribute_value") diff --git a/src/main/java/org/radarbase/management/domain/SourceType.kt b/src/main/java/org/radarbase/management/domain/SourceType.kt index 5e64cbfd4..baf41d505 100644 --- a/src/main/java/org/radarbase/management/domain/SourceType.kt +++ b/src/main/java/org/radarbase/management/domain/SourceType.kt @@ -79,7 +79,7 @@ class SourceType : AbstractEntity(), Serializable { @NotNull var canRegisterDynamically: Boolean? = false @JvmField - @set:JsonSetter(nulls = Nulls.AS_EMPTY) + @JsonSetter(nulls = Nulls.AS_EMPTY) @OneToMany(mappedBy = "sourceType", orphanRemoval = true, fetch = FetchType.LAZY) @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) @Cascade( @@ -122,14 +122,14 @@ class SourceType : AbstractEntity(), Serializable { return this } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val sourceType = o as SourceType + val sourceType = other as SourceType return if (sourceType.id == null || id == null) { false } else id == sourceType.id && producer == sourceType.producer && model == sourceType.model && catalogVersion == sourceType.catalogVersion && canRegisterDynamically == sourceType.canRegisterDynamically && sourceTypeScope == sourceType.sourceTypeScope && name == sourceType.name && description == sourceType.description && appProvider == sourceType.appProvider && assessmentType == sourceType.assessmentType diff --git a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt index 0cf7486dc..573d2ea7e 100644 --- a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt +++ b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionEntity.kt @@ -40,7 +40,7 @@ class CustomRevisionEntity : Serializable { var id = 0 @JvmField - @get:Temporal(TemporalType.TIMESTAMP) + @Temporal(TemporalType.TIMESTAMP) @RevisionTimestamp var timestamp: Date? = null @JvmField @@ -55,15 +55,14 @@ class CustomRevisionEntity : Serializable { ) @ModifiedEntityNames var modifiedEntityNames: Set? = null - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o !is CustomRevisionEntity) { + if (other !is CustomRevisionEntity) { return false } - val that = o - return id == that.id && timestamp == that.timestamp && auditor == that.auditor && modifiedEntityNames == that.modifiedEntityNames + return id == other.id && timestamp == other.timestamp && auditor == other.auditor && modifiedEntityNames == other.modifiedEntityNames } override fun hashCode(): Int { diff --git a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt index d23f92927..42853ec24 100644 --- a/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt +++ b/src/main/java/org/radarbase/management/domain/audit/CustomRevisionMetadata.kt @@ -26,27 +26,15 @@ class CustomRevisionMetadata(entity: CustomRevisionEntity) : RevisionMetadata { return Optional.ofNullable(entity.timestamp).map { ts: Date -> ts.toInstant() } } - override fun getRequiredRevisionInstant(): Instant { - return super.getRequiredRevisionInstant() - } - /* * (non-Javadoc) * @see org.springframework.data.history.RevisionMetadata#getDelegate() */ - override fun getDelegate(): T { + override fun getDelegate(): T { return entity as T } - - override fun getRevisionType(): RevisionMetadata.RevisionType { - return super.getRevisionType() - } } diff --git a/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt b/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt index cd1d2b73d..520ce9675 100644 --- a/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt +++ b/src/main/java/org/radarbase/management/domain/audit/EntityAuditInfo.kt @@ -36,14 +36,14 @@ class EntityAuditInfo { return this } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val that = o as EntityAuditInfo + val that = other as EntityAuditInfo return createdAt == that.createdAt && createdBy == that.createdBy && lastModifiedAt == that.lastModifiedAt && lastModifiedBy == that.lastModifiedBy } diff --git a/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt b/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt index defda715f..22efc363c 100644 --- a/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt +++ b/src/main/java/org/radarbase/management/domain/support/AutowireHelper.kt @@ -31,7 +31,7 @@ class AutowireHelper private constructor() : ApplicationContextAware { * @param beansToAutowireInClass the beans which have the @Autowire annotation in the specified * {#classToAutowire} */ - fun autowire(classToAutowire: Any?, vararg beansToAutowireInClass: Any?) { + fun autowire(classToAutowire: Any, vararg beansToAutowireInClass: Any?) { for (bean in beansToAutowireInClass) { if (bean == null) { applicationContext!!.autowireCapableBeanFactory.autowireBean(classToAutowire) diff --git a/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt b/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt index 9dc2110b3..4c6979ef4 100644 --- a/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt +++ b/src/main/java/org/radarbase/management/repository/filters/UserFilter.kt @@ -56,7 +56,7 @@ class UserFilter : Specification { if (authoritiesAllowed.isEmpty()) { val builder = predicates.criteriaBuilder // never match - predicates.add(builder!!.isTrue(builder.literal(false))) + predicates.add(builder.isTrue(builder.literal(false))) return } determineScope(predicates, roleJoin, query, authoritiesAllowed, allowNoRole) @@ -109,9 +109,9 @@ class UserFilter : Specification { ) } if (allowNoRoleInScope) { - authorityPredicates!!.isNull(roleJoin.get("id")) + authorityPredicates.isNull(roleJoin.get("id")) } - predicates.add(authorityPredicates!!.toOrPredicate()) + predicates.add(authorityPredicates.toOrPredicate()) } private fun addAllowedAuthorities( @@ -160,8 +160,8 @@ class UserFilter : Specification { subQuery.select(orgRoot.get("id")) val subqueryPredicates = predicates.newBuilder() queryMatch.accept(subqueryPredicates, orgRoot) - subQuery.where(subqueryPredicates!!.toAndPredicate()) - authorityPredicates!!.`in`( + subQuery.where(subqueryPredicates.toAndPredicate()) + authorityPredicates.`in`( roleJoin.get( when (scope) { RoleAuthority.Scope.ORGANIZATION -> "organization" diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt index d4e7f2a96..a57826d0a 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalJwtAccessTokenConverter.kt @@ -168,7 +168,7 @@ open class ManagementPortalJwtAccessTokenConverter( } override fun isRefreshToken(token: OAuth2AccessToken): Boolean { - return token?.additionalInformation?.containsKey(JwtAccessTokenConverter.ACCESS_TOKEN_ID) == true + return token.additionalInformation?.containsKey(JwtAccessTokenConverter.ACCESS_TOKEN_ID) == true } override fun encode(accessToken: OAuth2AccessToken, authentication: OAuth2Authentication): String { @@ -184,7 +184,7 @@ open class ManagementPortalJwtAccessTokenConverter( .forEach { claim: String -> builder.withArrayClaim( claim, - (claims[claim] as Collection?)!!.toTypedArray() + (claims[claim] as Collection).toTypedArray() ) } diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt index 57625c3f4..169ecb656 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt @@ -93,7 +93,7 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( val localStore = KeyStore.getInstance(type) localStore.load(resource.inputStream, password) logger.debug("Loaded JWT key store {}", resource) - if (resource != null && localStore != null) + if (localStore != null) return SimpleImmutableEntry(resource, localStore) } catch (ex: CertificateException) { logger.error("Cannot load JWT key store", ex) diff --git a/src/main/java/org/radarbase/management/service/AuditEventService.kt b/src/main/java/org/radarbase/management/service/AuditEventService.kt index 9881c7195..cc2b4c961 100644 --- a/src/main/java/org/radarbase/management/service/AuditEventService.kt +++ b/src/main/java/org/radarbase/management/service/AuditEventService.kt @@ -23,7 +23,7 @@ class AuditEventService( private val persistenceAuditEventRepository: PersistenceAuditEventRepository, private val auditEventConverter: AuditEventConverter ) { - fun findAll(pageable: Pageable?): Page { + fun findAll(pageable: Pageable): Page { return persistenceAuditEventRepository.findAll(pageable) .map { persistentAuditEvent: PersistentAuditEvent? -> auditEventConverter.convertToAuditEvent( diff --git a/src/main/java/org/radarbase/management/service/GroupService.kt b/src/main/java/org/radarbase/management/service/GroupService.kt index 3cda93ef0..400eb5e10 100644 --- a/src/main/java/org/radarbase/management/service/GroupService.kt +++ b/src/main/java/org/radarbase/management/service/GroupService.kt @@ -29,7 +29,7 @@ import javax.transaction.Transactional * Service to manage project groups. */ @Service -open class GroupService( +class GroupService( @Autowired private val groupRepository: GroupRepository, @Autowired private val projectRepository: ProjectRepository, @Autowired private val subjectRepository: SubjectRepository, @@ -45,7 +45,7 @@ open class GroupService( */ @Throws(NotFoundException::class) @Transactional - open fun getGroup(projectName: String, groupName: String): GroupDTO { + fun getGroup(projectName: String, groupName: String): GroupDTO { return groupMapper.groupToGroupDTOFull( groupRepository.findByProjectNameAndName( projectName, groupName @@ -54,7 +54,7 @@ open class GroupService( EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND ) - )!! + ) } /** @@ -65,7 +65,7 @@ open class GroupService( * @throws NotFoundException if the project or group is not found. */ @Transactional - open fun deleteGroup(projectName: String, groupName: String, unlinkSubjects: Boolean) { + fun deleteGroup(projectName: String, groupName: String, unlinkSubjects: Boolean) { val group = groupRepository.findByProjectNameAndName(projectName, groupName) ?: throw NotFoundException( "Group $groupName not found in project $projectName", EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND ) @@ -88,7 +88,7 @@ open class GroupService( * @throws ConflictException if the group name already exists. */ @Transactional - open fun createGroup(projectName: String, groupDto: GroupDTO): GroupDTO? { + fun createGroup(projectName: String, groupDto: GroupDTO): GroupDTO { val project = projectRepository.findOneWithGroupsByName(projectName) ?: throw NotFoundException( "Project with name $projectName not found", EntityName.PROJECT, ErrorConstants.ERR_PROJECT_NAME_NOT_FOUND ) @@ -99,19 +99,23 @@ open class GroupService( ErrorConstants.ERR_GROUP_EXISTS ) } - val group = groupMapper.groupDTOToGroup(groupDto) - if (group != null) { + return try { + val group = groupMapper.groupDTOToGroup(groupDto) + group.project = project val groupDtoResult = groupMapper.groupToGroupDTOFull(groupRepository.save(group)) project.groups.add(group) projectRepository.save(project) - return groupDtoResult - } - else { + groupDtoResult + } catch(e: Throwable) { throw NotFoundException( - "Group ${groupDto.name} not found in project $projectName", EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND + "Group ${groupDto.name} not found in project $projectName", + EntityName.GROUP, + ErrorConstants.ERR_GROUP_NOT_FOUND ) } + + } /** @@ -135,14 +139,14 @@ open class GroupService( * @throws NotFoundException if the project or group is not found. */ @Transactional - open fun updateGroupSubjects( + fun updateGroupSubjects( projectName: String, groupName: String, subjectsToAdd: List, subjectsToRemove: List ) { - groupRepository ?: throw NullPointerException() + groupRepository val group = groupRepository.findByProjectNameAndName(projectName, groupName) ?: throw NotFoundException( "Group $groupName not found in project $projectName", EntityName.GROUP, ErrorConstants.ERR_GROUP_NOT_FOUND diff --git a/src/main/java/org/radarbase/management/service/MailService.kt b/src/main/java/org/radarbase/management/service/MailService.kt index 671ec5277..05496e60f 100644 --- a/src/main/java/org/radarbase/management/service/MailService.kt +++ b/src/main/java/org/radarbase/management/service/MailService.kt @@ -54,10 +54,10 @@ class MailService( mimeMessage, isMultipart, StandardCharsets.UTF_8.name() ) - message.setTo(to) + message.setTo(to!!) message.setFrom(managementPortalProperties.mail.from) - message.setSubject(subject) - message.setText(content, isHtml) + message.setSubject(subject!!) + message.setText(content!!, isHtml) javaMailSender.send(mimeMessage) log.debug("Sent email to User '{}'", to) } catch (e: Exception) { @@ -81,7 +81,7 @@ class MailService( ) val content = templateEngine.process("activationEmail", context) val subject = messageSource.getMessage("email.activation.title", null, locale) - sendEmail(user.email, subject, content, false, true) + sendEmail(user.email, subject, content, isMultipart = false, isHtml = true) } /** @@ -101,7 +101,7 @@ class MailService( context.setVariable(EXPIRY, Duration.ofSeconds(duration).toHours()) val content = templateEngine.process("creationEmail", context) val subject = messageSource.getMessage("email.activation.title", null, locale) - sendEmail(user.email, subject, content, false, true) + sendEmail(user.email, subject, content, isMultipart = false, isHtml = true) } /** diff --git a/src/main/java/org/radarbase/management/service/RevisionService.kt b/src/main/java/org/radarbase/management/service/RevisionService.kt index 6676d7827..44940b681 100644 --- a/src/main/java/org/radarbase/management/service/RevisionService.kt +++ b/src/main/java/org/radarbase/management/service/RevisionService.kt @@ -43,7 +43,6 @@ import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentMap import java.util.function.Consumer import java.util.function.Function -import java.util.stream.Collectors import java.util.stream.Stream import javax.persistence.EntityManager import javax.persistence.NoResultException @@ -78,7 +77,7 @@ open class RevisionService(@param:Autowired private val revisionEntityRepository AuditEntity.revisionNumber().minimize() .computeAggregationInInstanceContext() ) - .singleResult as Array + .singleResult as Array<*> val first = firstRevision[1] as CustomRevisionEntity // find last revision of the entity @@ -89,7 +88,7 @@ open class RevisionService(@param:Autowired private val revisionEntityRepository AuditEntity.revisionNumber().maximize() .computeAggregationInInstanceContext() ) - .singleResult as Array + .singleResult as Array<*> val last = lastRevision[1] as CustomRevisionEntity // now populate the result object and return it @@ -177,34 +176,31 @@ open class RevisionService(@param:Autowired private val revisionEntityRepository .add(AuditEntity.id().eq(entity.id)) // add the page sorting information to the query - if (pageable.sort != null) { - pageable.sort - .forEach(Consumer { order: Sort.Order -> - query.addOrder( - if (order.direction.isAscending) AuditEntity.property( - order.property - ).asc() else AuditEntity.property(order.property).desc() - ) - }) - } + pageable.sort + .forEach(Consumer { order: Sort.Order -> + query.addOrder( + if (order.direction.isAscending) AuditEntity.property( + order.property + ).asc() else AuditEntity.property(order.property).desc() + ) + }) // add the page constraints (offset and amount of results) query.setFirstResult(Math.toIntExact(pageable.offset)) .setMaxResults(Math.toIntExact(pageable.pageSize.toLong())) val dtoMapper = getDtoMapper(entity.javaClass) - val resultList = query.resultList as List?> - val revisionDtos = resultList.stream() - .map { objArray: Array? -> + val resultList = query.resultList as List?> + val revisionDtos = resultList + .map { objArray: Array<*>? -> RevisionDTO( Revision.of( CustomRevisionMetadata((objArray!![1] as CustomRevisionEntity)), objArray[0] ), objArray[2] as RevisionType, - dtoMapper.apply(objArray[0]) + objArray[0]?.let { dtoMapper.apply(it) } ) } - .collect(Collectors.toList()) return PageImpl(revisionDtos, pageable, count.toLong()) } @@ -363,7 +359,7 @@ open class RevisionService(@param:Autowired private val revisionEntityRepository }) }) .findAny() - .orElse(Function { obj: Any? -> null }) + .orElse(Function { null }) } private fun beanFromDefinition(beanDefinition: BeanDefinition): Any { @@ -390,7 +386,7 @@ open class RevisionService(@param:Autowired private val revisionEntityRepository } private val auditReader: AuditReader - private get() = AuditReaderFactory.get(entityManager) + get() = AuditReaderFactory.get(entityManager) companion object { private val log = LoggerFactory.getLogger(RevisionService::class.java) diff --git a/src/main/java/org/radarbase/management/service/SourceDataService.kt b/src/main/java/org/radarbase/management/service/SourceDataService.kt index 0053f43f4..ec175844a 100644 --- a/src/main/java/org/radarbase/management/service/SourceDataService.kt +++ b/src/main/java/org/radarbase/management/service/SourceDataService.kt @@ -60,7 +60,7 @@ class SourceDataService( * @return the list of entities */ @Transactional(readOnly = true) - fun findAll(pageable: Pageable?): Page { + fun findAll(pageable: Pageable): Page { log.debug("Request to get all SourceData") return sourceDataRepository.findAll(pageable) .map { sourceData: SourceData? -> sourceDataMapper.sourceDataToSourceDataDTO(sourceData) } diff --git a/src/main/java/org/radarbase/management/service/SubjectService.kt b/src/main/java/org/radarbase/management/service/SubjectService.kt index f4b79a416..6c70e8bac 100644 --- a/src/main/java/org/radarbase/management/service/SubjectService.kt +++ b/src/main/java/org/radarbase/management/service/SubjectService.kt @@ -220,8 +220,12 @@ class SubjectService( } private fun ensureSubject(subjectDto: SubjectDTO): Subject { - return subjectRepository.findById(subjectDto.id).orElseThrow { - NotFoundException( + return try { + subjectDto.id?.let { subjectRepository.findById(it).get() } + ?: throw Exception("invalid subject ${subjectDto.login}: No ID") + } + catch(e: Throwable) { + throw NotFoundException( "Subject with ID " + subjectDto.id + " not found.", EntityName.SUBJECT, ErrorConstants.ERR_SUBJECT_NOT_FOUND diff --git a/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt b/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt index 9955c4d22..6db908179 100644 --- a/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/ClientPairInfoDTO.kt @@ -30,14 +30,14 @@ class ClientPairInfoDTO(baseUrl: URL, tokenName: String, tokenUrl: URL?, timeout timesOutAt = Instant.now().plus(timeout) } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val that = o as ClientPairInfoDTO + val that = other as ClientPairInfoDTO return tokenName == that.tokenName && tokenUrl == that.tokenUrl && baseUrl == that.baseUrl && timeout == that.timeout && timesOutAt == that.timesOutAt } diff --git a/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt b/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt index 73f60a599..25b487219 100644 --- a/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/RoleDTO.kt @@ -21,14 +21,14 @@ class RoleDTO { + '}') } - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val roleDto = o as RoleDTO + val roleDto = other as RoleDTO return id == roleDto.id && organizationId == roleDto.organizationId && organizationName == roleDto.organizationName && projectId == roleDto.projectId && projectName == roleDto.projectName && authorityName == roleDto.authorityName } diff --git a/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt b/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt index df681db36..71f4b2a0f 100644 --- a/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/TokenDTO.kt @@ -12,14 +12,14 @@ class TokenDTO * @param privacyPolicyUrl privacyPolicyUrl for this token. */(val refreshToken: String, val baseUrl: URL, val privacyPolicyUrl: URL) { - override fun equals(o: Any?): Boolean { - if (this === o) { + override fun equals(other: Any?): Boolean { + if (this === other) { return true } - if (o == null || javaClass != o.javaClass) { + if (other == null || javaClass != other.javaClass) { return false } - val that = o as TokenDTO + val that = other as TokenDTO return refreshToken == that.refreshToken && baseUrl == that.baseUrl && privacyPolicyUrl == that.privacyPolicyUrl } diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt index 9ce30725e..c19a17760 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/SourceMapperDecorator.kt @@ -11,7 +11,6 @@ import org.radarbase.management.web.rest.errors.ErrorConstants import org.radarbase.management.web.rest.errors.NotFoundException import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Qualifier -import java.util.Map /** * Created by nivethika on 13-6-17. @@ -29,7 +28,7 @@ abstract class SourceMapperDecorator() : SourceMapper { NotFoundException( "Source ID " + minimalSourceDetailsDto.sourceId + " not found", EntityName.Companion.SOURCE, ErrorConstants.ERR_SOURCE_NOT_FOUND, - Map.of("sourceId", minimalSourceDetailsDto.sourceId.toString()) + mapOf(Pair("sourceId", minimalSourceDetailsDto.sourceId.toString())) ) source.assigned = minimalSourceDetailsDto.isAssigned return source @@ -44,7 +43,7 @@ abstract class SourceMapperDecorator() : SourceMapper { NotFoundException( "Source ID " + sourceDto.id + " not found", EntityName.Companion.SOURCE, ErrorConstants.ERR_SOURCE_NOT_FOUND, - Map.of("sourceId", sourceDto.id.toString()) + mapOf(Pair("sourceId", sourceDto.id.toString())) ) } }!! diff --git a/src/main/java/org/radarbase/management/web/rest/AuditResource.kt b/src/main/java/org/radarbase/management/web/rest/AuditResource.kt index 04b80b4c4..cd7ca7502 100644 --- a/src/main/java/org/radarbase/management/web/rest/AuditResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/AuditResource.kt @@ -32,11 +32,11 @@ class AuditResource(private val auditEventService: AuditEventService, private va */ @GetMapping @Throws(NotAuthorizedException::class) - fun getAll(@Parameter pageable: Pageable?): ResponseEntity> { + fun getAll(@Parameter pageable: Pageable): ResponseEntity> { authService.checkPermission(Permission.AUDIT_READ) val page = auditEventService.findAll(pageable) val headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits") - return ResponseEntity(page!!.content, headers, HttpStatus.OK) + return ResponseEntity(page.content, headers, HttpStatus.OK) } /** @@ -58,7 +58,7 @@ class AuditResource(private val auditEventService: AuditEventService, private va val page = auditEventService .findByDates(fromDate.atTime(0, 0), toDate.atTime(23, 59), pageable) val headers = PaginationUtil.generatePaginationHttpHeaders(page, "/management/audits") - return ResponseEntity(page!!.content, headers, HttpStatus.OK) + return ResponseEntity(page.content, headers, HttpStatus.OK) } /** diff --git a/src/main/java/org/radarbase/management/web/rest/GroupResource.kt b/src/main/java/org/radarbase/management/web/rest/GroupResource.kt index dbd0ef7df..709eb1476 100644 --- a/src/main/java/org/radarbase/management/web/rest/GroupResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/GroupResource.kt @@ -36,12 +36,10 @@ import javax.validation.Valid @RestController @RequestMapping("/api/projects/{projectName:" + Constants.ENTITY_ID_REGEX + "}/groups") -class GroupResource { - @Autowired - private val groupService: GroupService? = null - - @Autowired - private val authService: AuthService? = null +class GroupResource( + @Autowired private val groupService: GroupService, + @Autowired private val authService: AuthService +) { /** * Create group. @@ -56,11 +54,11 @@ class GroupResource { @PathVariable projectName: String?, @RequestBody @Valid groupDto: GroupDTO? ): ResponseEntity { - authService!!.checkPermission(Permission.PROJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) - val groupDtoResult = groupService!!.createGroup(projectName!!, groupDto!!) + authService.checkPermission(Permission.PROJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) + val groupDtoResult = groupService.createGroup(projectName!!, groupDto!!) val location = MvcUriComponentsBuilder.fromController(javaClass) .path("/{groupName}") - .buildAndExpand(projectName, groupDtoResult?.name) + .buildAndExpand(projectName, groupDtoResult.name) .toUri() return ResponseEntity.created(location) .body(groupDtoResult) @@ -77,8 +75,8 @@ class GroupResource { fun listGroups( @PathVariable projectName: String? ): List { - authService!!.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.project(projectName) }) - return groupService!!.listGroups(projectName!!) + authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.project(projectName) }) + return groupService.listGroups(projectName!!) } /** @@ -96,8 +94,8 @@ class GroupResource { @PathVariable projectName: String?, @PathVariable groupName: String? ): GroupDTO { - authService!!.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.project(projectName) }) - return groupService!!.getGroup(projectName!!, groupName!!) + authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> e.project(projectName) }) + return groupService.getGroup(projectName!!, groupName!!) } /** @@ -115,8 +113,8 @@ class GroupResource { @PathVariable projectName: String?, @PathVariable groupName: String? ): ResponseEntity<*> { - authService!!.checkPermission(Permission.PROJECT_UPDATE, { (_, project): EntityDetails -> project }) - groupService!!.deleteGroup(projectName!!, groupName!!, unlinkSubjects!!) + authService.checkPermission(Permission.PROJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) + groupService.deleteGroup(projectName!!, groupName!!, unlinkSubjects!!) return ResponseEntity.noContent().build() } @@ -140,12 +138,11 @@ class GroupResource { // so it would make sense to check permissions per subject, // but I assume that only those who are authorized to perform project-wide actions // should be allowed to use this endpoint - authService!!.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) + authService.checkPermission(Permission.SUBJECT_UPDATE, { e: EntityDetails -> e.project(projectName) }) val addedItems = ArrayList() val removedItems = ArrayList() for (operation in patchOperations) { - val opCode = operation.op - when (opCode) { + when (val opCode = operation.op) { "add" -> operation.value?.let { addedItems.addAll(it) } "remove" -> operation.value?.let { removedItems.addAll(it) } else -> throw BadRequestException( @@ -154,7 +151,7 @@ class GroupResource { ) } } - groupService!!.updateGroupSubjects(projectName!!, groupName!!, addedItems.filterNotNull(), removedItems.filterNotNull()) + groupService.updateGroupSubjects(projectName!!, groupName!!, addedItems.filterNotNull(), removedItems.filterNotNull()) return ResponseEntity.noContent().build() } } diff --git a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt index 352934caa..f982fec0e 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceDataResource.kt @@ -114,7 +114,7 @@ class SourceDataResource( @Timed @Throws(NotAuthorizedException::class) fun getAllSourceData( - @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable? + @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable ): ResponseEntity> { log.debug("REST request to get all SourceData") authService.checkScope(Permission.SOURCEDATA_READ) diff --git a/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt b/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt index c405793cf..76b2b392c 100644 --- a/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt +++ b/src/main/java/org/radarbase/management/web/rest/errors/ExceptionTranslator.kt @@ -1,9 +1,6 @@ package org.radarbase.management.web.rest.errors import org.radarbase.management.security.NotAuthorizedException -import org.radarbase.management.web.rest.errors.InvalidStateException -import org.radarbase.management.web.rest.errors.RadarWebApplicationException -import org.radarbase.management.web.rest.errors.RequestGoneException import org.radarbase.management.web.rest.util.HeaderUtil import org.slf4j.LoggerFactory import org.springframework.core.annotation.AnnotationUtils @@ -48,7 +45,6 @@ class ExceptionTranslator { @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody fun processValidationError(ex: TransactionSystemException): ErrorVM { - // TODO: this is the top level exception that is thrown when e.g. a // ConstraintValidationException occurs. Need to investigate what other exceptions result // in this one and probably add a check for it. return ErrorVM(ErrorConstants.ERR_VALIDATION, ex.message) @@ -69,7 +65,7 @@ class ExceptionTranslator { for (fieldError in fieldErrors) { dto.add( fieldError.objectName, fieldError.field, - fieldError.code + ": " + fieldError.defaultMessage + (fieldError.code?.plus(": ") ?: "undefined.error.code") + fieldError.defaultMessage ) } return dto diff --git a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt index 513307e69..cb12ebb4c 100644 --- a/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OAuthClientsResourceIntTest.kt @@ -80,7 +80,7 @@ internal class OAuthClientsResourceIntTest @Autowired constructor( @Throws(Exception::class) fun createAndFetchOAuthClient() { // fetch the created oauth client and check the json result - var ans = restOauthClientMvc.perform( + restOauthClientMvc.perform( MockMvcRequestBuilders.get("/api/oauth-clients/" + details.clientId).accept(MediaType.APPLICATION_JSON) ).andExpect( MockMvcResultMatchers.status().isOk() diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt index 230042584..e5e230044 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt @@ -146,7 +146,6 @@ internal open class ProjectResourceIntTest( // Create the Project, which fails. val projectDto: ProjectDTO? = projectMapper.projectToProjectDTO(project) - val projectt: Project? = projectMapper.projectDTOToProject(projectDto) restProjectMockMvc.perform( MockMvcRequestBuilders.post("/api/projects") .contentType(TestUtil.APPLICATION_JSON_UTF8) From add1304e77e3c70f6fa89a23ace76bb9df06f3cf Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 6 Nov 2023 15:20:12 +0100 Subject: [PATCH 118/158] fix gatling tests project: organization was not provided as valid json Sourcetype: catalogversion was incorrectly set during save subject: incomplete projectDTO was provided (no name). this could be resolved by looking up the name if an id is provided. --- src/gatling/scala/ProjectGatlingTest.scala | 2 +- src/gatling/scala/SubjectGatlingTest.scala | 3 +- .../management/service/ProjectService.kt | 12 +++---- .../management/service/ResourceUriService.kt | 2 +- .../management/service/SourceTypeService.kt | 32 ++++++++++++------- .../management/web/rest/ProjectResource.kt | 6 ++-- .../management/web/rest/SourceTypeResource.kt | 2 +- .../management/web/rest/SubjectResource.kt | 5 ++- 8 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/gatling/scala/ProjectGatlingTest.scala b/src/gatling/scala/ProjectGatlingTest.scala index fde7b673d..0f8211fe9 100644 --- a/src/gatling/scala/ProjectGatlingTest.scala +++ b/src/gatling/scala/ProjectGatlingTest.scala @@ -44,7 +44,7 @@ class ProjectGatlingTest extends ManagementPortalSimulation { .exec(http("Create new project") .post("/api/projects") .headers(headers_http_authenticated) - .body(StringBody("""{"id":null, "projectName":"PROJECT-${randstring}", "description":"SAMPLE_TEXT", "organization":"SAMPLE_TEXT", "location":"SAMPLE_TEXT", "startDate":"2020-01-01T00:00:00.000Z", "projectStatus":null, "endDate":"2020-01-01T00:00:00.000Z", "projectAdmin":null}""")).asJson + .body(StringBody("""{"id":null, "projectName":"PROJECT-${randstring}", "description":"SAMPLE_TEXT", "organizationName":"SAMPLE_TEXT", "location":"SAMPLE_TEXT", "startDate":"2020-01-01T00:00:00.000Z", "projectStatus":null, "endDate":"2020-01-01T00:00:00.000Z", "projectAdmin":null}""")).asJson .check(status.is(201)) .check(headerRegex("Location", "(.*)").saveAs("new_project_url"))).exitHereIfFailed .pause(5) diff --git a/src/gatling/scala/SubjectGatlingTest.scala b/src/gatling/scala/SubjectGatlingTest.scala index baea1fdf3..bba54636e 100644 --- a/src/gatling/scala/SubjectGatlingTest.scala +++ b/src/gatling/scala/SubjectGatlingTest.scala @@ -38,6 +38,7 @@ class SubjectGatlingTest extends ManagementPortalSimulation { .get("/api/projects") .headers(headers_http_authenticated) .check(status.is(200)) + .check(jsonPath("$[0].projectName").saveAs("project_name")) .check(jsonPath("$[0].id").saveAs("project_id"))).exitHereIfFailed .repeat(2) { exec(http("Get all subjects") @@ -49,7 +50,7 @@ class SubjectGatlingTest extends ManagementPortalSimulation { .exec(http("Create new subject") .post("/api/subjects") .headers(headers_http_authenticated) - .body(StringBody("""{"id":null, "externalLink":"SAMPLE_TEXT", "enternalId":"${randstring}", "project": {"id": "${project_id}"}}""")).asJson + .body(StringBody("""{"id":null, "externalLink":"SAMPLE_TEXT", "externalId":"${randstring}", "project": {"id": "${project_id}", "projectName": "${project_name}"}}""")).asJson .check(status.is(201)) .check(headerRegex("Location", "(.*)").saveAs("new_subject_url"))).exitHereIfFailed .pause(5) diff --git a/src/main/java/org/radarbase/management/service/ProjectService.kt b/src/main/java/org/radarbase/management/service/ProjectService.kt index adaaaa547..0975c75bc 100644 --- a/src/main/java/org/radarbase/management/service/ProjectService.kt +++ b/src/main/java/org/radarbase/management/service/ProjectService.kt @@ -24,7 +24,7 @@ import java.util.* */ @Service @Transactional -open class ProjectService( +class ProjectService( @Autowired private val projectRepository: ProjectRepository, @Autowired private val projectMapper: ProjectMapper, @Autowired private val sourceTypeMapper: SourceTypeMapper, @@ -50,7 +50,7 @@ open class ProjectService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(fetchMinimal: Boolean, pageable: Pageable): Page<*> { + fun findAll(fetchMinimal: Boolean, pageable: Pageable): Page<*> { val projects: Page val referents = authService.referentsByScope(Permission.PROJECT_READ) projects = if (referents.isEmpty()) { @@ -76,7 +76,7 @@ open class ProjectService( * @return the entity */ @Transactional(readOnly = true) - open fun findOne(id: Long): ProjectDTO? { + fun findOne(id: Long): ProjectDTO? { log.debug("Request to get Project : {}", id) val project = projectRepository.findOneWithEagerRelationships(id) ?: throw NotFoundException( @@ -96,7 +96,7 @@ open class ProjectService( * @return the entity */ @Transactional(readOnly = true) - open fun findOneByName(name: String): ProjectDTO { + fun findOneByName(name: String): ProjectDTO { log.debug("Request to get Project by name: {}", name) val project = projectRepository.findOneWithEagerRelationshipsByName(name) ?: throw NotFoundException( @@ -115,10 +115,10 @@ open class ProjectService( * @return the list of source-types assigned. */ @Transactional(readOnly = true) - open fun findSourceTypesByProjectId(id: Long): List { + fun findSourceTypesByProjectId(id: Long): List { log.debug("Request to get Project.sourceTypes of project: {}", id) val sourceTypes = projectRepository.findSourceTypesByProjectId(id) - return sourceTypeMapper.sourceTypesToSourceTypeDTOs(sourceTypes).filterNotNull() + return sourceTypeMapper.sourceTypesToSourceTypeDTOs(sourceTypes) } /** diff --git a/src/main/java/org/radarbase/management/service/ResourceUriService.kt b/src/main/java/org/radarbase/management/service/ResourceUriService.kt index c02792779..ecb5ad361 100644 --- a/src/main/java/org/radarbase/management/service/ResourceUriService.kt +++ b/src/main/java/org/radarbase/management/service/ResourceUriService.kt @@ -91,7 +91,7 @@ object ResourceUriService { return URI( HeaderUtil.buildPath( "api", "source-types", resource.producer, - resource.model, resource.model + resource.model, resource.catalogVersion ) ) } diff --git a/src/main/java/org/radarbase/management/service/SourceTypeService.kt b/src/main/java/org/radarbase/management/service/SourceTypeService.kt index bc2c42ed6..da67436af 100644 --- a/src/main/java/org/radarbase/management/service/SourceTypeService.kt +++ b/src/main/java/org/radarbase/management/service/SourceTypeService.kt @@ -28,7 +28,7 @@ import javax.validation.constraints.NotNull */ @Service @Transactional -open class SourceTypeService( +class SourceTypeService( @Autowired private val sourceTypeRepository: SourceTypeRepository, @Autowired private val sourceTypeMapper: SourceTypeMapper, @Autowired private val sourceDataRepository: SourceDataRepository, @@ -61,7 +61,7 @@ open class SourceTypeService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(): List { + fun findAll(): List { log.debug("Request to get all SourceTypes") val result = sourceTypeRepository.findAllWithEagerRelationships() return result @@ -95,23 +95,33 @@ open class SourceTypeService( * Fetch SourceType by producer and model. */ fun findByProducerAndModelAndVersion( - @NotNull producer: String, - @NotNull model: String, @NotNull version: String + @NotNull producer: String?, + @NotNull model: String?, @NotNull version: String? ): SourceTypeDTO { log.debug( "Request to get SourceType by producer and model and version: {}, {}, {}", producer, model, version ) - return sourceTypeRepository - .findOneWithEagerRelationshipsByProducerAndModelAndVersion(producer, model, version) - .let { sourceType: SourceType? -> sourceType?.let { sourceTypeMapper.sourceTypeToSourceTypeDTO(it) } } - ?: throw NotFoundException( - "SourceType not found with producer, model, " + "version ", EntityName.Companion.SOURCE_TYPE, - ErrorConstants.ERR_SOURCE_TYPE_NOT_FOUND, Collections.singletonMap( + if (producer == null || model == null || version == null) { + throw NotFoundException( + "SourceType not found with producer, model, " + "version ", EntityName.SOURCE_TYPE, + ErrorConstants.ERR_SOURCE_TYPE_NOT_FOUND, Collections.singletonMap( + "producer-model-version", + "$producer-$model-$version" + ) + ) + } + val result = + sourceTypeRepository.findOneWithEagerRelationshipsByProducerAndModelAndVersion(producer, model, version) + ?: throw NotFoundException( + "SourceType not found with producer, model, " + "version ", EntityName.SOURCE_TYPE, + ErrorConstants.ERR_SOURCE_TYPE_NOT_FOUND, Collections.singletonMap( "producer-model-version", "$producer-$model-$version" ) ) + + return sourceTypeMapper.sourceTypeToSourceTypeDTO(result) } /** @@ -159,7 +169,7 @@ open class SourceTypeService( * @param catalogSourceTypes list of source-type from catalogue-server. */ @Transactional - open fun saveSourceTypesFromCatalogServer(catalogSourceTypes: List) { + fun saveSourceTypesFromCatalogServer(catalogSourceTypes: List) { for (catalogSourceType in catalogSourceTypes) { var sourceType = catalogSourceTypeMapper .catalogSourceTypeToSourceType(catalogSourceType) diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index 725e15a88..ce44a1b5a 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -76,8 +76,8 @@ class ProjectResource( @Throws(URISyntaxException::class, NotAuthorizedException::class) fun createProject(@RequestBody @Valid projectDto: ProjectDTO?): ResponseEntity { log.debug("REST request to save Project : {}", projectDto) - val org = projectDto?.organization - if (org?.name == null) { + val org = projectDto?.organizationName + if (org == null) { throw BadRequestException( "Organization must be provided", ENTITY_NAME, ErrorConstants.ERR_VALIDATION @@ -85,7 +85,7 @@ class ProjectResource( } authService.checkPermission( Permission.PROJECT_CREATE, - { e: EntityDetails -> e.organization(org.name) }) + { e: EntityDetails -> e.organization(org) }) if (projectDto.id != null) { return ResponseEntity.badRequest() .headers( diff --git a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt index b94d22046..1cb524223 100644 --- a/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SourceTypeResource.kt @@ -242,7 +242,7 @@ class SourceTypeResource( producer, model, version ) - if (!projects.isEmpty()) { + if (projects.isNotEmpty()) { throw InvalidRequestException( // we know the list is not empty so calling get() is safe here "Cannot delete a source-type that " + "is being used by project(s)", EntityName.SOURCE_TYPE, ErrorConstants.ERR_SOURCE_TYPE_IN_USE, Collections.singletonMap( diff --git a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt index 7d92ccc7f..3bba61551 100644 --- a/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/SubjectResource.kt @@ -110,7 +110,10 @@ class SubjectResource( .body(result) } + private fun getProjectName(subjectDto: SubjectDTO): String { + // not ideal, because only name is needed. however, id is checked to verify the project is in the database + // this does prevent calls to the database? if (subjectDto.project == null || subjectDto.project!!.id == null || subjectDto.project!!.projectName == null) { throw BadRequestException( "A subject should be assigned to a project", EntityName.SUBJECT, @@ -215,7 +218,7 @@ class SubjectResource( listOf( subjectMapper.subjectToSubjectReducedProjectDTO(s) ) - }); + }) ResponseUtil.wrapOrNotFound(subject) } else if (projectName == null && externalId != null) { val page = subjectService.findAll(subjectCriteria) From 0c4a1f9110a5f60e8a4d5bb5f68762c626bef8c5 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 6 Nov 2023 17:46:54 +0100 Subject: [PATCH 119/158] project.organizationName now defaults to the project.organization.name, and overwrites the field on get() to prevent inconsistencies. Only if there is no organization.name, the original field can be used. --- src/gatling/scala/ProjectGatlingTest.scala | 2 +- .../config/AuthorizationConfiguration.kt | 6 ++-- .../radarbase/management/domain/Project.kt | 12 ++++++- .../repository/ProjectRepository.kt | 6 ++-- .../management/service/UserService.kt | 16 ++++----- .../management/service/dto/ProjectDTO.kt | 9 +++++ .../decorator/ProjectMapperDecorator.kt | 10 +++--- .../management/web/rest/ProjectResource.kt | 18 +++++----- .../web/rest/ProjectResourceIntTest.kt | 35 +++++++++---------- 9 files changed, 65 insertions(+), 49 deletions(-) diff --git a/src/gatling/scala/ProjectGatlingTest.scala b/src/gatling/scala/ProjectGatlingTest.scala index 0f8211fe9..c1eba2ccb 100644 --- a/src/gatling/scala/ProjectGatlingTest.scala +++ b/src/gatling/scala/ProjectGatlingTest.scala @@ -44,7 +44,7 @@ class ProjectGatlingTest extends ManagementPortalSimulation { .exec(http("Create new project") .post("/api/projects") .headers(headers_http_authenticated) - .body(StringBody("""{"id":null, "projectName":"PROJECT-${randstring}", "description":"SAMPLE_TEXT", "organizationName":"SAMPLE_TEXT", "location":"SAMPLE_TEXT", "startDate":"2020-01-01T00:00:00.000Z", "projectStatus":null, "endDate":"2020-01-01T00:00:00.000Z", "projectAdmin":null}""")).asJson + .body(StringBody("""{"id":null, "projectName":"PROJECT-${randstring}", "description":"SAMPLE_TEXT", "organization": {"id": 1, "name": "main" }, "location":"SAMPLE_TEXT", "startDate":"2020-01-01T00:00:00.000Z", "projectStatus":null, "endDate":"2020-01-01T00:00:00.000Z", "projectAdmin":null}""")).asJson .check(status.is(201)) .check(headerRegex("Location", "(.*)").saveAs("new_project_url"))).exitHereIfFailed .pause(5) diff --git a/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt b/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt index 6b479d296..c175df23c 100644 --- a/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/AuthorizationConfiguration.kt @@ -10,15 +10,15 @@ import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration -open class AuthorizationConfiguration( +class AuthorizationConfiguration( private val projectRepository: ProjectRepository, ) { @Bean - open fun authorizationOracle(): AuthorizationOracle = MPAuthorizationOracle( + fun authorizationOracle(): AuthorizationOracle = MPAuthorizationOracle( object : EntityRelationService { override suspend fun findOrganizationOfProject(project: String): String? = withContext(Dispatchers.IO) { projectRepository.findOneWithEagerRelationshipsByName(project) - ?.organization?.name + ?.organizationName } } ) diff --git a/src/main/java/org/radarbase/management/domain/Project.kt b/src/main/java/org/radarbase/management/domain/Project.kt index 0713e5f72..7beb687fa 100644 --- a/src/main/java/org/radarbase/management/domain/Project.kt +++ b/src/main/java/org/radarbase/management/domain/Project.kt @@ -61,9 +61,19 @@ class Project : AbstractEntity(), Serializable { @Column(name = "description", nullable = false) @NotNull var description: String? = null - @JvmField + // Defaults to organization name, but if that is not set then we can use the organizationName @Column(name = "jhi_organization") var organizationName: String? = null + get() { + if (organization?.name != null) + field = organization?.name + return field + } + // needed because the @JVMField annotation cannot be added when a custom getter/setter is set + set(value) { + field = value + } + @JvmField @ManyToOne(fetch = FetchType.EAGER) diff --git a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt index 2eb10938f..fdcf4f1d4 100644 --- a/src/main/java/org/radarbase/management/repository/ProjectRepository.kt +++ b/src/main/java/org/radarbase/management/repository/ProjectRepository.kt @@ -27,10 +27,10 @@ interface ProjectRepository : JpaRepository, RevisionRepository< value = "select distinct project from Project project " + "left join fetch project.sourceTypes " + "WHERE project.projectName in (:projectNames) " - + "OR project.organization.name in (:organizationNames)", + + "OR project.organizationName in (:organizationNames)", countQuery = "select distinct count(project) from Project project " + "WHERE project.projectName in (:projectNames) " - + "OR project.organization.name in (:organizationNames)" + + "OR project.organizationName in (:organizationNames)" ) fun findAllWithEagerRelationshipsInOrganizationsOrProjects( pageable: Pageable?, @@ -40,7 +40,7 @@ interface ProjectRepository : JpaRepository, RevisionRepository< @Query( "select project from Project project " - + "WHERE project.organization.name = :organization_name" + + "WHERE project.organizationName = :organization_name" ) fun findAllByOrganizationName( @Param("organization_name") organizationName: String diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt index b666cb90b..c35f24538 100644 --- a/src/main/java/org/radarbase/management/service/UserService.kt +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -38,7 +38,7 @@ import java.util.function.Function */ @Service @Transactional -open class UserService @Autowired constructor( +class UserService @Autowired constructor( private val userRepository: UserRepository, private val passwordService: PasswordService, private val userMapper: UserMapper, @@ -205,7 +205,7 @@ open class UserService @Autowired constructor( RoleAuthority.Scope.ORGANIZATION -> e.organization(role.organization?.name) RoleAuthority.Scope.PROJECT -> { if (role.project?.organization != null) { - e.organization(role.project?.organization?.name) + e.organization(role.project?.organizationName) } e.project(role.project?.projectName) } @@ -262,7 +262,7 @@ open class UserService @Autowired constructor( */ @Transactional @Throws(NotAuthorizedException::class) - open fun updateUser(userDto: UserDTO): UserDTO? { + fun updateUser(userDto: UserDTO): UserDTO? { val userOpt = userDto.id?.let { userRepository.findById(it) } return if (userOpt?.isPresent == true) { var user = userOpt.get() @@ -314,7 +314,7 @@ open class UserService @Autowired constructor( * @param password the new password * @param login of the user to change password */ - open fun changePassword(login: String, password: String) { + fun changePassword(login: String, password: String) { val user = userRepository.findOneByLogin(login) if (user != null) { @@ -331,7 +331,7 @@ open class UserService @Autowired constructor( * @return the requested page of users */ @Transactional(readOnly = true) - open fun getAllManagedUsers(pageable: Pageable): Page { + fun getAllManagedUsers(pageable: Pageable): Page { log.debug("Request to get all Users") return userRepository.findAllByLoginNot(pageable, Constants.ANONYMOUS_USER) .map { user: User? -> userMapper.userToUserDTO(user) } @@ -344,12 +344,12 @@ open class UserService @Autowired constructor( * and is empty otherwise */ @Transactional(readOnly = true) - open fun getUserWithAuthoritiesByLogin(login: String): UserDTO? { + fun getUserWithAuthoritiesByLogin(login: String): UserDTO? { return userMapper.userToUserDTO(userRepository.findOneWithRolesByLogin(login)) } @get:Transactional(readOnly = true) - open val userWithAuthorities: User? + val userWithAuthorities: User? /** * Get the current user. * @return the currently authenticated user, or null if no user is currently authenticated @@ -412,7 +412,7 @@ open class UserService @Autowired constructor( */ @Transactional @Throws(NotAuthorizedException::class) - open fun updateRoles(login: String, roleDtos: Set?) { + fun updateRoles(login: String, roleDtos: Set?) { val user = userRepository.findOneByLogin(login) ?: throw NotFoundException( "User with login $login not found", diff --git a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt index 0955cec77..f7376bab0 100644 --- a/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt +++ b/src/main/java/org/radarbase/management/service/dto/ProjectDTO.kt @@ -17,7 +17,16 @@ class ProjectDTO : Serializable { var humanReadableProjectName: String? = null @NotNull var description: String? = null var organization: OrganizationDTO? = null + + // Defaults to organization name, but if that is not set then we can use the organizationName var organizationName: String? = null + get() { + if (organization?.name != null) + field = organization?.name + return field + } + + @NotNull var location: String? = null var startDate: ZonedDateTime? = null var projectStatus: ProjectStatus? = null diff --git a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt index 9f7811647..3fae78093 100644 --- a/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt +++ b/src/main/java/org/radarbase/management/service/mapper/decorator/ProjectMapperDecorator.kt @@ -53,17 +53,17 @@ abstract class ProjectMapperDecorator : ProjectMapper { val project = delegate.projectDTOToProject(projectDto) val projectName = projectDto.humanReadableProjectName if (!projectName.isNullOrEmpty()) { - project!!.attributes[ProjectDTO.Companion.HUMAN_READABLE_PROJECT_NAME] = projectName + project!!.attributes[ProjectDTO.HUMAN_READABLE_PROJECT_NAME] = projectName } - val name = projectDto.organization?.name - if (name != null) { + val name = projectDto.organizationName + if (name != null && projectDto.organization != null) { val org = organizationRepository.findOneByName(name) ?: throw NotFoundException( "Organization not found with name", - EntityName.Companion.ORGANIZATION, + EntityName.ORGANIZATION, ErrorConstants.ERR_ORGANIZATION_NAME_NOT_FOUND, - Collections.singletonMap("name", name) + Collections.singletonMap("name", name) ) project!!.organization = org } diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index ce44a1b5a..9b052727d 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -77,12 +77,10 @@ class ProjectResource( fun createProject(@RequestBody @Valid projectDto: ProjectDTO?): ResponseEntity { log.debug("REST request to save Project : {}", projectDto) val org = projectDto?.organizationName - if (org == null) { - throw BadRequestException( + ?: throw BadRequestException( "Organization must be provided", ENTITY_NAME, ErrorConstants.ERR_VALIDATION ) - } authService.checkPermission( Permission.PROJECT_CREATE, { e: EntityDetails -> e.organization(org) }) @@ -156,7 +154,7 @@ class ProjectResource( e.organization(newOrgName) e.project(existingProject?.projectName) }) - val oldOrgName = existingProject?.organization?.name + val oldOrgName = existingProject?.organizationName if (newOrgName != oldOrgName) { authService.checkPermission( Permission.PROJECT_UPDATE, @@ -210,7 +208,7 @@ class ProjectResource( log.debug("REST request to get Project : {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> - e.organization(projectDto.organization?.name) + e.organization(projectDto.organizationName) e.project(projectDto.projectName) }) return ResponseEntity.ok(projectDto) @@ -233,7 +231,7 @@ class ProjectResource( log.debug("REST request to get Project : {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.PROJECT_READ, { e: EntityDetails -> - e.organization(projectDto.organization?.name) + e.organization(projectDto.organizationName) e.project(projectDto.projectName) }) return projectService.findSourceTypesByProjectId(projectDto.id!!) @@ -255,7 +253,7 @@ class ProjectResource( log.debug("REST request to delete Project : {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.PROJECT_DELETE, { e: EntityDetails -> - e.organization(projectDto.organization?.name) + e.organization(projectDto.organizationName) e.project(projectDto.projectName) }) return try { @@ -284,7 +282,7 @@ class ProjectResource( log.debug("REST request to get all Roles for project {}", projectName) val projectDto = projectService.findOneByName(projectName!!) authService.checkPermission(Permission.ROLE_READ, { e: EntityDetails -> - e.organization(projectDto.organization?.name) + e.organization(projectDto.organizationName) e.project(projectDto.projectName) }) return ResponseEntity.ok(roleService.getRolesByProject(projectName)) @@ -311,7 +309,7 @@ class ProjectResource( val projectDto = projectService.findOneByName(projectName) //?: throw NoSuchElementException() authService.checkPermission(Permission.SOURCE_READ, { e: EntityDetails -> - e.organization(projectDto.organization?.name) + e.organization(projectDto.organizationName) e.project(projectDto.projectName) }) return if (assigned != null) { @@ -375,7 +373,7 @@ class ProjectResource( // this checks if the project exists val projectDto = projectName.let { projectService.findOneByName(it) } authService.checkPermission(Permission.SUBJECT_READ, { e: EntityDetails -> - e.organization(projectDto.organization?.name) + e.organization(projectDto.organizationName) e.project(projectDto.projectName) }) diff --git a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt index e5e230044..25f97edd6 100644 --- a/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/ProjectResourceIntTest.kt @@ -44,7 +44,7 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class ProjectResourceIntTest( +internal class ProjectResourceIntTest( @Autowired private val projectResource: ProjectResource, // @Autowired private val subjectMapper: SubjectMapper, @@ -88,7 +88,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createProject() { + fun createProject() { val databaseSizeBeforeCreate = projectRepository.findAll().size // Create the Project @@ -116,7 +116,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createProjectWithExistingId() { + fun createProjectWithExistingId() { val databaseSizeBeforeCreate = projectRepository.findAll().size // Create the Project with an existing ID @@ -139,7 +139,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkProjectNameIsRequired() { + fun checkProjectNameIsRequired() { val databaseSizeBeforeTest = projectRepository.findAll().size // set the field null project.projectName = null @@ -159,7 +159,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkDescriptionIsRequired() { + fun checkDescriptionIsRequired() { val databaseSizeBeforeTest = projectRepository.findAll().size // set the field null project.description = null @@ -179,7 +179,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkLocationIsRequired() { + fun checkLocationIsRequired() { val databaseSizeBeforeTest = projectRepository.findAll().size // set the field null project.location = null @@ -199,7 +199,7 @@ internal open class ProjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun allProjects() { + fun allProjects() { // Initialize the database projectRepository.saveAndFlush(project) @@ -266,7 +266,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun getProject() { + fun getProject() { // Initialize the database projectRepository.saveAndFlush(project) @@ -287,7 +287,7 @@ internal open class ProjectResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun nonExistingProject() { + fun nonExistingProject() { // Get the project restProjectMockMvc.perform(MockMvcRequestBuilders.get("/api/projects/{id}", Long.MAX_VALUE)) .andExpect(MockMvcResultMatchers.status().isNotFound()) @@ -296,11 +296,11 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateProject() { + fun updateProject() { // Initialize the database projectRepository.saveAndFlush(project) val org = Organization() - org.name = "org1" + org.name = UPDATED_ORGANIZATION org.description = "Test Organization 1" org.location = "Somewhere" organizationRepository.saveAndFlush(org) @@ -312,7 +312,6 @@ internal open class ProjectResourceIntTest( updatedProject .projectName(UPDATED_PROJECT_NAME) .description(UPDATED_DESCRIPTION) - .organizationName(UPDATED_ORGANIZATION) .organization(org) .location(UPDATED_LOCATION) .startDate(UPDATED_START_DATE) @@ -345,7 +344,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateNonExistingProject() { + fun updateNonExistingProject() { val databaseSizeBeforeUpdate = projectRepository.findAll().size // Create the Project @@ -367,7 +366,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun deleteProject() { + fun deleteProject() { // Initialize the database projectRepository.saveAndFlush(project) val databaseSizeBeforeDelete = projectRepository.findAll().size @@ -387,7 +386,7 @@ internal open class ProjectResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun equalsVerifier() { + fun equalsVerifier() { org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(Project::class.java)) } @@ -396,8 +395,8 @@ internal open class ProjectResourceIntTest( private const val UPDATED_PROJECT_NAME = "BBBBBBBBBB" private const val DEFAULT_DESCRIPTION = "AAAAAAAAAA" private const val UPDATED_DESCRIPTION = "BBBBBBBBBB" - private const val DEFAULT_ORGANIZATION = "AAAAAAAAAA" - private const val UPDATED_ORGANIZATION = "BBBBBBBBBB" + private const val DEFAULT_ORGANIZATION = "main" + private const val UPDATED_ORGANIZATION = "org1" private const val DEFAULT_LOCATION = "AAAAAAAAAA" private const val UPDATED_LOCATION = "BBBBBBBBBB" private val DEFAULT_START_DATE = ZonedDateTime.ofInstant( @@ -425,7 +424,7 @@ internal open class ProjectResourceIntTest( fun createEntity(): Project { val organization = Organization() organization.id = 1L - organization.name = "main" + organization.name = DEFAULT_ORGANIZATION organization.description = "test" return Project() .projectName(DEFAULT_PROJECT_NAME) From 3f52d6b7f5b8e95d93d0f0a30767b0ac51136dba Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Mon, 6 Nov 2023 18:05:43 +0100 Subject: [PATCH 120/158] resolve Joris' comments --- .../java/org/radarbase/auth/token/DataRadarToken.kt | 4 ++-- .../main/java/org/radarbase/auth/token/RadarToken.kt | 4 ++-- .../auth/authentication/TokenValidatorTest.kt | 10 +++++----- .../radarbase/management/config/AsyncConfiguration.kt | 2 +- .../management/config/DatabaseConfiguration.kt | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt b/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt index 27bba10c1..7a2392ee7 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/token/DataRadarToken.kt @@ -12,7 +12,7 @@ data class DataRadarToken( * Get all roles defined in this token. * @return non-null set describing the roles defined in this token. */ - override val roles: Set?, + override val roles: Set, /** * Get a list of scopes assigned to this token. @@ -101,7 +101,7 @@ data class DataRadarToken( clientId = radarToken.clientId, ) - override fun copyWithRoles(roles: Set?): DataRadarToken = copy(roles = roles) + override fun copyWithRoles(roles: Set): DataRadarToken = copy(roles = roles) companion object { fun RadarToken.toDataRadarToken(): DataRadarToken = DataRadarToken(this) diff --git a/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt b/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt index 39341d0c9..52acb36d9 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/token/RadarToken.kt @@ -11,7 +11,7 @@ interface RadarToken { * Get all roles defined in this token. * @return non-null set describing the roles defined in this token. */ - val roles: Set? + val roles: Set /** * Get a list of scopes assigned to this token. @@ -92,7 +92,7 @@ interface RadarToken { val isClientCredentials: Boolean get() = grantType == CLIENT_CREDENTIALS - fun copyWithRoles(roles: Set?): RadarToken + fun copyWithRoles(roles: Set): RadarToken companion object { const val CLIENT_CREDENTIALS = "client_credentials" diff --git a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt index 9c35dc29e..2dca2a112 100644 --- a/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt +++ b/radar-auth/src/test/java/org/radarbase/auth/authentication/TokenValidatorTest.kt @@ -28,7 +28,7 @@ internal class TokenValidatorTest { */ @BeforeEach fun setUp() { - wireMockServer!!.stubFor( + wireMockServer.stubFor( WireMock.get(WireMock.urlEqualTo(TokenTestUtils.PUBLIC_KEY_PATH)) .willReturn( WireMock.aResponse() @@ -48,7 +48,7 @@ internal class TokenValidatorTest { @AfterEach fun reset() { - wireMockServer!!.resetAll() + wireMockServer.resetAll() } @Test @@ -78,7 +78,7 @@ internal class TokenValidatorTest { } companion object { - private var wireMockServer: WireMockServer? = null + private lateinit var wireMockServer: WireMockServer @JvmStatic @BeforeAll @@ -87,13 +87,13 @@ internal class TokenValidatorTest { WireMockConfiguration() .port(WIREMOCK_PORT) ) - wireMockServer!!.start() + wireMockServer.start() } @JvmStatic @AfterAll fun tearDown() { - wireMockServer!!.stop() + wireMockServer.stop() } } } diff --git a/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt index bca9e4d4f..2f89550b0 100644 --- a/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/AsyncConfiguration.kt @@ -16,7 +16,7 @@ import tech.jhipster.config.JHipsterProperties @Configuration @EnableAsync @EnableScheduling -open class AsyncConfiguration( +class AsyncConfiguration( @Autowired private val jHipsterProperties: JHipsterProperties) : AsyncConfigurer { @Bean(name = ["taskExecutor"]) override fun getAsyncExecutor(): ExceptionHandlingAsyncTaskExecutor { diff --git a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt index 896feab14..8c301a5a2 100644 --- a/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/DatabaseConfiguration.kt @@ -23,11 +23,11 @@ import javax.sql.DataSource ) @EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware") @EnableTransactionManagement -open class DatabaseConfiguration { +class DatabaseConfiguration { @Autowired private val env: Environment? = null @Bean - open fun liquibase( + fun liquibase( dataSource: DataSource, liquibaseProperties: LiquibaseProperties ): SpringLiquibase { @@ -50,7 +50,7 @@ open class DatabaseConfiguration { } @Bean - open fun hibernate5Module(): Hibernate5Module { + fun hibernate5Module(): Hibernate5Module { return Hibernate5Module() } From 553754bdb8dfb4602045d85c43dcb038bb133e8e Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 7 Nov 2023 16:52:55 +0100 Subject: [PATCH 121/158] minor fix --- .../auth/authorization/MPAuthorizationOracle.kt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt b/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt index ef7f0ad5d..35601eeeb 100644 --- a/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt +++ b/radar-auth/src/main/java/org/radarbase/auth/authorization/MPAuthorizationOracle.kt @@ -24,9 +24,9 @@ class MPAuthorizationOracle( if (identity.isClientCredentials) return true - return identity.roles?.forkAny { + return identity.roles.forkAny { it.hasPermission(identity, permission, entity, entityScope) - } ?: false + } } /** @@ -39,8 +39,7 @@ class MPAuthorizationOracle( if (identity.isClientCredentials) return true - return identity.roles?.any { it.role.mayBeGranted(permission) } - ?: false + return identity.roles.any { it.role.mayBeGranted(permission) } } /** @@ -62,7 +61,7 @@ class MPAuthorizationOracle( val projects = mutableSetOf() val personalProjects = mutableSetOf() - identity.roles?.forEach { + identity.roles.forEach { if (it.role.mayBeGranted(permission)) { when (it.role.scope) { RoleAuthority.Scope.GLOBAL -> global = true From e04a81bfe486bcd3349a566a4d0d19d61208cba0 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 13:56:50 +0100 Subject: [PATCH 122/158] revert ClaimsTokenEnhancer to java and reintegrate it in the oAuth2ServerConfig --- .../config/OAuth2ServerConfiguration.kt | 34 ++-- .../security/ClaimsTokenEnhancer.java | 154 ++++++++++++++++++ .../security/ClaimsTokenEnhancer.kt | 132 --------------- 3 files changed, 174 insertions(+), 146 deletions(-) create mode 100644 src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java delete mode 100644 src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt diff --git a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt index ca7cc87a8..f0e582027 100644 --- a/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/OAuth2ServerConfiguration.kt @@ -2,6 +2,7 @@ package org.radarbase.management.config import org.radarbase.auth.authorization.RoleAuthority import org.radarbase.management.repository.UserRepository +import org.radarbase.management.security.ClaimsTokenEnhancer import org.radarbase.management.security.Http401UnauthorizedEntryPoint import org.radarbase.management.security.JwtAuthenticationFilter import org.radarbase.management.security.PostgresApprovalStore @@ -41,6 +42,7 @@ import org.springframework.security.oauth2.provider.client.JdbcClientDetailsServ import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices import org.springframework.security.oauth2.provider.token.DefaultTokenServices +import org.springframework.security.oauth2.provider.token.TokenEnhancer import org.springframework.security.oauth2.provider.token.TokenEnhancerChain import org.springframework.security.oauth2.provider.token.TokenStore import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter @@ -49,7 +51,7 @@ import java.util.* import javax.sql.DataSource @Configuration -open class OAuth2ServerConfiguration { +class OAuth2ServerConfiguration { @Autowired private val dataSource: DataSource? = null @@ -58,7 +60,7 @@ open class OAuth2ServerConfiguration { @Configuration @Order(-20) - protected open class LoginConfig : WebSecurityConfigurerAdapter() { + protected class LoginConfig : WebSecurityConfigurerAdapter() { @Autowired private val authenticationManager: AuthenticationManager? = null @@ -87,7 +89,7 @@ open class OAuth2ServerConfiguration { } @Configuration - open class JwtAuthenticationFilterConfiguration { + class JwtAuthenticationFilterConfiguration { @Autowired private val authenticationManager: AuthenticationManager? = null @@ -98,7 +100,7 @@ open class OAuth2ServerConfiguration { private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler? = null @Bean - open fun jwtAuthenticationFilter(): JwtAuthenticationFilter { + fun jwtAuthenticationFilter(): JwtAuthenticationFilter { return JwtAuthenticationFilter( keyStoreHandler!!.tokenValidator, authenticationManager!!, @@ -109,7 +111,7 @@ open class OAuth2ServerConfiguration { } @Bean - open fun jdbcClientDetailsService(): JdbcClientDetailsService { + fun jdbcClientDetailsService(): JdbcClientDetailsService { val clientDetailsService = JdbcClientDetailsService(dataSource) clientDetailsService.setPasswordEncoder(passwordEncoder) return clientDetailsService @@ -117,7 +119,7 @@ open class OAuth2ServerConfiguration { @Configuration @EnableResourceServer - protected open class ResourceServerConfiguration( + protected class ResourceServerConfiguration( @Autowired private val keyStoreHandler: ManagementPortalOauthKeyStoreHandler, @Autowired private val tokenStore: TokenStore, @Autowired private val http401UnauthorizedEntryPoint: Http401UnauthorizedEntryPoint, @@ -200,7 +202,7 @@ open class OAuth2ServerConfiguration { @Configuration @EnableAuthorizationServer - protected open class AuthorizationServerConfiguration( + protected class AuthorizationServerConfiguration( @Autowired private val jpaProperties: JpaProperties, @Autowired @Qualifier("authenticationManagerBean") private val authenticationManager: AuthenticationManager, @Autowired private val dataSource: DataSource, @@ -209,12 +211,12 @@ open class OAuth2ServerConfiguration { ) : AuthorizationServerConfigurerAdapter() { @Bean - protected open fun authorizationCodeServices(): AuthorizationCodeServices { + protected fun authorizationCodeServices(): AuthorizationCodeServices { return JdbcAuthorizationCodeServices(dataSource) } @Bean - open fun approvalStore(): ApprovalStore { + fun approvalStore(): ApprovalStore { return if (jpaProperties.database == Database.POSTGRESQL) { PostgresApprovalStore(dataSource) } else { @@ -224,12 +226,17 @@ open class OAuth2ServerConfiguration { } @Bean - open fun tokenStore(): TokenStore { + fun tokenEnhancer(): TokenEnhancer { + return ClaimsTokenEnhancer() + } + + @Bean + fun tokenStore(): TokenStore { return ManagementPortalJwtTokenStore(accessTokenConverter()) } @Bean - open fun accessTokenConverter(): ManagementPortalJwtAccessTokenConverter { + fun accessTokenConverter(): ManagementPortalJwtAccessTokenConverter { logger.debug("loading token converter from keystore configurations") return ManagementPortalJwtAccessTokenConverter( keyStoreHandler.algorithmForSigning, @@ -240,7 +247,7 @@ open class OAuth2ServerConfiguration { @Bean @Primary - open fun tokenServices(tokenStore: TokenStore?): DefaultTokenServices { + fun tokenServices(tokenStore: TokenStore?): DefaultTokenServices { val defaultTokenServices = DefaultTokenServices() defaultTokenServices.setTokenStore(tokenStore) defaultTokenServices.setSupportRefreshToken(true) @@ -251,8 +258,7 @@ open class OAuth2ServerConfiguration { override fun configure(endpoints: AuthorizationServerEndpointsConfigurer) { val tokenEnhancerChain = TokenEnhancerChain() tokenEnhancerChain.setTokenEnhancers( - //TODO listOf(tokenEnhancer(), accessTokenConverter()) - listOf(accessTokenConverter()) + listOf(tokenEnhancer(), accessTokenConverter()) ) endpoints .authorizationCodeServices(authorizationCodeServices()) diff --git a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java new file mode 100644 index 000000000..8fdf15b7c --- /dev/null +++ b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java @@ -0,0 +1,154 @@ +package org.radarbase.management.security; + +import org.radarbase.auth.authorization.AuthorizationOracle; +import org.radarbase.auth.authorization.Permission; +import org.radarbase.auth.authorization.RoleAuthority; +import org.radarbase.management.domain.Role; +import org.radarbase.management.domain.Source; +import org.radarbase.management.repository.SubjectRepository; +import org.radarbase.management.repository.UserRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.actuate.audit.AuditEvent; +import org.springframework.boot.actuate.audit.AuditEventRepository; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.security.oauth2.provider.OAuth2Authentication; +import org.springframework.security.oauth2.provider.OAuth2Request; +import org.springframework.security.oauth2.provider.token.TokenEnhancer; +import org.springframework.stereotype.Component; + +import java.security.Principal; +import java.time.Instant; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import static org.radarbase.auth.jwt.JwtTokenVerifier.GRANT_TYPE_CLAIM; +import static org.radarbase.auth.jwt.JwtTokenVerifier.ROLES_CLAIM; +import static org.radarbase.auth.jwt.JwtTokenVerifier.SOURCES_CLAIM; + +@Component +public class ClaimsTokenEnhancer implements TokenEnhancer, InitializingBean { + private static final Logger logger = LoggerFactory.getLogger(ClaimsTokenEnhancer.class); + + @Autowired + private SubjectRepository subjectRepository; + + @Autowired + private UserRepository userRepository; + + @Autowired + private AuditEventRepository auditEventRepository; + + @Autowired + private AuthorizationOracle authorizationOracle; + + @Value("${spring.application.name}") + private String appName; + + private static final String GRANT_TOKEN_EVENT = "GRANT_ACCESS_TOKEN"; + + @Override + public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, + OAuth2Authentication authentication) { + logger.debug("Enhancing token of authentication {}" , authentication); + + Map additionalInfo = new HashMap<>(); + + String userName = authentication.getName(); + + if (authentication.getPrincipal() instanceof Principal + || authentication.getPrincipal() instanceof UserDetails) { + // add the 'sub' claim in accordance with JWT spec + additionalInfo.put("sub", userName); + + Optional.ofNullable(userRepository.findOneByLogin(userName)) + .ifPresent(user -> { + var roles = user.roles.stream() + .map(role -> { + var auth = role.authority.name; + return switch (role.getRole().getScope()) { + case GLOBAL -> auth; + case ORGANIZATION -> role.organization.name + + ":" + auth; + case PROJECT -> role.project.getProjectName() + + ":" + auth; + }; + }) + .toList(); + additionalInfo.put(ROLES_CLAIM, roles); + + // Do not grant scopes that cannot be given to a user. + Set currentScopes = accessToken.getScope(); + Set newScopes = currentScopes.stream() + .filter(scope -> { + Permission permission = Permission.ofScope(scope); + var roleAuthorities = user.roles.stream() + .map(Role::getRole) + .collect(Collectors.toCollection(() -> + EnumSet.noneOf(RoleAuthority.class))); + return authorizationOracle.mayBeGranted(roleAuthorities, + permission); + }) + .collect(Collectors.toCollection(TreeSet::new)); + + if (!newScopes.equals(currentScopes)) { + ((DefaultOAuth2AccessToken) accessToken).setScope(newScopes); + } + }); + + List assignedSources = subjectRepository.findSourcesBySubjectLogin(userName); + + List sourceIds = assignedSources.stream() + .map(s -> s.sourceId.toString()) + .toList(); + additionalInfo.put(SOURCES_CLAIM, sourceIds); + } + // add iat and iss optional JWT claims + additionalInfo.put("iat", Instant.now().getEpochSecond()); + additionalInfo.put("iss", appName); + additionalInfo.put(GRANT_TYPE_CLAIM, + authentication.getOAuth2Request().getGrantType()); + ((DefaultOAuth2AccessToken) accessToken) + .setAdditionalInformation(additionalInfo); + + // HACK: since all granted tokens need to pass here, we can use this point to create an + // audit event for a granted token, there is an open issue about oauth2 audit events in + // spring security but it has been inactive for a long time: + // https://github.com/spring-projects/spring-security-oauth/issues/223 + Map auditData = auditData(accessToken, authentication); + auditEventRepository.add(new AuditEvent(userName, GRANT_TOKEN_EVENT, + auditData)); + logger.info("[{}] for {}: {}", GRANT_TOKEN_EVENT, userName, auditData); + + return accessToken; + } + + @Override + public void afterPropertiesSet() throws Exception { + // nothing to do for now + } + + private Map auditData(OAuth2AccessToken accessToken, + OAuth2Authentication authentication) { + Map result = new HashMap<>(); + result.put("tokenType", accessToken.getTokenType()); + result.put("scope", String.join(", ", accessToken.getScope())); + result.put("expiresIn", Integer.toString(accessToken.getExpiresIn())); + result.putAll(accessToken.getAdditionalInformation()); + OAuth2Request request = authentication.getOAuth2Request(); + result.put("clientId", request.getClientId()); + result.put("grantType", request.getGrantType()); + return result; + } +} diff --git a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt deleted file mode 100644 index 6000870db..000000000 --- a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.kt +++ /dev/null @@ -1,132 +0,0 @@ -package org.radarbase.management.security - -import org.radarbase.auth.authorization.AuthorizationOracle -import org.radarbase.auth.authorization.Permission -import org.radarbase.auth.authorization.RoleAuthority -import org.radarbase.auth.jwt.JwtTokenVerifier -import org.radarbase.management.domain.Role -import org.radarbase.management.domain.Source -import org.radarbase.management.domain.User -import org.radarbase.management.repository.SubjectRepository -import org.radarbase.management.repository.UserRepository -import org.slf4j.LoggerFactory -import org.springframework.beans.factory.InitializingBean -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Value -import org.springframework.boot.actuate.audit.AuditEvent -import org.springframework.boot.actuate.audit.AuditEventRepository -import org.springframework.security.core.userdetails.UserDetails -import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken -import org.springframework.security.oauth2.common.OAuth2AccessToken -import org.springframework.security.oauth2.provider.OAuth2Authentication -import org.springframework.security.oauth2.provider.token.TokenEnhancer -import java.security.Principal -import java.time.Instant -import java.util.* - -class ClaimsTokenEnhancer( - @Autowired private val subjectRepository: SubjectRepository, - @Autowired private val userRepository: UserRepository, - @Autowired private val auditEventRepository: AuditEventRepository, - @Autowired private val authorizationOracle: AuthorizationOracle -) : TokenEnhancer, InitializingBean { - - @Value("\${spring.application.name}") - private val appName: String? = null - override fun enhance( - accessToken: OAuth2AccessToken, authentication: OAuth2Authentication - ): OAuth2AccessToken { - logger.debug("Enhancing token of authentication {}", authentication) - val additionalInfo: MutableMap = HashMap() - val userName = authentication.getName() - if (authentication.principal is Principal || authentication.principal is UserDetails) { - // add the 'sub' claim in accordance with JWT spec - additionalInfo["sub"] = userName - userRepository.findOneByLogin(userName)?.let { user: User? -> - val roles = user!!.roles!!.stream().map { role: Role -> - val auth = role.authority!!.name - when (role.role!!.scope) { - RoleAuthority.Scope.GLOBAL -> auth - RoleAuthority.Scope.ORGANIZATION -> (role.organization!!.name + ":" + auth) - - RoleAuthority.Scope.PROJECT -> (role.project!!.projectName + ":" + auth) - } - }.toList() - additionalInfo[JwtTokenVerifier.ROLES_CLAIM] = roles - - // Do not grant scopes that cannot be given to a user. - val currentScopes: MutableSet = accessToken.scope - val newScopes: Set = currentScopes - .filter { scope: String -> - val permission: Permission = Permission.ofScope(scope) - - val roleAuthorities = user - .roles!!.mapNotNull { it.role } - .let{ _ -> EnumSet.noneOf(RoleAuthority::class.java)} - .filterNotNull() - - roleAuthorities.mayBeGranted(permission) - } - .toSet() - - if (newScopes != currentScopes) { - (accessToken as DefaultOAuth2AccessToken).scope = newScopes - } - } - val assignedSources = subjectRepository.findSourcesBySubjectLogin(userName) - val sourceIds = assignedSources.stream().map { s: Source? -> s!!.sourceId.toString() }.toList() - additionalInfo[JwtTokenVerifier.SOURCES_CLAIM] = sourceIds - } - // add iat and iss optional JWT claims - additionalInfo["iat"] = Instant.now().epochSecond - additionalInfo["iss"] = appName - additionalInfo[JwtTokenVerifier.GRANT_TYPE_CLAIM] = authentication.oAuth2Request.getGrantType() - (accessToken as DefaultOAuth2AccessToken).additionalInformation = additionalInfo - - // HACK: since all granted tokens need to pass here, we can use this point to create an - // audit event for a granted token, there is an open issue about oauth2 audit events in - // spring security but it has been inactive for a long time: - // https://github.com/spring-projects/spring-security-oauth/issues/223 - val auditData = auditData(accessToken, authentication) - auditEventRepository.add( - AuditEvent( - userName, GRANT_TOKEN_EVENT, auditData - ) - ) - logger.info("[{}] for {}: {}", GRANT_TOKEN_EVENT, userName, auditData) - return accessToken - } - - @Throws(Exception::class) - override fun afterPropertiesSet() { - // nothing to do for now - } - - private fun auditData( - accessToken: OAuth2AccessToken, authentication: OAuth2Authentication - ): Map { - val result: MutableMap = HashMap() - result["tokenType"] = accessToken.tokenType - result["scope"] = java.lang.String.join(", ", accessToken.scope) - result["expiresIn"] = accessToken.expiresIn.toString() - result.putAll(accessToken.additionalInformation) - val request = authentication.oAuth2Request - result["clientId"] = request.clientId - result["grantType"] = request.getGrantType() - return result - } - - open fun mayBeGranted(role: RoleAuthority, permission: Permission): Boolean = with(authorizationOracle) { - role.mayBeGranted(permission) - } - - fun Collection.mayBeGranted(permission: Permission): Boolean = with(authorizationOracle) { - return any { it.mayBeGranted(permission) } - } - - companion object { - private val logger = LoggerFactory.getLogger(ClaimsTokenEnhancer::class.java) - private const val GRANT_TOKEN_EVENT = "GRANT_ACCESS_TOKEN" - } -} - From e9304ed80685883738cbc2c5363ec0dd7495e614 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:08:44 +0100 Subject: [PATCH 123/158] get rid of some TODOs --- .../filters/SubjectSpecification.kt | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt index 312073fe2..e53c7b0c8 100644 --- a/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt +++ b/src/main/java/org/radarbase/management/repository/filters/SubjectSpecification.kt @@ -35,8 +35,8 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification private val externalId: String? private val subjectId: String? private val sort: List? - private val authority: Set - private var sortLastValues: List? = null + private val authority: Set + private var sortLastValues: List? = null /** * Subject specification based on criteria. @@ -44,7 +44,7 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification */ init { authority = criteria.authority - .map { obj: SubjectAuthority? -> obj?.name } + .map { obj: SubjectAuthority -> obj.name } .toSet() dateOfBirth = criteria.dateOfBirth enrollmentDate = criteria.enrollmentDate @@ -58,7 +58,7 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification sort = criteria.parsedSort sortLastValues = if (last != null) { sort - ?.map { o: SubjectSortOrder -> getLastValue(o.sortBy) } + ?.mapNotNull { o: SubjectSortOrder -> getLastValue(o.sortBy) } ?.toList() } else { null @@ -93,7 +93,6 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification return predicates.toAndPredicate()!! } - //TODO I don't think return type needs to be nullable private fun filterLastValues(root: Root, builder: CriteriaBuilder): Predicate? { val lastPredicates = arrayOfNulls( sort!!.size @@ -111,10 +110,15 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification lastAndPredicates!![j] = builder.equal(paths[j], sortLastValues!![j]) } val order = sort[i] + val saveVal = sortLastValues + ?: throw BadRequestException( + "No last value given", + EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION + ) val currentSort: Predicate? = if (order.direction.isAscending) { - builder.greaterThan(paths[i], sortLastValues!![i]!!)//TODO + builder.greaterThan(paths[i], saveVal[i]) } else { - builder.lessThan(paths[i], sortLastValues!![i]!!)//TODO + builder.lessThan(paths[i], saveVal[i]) } if (lastAndPredicates != null) { lastAndPredicates[i] = currentSort @@ -154,7 +158,7 @@ class SubjectSpecification(criteria: SubjectCriteria) : Specification if (property.isUnique && result == null) { throw BadRequestException( "No last value given for sort property $property", - EntityName.Companion.SUBJECT, ErrorConstants.ERR_VALIDATION + EntityName.SUBJECT, ErrorConstants.ERR_VALIDATION ) } return result From 219e99a47fe7ddf2700fffb3bcdb69ee32211f8d Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:10:48 +0100 Subject: [PATCH 124/158] get rid of some TODOs --- .../org/radarbase/management/domain/User.kt | 3 +-- .../ManagementPortalOauthKeyStoreHandler.kt | 24 ++++++++++++------- .../management/service/SourceService.kt | 3 +-- .../web/rest/OrganizationResourceIntTest.kt | 1 - 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/radarbase/management/domain/User.kt b/src/main/java/org/radarbase/management/domain/User.kt index a780da221..240f74880 100644 --- a/src/main/java/org/radarbase/management/domain/User.kt +++ b/src/main/java/org/radarbase/management/domain/User.kt @@ -107,8 +107,7 @@ class User : AbstractEntity(), Serializable { @Cascade( CascadeType.SAVE_UPDATE ) - //TODO remove ? - var roles: MutableSet? = HashSet() + var roles: MutableSet = HashSet() //Lowercase the login before saving it in database fun setLogin(login: String?) { diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt index 169ecb656..a31cd5f36 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt @@ -268,15 +268,21 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( return null } val privateKey = keyPair.private - return if (privateKey is ECPrivateKey) { - EcdsaJwtAlgorithm(keyPair) - } else if (privateKey is RSAPrivateKey) { - RsaJwtAlgorithm(keyPair) - } else { - logger.warn( - "No JWT algorithm found for key type {}", privateKey.javaClass - ) - null + return when (privateKey) { + is ECPrivateKey -> { + EcdsaJwtAlgorithm(keyPair) + } + + is RSAPrivateKey -> { + RsaJwtAlgorithm(keyPair) + } + + else -> { + logger.warn( + "No JWT algorithm found for key type {}", privateKey.javaClass + ) + null + } } } } diff --git a/src/main/java/org/radarbase/management/service/SourceService.kt b/src/main/java/org/radarbase/management/service/SourceService.kt index eb21d13e9..1f1e11778 100644 --- a/src/main/java/org/radarbase/management/service/SourceService.kt +++ b/src/main/java/org/radarbase/management/service/SourceService.kt @@ -247,9 +247,8 @@ open class SourceService( + "source-type", IdentifierGenerator.ENTITY_NAME, "error.invalidTransfer" ) - //TODO all the nullchecks are the result of jvmfiel;d annotations not allowing lateinits // set old source-type, ensures compatibility - sourceDto.sourceType = existingSource.sourceType?.let { sourceTypeMapper.sourceTypeToSourceTypeDTO(it) }!! + sourceDto.sourceType = existingSource.sourceType?.let { sourceTypeMapper.sourceTypeToSourceTypeDTO(it) } } return save(sourceDto) } diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index 5abcf00e0..f15d6fcd2 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -176,7 +176,6 @@ internal open class OrganizationResourceIntTest( @Test @Throws(Exception::class) - //TODO this is covered by not using a nullable type fun checkGroupNameIsRequired() { val orgDto: OrganizationDTO = organizationMapper.organizationToOrganizationDTO(organization) orgDto.name = null From 0b7005eb70bee055ec07981122d69c2ebb79beab Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:20:30 +0100 Subject: [PATCH 125/158] fix compilation error --- .../org/radarbase/management/service/SubjectService.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/SubjectService.kt b/src/main/java/org/radarbase/management/service/SubjectService.kt index 6c70e8bac..ad281e4c4 100644 --- a/src/main/java/org/radarbase/management/service/SubjectService.kt +++ b/src/main/java/org/radarbase/management/service/SubjectService.kt @@ -174,11 +174,11 @@ class SubjectService( ) } - private fun updateParticipantRoles(subject: Subject, subjectDto: SubjectDTO): MutableSet? { + private fun updateParticipantRoles(subject: Subject, subjectDto: SubjectDTO): MutableSet { if (subjectDto.project == null || subjectDto.project!!.projectName == null) { return subject.user!!.roles } - val existingRoles = subject.user!!.roles?.map { + val existingRoles = subject.user!!.roles.map { // make participant inactive in projects that do not match the new project if (it.authority!!.name == RoleAuthority.PARTICIPANT.authority && it.project!!.projectName != subjectDto.project!!.projectName) { return@map getProjectParticipantRole(it.project, RoleAuthority.INACTIVE_PARTICIPANT) @@ -186,12 +186,12 @@ class SubjectService( // do not modify other roles. return@map it } - }?.toMutableSet() + }.toMutableSet() // Ensure that given project is present val newProjectRole = getProjectParticipantRole(projectMapper.projectDTOToProject(subjectDto.project), RoleAuthority.PARTICIPANT) - existingRoles?.add(newProjectRole) + existingRoles.add(newProjectRole) return existingRoles From 874856ed0c46727467a25dd5ecd3aee803ad3897 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:27:43 +0100 Subject: [PATCH 126/158] more native kotlin --- .../ManagementPortalOauthKeyStoreHandler.kt | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt index a31cd5f36..2c783ca6c 100644 --- a/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt +++ b/src/main/java/org/radarbase/management/security/jwt/ManagementPortalOauthKeyStoreHandler.kt @@ -31,7 +31,6 @@ import java.security.interfaces.ECPrivateKey import java.security.interfaces.RSAPrivateKey import java.util.* import java.util.AbstractMap.SimpleImmutableEntry -import java.util.stream.Stream import javax.annotation.Nonnull import javax.servlet.ServletContext import kotlin.collections.Map.Entry @@ -72,12 +71,12 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( ("http://localhost:" + environment.getProperty("server.port") + servletContext.contextPath) logger.info("Using Management Portal base-url {}", managementPortalBaseUrl) val algorithms = loadAlgorithmsFromAlias().filter { obj: Algorithm? -> Objects.nonNull(obj) }.toList() - verifiers = algorithms.stream().map { algo: Algorithm? -> - JWT.require(algo).withAudience(ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL).build() - }.toList() + verifiers = algorithms.map { algo: Algorithm? -> + JWT.require(algo).withAudience(ManagementPortalJwtAccessTokenConverter.RES_MANAGEMENT_PORTAL).build() + }.toMutableList() // No need to check audience with a refresh token: it can be used // to refresh tokens intended for other resources. - refreshTokenVerifiers = algorithms.stream().map { algo: Algorithm? -> JWT.require(algo).build() }.toList() + refreshTokenVerifiers = algorithms.map { algo: Algorithm -> JWT.require(algo).build() }.toMutableList() } @Nonnull @@ -124,17 +123,18 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( * @return List of public keys for token verification. */ fun loadJwks(): JsonWebKeySet { - return JsonWebKeySet(verifierPublicKeyAliasList.map { alias: String? -> this.getKeyPair(alias) } + return JsonWebKeySet(verifierPublicKeyAliasList.map { alias: String -> this.getKeyPair(alias) } .map { keyPair: KeyPair? -> getJwtAlgorithm(keyPair) }.mapNotNull { obj: JwtAlgorithm? -> obj?.jwk }) } /** * Load default verifiers from configured keystore and aliases. */ - private fun loadAlgorithmsFromAlias(): Stream { - return verifierPublicKeyAliasList.stream().map { alias: String? -> this.getKeyPair(alias) } - .map { keyPair: KeyPair? -> getJwtAlgorithm(keyPair) }.filter { obj: JwtAlgorithm? -> Objects.nonNull(obj) } - .map { obj: JwtAlgorithm? -> obj?.algorithm } + private fun loadAlgorithmsFromAlias(): Collection { + return verifierPublicKeyAliasList + .map { alias: String -> this.getKeyPair(alias) } + .mapNotNull { keyPair -> getJwtAlgorithm(keyPair) } + .map { obj: JwtAlgorithm -> obj.algorithm } } val algorithmForSigning: Algorithm @@ -159,7 +159,7 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( * @throws IllegalArgumentException if the key alias password is wrong or the key cannot * loaded. */ - private fun getKeyPair(alias: String?): KeyPair? { + private fun getKeyPair(alias: String): KeyPair? { return getKeyPair(alias, password) } @@ -172,7 +172,7 @@ class ManagementPortalOauthKeyStoreHandler @Autowired constructor( * @throws IllegalArgumentException if the key alias password is wrong or the key cannot * load. */ - private fun getKeyPair(alias: String?, password: CharArray): KeyPair? { + private fun getKeyPair(alias: String, password: CharArray): KeyPair? { return try { val key = store.getKey(alias, password) as PrivateKey? if (key == null) { From 6f5a246694476a06f1b3923dd82f315879c6b223 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:40:46 +0100 Subject: [PATCH 127/158] fixing compilation errors --- .../management/service/UserService.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/UserService.kt b/src/main/java/org/radarbase/management/service/UserService.kt index c35f24538..cf46ccbb9 100644 --- a/src/main/java/org/radarbase/management/service/UserService.kt +++ b/src/main/java/org/radarbase/management/service/UserService.kt @@ -155,16 +155,16 @@ class UserService @Autowired constructor( user.resetKey = passwordService.generateResetKey() user.resetDate = ZonedDateTime.now() user.activated = false - user.roles = userDto.roles?.let { getUserRoles(it, mutableSetOf()) } + user.roles = getUserRoles(userDto.roles, mutableSetOf()) user = userRepository.save(user) log.debug("Created Information for User: {}", user) return user } @Throws(NotAuthorizedException::class) - private fun getUserRoles(roleDtos: Set?, oldRoles: MutableSet): MutableSet? { + private fun getUserRoles(roleDtos: Set?, oldRoles: MutableSet): MutableSet { if (roleDtos == null) { - return null + return mutableSetOf() } val roles = roleDtos.map { roleDto: RoleDTO -> val authority = getRoleAuthority(roleDto) @@ -273,8 +273,8 @@ class UserService @Autowired constructor( user.langKey = userDto.langKey val managedRoles = user.roles val oldRoles = java.util.Set.copyOf(managedRoles) - managedRoles?.clear() - managedRoles?.addAll(getUserRoles(userDto.roles, oldRoles)!!) + managedRoles.clear() + managedRoles.addAll(getUserRoles(userDto.roles, oldRoles)) user = userRepository.save(user) log.debug("Changed Information for User: {}", user) userMapper.userToUserDTO(user) @@ -422,11 +422,11 @@ class UserService @Autowired constructor( ) val managedRoles = user.roles - val oldRoles = managedRoles?.toMutableSet() + val oldRoles = managedRoles.toMutableSet() - managedRoles?.clear() - managedRoles?.addAll(roleDtos?.let { oldRoles?.let { oldroles -> getUserRoles(it, oldroles) } }!!) - ?: throw Exception("could not add rolser for user: $user") + managedRoles.clear() + roleDtos?.let { getUserRoles(it, oldRoles) }?.let { managedRoles.addAll(it) } + ?: throw Exception("could not add roles for user: $user") userRepository.save(user) } From d39dab1e2aa20c72ba3ac035c23217b128351ee3 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 14:41:02 +0100 Subject: [PATCH 128/158] nullcheck sessionId to prevent throwing errors --- .../radarbase/management/config/audit/AuditEventConverter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt index 09b6872b6..d2f742049 100644 --- a/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt +++ b/src/main/java/org/radarbase/management/config/audit/AuditEventConverter.kt @@ -73,7 +73,7 @@ class AuditEventConverter { for ((key, value) in data) { // Extract the data that will be saved. - if (value is WebAuthenticationDetails) { + if (value is WebAuthenticationDetails && value.sessionId != null) { results["sessionId"] = value.sessionId } else if (value != null) { results[key] = value.toString() From a520b60210696606ffb4eeed5c45ba29168664f5 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 10 Nov 2023 15:08:16 +0100 Subject: [PATCH 129/158] stylefixes --- .../security/ClaimsTokenEnhancer.java | 63 ++++++++----------- .../web/rest/SubjectResourceIntTest.kt | 4 +- 2 files changed, 27 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java index 8fdf15b7c..d645f0cba 100644 --- a/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java +++ b/src/main/java/org/radarbase/management/security/ClaimsTokenEnhancer.java @@ -60,47 +60,38 @@ public class ClaimsTokenEnhancer implements TokenEnhancer, InitializingBean { @Override public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, - OAuth2Authentication authentication) { - logger.debug("Enhancing token of authentication {}" , authentication); + OAuth2Authentication authentication) { + logger.debug("Enhancing token of authentication {}", authentication); Map additionalInfo = new HashMap<>(); String userName = authentication.getName(); if (authentication.getPrincipal() instanceof Principal - || authentication.getPrincipal() instanceof UserDetails) { + || authentication.getPrincipal() instanceof UserDetails) { // add the 'sub' claim in accordance with JWT spec additionalInfo.put("sub", userName); - Optional.ofNullable(userRepository.findOneByLogin(userName)) - .ifPresent(user -> { - var roles = user.roles.stream() - .map(role -> { - var auth = role.authority.name; - return switch (role.getRole().getScope()) { - case GLOBAL -> auth; - case ORGANIZATION -> role.organization.name - + ":" + auth; - case PROJECT -> role.project.getProjectName() - + ":" + auth; - }; - }) - .toList(); + Optional.ofNullable(userRepository.findOneByLogin(userName)).ifPresent(user -> { + var roles = user.roles.stream().map(role -> { + var auth = role.authority.name; + return switch (role.getRole().getScope()) { + case GLOBAL -> auth; + case ORGANIZATION -> role.organization.name + ":" + auth; + case PROJECT -> role.project.getProjectName() + ":" + auth; + }; + }).toList(); additionalInfo.put(ROLES_CLAIM, roles); // Do not grant scopes that cannot be given to a user. Set currentScopes = accessToken.getScope(); - Set newScopes = currentScopes.stream() - .filter(scope -> { - Permission permission = Permission.ofScope(scope); - var roleAuthorities = user.roles.stream() - .map(Role::getRole) - .collect(Collectors.toCollection(() -> - EnumSet.noneOf(RoleAuthority.class))); - return authorizationOracle.mayBeGranted(roleAuthorities, - permission); - }) - .collect(Collectors.toCollection(TreeSet::new)); + Set newScopes = currentScopes.stream().filter(scope -> { + Permission permission = Permission.ofScope(scope); + var roleAuthorities = user.roles.stream().map(Role::getRole) + .collect(Collectors.toCollection(() -> + EnumSet.noneOf(RoleAuthority.class))); + return authorizationOracle.mayBeGranted(roleAuthorities, permission); + }).collect(Collectors.toCollection(TreeSet::new)); if (!newScopes.equals(currentScopes)) { ((DefaultOAuth2AccessToken) accessToken).setScope(newScopes); @@ -109,26 +100,22 @@ public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, List assignedSources = subjectRepository.findSourcesBySubjectLogin(userName); - List sourceIds = assignedSources.stream() - .map(s -> s.sourceId.toString()) - .toList(); + List sourceIds = assignedSources.stream().map(s -> + s.sourceId.toString()).toList(); additionalInfo.put(SOURCES_CLAIM, sourceIds); } // add iat and iss optional JWT claims additionalInfo.put("iat", Instant.now().getEpochSecond()); additionalInfo.put("iss", appName); - additionalInfo.put(GRANT_TYPE_CLAIM, - authentication.getOAuth2Request().getGrantType()); - ((DefaultOAuth2AccessToken) accessToken) - .setAdditionalInformation(additionalInfo); + additionalInfo.put(GRANT_TYPE_CLAIM, authentication.getOAuth2Request().getGrantType()); + ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); // HACK: since all granted tokens need to pass here, we can use this point to create an // audit event for a granted token, there is an open issue about oauth2 audit events in // spring security but it has been inactive for a long time: // https://github.com/spring-projects/spring-security-oauth/issues/223 Map auditData = auditData(accessToken, authentication); - auditEventRepository.add(new AuditEvent(userName, GRANT_TOKEN_EVENT, - auditData)); + auditEventRepository.add(new AuditEvent(userName, GRANT_TOKEN_EVENT, auditData)); logger.info("[{}] for {}: {}", GRANT_TOKEN_EVENT, userName, auditData); return accessToken; @@ -140,7 +127,7 @@ public void afterPropertiesSet() throws Exception { } private Map auditData(OAuth2AccessToken accessToken, - OAuth2Authentication authentication) { + OAuth2Authentication authentication) { Map result = new HashMap<>(); result.put("tokenType", accessToken.getTokenType()); result.put("scope", String.join(", ", accessToken.getScope())); diff --git a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt index 0fd79e5af..de0fc3a96 100644 --- a/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SubjectResourceIntTest.kt @@ -97,7 +97,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.DEFAULT_EXTERNAL_LINK) Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.DEFAULT_ENTERNAL_ID) Assertions.assertThat(testSubject.removed).isEqualTo(SubjectServiceTest.DEFAULT_REMOVED) - Assertions.assertThat(testSubject.user!!.roles!!.size).isEqualTo(1) + Assertions.assertThat(testSubject.user!!.roles.size).isEqualTo(1) } @Test @@ -233,7 +233,7 @@ internal class SubjectResourceIntTest( Assertions.assertThat(testSubject.externalLink).isEqualTo(SubjectServiceTest.UPDATED_EXTERNAL_LINK) Assertions.assertThat(testSubject.externalId).isEqualTo(SubjectServiceTest.UPDATED_ENTERNAL_ID) Assertions.assertThat(testSubject.removed).isEqualTo(SubjectServiceTest.UPDATED_REMOVED) - Assertions.assertThat(testSubject.user!!.roles!!.size).isEqualTo(2) + Assertions.assertThat(testSubject.user!!.roles.size).isEqualTo(2) } @Test From af6d5611818f6cdf2ecc28c86039a5c3fbe0dd8a Mon Sep 17 00:00:00 2001 From: snyk-bot Date: Thu, 30 Nov 2023 14:45:58 +0000 Subject: [PATCH 130/158] fix: package.json & yarn.lock to reduce vulnerabilities The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-JS-INFLIGHT-6095116 --- package.json | 2 +- yarn.lock | 506 ++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 459 insertions(+), 49 deletions(-) diff --git a/package.json b/package.json index b903347f8..740a3d759 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "@angular/common": "^12.2.12", "@angular/core": "^12.2.12", "@angular/forms": "^12.2.12", - "@angular/localize": "^12.2.12", + "@angular/localize": "^16.0.6", "@angular/platform-browser": "^12.2.12", "@angular/platform-browser-dynamic": "^12.2.12", "@angular/router": "^12.2.12", diff --git a/yarn.lock b/yarn.lock index d74f90cb5..52cea446a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,6 +15,16 @@ __metadata: languageName: node linkType: hard +"@ampproject/remapping@npm:^2.2.0": + version: 2.2.1 + resolution: "@ampproject/remapping@npm:2.2.1" + dependencies: + "@jridgewell/gen-mapping": ^0.3.0 + "@jridgewell/trace-mapping": ^0.3.9 + checksum: 03c04fd526acc64a1f4df22651186f3e5ef0a9d6d6530ce4482ec9841269cf7a11dbb8af79237c282d721c5312024ff17529cd72cc4768c11e999b58e2302079 + languageName: node + linkType: hard + "@angular-builders/custom-webpack@npm:^12.1.3": version: 12.1.3 resolution: "@angular-builders/custom-webpack@npm:12.1.3" @@ -511,21 +521,21 @@ __metadata: languageName: node linkType: hard -"@angular/localize@npm:^12.2.12": - version: 12.2.12 - resolution: "@angular/localize@npm:12.2.12" +"@angular/localize@npm:^16.0.6": + version: 16.2.12 + resolution: "@angular/localize@npm:16.2.12" dependencies: - "@babel/core": 7.8.3 - glob: 7.1.7 - yargs: ^17.0.0 + "@babel/core": 7.23.2 + fast-glob: 3.3.0 + yargs: ^17.2.1 peerDependencies: - "@angular/compiler": 12.2.12 - "@angular/compiler-cli": 12.2.12 + "@angular/compiler": 16.2.12 + "@angular/compiler-cli": 16.2.12 bin: - localize-extract: src/tools/src/extract/main.js - localize-migrate: src/tools/src/migrate/main.js - localize-translate: src/tools/src/translate/main.js - checksum: bcfa1dbc95f47206c6e3771c5d6d981fc00185afa1c7c6917b624e37ca7be2d32964b71b4add52abb031172bf51f57fda0d960ec2fca9b419d16170cc72a92ee + localize-extract: tools/bundles/src/extract/cli.js + localize-migrate: tools/bundles/src/migrate/cli.js + localize-translate: tools/bundles/src/translate/cli.js + checksum: 420a76ddfddf869b97d63f8d19103794fbffc860617df880059f3b00df4a3047c309c0d959f0fc1843ff4b680fd74b1b2a36138d8e9e2c4f02fd3745a5af8a32 languageName: node linkType: hard @@ -580,7 +590,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.14.5, @babel/code-frame@npm:^7.8.3": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.14.5": version: 7.14.5 resolution: "@babel/code-frame@npm:7.14.5" dependencies: @@ -589,6 +599,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/code-frame@npm:7.23.5" + dependencies: + "@babel/highlight": ^7.23.4 + chalk: ^2.4.2 + checksum: d90981fdf56a2824a9b14d19a4c0e8db93633fd488c772624b4e83e0ceac6039a27cd298a247c3214faa952bf803ba23696172ae7e7235f3b97f43ba278c569a + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.13.11, @babel/compat-data@npm:^7.14.7, @babel/compat-data@npm:^7.15.0": version: 7.15.0 resolution: "@babel/compat-data@npm:7.15.0" @@ -596,6 +616,13 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.22.9": + version: 7.23.5 + resolution: "@babel/compat-data@npm:7.23.5" + checksum: 06ce244cda5763295a0ea924728c09bae57d35713b675175227278896946f922a63edf803c322f855a3878323d48d0255a2a3023409d2a123483c8a69ebb4744 + languageName: node + linkType: hard + "@babel/core@npm:7.14.8": version: 7.14.8 resolution: "@babel/core@npm:7.14.8" @@ -619,26 +646,26 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:7.8.3": - version: 7.8.3 - resolution: "@babel/core@npm:7.8.3" - dependencies: - "@babel/code-frame": ^7.8.3 - "@babel/generator": ^7.8.3 - "@babel/helpers": ^7.8.3 - "@babel/parser": ^7.8.3 - "@babel/template": ^7.8.3 - "@babel/traverse": ^7.8.3 - "@babel/types": ^7.8.3 - convert-source-map: ^1.7.0 +"@babel/core@npm:7.23.2": + version: 7.23.2 + resolution: "@babel/core@npm:7.23.2" + dependencies: + "@ampproject/remapping": ^2.2.0 + "@babel/code-frame": ^7.22.13 + "@babel/generator": ^7.23.0 + "@babel/helper-compilation-targets": ^7.22.15 + "@babel/helper-module-transforms": ^7.23.0 + "@babel/helpers": ^7.23.2 + "@babel/parser": ^7.23.0 + "@babel/template": ^7.22.15 + "@babel/traverse": ^7.23.2 + "@babel/types": ^7.23.0 + convert-source-map: ^2.0.0 debug: ^4.1.0 - gensync: ^1.0.0-beta.1 - json5: ^2.1.0 - lodash: ^4.17.13 - resolve: ^1.3.2 - semver: ^5.4.1 - source-map: ^0.5.0 - checksum: 57228193e26835430b30fbc3a1e78acdfb66d42a147e2d3335b77f677cef6803c67980ab5a466a51a4f7064fe70d1f2aa22f712a8a83fd078556488ba06bd505 + gensync: ^1.0.0-beta.2 + json5: ^2.2.3 + semver: ^6.3.1 + checksum: 003897718ded16f3b75632d63cd49486bf67ff206cc7ebd1a10d49e2456f8d45740910d5ec7e42e3faf0deec7a2e96b1a02e766d19a67a8309053f0d4e57c0fe languageName: node linkType: hard @@ -676,7 +703,7 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.14.8, @babel/generator@npm:^7.15.0, @babel/generator@npm:^7.8.3": +"@babel/generator@npm:^7.14.8, @babel/generator@npm:^7.15.0": version: 7.15.0 resolution: "@babel/generator@npm:7.15.0" dependencies: @@ -687,6 +714,18 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.23.0, @babel/generator@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/generator@npm:7.23.5" + dependencies: + "@babel/types": ^7.23.5 + "@jridgewell/gen-mapping": ^0.3.2 + "@jridgewell/trace-mapping": ^0.3.17 + jsesc: ^2.5.1 + checksum: 845ddda7cf38a3edf4be221cc8a439dee9ea6031355146a1a74047aa8007bc030305b27d8c68ec9e311722c910610bde38c0e13a9ce55225251e7cb7e7f3edc8 + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:7.14.5, @babel/helper-annotate-as-pure@npm:^7.14.5": version: 7.14.5 resolution: "@babel/helper-annotate-as-pure@npm:7.14.5" @@ -720,6 +759,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-compilation-targets@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helper-compilation-targets@npm:7.22.15" + dependencies: + "@babel/compat-data": ^7.22.9 + "@babel/helper-validator-option": ^7.22.15 + browserslist: ^4.21.9 + lru-cache: ^5.1.1 + semver: ^6.3.1 + checksum: ce85196769e091ae54dd39e4a80c2a9df1793da8588e335c383d536d54f06baf648d0a08fc873044f226398c4ded15c4ae9120ee18e7dfd7c639a68e3cdc9980 + languageName: node + linkType: hard + "@babel/helper-create-class-features-plugin@npm:^7.14.5": version: 7.15.0 resolution: "@babel/helper-create-class-features-plugin@npm:7.15.0" @@ -766,6 +818,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-environment-visitor@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-environment-visitor@npm:7.22.20" + checksum: d80ee98ff66f41e233f36ca1921774c37e88a803b2f7dca3db7c057a5fea0473804db9fb6729e5dbfd07f4bed722d60f7852035c2c739382e84c335661590b69 + languageName: node + linkType: hard + "@babel/helper-explode-assignable-expression@npm:^7.14.5": version: 7.14.5 resolution: "@babel/helper-explode-assignable-expression@npm:7.14.5" @@ -786,6 +845,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-function-name@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-function-name@npm:7.23.0" + dependencies: + "@babel/template": ^7.22.15 + "@babel/types": ^7.23.0 + checksum: e44542257b2d4634a1f979244eb2a4ad8e6d75eb6761b4cfceb56b562f7db150d134bc538c8e6adca3783e3bc31be949071527aa8e3aab7867d1ad2d84a26e10 + languageName: node + linkType: hard + "@babel/helper-get-function-arity@npm:^7.14.5": version: 7.14.5 resolution: "@babel/helper-get-function-arity@npm:7.14.5" @@ -804,6 +873,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-hoist-variables@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-hoist-variables@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: 394ca191b4ac908a76e7c50ab52102669efe3a1c277033e49467913c7ed6f7c64d7eacbeabf3bed39ea1f41731e22993f763b1edce0f74ff8563fd1f380d92cc + languageName: node + linkType: hard + "@babel/helper-member-expression-to-functions@npm:^7.15.0": version: 7.15.0 resolution: "@babel/helper-member-expression-to-functions@npm:7.15.0" @@ -822,6 +900,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helper-module-imports@npm:7.22.15" + dependencies: + "@babel/types": ^7.22.15 + checksum: ecd7e457df0a46f889228f943ef9b4a47d485d82e030676767e6a2fdcbdaa63594d8124d4b55fd160b41c201025aec01fc27580352b1c87a37c9c6f33d116702 + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.14.5, @babel/helper-module-transforms@npm:^7.14.8, @babel/helper-module-transforms@npm:^7.15.0": version: 7.15.0 resolution: "@babel/helper-module-transforms@npm:7.15.0" @@ -838,6 +925,21 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.23.0": + version: 7.23.3 + resolution: "@babel/helper-module-transforms@npm:7.23.3" + dependencies: + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-module-imports": ^7.22.15 + "@babel/helper-simple-access": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/helper-validator-identifier": ^7.22.20 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 5d0895cfba0e16ae16f3aa92fee108517023ad89a855289c4eb1d46f7aef4519adf8e6f971e1d55ac20c5461610e17213f1144097a8f932e768a9132e2278d71 + languageName: node + linkType: hard + "@babel/helper-optimise-call-expression@npm:^7.14.5": version: 7.14.5 resolution: "@babel/helper-optimise-call-expression@npm:7.14.5" @@ -886,6 +988,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-simple-access@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-simple-access@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: fe9686714caf7d70aedb46c3cce090f8b915b206e09225f1e4dbc416786c2fdbbee40b38b23c268b7ccef749dd2db35f255338fb4f2444429874d900dede5ad2 + languageName: node + linkType: hard + "@babel/helper-skip-transparent-expression-wrappers@npm:^7.14.5": version: 7.14.5 resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.14.5" @@ -904,6 +1015,22 @@ __metadata: languageName: node linkType: hard +"@babel/helper-split-export-declaration@npm:^7.22.6": + version: 7.22.6 + resolution: "@babel/helper-split-export-declaration@npm:7.22.6" + dependencies: + "@babel/types": ^7.22.5 + checksum: e141cace583b19d9195f9c2b8e17a3ae913b7ee9b8120246d0f9ca349ca6f03cb2c001fd5ec57488c544347c0bb584afec66c936511e447fd20a360e591ac921 + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/helper-string-parser@npm:7.23.4" + checksum: c0641144cf1a7e7dc93f3d5f16d5327465b6cf5d036b48be61ecba41e1eece161b48f46b7f960951b67f8c3533ce506b16dece576baef4d8b3b49f8c65410f90 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.14.5, @babel/helper-validator-identifier@npm:^7.14.9": version: 7.14.9 resolution: "@babel/helper-validator-identifier@npm:7.14.9" @@ -911,6 +1038,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 136412784d9428266bcdd4d91c32bcf9ff0e8d25534a9d94b044f77fe76bc50f941a90319b05aafd1ec04f7d127cd57a179a3716009ff7f3412ef835ada95bdc + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.14.5": version: 7.14.5 resolution: "@babel/helper-validator-option@npm:7.14.5" @@ -918,6 +1052,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.22.15": + version: 7.23.5 + resolution: "@babel/helper-validator-option@npm:7.23.5" + checksum: 537cde2330a8aede223552510e8a13e9c1c8798afee3757995a7d4acae564124fe2bf7e7c3d90d62d3657434a74340a274b3b3b1c6f17e9a2be1f48af29cb09e + languageName: node + linkType: hard + "@babel/helper-wrap-function@npm:^7.14.5": version: 7.14.5 resolution: "@babel/helper-wrap-function@npm:7.14.5" @@ -930,7 +1071,7 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.14.8, @babel/helpers@npm:^7.8.3": +"@babel/helpers@npm:^7.14.8": version: 7.15.3 resolution: "@babel/helpers@npm:7.15.3" dependencies: @@ -941,6 +1082,17 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.23.2": + version: 7.23.5 + resolution: "@babel/helpers@npm:7.23.5" + dependencies: + "@babel/template": ^7.22.15 + "@babel/traverse": ^7.23.5 + "@babel/types": ^7.23.5 + checksum: c16dc8a3bb3d0e02c7ee1222d9d0865ed4b92de44fb8db43ff5afd37a0fc9ea5e2906efa31542c95b30c1a3a9540d66314663c9a23b5bb9b5ec76e8ebc896064 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.14.5": version: 7.14.5 resolution: "@babel/highlight@npm:7.14.5" @@ -952,7 +1104,18 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.14.5, @babel/parser@npm:^7.14.8, @babel/parser@npm:^7.15.0, @babel/parser@npm:^7.8.3": +"@babel/highlight@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/highlight@npm:7.23.4" + dependencies: + "@babel/helper-validator-identifier": ^7.22.20 + chalk: ^2.4.2 + js-tokens: ^4.0.0 + checksum: 643acecdc235f87d925979a979b539a5d7d1f31ae7db8d89047269082694122d11aa85351304c9c978ceeb6d250591ccadb06c366f358ccee08bb9c122476b89 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.14.5, @babel/parser@npm:^7.14.8, @babel/parser@npm:^7.15.0": version: 7.15.3 resolution: "@babel/parser@npm:7.15.3" bin: @@ -961,6 +1124,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/parser@npm:7.23.5" + bin: + parser: ./bin/babel-parser.js + checksum: ea763629310f71580c4a3ea9d3705195b7ba994ada2cc98f9a584ebfdacf54e92b2735d351672824c2c2b03c7f19206899f4d95650d85ce514a822b19a8734c7 + languageName: node + linkType: hard + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.14.5" @@ -1837,7 +2009,7 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:7.14.5, @babel/template@npm:^7.14.5, @babel/template@npm:^7.8.3": +"@babel/template@npm:7.14.5, @babel/template@npm:^7.14.5": version: 7.14.5 resolution: "@babel/template@npm:7.14.5" dependencies: @@ -1848,7 +2020,18 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.13.0, @babel/traverse@npm:^7.14.5, @babel/traverse@npm:^7.14.8, @babel/traverse@npm:^7.15.0, @babel/traverse@npm:^7.8.3": +"@babel/template@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/template@npm:7.22.15" + dependencies: + "@babel/code-frame": ^7.22.13 + "@babel/parser": ^7.22.15 + "@babel/types": ^7.22.15 + checksum: 1f3e7dcd6c44f5904c184b3f7fe280394b191f2fed819919ffa1e529c259d5b197da8981b6ca491c235aee8dbad4a50b7e31304aa531271cb823a4a24a0dd8fd + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.13.0, @babel/traverse@npm:^7.14.5, @babel/traverse@npm:^7.14.8, @babel/traverse@npm:^7.15.0": version: 7.15.0 resolution: "@babel/traverse@npm:7.15.0" dependencies: @@ -1865,6 +2048,24 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.23.2, @babel/traverse@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/traverse@npm:7.23.5" + dependencies: + "@babel/code-frame": ^7.23.5 + "@babel/generator": ^7.23.5 + "@babel/helper-environment-visitor": ^7.22.20 + "@babel/helper-function-name": ^7.23.0 + "@babel/helper-hoist-variables": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/parser": ^7.23.5 + "@babel/types": ^7.23.5 + debug: ^4.1.0 + globals: ^11.1.0 + checksum: 0558b05360850c3ad6384e85bd55092126a8d5f93e29a8e227dd58fa1f9e1a4c25fd337c07c7ae509f0983e7a2b1e761ffdcfaa77a1e1bedbc867058e1de5a7d + languageName: node + linkType: hard + "@babel/types@npm:^7.14.5, @babel/types@npm:^7.14.8, @babel/types@npm:^7.15.0, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3, @babel/types@npm:^7.8.6": version: 7.15.0 resolution: "@babel/types@npm:7.15.0" @@ -1875,6 +2076,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/types@npm:7.23.5" + dependencies: + "@babel/helper-string-parser": ^7.23.4 + "@babel/helper-validator-identifier": ^7.22.20 + to-fast-properties: ^2.0.0 + checksum: 3d21774480a459ef13b41c2e32700d927af649e04b70c5d164814d8e04ab584af66a93330602c2925e1a6925c2b829cc153418a613a4e7d79d011be1f29ad4b2 + languageName: node + linkType: hard + "@cspotcode/source-map-consumer@npm:0.8.0": version: 0.8.0 resolution: "@cspotcode/source-map-consumer@npm:0.8.0" @@ -1970,6 +2182,17 @@ __metadata: languageName: node linkType: hard +"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2": + version: 0.3.3 + resolution: "@jridgewell/gen-mapping@npm:0.3.3" + dependencies: + "@jridgewell/set-array": ^1.0.1 + "@jridgewell/sourcemap-codec": ^1.4.10 + "@jridgewell/trace-mapping": ^0.3.9 + checksum: 4a74944bd31f22354fc01c3da32e83c19e519e3bbadafa114f6da4522ea77dd0c2842607e923a591d60a76699d819a2fbb6f3552e277efdb9b58b081390b60ab + languageName: node + linkType: hard + "@jridgewell/resolve-uri@npm:1.0.0": version: 1.0.0 resolution: "@jridgewell/resolve-uri@npm:1.0.0" @@ -1977,6 +2200,37 @@ __metadata: languageName: node linkType: hard +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.1 + resolution: "@jridgewell/resolve-uri@npm:3.1.1" + checksum: f5b441fe7900eab4f9155b3b93f9800a916257f4e8563afbcd3b5a5337b55e52bd8ae6735453b1b745457d9f6cdb16d74cd6220bbdd98cf153239e13f6cbb653 + languageName: node + linkType: hard + +"@jridgewell/set-array@npm:^1.0.1": + version: 1.1.2 + resolution: "@jridgewell/set-array@npm:1.1.2" + checksum: 69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": + version: 1.4.15 + resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" + checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.9": + version: 0.3.20 + resolution: "@jridgewell/trace-mapping@npm:0.3.20" + dependencies: + "@jridgewell/resolve-uri": ^3.1.0 + "@jridgewell/sourcemap-codec": ^1.4.14 + checksum: cd1a7353135f385909468ff0cf20bdd37e59f2ee49a13a966dedf921943e222082c583ade2b579ff6cd0d8faafcb5461f253e1bf2a9f48fec439211fdbe788f5 + languageName: node + linkType: hard + "@jsdevtools/coverage-istanbul-loader@npm:3.0.5": version: 3.0.5 resolution: "@jsdevtools/coverage-istanbul-loader@npm:3.0.5" @@ -3295,6 +3549,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.21.9": + version: 4.22.1 + resolution: "browserslist@npm:4.22.1" + dependencies: + caniuse-lite: ^1.0.30001541 + electron-to-chromium: ^1.4.535 + node-releases: ^2.0.13 + update-browserslist-db: ^1.0.13 + bin: + browserslist: cli.js + checksum: 7e6b10c53f7dd5d83fd2b95b00518889096382539fed6403829d447e05df4744088de46a571071afb447046abc3c66ad06fbc790e70234ec2517452e32ffd862 + languageName: node + linkType: hard + "buffer-alloc-unsafe@npm:^1.1.0": version: 1.1.0 resolution: "buffer-alloc-unsafe@npm:1.1.0" @@ -3489,6 +3757,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001541": + version: 1.0.30001565 + resolution: "caniuse-lite@npm:1.0.30001565" + checksum: 7621f358d0e1158557430a111ca5506008ae0b2c796039ef53aeebf4e2ba15e5241cb89def21ea3a633b6a609273085835b44a522165d871fa44067cdf29cccd + languageName: node + linkType: hard + "canonical-path@npm:1.0.0": version: 1.0.0 resolution: "canonical-path@npm:1.0.0" @@ -3698,6 +3973,17 @@ __metadata: languageName: node linkType: hard +"cliui@npm:^8.0.1": + version: 8.0.1 + resolution: "cliui@npm:8.0.1" + dependencies: + string-width: ^4.2.0 + strip-ansi: ^6.0.1 + wrap-ansi: ^7.0.0 + checksum: 79648b3b0045f2e285b76fb2e24e207c6db44323581e421c3acbd0e86454cba1b37aea976ab50195a49e7384b871e6dfb2247ad7dec53c02454ac6497394cb56 + languageName: node + linkType: hard + "clone-deep@npm:^4.0.1": version: 4.0.1 resolution: "clone-deep@npm:4.0.1" @@ -3926,6 +4212,13 @@ __metadata: languageName: node linkType: hard +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: 63ae9933be5a2b8d4509daca5124e20c14d023c820258e484e32dc324d34c2754e71297c94a05784064ad27615037ef677e3f0c00469fb55f409d2bb21261035 + languageName: node + linkType: hard + "cookie-signature@npm:1.0.6": version: 1.0.6 resolution: "cookie-signature@npm:1.0.6" @@ -4740,6 +5033,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.4.535": + version: 1.4.597 + resolution: "electron-to-chromium@npm:1.4.597" + checksum: 3dc5d6a6f1dcdda3251a2d112f418a5e4924fcc2320cff68f82a73be6fcd68895637b04c0086e2ea8d2c83dd126d62112777a0dda9f1cd45d5596ec3a6b2a6f5 + languageName: node + linkType: hard + "emoji-regex@npm:^7.0.1": version: 7.0.3 resolution: "emoji-regex@npm:7.0.3" @@ -5373,6 +5673,19 @@ __metadata: languageName: node linkType: hard +"fast-glob@npm:3.3.0": + version: 3.3.0 + resolution: "fast-glob@npm:3.3.0" + dependencies: + "@nodelib/fs.stat": ^2.0.2 + "@nodelib/fs.walk": ^1.2.3 + glob-parent: ^5.1.2 + merge2: ^1.3.0 + micromatch: ^4.0.4 + checksum: 20df62be28eb5426fe8e40e0d05601a63b1daceb7c3d87534afcad91bdcf1e4b1743cf2d5247d6e225b120b46df0b9053a032b2691ba34ee121e033acd81f547 + languageName: node + linkType: hard + "fast-glob@npm:^3.1.1, fast-glob@npm:^3.2.5, fast-glob@npm:^3.2.7": version: 3.2.7 resolution: "fast-glob@npm:3.2.7" @@ -5661,7 +5974,7 @@ __metadata: "fsevents@patch:fsevents@^1.2.7#~builtin": version: 1.2.13 - resolution: "fsevents@patch:fsevents@npm%3A1.2.13#~builtin::version=1.2.13&hash=d11327" + resolution: "fsevents@patch:fsevents@npm%3A1.2.13#~builtin::version=1.2.13&hash=18f3a7" dependencies: bindings: ^1.5.0 nan: ^2.12.1 @@ -5671,7 +5984,7 @@ __metadata: "fsevents@patch:fsevents@~2.3.2#~builtin": version: 2.3.2 - resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" + resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=18f3a7" dependencies: node-gyp: latest conditions: os=darwin @@ -5701,7 +6014,7 @@ __metadata: languageName: node linkType: hard -"gensync@npm:^1.0.0-beta.1, gensync@npm:^1.0.0-beta.2": +"gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" checksum: a7437e58c6be12aa6c90f7730eac7fa9833dc78872b4ad2963d2031b00a3367a93f98aec75f9aaac7220848e4026d67a8655e870b24f20a543d103c0d65952ec @@ -6951,7 +7264,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.1.0, json5@npm:^2.1.2": +"json5@npm:^2.1.2": version: 2.2.0 resolution: "json5@npm:2.2.0" dependencies: @@ -6962,6 +7275,15 @@ __metadata: languageName: node linkType: hard +"json5@npm:^2.2.3": + version: 2.2.3 + resolution: "json5@npm:2.2.3" + bin: + json5: lib/cli.js + checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349 + languageName: node + linkType: hard + "jsonc-parser@npm:3.0.0, jsonc-parser@npm:^3.0.0": version: 3.0.0 resolution: "jsonc-parser@npm:3.0.0" @@ -7338,7 +7660,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.11, lodash@npm:^4.17.13, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.21": +"lodash@npm:^4.17.11, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -7387,6 +7709,15 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^5.1.1": + version: 5.1.1 + resolution: "lru-cache@npm:5.1.1" + dependencies: + yallist: ^3.0.2 + checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb + languageName: node + linkType: hard + "lru-cache@npm:^6.0.0": version: 6.0.0 resolution: "lru-cache@npm:6.0.0" @@ -7468,7 +7799,7 @@ __metadata: "@angular/compiler-cli": ^12.2.12 "@angular/core": ^12.2.12 "@angular/forms": ^12.2.12 - "@angular/localize": ^12.2.12 + "@angular/localize": ^16.0.6 "@angular/platform-browser": ^12.2.12 "@angular/platform-browser-dynamic": ^12.2.12 "@angular/router": ^12.2.12 @@ -8132,6 +8463,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.13": + version: 2.0.13 + resolution: "node-releases@npm:2.0.13" + checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 + languageName: node + linkType: hard + "nopt@npm:^5.0.0": version: 5.0.0 resolution: "nopt@npm:5.0.0" @@ -10114,7 +10452,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:1.20.0, resolve@npm:^1.1.7, resolve@npm:^1.14.2, resolve@npm:^1.3.2": +"resolve@npm:1.20.0, resolve@npm:^1.1.7, resolve@npm:^1.14.2": version: 1.20.0 resolution: "resolve@npm:1.20.0" dependencies: @@ -10124,9 +10462,9 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@1.20.0#~builtin, resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.3.2#~builtin": +"resolve@patch:resolve@1.20.0#~builtin, resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.14.2#~builtin": version: 1.20.0 - resolution: "resolve@patch:resolve@npm%3A1.20.0#~builtin::version=1.20.0&hash=c3c19d" + resolution: "resolve@patch:resolve@npm%3A1.20.0#~builtin::version=1.20.0&hash=07638b" dependencies: is-core-module: ^2.2.0 path-parse: ^1.0.6 @@ -10378,7 +10716,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^5.4.1, semver@npm:^5.5.0, semver@npm:^5.6.0": +"semver@npm:^5.5.0, semver@npm:^5.6.0": version: 5.7.2 resolution: "semver@npm:5.7.2" bin: @@ -10396,6 +10734,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^6.3.1": + version: 6.3.1 + resolution: "semver@npm:6.3.1" + bin: + semver: bin/semver.js + checksum: ae47d06de28836adb9d3e25f22a92943477371292d9b665fb023fae278d345d508ca1958232af086d85e0155aee22e313e100971898bbb8d5d89b8b1d4054ca2 + languageName: node + linkType: hard + "send@npm:0.17.1": version: 0.17.1 resolution: "send@npm:0.17.1" @@ -10933,6 +11280,17 @@ __metadata: languageName: node linkType: hard +"string-width@npm:^4.2.3": + version: 4.2.3 + resolution: "string-width@npm:4.2.3" + dependencies: + emoji-regex: ^8.0.0 + is-fullwidth-code-point: ^3.0.0 + strip-ansi: ^6.0.1 + checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb + languageName: node + linkType: hard + "string_decoder@npm:^1.1.1": version: 1.3.0 resolution: "string_decoder@npm:1.3.0" @@ -10987,6 +11345,15 @@ __metadata: languageName: node linkType: hard +"strip-ansi@npm:^6.0.1": + version: 6.0.1 + resolution: "strip-ansi@npm:6.0.1" + dependencies: + ansi-regex: ^5.0.1 + checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c + languageName: node + linkType: hard + "strip-bom@npm:^3.0.0": version: 3.0.0 resolution: "strip-bom@npm:3.0.0" @@ -11431,7 +11798,7 @@ __metadata: "typescript@patch:typescript@4.3.5#~builtin, typescript@patch:typescript@~4.3.5#~builtin": version: 4.3.5 - resolution: "typescript@patch:typescript@npm%3A4.3.5#~builtin::version=4.3.5&hash=dba6d9" + resolution: "typescript@patch:typescript@npm%3A4.3.5#~builtin::version=4.3.5&hash=701156" bin: tsc: bin/tsc tsserver: bin/tsserver @@ -11566,6 +11933,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.0.13": + version: 1.0.13 + resolution: "update-browserslist-db@npm:1.0.13" + dependencies: + escalade: ^3.1.1 + picocolors: ^1.0.0 + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 1e47d80182ab6e4ad35396ad8b61008ae2a1330221175d0abd37689658bdb61af9b705bfc41057fd16682474d79944fb2d86767c5ed5ae34b6276b9bed353322 + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -12032,6 +12413,13 @@ __metadata: languageName: node linkType: hard +"yallist@npm:^3.0.2": + version: 3.1.1 + resolution: "yallist@npm:3.1.1" + checksum: 48f7bb00dc19fc635a13a39fe547f527b10c9290e7b3e836b9a8f1ca04d4d342e85714416b3c2ab74949c9c66f9cebb0473e6bc353b79035356103b47641285d + languageName: node + linkType: hard + "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" @@ -12063,6 +12451,13 @@ __metadata: languageName: node linkType: hard +"yargs-parser@npm:^21.1.1": + version: 21.1.1 + resolution: "yargs-parser@npm:21.1.1" + checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c + languageName: node + linkType: hard + "yargs@npm:^13.2.4, yargs@npm:^13.3.2": version: 13.3.2 resolution: "yargs@npm:13.3.2" @@ -12111,6 +12506,21 @@ __metadata: languageName: node linkType: hard +"yargs@npm:^17.2.1": + version: 17.7.2 + resolution: "yargs@npm:17.7.2" + dependencies: + cliui: ^8.0.1 + escalade: ^3.1.1 + get-caller-file: ^2.0.5 + require-directory: ^2.1.1 + string-width: ^4.2.3 + y18n: ^5.0.5 + yargs-parser: ^21.1.1 + checksum: 73b572e863aa4a8cbef323dd911d79d193b772defd5a51aab0aca2d446655216f5002c42c5306033968193bdbf892a7a4c110b0d77954a7fdf563e653967b56a + languageName: node + linkType: hard + "yauzl@npm:^2.10.0": version: 2.10.0 resolution: "yauzl@npm:2.10.0" From 39c7f05da438462460e4f092a1ed546ead08c4a5 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 2 Jan 2024 11:52:21 +0100 Subject: [PATCH 131/158] remove redundant open modifiers --- .../management/config/LocaleConfiguration.kt | 4 +-- .../config/LoggingAspectConfiguration.kt | 4 +-- .../management/config/LoggingConfiguration.kt | 2 +- .../management/config/OpenApiConfiguration.kt | 4 +-- .../config/RadarTokenConfiguration.kt | 4 +-- .../config/SecurityConfiguration.kt | 8 ++--- .../config/ThymeleafConfiguration.kt | 4 +-- .../management/config/WebConfigurer.kt | 4 +-- .../repository/CustomAuditEventRepository.kt | 2 +- .../security/DomainUserDetailsService.kt | 2 +- .../management/service/AuthService.kt | 11 +++---- .../management/service/MetaTokenService.kt | 4 +-- .../management/service/OrganizationService.kt | 8 ++--- .../management/service/PasswordService.kt | 2 +- .../management/service/RevisionService.kt | 2 +- .../management/service/SiteSettingsService.kt | 2 +- .../management/service/SourceService.kt | 14 ++++----- .../management/config/MockConfiguration.kt | 4 +-- .../service/MetaTokenServiceTest.kt | 2 +- ...apIntegrationWorkFlowOnServiceLevelTest.kt | 2 +- .../web/rest/AuditResourceIntTest.kt | 2 +- .../web/rest/OrganizationResourceIntTest.kt | 2 +- .../web/rest/SourceTypeResourceIntTest.kt | 30 +++++++++---------- 23 files changed, 62 insertions(+), 61 deletions(-) diff --git a/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt b/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt index 856175555..99ac5080b 100644 --- a/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/LocaleConfiguration.kt @@ -11,13 +11,13 @@ import org.springframework.web.servlet.i18n.LocaleChangeInterceptor import tech.jhipster.config.locale.AngularCookieLocaleResolver @Configuration -open class LocaleConfiguration : WebMvcConfigurer, EnvironmentAware { +class LocaleConfiguration : WebMvcConfigurer, EnvironmentAware { override fun setEnvironment(environment: Environment) { // unused } @Bean(name = ["localeResolver"]) - open fun localeResolver(): LocaleResolver { + fun localeResolver(): LocaleResolver { val cookieLocaleResolver = AngularCookieLocaleResolver() cookieLocaleResolver.cookieName = "NG_TRANSLATE_LANG_KEY" return cookieLocaleResolver diff --git a/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt b/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt index 33bdb8a5c..8e42853cf 100644 --- a/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/LoggingAspectConfiguration.kt @@ -10,10 +10,10 @@ import tech.jhipster.config.JHipsterConstants @Configuration @EnableAspectJAutoProxy -open class LoggingAspectConfiguration { +class LoggingAspectConfiguration { @Bean @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) - open fun loggingAspect(env: Environment?): LoggingAspect { + fun loggingAspect(env: Environment?): LoggingAspect { return LoggingAspect(env!!) } } diff --git a/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt b/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt index 0ef95ad72..31094d692 100644 --- a/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/LoggingConfiguration.kt @@ -9,7 +9,7 @@ import tech.jhipster.config.JHipsterProperties import tech.jhipster.config.logging.LoggingUtils @Configuration -open class LoggingConfiguration( +class LoggingConfiguration( @Value("\${spring.application.name}") appName: String, @Value("\${server.port}") serverPort: String, jHipsterProperties: JHipsterProperties, diff --git a/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt b/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt index 7e3d96126..78c988cc5 100644 --- a/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/OpenApiConfiguration.kt @@ -22,9 +22,9 @@ import tech.jhipster.config.JHipsterConstants @Configuration @Profile(JHipsterConstants.SPRING_PROFILE_API_DOCS) -open class OpenApiConfiguration { +class OpenApiConfiguration { @Bean - open fun customOpenAPI(): OpenAPI { + fun customOpenAPI(): OpenAPI { return OpenAPI() .components( Components() diff --git a/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt b/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt index b7b032cc1..deb2e5484 100644 --- a/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/RadarTokenConfiguration.kt @@ -10,10 +10,10 @@ import org.springframework.context.annotation.ScopedProxyMode import javax.servlet.http.HttpServletRequest @Configuration -open class RadarTokenConfiguration @Autowired constructor(private val radarTokenLoader: RadarTokenLoader) { +class RadarTokenConfiguration @Autowired constructor(private val radarTokenLoader: RadarTokenLoader) { @Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS) @Bean - open fun radarToken(request: HttpServletRequest?): RadarToken? { + fun radarToken(request: HttpServletRequest?): RadarToken? { return radarTokenLoader.loadToken(request!!) } } diff --git a/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt b/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt index 8089515f7..e39265762 100644 --- a/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/SecurityConfiguration.kt @@ -27,7 +27,7 @@ import javax.annotation.PostConstruct @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) -open class SecurityConfiguration +class SecurityConfiguration /** Security configuration constructor. */ @Autowired constructor( private val authenticationManagerBuilder: AuthenticationManagerBuilder, private val userDetailsService: UserDetailsService, @@ -51,12 +51,12 @@ open class SecurityConfiguration } @Bean - open fun logoutSuccessHandler(): LogoutSuccessHandler { + fun logoutSuccessHandler(): LogoutSuccessHandler { return AjaxLogoutSuccessHandler() } @Bean - open fun http401UnauthorizedEntryPoint(): Http401UnauthorizedEntryPoint { + fun http401UnauthorizedEntryPoint(): Http401UnauthorizedEntryPoint { return Http401UnauthorizedEntryPoint() } @@ -99,7 +99,7 @@ open class SecurityConfiguration } @Bean - open fun securityEvaluationContextExtension(): SecurityEvaluationContextExtension { + fun securityEvaluationContextExtension(): SecurityEvaluationContextExtension { return SecurityEvaluationContextExtension() } } diff --git a/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt b/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt index 2ef1685e6..16dc8fd58 100644 --- a/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt +++ b/src/main/java/org/radarbase/management/config/ThymeleafConfiguration.kt @@ -7,10 +7,10 @@ import org.thymeleaf.templateresolver.ClassLoaderTemplateResolver import java.nio.charset.StandardCharsets @Configuration -open class ThymeleafConfiguration { +class ThymeleafConfiguration { @Bean @Description("Thymeleaf template resolver serving HTML 5 emails") - open fun emailTemplateResolver(): ClassLoaderTemplateResolver { + fun emailTemplateResolver(): ClassLoaderTemplateResolver { val emailTemplateResolver = ClassLoaderTemplateResolver() emailTemplateResolver.prefix = "templates/" emailTemplateResolver.suffix = ".html" diff --git a/src/main/java/org/radarbase/management/config/WebConfigurer.kt b/src/main/java/org/radarbase/management/config/WebConfigurer.kt index 205656634..1ff446223 100644 --- a/src/main/java/org/radarbase/management/config/WebConfigurer.kt +++ b/src/main/java/org/radarbase/management/config/WebConfigurer.kt @@ -25,7 +25,7 @@ import javax.servlet.ServletContext * Configuration of web application with Servlet 3.0 APIs. */ @Configuration -open class WebConfigurer : ServletContextInitializer, WebServerFactoryCustomizer { +class WebConfigurer : ServletContextInitializer, WebServerFactoryCustomizer { @Autowired private val env: Environment? = null @@ -100,7 +100,7 @@ open class WebConfigurer : ServletContextInitializer, WebServerFactoryCustomizer } @Bean - open fun passwordEncoder(): PasswordEncoder { + fun passwordEncoder(): PasswordEncoder { return BCryptPasswordEncoder() } diff --git a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt index e8b68ced7..ce5bfe4f5 100644 --- a/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt +++ b/src/main/java/org/radarbase/management/repository/CustomAuditEventRepository.kt @@ -19,7 +19,7 @@ import java.time.ZoneId * An implementation of Spring Boot's AuditEventRepository. */ @Repository -open class CustomAuditEventRepository( +class CustomAuditEventRepository( @Autowired private val auditEventConverter: AuditEventConverter, @Autowired private val persistenceAuditEventRepository: PersistenceAuditEventRepository ) : AuditEventRepository { diff --git a/src/main/java/org/radarbase/management/security/DomainUserDetailsService.kt b/src/main/java/org/radarbase/management/security/DomainUserDetailsService.kt index 6ccd12116..b3fc07064 100644 --- a/src/main/java/org/radarbase/management/security/DomainUserDetailsService.kt +++ b/src/main/java/org/radarbase/management/security/DomainUserDetailsService.kt @@ -14,7 +14,7 @@ import org.springframework.transaction.annotation.Transactional * Authenticate a user from the database. */ @Component("userDetailsService") -open class DomainUserDetailsService( +class DomainUserDetailsService( private val userRepository: UserRepository ) : UserDetailsService { @Transactional diff --git a/src/main/java/org/radarbase/management/service/AuthService.kt b/src/main/java/org/radarbase/management/service/AuthService.kt index e574220a5..777b77c05 100644 --- a/src/main/java/org/radarbase/management/service/AuthService.kt +++ b/src/main/java/org/radarbase/management/service/AuthService.kt @@ -10,7 +10,7 @@ import java.util.function.Consumer import javax.annotation.Nullable @Service -open class AuthService( +class AuthService( @Nullable private val token: RadarToken?, private val oracle: AuthorizationOracle, @@ -21,7 +21,7 @@ open class AuthService( * @throws NotAuthorizedException if identity does not have scope */ @Throws(NotAuthorizedException::class) - open fun checkScope(permission: Permission) { + fun checkScope(permission: Permission) { val token = token ?: throw NotAuthorizedException("User without authentication does not have permission.") if (!oracle.hasScope(token, permission)) { @@ -39,13 +39,14 @@ open class AuthService( */ @JvmOverloads @Throws(NotAuthorizedException::class) - open fun checkPermission( + fun checkPermission( permission: Permission, builder: Consumer? = null, scope: Permission.Entity = permission.entity, ) { val token = token ?: throw NotAuthorizedException("User without authentication does not have permission.") + // entitydetails builder is null means we require global permission val entity = if (builder != null) entityDetailsBuilder(builder) else EntityDetails.global val hasPermission = runBlocking { @@ -59,12 +60,12 @@ open class AuthService( } } - open fun referentsByScope(permission: Permission): AuthorityReferenceSet { + fun referentsByScope(permission: Permission): AuthorityReferenceSet { val token = token ?: return AuthorityReferenceSet() return oracle.referentsByScope(token, permission) } - open fun mayBeGranted(role: RoleAuthority, permission: Permission): Boolean = with(oracle) { + fun mayBeGranted(role: RoleAuthority, permission: Permission): Boolean = with(oracle) { role.mayBeGranted(permission) } } diff --git a/src/main/java/org/radarbase/management/service/MetaTokenService.kt b/src/main/java/org/radarbase/management/service/MetaTokenService.kt index a89752a6b..529011bd7 100644 --- a/src/main/java/org/radarbase/management/service/MetaTokenService.kt +++ b/src/main/java/org/radarbase/management/service/MetaTokenService.kt @@ -39,7 +39,7 @@ import javax.validation.ConstraintViolationException */ @Service @Transactional -open class MetaTokenService { +class MetaTokenService { @Autowired private val metaTokenRepository: MetaTokenRepository? = null @@ -110,7 +110,7 @@ open class MetaTokenService { * @return fetched token as [MetaToken]. */ @Transactional(readOnly = true) - open fun getToken(tokenName: String): MetaToken { + fun getToken(tokenName: String): MetaToken { return metaTokenRepository!!.findOneByTokenName(tokenName) ?: throw NotFoundException( "Meta token not found with tokenName", diff --git a/src/main/java/org/radarbase/management/service/OrganizationService.kt b/src/main/java/org/radarbase/management/service/OrganizationService.kt index aeb07f9de..46f3c8e3e 100644 --- a/src/main/java/org/radarbase/management/service/OrganizationService.kt +++ b/src/main/java/org/radarbase/management/service/OrganizationService.kt @@ -19,7 +19,7 @@ import org.springframework.transaction.annotation.Transactional */ @Service @Transactional -open class OrganizationService( +class OrganizationService( @Autowired private val organizationRepository: OrganizationRepository, @Autowired private val projectRepository: ProjectRepository, @Autowired private val organizationMapper: OrganizationMapper, @@ -46,7 +46,7 @@ open class OrganizationService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(): List { + fun findAll(): List { val organizationsOfUser: List val referents = authService.referentsByScope(Permission.ORGANIZATION_READ) organizationsOfUser = if (referents.global) { @@ -71,7 +71,7 @@ open class OrganizationService( * @return the entity */ @Transactional(readOnly = true) - open fun findByName(name: String): OrganizationDTO? { + fun findByName(name: String): OrganizationDTO? { log.debug("Request to get Organization by name: {}", name) return organizationRepository.findOneByName(name)?.let { organizationMapper.organizationToOrganizationDTO(it) } } @@ -82,7 +82,7 @@ open class OrganizationService( * @return the list of projects */ @Transactional(readOnly = true) - open fun findAllProjectsByOrganizationName(organizationName: String): List { + fun findAllProjectsByOrganizationName(organizationName: String): List { val referents = authService.referentsByScope(Permission.ORGANIZATION_READ) if (referents.isEmpty()) { return emptyList() diff --git a/src/main/java/org/radarbase/management/service/PasswordService.kt b/src/main/java/org/radarbase/management/service/PasswordService.kt index abda1038f..9245e110e 100644 --- a/src/main/java/org/radarbase/management/service/PasswordService.kt +++ b/src/main/java/org/radarbase/management/service/PasswordService.kt @@ -17,7 +17,7 @@ import java.security.SecureRandom import java.util.* @Service -open class PasswordService(private val passwordEncoder: PasswordEncoder) { +class PasswordService(private val passwordEncoder: PasswordEncoder) { private val random: Random = SecureRandom() /** diff --git a/src/main/java/org/radarbase/management/service/RevisionService.kt b/src/main/java/org/radarbase/management/service/RevisionService.kt index 44940b681..b04b9a59c 100644 --- a/src/main/java/org/radarbase/management/service/RevisionService.kt +++ b/src/main/java/org/radarbase/management/service/RevisionService.kt @@ -52,7 +52,7 @@ import javax.validation.constraints.NotNull @Service @Transactional(isolation = Isolation.REPEATABLE_READ, readOnly = true) -open class RevisionService(@param:Autowired private val revisionEntityRepository: CustomRevisionEntityRepository) : +class RevisionService(@param:Autowired private val revisionEntityRepository: CustomRevisionEntityRepository) : ApplicationContextAware { @PersistenceContext private val entityManager: EntityManager? = null diff --git a/src/main/java/org/radarbase/management/service/SiteSettingsService.kt b/src/main/java/org/radarbase/management/service/SiteSettingsService.kt index cabb2e47e..ae35231e5 100644 --- a/src/main/java/org/radarbase/management/service/SiteSettingsService.kt +++ b/src/main/java/org/radarbase/management/service/SiteSettingsService.kt @@ -12,7 +12,7 @@ import org.springframework.transaction.annotation.Transactional */ @Service @Transactional -open class SiteSettingsService( +class SiteSettingsService( @Autowired private val managementPortalProperties: ManagementPortalProperties) { /** diff --git a/src/main/java/org/radarbase/management/service/SourceService.kt b/src/main/java/org/radarbase/management/service/SourceService.kt index 1f1e11778..84d84c586 100644 --- a/src/main/java/org/radarbase/management/service/SourceService.kt +++ b/src/main/java/org/radarbase/management/service/SourceService.kt @@ -26,7 +26,7 @@ import java.util.* */ @Service @Transactional -open class SourceService( +class SourceService( @Autowired private val sourceRepository: SourceRepository, @Autowired private val sourceMapper: SourceMapper, @Autowired private val projectRepository: ProjectRepository, @@ -53,7 +53,7 @@ open class SourceService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(): List { + fun findAll(): List { return sourceRepository .findAll() .filterNotNull() @@ -67,7 +67,7 @@ open class SourceService( * @return the list of entities */ @Transactional(readOnly = true) - open fun findAll(pageable: Pageable?): Page? { + fun findAll(pageable: Pageable?): Page? { log.debug("Request to get SourceData with pagination") // somehow the compiler does not understand what's going on here, so we suppress the warning @Suppress("UNNECESSARY_SAFE_CALL") @@ -87,7 +87,7 @@ open class SourceService( * @return the entity */ @Transactional(readOnly = true) - open fun findOneByName(sourceName: String): SourceDTO? { + fun findOneByName(sourceName: String): SourceDTO? { log.debug("Request to get Source : {}", sourceName) return sourceRepository.findOneBySourceName(sourceName) .let { source: Source? -> source?.let { sourceMapper.sourceToSourceDTO(it) } } @@ -100,7 +100,7 @@ open class SourceService( * @return the entity */ @Transactional(readOnly = true) - open fun findOneById(id: Long): Optional { + fun findOneById(id: Long): Optional { log.debug("Request to get Source by id: {}", id) return Optional.ofNullable(sourceRepository.findById(id).orElse(null)) .map { source: Source? -> source?.let { sourceMapper.sourceToSourceDTO(it) } } @@ -112,7 +112,7 @@ open class SourceService( * @param id the id of the entity */ @Transactional - open fun delete(id: Long) { + fun delete(id: Long) { log.info("Request to delete Source : {}", id) val sourceHistory = sourceRepository.findRevisions(id) val sources = sourceHistory.content @@ -210,7 +210,7 @@ open class SourceService( */ @Transactional @Throws(NotAuthorizedException::class) - open fun updateSource(sourceDto: SourceDTO): SourceDTO? { + fun updateSource(sourceDto: SourceDTO): SourceDTO? { val existingSourceOpt = sourceDto.id?.let { sourceRepository.findById(it) } ?: return null val existingSource = existingSourceOpt.get() diff --git a/src/test/java/org/radarbase/management/config/MockConfiguration.kt b/src/test/java/org/radarbase/management/config/MockConfiguration.kt index 74505f56b..45724c740 100644 --- a/src/test/java/org/radarbase/management/config/MockConfiguration.kt +++ b/src/test/java/org/radarbase/management/config/MockConfiguration.kt @@ -20,10 +20,10 @@ import java.time.Duration import java.time.Instant @Configuration -open class MockConfiguration { +class MockConfiguration { @Bean @Primary - open fun radarTokenMock(): RadarToken = DataRadarToken( + fun radarTokenMock(): RadarToken = DataRadarToken( subject = "admin", username = "admin", roles = setOf(AuthorityReference(RoleAuthority.SYS_ADMIN)), diff --git a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt index 5a79aae77..55834309e 100644 --- a/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt +++ b/src/test/java/org/radarbase/management/service/MetaTokenServiceTest.kt @@ -28,7 +28,7 @@ import java.util.* @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -internal open class MetaTokenServiceTest( +internal class MetaTokenServiceTest( @Autowired private val metaTokenService: MetaTokenService, @Autowired private val metaTokenRepository: MetaTokenRepository, @Autowired private val subjectService: SubjectService, diff --git a/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt b/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt index 69a4efc1c..e1ca52688 100644 --- a/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt +++ b/src/test/java/org/radarbase/management/service/RedcapIntegrationWorkFlowOnServiceLevelTest.kt @@ -19,7 +19,7 @@ import java.util.* @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -internal open class RedcapIntegrationWorkFlowOnServiceLevelTest { +internal class RedcapIntegrationWorkFlowOnServiceLevelTest { @Autowired private val projectService: ProjectService? = null diff --git a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt index 3924e62f3..305de6e7d 100644 --- a/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/AuditResourceIntTest.kt @@ -38,7 +38,7 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @Transactional -internal open class AuditResourceIntTest( +internal class AuditResourceIntTest( @Autowired private val auditEventRepository: PersistenceAuditEventRepository, @Autowired private val auditEventConverter: AuditEventConverter, @Autowired private val jacksonMessageConverter: MappingJackson2HttpMessageConverter, diff --git a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt index f15d6fcd2..ee67f7643 100644 --- a/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/OrganizationResourceIntTest.kt @@ -41,7 +41,7 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class OrganizationResourceIntTest( +internal class OrganizationResourceIntTest( @Autowired private val organizationResource: OrganizationResource, @Autowired private val organizationService: OrganizationService, diff --git a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt index ad2dbf537..bec5c0183 100644 --- a/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt +++ b/src/test/java/org/radarbase/management/web/rest/SourceTypeResourceIntTest.kt @@ -41,7 +41,7 @@ import javax.servlet.ServletException @ExtendWith(SpringExtension::class) @SpringBootTest(classes = [ManagementPortalTestApp::class]) @WithMockUser -internal open class SourceTypeResourceIntTest( +internal class SourceTypeResourceIntTest( @Autowired private val sourceTypeRepository: SourceTypeRepository, @Autowired private val sourceTypeMapper: SourceTypeMapper, @Autowired private val sourceTypeService: SourceTypeService, @@ -84,7 +84,7 @@ internal open class SourceTypeResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSourceType() { + fun createSourceType() { val databaseSizeBeforeCreate = sourceTypeRepository.findAll().size // Create the SourceType @@ -123,7 +123,7 @@ internal open class SourceTypeResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun createSourceTypeWithExistingId() { + fun createSourceTypeWithExistingId() { val databaseSizeBeforeCreate = sourceTypeRepository.findAll().size // Create the SourceType with an existing ID @@ -146,7 +146,7 @@ internal open class SourceTypeResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkModelIsRequired() { + fun checkModelIsRequired() { val databaseSizeBeforeTest = sourceTypeRepository.findAll().size // set the field null sourceType.model = null @@ -166,7 +166,7 @@ internal open class SourceTypeResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkSourceTypeIsRequired() { + fun checkSourceTypeIsRequired() { val databaseSizeBeforeTest = sourceTypeRepository.findAll().size // set the field null sourceType.sourceTypeScope = null @@ -186,7 +186,7 @@ internal open class SourceTypeResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun checkVersionIsRequired() { + fun checkVersionIsRequired() { val databaseSizeBeforeTest = sourceTypeRepository.findAll().size // set the field null sourceType.catalogVersion(null) @@ -206,7 +206,7 @@ internal open class SourceTypeResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun allSourceTypes() { + fun allSourceTypes() { // Initialize the database sourceTypeRepository.saveAndFlush(sourceType) @@ -252,7 +252,7 @@ internal open class SourceTypeResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun allSourceTypesWithPagination() { + fun allSourceTypesWithPagination() { // Initialize the database sourceTypeRepository.saveAndFlush(sourceType) @@ -298,7 +298,7 @@ internal open class SourceTypeResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun getSourceType() { + fun getSourceType() { // Initialize the database sourceTypeRepository.saveAndFlush(sourceType) @@ -324,7 +324,7 @@ internal open class SourceTypeResourceIntTest( @Throws(Exception::class) @Transactional @Test - open fun nonExistingSourceType() { + fun nonExistingSourceType() { // Get the sourceType restSourceTypeMockMvc.perform( MockMvcRequestBuilders.get( @@ -338,7 +338,7 @@ internal open class SourceTypeResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateSourceType() { + fun updateSourceType() { // Initialize the database sourceTypeRepository.saveAndFlush(sourceType) val databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size @@ -371,7 +371,7 @@ internal open class SourceTypeResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun updateNonExistingSourceType() { + fun updateNonExistingSourceType() { val databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size // Create the SourceType @@ -393,7 +393,7 @@ internal open class SourceTypeResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun deleteSourceType() { + fun deleteSourceType() { // Initialize the database sourceTypeRepository.saveAndFlush(sourceType) val databaseSizeBeforeDelete = sourceTypeRepository.findAll().size @@ -416,14 +416,14 @@ internal open class SourceTypeResourceIntTest( @Test @Transactional @Throws(Exception::class) - open fun equalsVerifier() { + fun equalsVerifier() { org.junit.jupiter.api.Assertions.assertTrue(TestUtil.equalsVerifier(SourceType::class.java)) } @Test @Transactional @Throws(Exception::class) - open fun idempotentPutWithoutId() { + fun idempotentPutWithoutId() { val databaseSizeBeforeUpdate = sourceTypeRepository.findAll().size val sensorsSizeBeforeUpdate = sourceDataRepository.findAll().size sourceType.sourceData = setOf(SourceDataResourceIntTest.Companion.createEntity()) From af5f423780a295cbea024b7991b5359082a622e1 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Tue, 2 Jan 2024 12:47:38 +0100 Subject: [PATCH 132/158] remove redundant authCheck as the results of the query are filtered using the permissions of the logged in user anyway --- .../java/org/radarbase/management/service/ProjectService.kt | 2 +- .../java/org/radarbase/management/web/rest/ProjectResource.kt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/radarbase/management/service/ProjectService.kt b/src/main/java/org/radarbase/management/service/ProjectService.kt index 0975c75bc..d8b28a075 100644 --- a/src/main/java/org/radarbase/management/service/ProjectService.kt +++ b/src/main/java/org/radarbase/management/service/ProjectService.kt @@ -45,7 +45,7 @@ class ProjectService( } /** - * Get all the projects. + * Get all projects for which the user has READ permission. * * @return the list of entities */ diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index 9b052727d..822313ab2 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -184,7 +184,6 @@ class ProjectResource( @RequestParam(name = "minimized", required = false, defaultValue = "false") minimized: Boolean ): ResponseEntity<*> { log.debug("REST request to get Projects") - authService.checkPermission(Permission.PROJECT_READ) val page = projectService.findAll(minimized, pageable) val headers = PaginationUtil .generatePaginationHttpHeaders(page, "/api/projects") From 538301f44ff7ec42a1a055f2956182c88b643b9c Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Thu, 15 Feb 2024 13:14:16 +0100 Subject: [PATCH 133/158] replace permission checks with scope checks for resources that should not be subject to entity-based filtering --- .../management/web/rest/OAuthClientsResource.kt | 9 ++++----- .../org/radarbase/management/web/rest/ProjectResource.kt | 1 + .../org/radarbase/management/web/rest/UserResource.kt | 7 ++++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt index eec2b4409..771b310bd 100644 --- a/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/OAuthClientsResource.kt @@ -65,11 +65,10 @@ class OAuthClientsResource( * @return the list of registered clients as a list of [ClientDetailsDTO] */ fun oAuthClients(): ResponseEntity> { - authService.checkPermission(Permission.OAUTHCLIENTS_READ) - return ResponseEntity.ok().body( - clientDetailsMapper.clientDetailsToClientDetailsDTO(oAuthClientService.findAllOAuthClients()) - ) - } + authService.checkScope(Permission.OAUTHCLIENTS_READ) + val clients = clientDetailsMapper.clientDetailsToClientDetailsDTO(oAuthClientService.findAllOAuthClients()) + return ResponseEntity.ok().body(clients) + } /** * GET /api/oauth-clients/:id. diff --git a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt index 822313ab2..73ebf0f1e 100644 --- a/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/ProjectResource.kt @@ -184,6 +184,7 @@ class ProjectResource( @RequestParam(name = "minimized", required = false, defaultValue = "false") minimized: Boolean ): ResponseEntity<*> { log.debug("REST request to get Projects") + authService.checkScope(Permission.PROJECT_READ) val page = projectService.findAll(minimized, pageable) val headers = PaginationUtil .generatePaginationHttpHeaders(page, "/api/projects") diff --git a/src/main/java/org/radarbase/management/web/rest/UserResource.kt b/src/main/java/org/radarbase/management/web/rest/UserResource.kt index a2d217099..424530a46 100644 --- a/src/main/java/org/radarbase/management/web/rest/UserResource.kt +++ b/src/main/java/org/radarbase/management/web/rest/UserResource.kt @@ -190,11 +190,12 @@ class UserResource( @Throws(NotAuthorizedException::class) fun getUsers( @PageableDefault(page = 0, size = Int.MAX_VALUE) pageable: Pageable?, - userFilter: UserFilter?, + userFilter: UserFilter, @RequestParam(defaultValue = "true") includeProvenance: Boolean ): ResponseEntity> { - authService.checkPermission(Permission.USER_READ) - val page = userService.findUsers(userFilter!!, pageable, includeProvenance) + authService.checkScope(Permission.USER_READ) + + val page = userService.findUsers(userFilter, pageable, includeProvenance) return ResponseEntity( page!!.content, PaginationUtil.generatePaginationHttpHeaders(page, "/api/users"), HttpStatus.OK ) From 82ac2f5d4f15b21eeb25763b94d00362878a2943 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:04:02 +0000 Subject: [PATCH 134/158] Bump minimist from 1.2.5 to 1.2.8 Bumps [minimist](https://github.com/minimistjs/minimist) from 1.2.5 to 1.2.8. - [Release notes](https://github.com/minimistjs/minimist/releases) - [Changelog](https://github.com/minimistjs/minimist/blob/main/CHANGELOG.md) - [Commits](https://github.com/minimistjs/minimist/compare/v1.2.5...v1.2.8) --- updated-dependencies: - dependency-name: minimist dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d74f90cb5..133ef36d8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7746,9 +7746,9 @@ __metadata: linkType: hard "minimist@npm:^1.2.0, minimist@npm:^1.2.5": - version: 1.2.5 - resolution: "minimist@npm:1.2.5" - checksum: 86706ce5b36c16bfc35c5fe3dbb01d5acdc9a22f2b6cc810b6680656a1d2c0e44a0159c9a3ba51fb072bb5c203e49e10b51dcd0eec39c481f4c42086719bae52 + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 languageName: node linkType: hard From 41729163101d298241ba002ff03e9da3c633024a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:47:05 +0000 Subject: [PATCH 135/158] Bump http-cache-semantics from 4.1.0 to 4.1.1 Bumps [http-cache-semantics](https://github.com/kornelski/http-cache-semantics) from 4.1.0 to 4.1.1. - [Release notes](https://github.com/kornelski/http-cache-semantics/releases) - [Commits](https://github.com/kornelski/http-cache-semantics/compare/v4.1.0...v4.1.1) --- updated-dependencies: - dependency-name: http-cache-semantics dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d74f90cb5..b76b7f8b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6038,9 +6038,9 @@ __metadata: linkType: hard "http-cache-semantics@npm:^4.1.0": - version: 4.1.0 - resolution: "http-cache-semantics@npm:4.1.0" - checksum: 974de94a81c5474be07f269f9fd8383e92ebb5a448208223bfb39e172a9dbc26feff250192ecc23b9593b3f92098e010406b0f24bd4d588d631f80214648ed42 + version: 4.1.1 + resolution: "http-cache-semantics@npm:4.1.1" + checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 languageName: node linkType: hard From a586ea45d877a7f99c3175ca5267989ec432c308 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:49:49 +0000 Subject: [PATCH 136/158] Bump express from 4.17.1 to 4.18.2 Bumps [express](https://github.com/expressjs/express) from 4.17.1 to 4.18.2. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/master/History.md) - [Commits](https://github.com/expressjs/express/compare/4.17.1...4.18.2) --- updated-dependencies: - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 403 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 332 insertions(+), 71 deletions(-) diff --git a/yarn.lock b/yarn.lock index d74f90cb5..d8170c54a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2560,7 +2560,7 @@ __metadata: languageName: node linkType: hard -"accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.7": +"accepts@npm:~1.3.4, accepts@npm:~1.3.5": version: 1.3.7 resolution: "accepts@npm:1.3.7" dependencies: @@ -2570,6 +2570,16 @@ __metadata: languageName: node linkType: hard +"accepts@npm:~1.3.8": + version: 1.3.8 + resolution: "accepts@npm:1.3.8" + dependencies: + mime-types: ~2.1.34 + negotiator: 0.6.3 + checksum: 50c43d32e7b50285ebe84b613ee4a3aa426715a7d131b65b786e2ead0fd76b6b60091b9916d3478a75f11f162628a2139991b6c03ab3f1d9ab7c86075dc8eab4 + languageName: node + linkType: hard + "acorn-import-assertions@npm:^1.7.6": version: 1.7.6 resolution: "acorn-import-assertions@npm:1.7.6" @@ -3194,7 +3204,27 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.19.0, body-parser@npm:^1.19.0": +"body-parser@npm:1.20.1": + version: 1.20.1 + resolution: "body-parser@npm:1.20.1" + dependencies: + bytes: 3.1.2 + content-type: ~1.0.4 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.1 + type-is: ~1.6.18 + unpipe: 1.0.0 + checksum: f1050dbac3bede6a78f0b87947a8d548ce43f91ccc718a50dd774f3c81f2d8b04693e52acf62659fad23101827dd318da1fb1363444ff9a8482b886a3e4a5266 + languageName: node + linkType: hard + +"body-parser@npm:^1.19.0": version: 1.19.0 resolution: "body-parser@npm:1.19.0" dependencies: @@ -3371,6 +3401,13 @@ __metadata: languageName: node linkType: hard +"bytes@npm:3.1.2": + version: 3.1.2 + resolution: "bytes@npm:3.1.2" + checksum: e4bcd3948d289c5127591fbedf10c0b639ccbf00243504e4e127374a15c3bc8eed0d28d4aaab08ff6f1cf2abc0cce6ba3085ed32f4f90e82a5683ce0014e1b6e + languageName: node + linkType: hard + "cacache@npm:15.2.0": version: 15.2.0 resolution: "cacache@npm:15.2.0" @@ -3456,6 +3493,19 @@ __metadata: languageName: node linkType: hard +"call-bind@npm:^1.0.6": + version: 1.0.7 + resolution: "call-bind@npm:1.0.7" + dependencies: + es-define-property: ^1.0.0 + es-errors: ^1.3.0 + function-bind: ^1.1.2 + get-intrinsic: ^1.2.4 + set-function-length: ^1.2.1 + checksum: 295c0c62b90dd6522e6db3b0ab1ce26bdf9e7404215bda13cfee25b626b5ff1a7761324d58d38b1ef1607fc65aca2d06e44d2e18d0dfc6c14b465b00d8660029 + languageName: node + linkType: hard + "callsites@npm:^3.0.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" @@ -3901,12 +3951,12 @@ __metadata: languageName: node linkType: hard -"content-disposition@npm:0.5.3": - version: 0.5.3 - resolution: "content-disposition@npm:0.5.3" +"content-disposition@npm:0.5.4": + version: 0.5.4 + resolution: "content-disposition@npm:0.5.4" dependencies: - safe-buffer: 5.1.2 - checksum: 95bf164c0b0b8199d3f44b7631e51b37f683c6a90b9baa4315bd3d405a6d1bc81b7346f0981046aa004331fb3d7a28b629514d01fc209a5251573fc7e4d33380 + safe-buffer: 5.2.1 + checksum: afb9d545e296a5171d7574fcad634b2fdf698875f4006a9dd04a3e1333880c5c0c98d47b560d01216fb6505a54a2ba6a843ee3a02ec86d7e911e8315255f56c3 languageName: node linkType: hard @@ -3933,10 +3983,10 @@ __metadata: languageName: node linkType: hard -"cookie@npm:0.4.0": - version: 0.4.0 - resolution: "cookie@npm:0.4.0" - checksum: 760384ba0aef329c52523747e36a452b5e51bc49b34160363a6934e7b7df3f93fcc88b35e33450361535d40a92a96412da870e1816aba9aa6cc556a9fedd8492 +"cookie@npm:0.5.0": + version: 0.5.0 + resolution: "cookie@npm:0.5.0" + checksum: 1f4bd2ca5765f8c9689a7e8954183f5332139eb72b6ff783d8947032ec1fdf43109852c178e21a953a30c0dd42257828185be01b49d1eb1a67fd054ca588a180 languageName: node linkType: hard @@ -4509,6 +4559,17 @@ __metadata: languageName: node linkType: hard +"define-data-property@npm:^1.1.2": + version: 1.1.4 + resolution: "define-data-property@npm:1.1.4" + dependencies: + es-define-property: ^1.0.0 + es-errors: ^1.3.0 + gopd: ^1.0.1 + checksum: 8068ee6cab694d409ac25936eb861eea704b7763f7f342adbdfe337fc27c78d7ae0eff2364b2917b58c508d723c7a074326d068eef2e45c4edcd85cf94d0313b + languageName: node + linkType: hard + "define-lazy-prop@npm:^2.0.0": version: 2.0.0 resolution: "define-lazy-prop@npm:2.0.0" @@ -4582,6 +4643,13 @@ __metadata: languageName: node linkType: hard +"depd@npm:2.0.0": + version: 2.0.0 + resolution: "depd@npm:2.0.0" + checksum: abbe19c768c97ee2eed6282d8ce3031126662252c58d711f646921c9623f9052e3e1906443066beec1095832f534e57c523b7333f8e7e0d93051ab6baef5ab3a + languageName: node + linkType: hard + "depd@npm:^1.1.2, depd@npm:~1.1.2": version: 1.1.2 resolution: "depd@npm:1.1.2" @@ -4596,10 +4664,10 @@ __metadata: languageName: node linkType: hard -"destroy@npm:~1.0.4": - version: 1.0.4 - resolution: "destroy@npm:1.0.4" - checksum: da9ab4961dc61677c709da0c25ef01733042614453924d65636a7db37308fef8a24cd1e07172e61173d471ca175371295fbc984b0af5b2b4ff47cd57bd784c03 +"destroy@npm:1.2.0": + version: 1.2.0 + resolution: "destroy@npm:1.2.0" + checksum: 0acb300b7478a08b92d810ab229d5afe0d2f4399272045ab22affa0d99dbaf12637659411530a6fcd597a9bdac718fc94373a61a95b4651bbc7b83684a565e38 languageName: node linkType: hard @@ -4877,6 +4945,22 @@ __metadata: languageName: node linkType: hard +"es-define-property@npm:^1.0.0": + version: 1.0.0 + resolution: "es-define-property@npm:1.0.0" + dependencies: + get-intrinsic: ^1.2.4 + checksum: f66ece0a887b6dca71848fa71f70461357c0e4e7249696f81bad0a1f347eed7b31262af4a29f5d726dc026426f085483b6b90301855e647aa8e21936f07293c6 + languageName: node + linkType: hard + +"es-errors@npm:^1.3.0": + version: 1.3.0 + resolution: "es-errors@npm:1.3.0" + checksum: ec1414527a0ccacd7f15f4a3bc66e215f04f595ba23ca75cdae0927af099b5ec865f9f4d33e9d7e86f512f252876ac77d4281a7871531a50678132429b1271b5 + languageName: node + linkType: hard + "es-module-lexer@npm:^0.7.1": version: 0.7.1 resolution: "es-module-lexer@npm:0.7.1" @@ -5245,40 +5329,41 @@ __metadata: linkType: hard "express@npm:^4.17.1": - version: 4.17.1 - resolution: "express@npm:4.17.1" + version: 4.18.2 + resolution: "express@npm:4.18.2" dependencies: - accepts: ~1.3.7 + accepts: ~1.3.8 array-flatten: 1.1.1 - body-parser: 1.19.0 - content-disposition: 0.5.3 + body-parser: 1.20.1 + content-disposition: 0.5.4 content-type: ~1.0.4 - cookie: 0.4.0 + cookie: 0.5.0 cookie-signature: 1.0.6 debug: 2.6.9 - depd: ~1.1.2 + depd: 2.0.0 encodeurl: ~1.0.2 escape-html: ~1.0.3 etag: ~1.8.1 - finalhandler: ~1.1.2 + finalhandler: 1.2.0 fresh: 0.5.2 + http-errors: 2.0.0 merge-descriptors: 1.0.1 methods: ~1.1.2 - on-finished: ~2.3.0 + on-finished: 2.4.1 parseurl: ~1.3.3 path-to-regexp: 0.1.7 - proxy-addr: ~2.0.5 - qs: 6.7.0 + proxy-addr: ~2.0.7 + qs: 6.11.0 range-parser: ~1.2.1 - safe-buffer: 5.1.2 - send: 0.17.1 - serve-static: 1.14.1 - setprototypeof: 1.1.1 - statuses: ~1.5.0 + safe-buffer: 5.2.1 + send: 0.18.0 + serve-static: 1.15.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 type-is: ~1.6.18 utils-merge: 1.0.1 vary: ~1.1.2 - checksum: d964e9e17af331ea6fa2f84999b063bc47189dd71b4a735df83f9126d3bb2b92e830f1cb1d7c2742530eb625e2689d7a9a9c71f0c3cc4dd6015c3cd32a01abd5 + checksum: 3c4b9b076879442f6b968fe53d85d9f1eeacbb4f4c41e5f16cc36d77ce39a2b0d81b3f250514982110d815b2f7173f5561367f9110fcc541f9371948e8c8b037 languageName: node linkType: hard @@ -5457,7 +5542,7 @@ __metadata: languageName: node linkType: hard -"finalhandler@npm:1.1.2, finalhandler@npm:~1.1.2": +"finalhandler@npm:1.1.2": version: 1.1.2 resolution: "finalhandler@npm:1.1.2" dependencies: @@ -5472,6 +5557,21 @@ __metadata: languageName: node linkType: hard +"finalhandler@npm:1.2.0": + version: 1.2.0 + resolution: "finalhandler@npm:1.2.0" + dependencies: + debug: 2.6.9 + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + on-finished: 2.4.1 + parseurl: ~1.3.3 + statuses: 2.0.1 + unpipe: ~1.0.0 + checksum: 92effbfd32e22a7dff2994acedbd9bcc3aa646a3e919ea6a53238090e87097f8ef07cced90aa2cc421abdf993aefbdd5b00104d55c7c5479a8d00ed105b45716 + languageName: node + linkType: hard + "find-cache-dir@npm:3.3.1": version: 3.3.1 resolution: "find-cache-dir@npm:3.3.1" @@ -5685,6 +5785,13 @@ __metadata: languageName: node linkType: hard +"function-bind@npm:^1.1.2": + version: 1.1.2 + resolution: "function-bind@npm:1.1.2" + checksum: 2b0ff4ce708d99715ad14a6d1f894e2a83242e4a52ccfcefaee5e40050562e5f6dafc1adbb4ce2d4ab47279a45dc736ab91ea5042d843c3c092820dfe032efb1 + languageName: node + linkType: hard + "gauge@npm:~2.7.3": version: 2.7.4 resolution: "gauge@npm:2.7.4" @@ -5726,6 +5833,19 @@ __metadata: languageName: node linkType: hard +"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": + version: 1.2.4 + resolution: "get-intrinsic@npm:1.2.4" + dependencies: + es-errors: ^1.3.0 + function-bind: ^1.1.2 + has-proto: ^1.0.1 + has-symbols: ^1.0.3 + hasown: ^2.0.0 + checksum: 414e3cdf2c203d1b9d7d33111df746a4512a1aa622770b361dadddf8ed0b5aeb26c560f49ca077e24bfafb0acb55ca908d1f709216ccba33ffc548ec8a79a951 + languageName: node + linkType: hard + "get-stream@npm:^4.0.0": version: 4.1.0 resolution: "get-stream@npm:4.1.0" @@ -5861,6 +5981,15 @@ __metadata: languageName: node linkType: hard +"gopd@npm:^1.0.1": + version: 1.0.1 + resolution: "gopd@npm:1.0.1" + dependencies: + get-intrinsic: ^1.1.3 + checksum: a5ccfb8806e0917a94e0b3de2af2ea4979c1da920bc381667c260e00e7cafdbe844e2cb9c5bcfef4e5412e8bf73bab837285bc35c7ba73aaaf0134d4583393a6 + languageName: node + linkType: hard + "graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.3, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": version: 4.2.8 resolution: "graceful-fs@npm:4.2.8" @@ -5913,6 +6042,22 @@ __metadata: languageName: node linkType: hard +"has-property-descriptors@npm:^1.0.1": + version: 1.0.2 + resolution: "has-property-descriptors@npm:1.0.2" + dependencies: + es-define-property: ^1.0.0 + checksum: fcbb246ea2838058be39887935231c6d5788babed499d0e9d0cc5737494c48aba4fe17ba1449e0d0fbbb1e36175442faa37f9c427ae357d6ccb1d895fbcd3de3 + languageName: node + linkType: hard + +"has-proto@npm:^1.0.1": + version: 1.0.3 + resolution: "has-proto@npm:1.0.3" + checksum: fe7c3d50b33f50f3933a04413ed1f69441d21d2d2944f81036276d30635cad9279f6b43bc8f32036c31ebdfcf6e731150f46c1907ad90c669ffe9b066c3ba5c4 + languageName: node + linkType: hard + "has-symbols@npm:^1.0.1, has-symbols@npm:^1.0.2": version: 1.0.2 resolution: "has-symbols@npm:1.0.2" @@ -5920,6 +6065,13 @@ __metadata: languageName: node linkType: hard +"has-symbols@npm:^1.0.3": + version: 1.0.3 + resolution: "has-symbols@npm:1.0.3" + checksum: a054c40c631c0d5741a8285010a0777ea0c068f99ed43e5d6eb12972da223f8af553a455132fdb0801bdcfa0e0f443c0c03a68d8555aa529b3144b446c3f2410 + languageName: node + linkType: hard + "has-tostringtag@npm:^1.0.0": version: 1.0.0 resolution: "has-tostringtag@npm:1.0.0" @@ -5984,6 +6136,15 @@ __metadata: languageName: node linkType: hard +"hasown@npm:^2.0.0": + version: 2.0.1 + resolution: "hasown@npm:2.0.1" + dependencies: + function-bind: ^1.1.2 + checksum: 9081c382a4fe8a62639a8da5c7d3322b203c319147e48783763dd741863d9f2dcaa743574fe2a1283871c445d8ba99ea45d5fff384e5ad27ca9dd7a367d79de0 + languageName: node + linkType: hard + "hdr-histogram-js@npm:^2.0.1": version: 2.0.1 resolution: "hdr-histogram-js@npm:2.0.1" @@ -6064,6 +6225,19 @@ __metadata: languageName: node linkType: hard +"http-errors@npm:2.0.0": + version: 2.0.0 + resolution: "http-errors@npm:2.0.0" + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + checksum: 9b0a3782665c52ce9dc658a0d1560bcb0214ba5699e4ea15aefb2a496e2ca83db03ebc42e1cce4ac1f413e4e0d2d736a3fd755772c556a9a06853ba2a0b7d920 + languageName: node + linkType: hard + "http-errors@npm:~1.6.2": version: 1.6.3 resolution: "http-errors@npm:1.6.3" @@ -6076,19 +6250,6 @@ __metadata: languageName: node linkType: hard -"http-errors@npm:~1.7.2": - version: 1.7.3 - resolution: "http-errors@npm:1.7.3" - dependencies: - depd: ~1.1.2 - inherits: 2.0.4 - setprototypeof: 1.1.1 - statuses: ">= 1.5.0 < 2" - toidentifier: 1.0.0 - checksum: a59f359473f4b3ea78305beee90d186268d6075432622a46fb7483059068a2dd4c854a20ac8cd438883127e06afb78c1309168bde6cdfeed1e3700eb42487d99 - languageName: node - linkType: hard - "http-parser-js@npm:>=0.5.1": version: 0.5.3 resolution: "http-parser-js@npm:0.5.3" @@ -7666,6 +7827,13 @@ __metadata: languageName: node linkType: hard +"mime-db@npm:1.52.0": + version: 1.52.0 + resolution: "mime-db@npm:1.52.0" + checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f + languageName: node + linkType: hard + "mime-types@npm:^2.1.12, mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:~2.1.17, mime-types@npm:~2.1.19, mime-types@npm:~2.1.24": version: 2.1.32 resolution: "mime-types@npm:2.1.32" @@ -7675,6 +7843,15 @@ __metadata: languageName: node linkType: hard +"mime-types@npm:~2.1.34": + version: 2.1.35 + resolution: "mime-types@npm:2.1.35" + dependencies: + mime-db: 1.52.0 + checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836 + languageName: node + linkType: hard + "mime@npm:1.6.0, mime@npm:^1.4.1": version: 1.6.0 resolution: "mime@npm:1.6.0" @@ -7869,13 +8046,6 @@ __metadata: languageName: node linkType: hard -"ms@npm:2.1.1": - version: 2.1.1 - resolution: "ms@npm:2.1.1" - checksum: 0078a23cd916a9a7435c413caa14c57d4b4f6e2470e0ab554b6964163c8a4436448ac7ae020e883685475da6b6796cc396b670f579cb275db288a21e3e57721e - languageName: node - linkType: hard - "ms@npm:2.1.2": version: 2.1.2 resolution: "ms@npm:2.1.2" @@ -7883,7 +8053,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:^2.0.0, ms@npm:^2.1.1": +"ms@npm:2.1.3, ms@npm:^2.0.0, ms@npm:^2.1.1": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d @@ -7982,6 +8152,13 @@ __metadata: languageName: node linkType: hard +"negotiator@npm:0.6.3": + version: 0.6.3 + resolution: "negotiator@npm:0.6.3" + checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 + languageName: node + linkType: hard + "neo-async@npm:^2.6.2": version: 2.6.2 resolution: "neo-async@npm:2.6.2" @@ -8327,6 +8504,13 @@ __metadata: languageName: node linkType: hard +"object-inspect@npm:^1.13.1": + version: 1.13.1 + resolution: "object-inspect@npm:1.13.1" + checksum: 7d9fa9221de3311dcb5c7c307ee5dc011cdd31dc43624b7c184b3840514e118e05ef0002be5388304c416c0eb592feb46e983db12577fc47e47d5752fbbfb61f + languageName: node + linkType: hard + "object-is@npm:^1.0.1": version: 1.1.5 resolution: "object-is@npm:1.1.5" @@ -8381,6 +8565,15 @@ __metadata: languageName: node linkType: hard +"on-finished@npm:2.4.1": + version: 2.4.1 + resolution: "on-finished@npm:2.4.1" + dependencies: + ee-first: 1.1.1 + checksum: d20929a25e7f0bb62f937a425b5edeb4e4cde0540d77ba146ec9357f00b0d497cdb3b9b05b9c8e46222407d1548d08166bff69cc56dfa55ba0e4469228920ff0 + languageName: node + linkType: hard + "on-finished@npm:~2.3.0": version: 2.3.0 resolution: "on-finished@npm:2.3.0" @@ -9672,7 +9865,7 @@ __metadata: languageName: node linkType: hard -"proxy-addr@npm:~2.0.5": +"proxy-addr@npm:~2.0.7": version: 2.0.7 resolution: "proxy-addr@npm:2.0.7" dependencies: @@ -9744,6 +9937,15 @@ __metadata: languageName: node linkType: hard +"qs@npm:6.11.0": + version: 6.11.0 + resolution: "qs@npm:6.11.0" + dependencies: + side-channel: ^1.0.4 + checksum: 6e1f29dd5385f7488ec74ac7b6c92f4d09a90408882d0c208414a34dd33badc1a621019d4c799a3df15ab9b1d0292f97c1dd71dc7c045e69f81a8064e5af7297 + languageName: node + linkType: hard + "qs@npm:6.7.0": version: 6.7.0 resolution: "qs@npm:6.7.0" @@ -9814,6 +10016,18 @@ __metadata: languageName: node linkType: hard +"raw-body@npm:2.5.1": + version: 2.5.1 + resolution: "raw-body@npm:2.5.1" + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + checksum: 5362adff1575d691bb3f75998803a0ffed8c64eabeaa06e54b4ada25a0cd1b2ae7f4f5ec46565d1bec337e08b5ac90c76eaa0758de6f72a633f025d754dec29e + languageName: node + linkType: hard + "read-cache@npm:^1.0.0": version: 1.0.0 resolution: "read-cache@npm:1.0.0" @@ -10246,7 +10460,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.2, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.2, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 @@ -10396,24 +10610,24 @@ __metadata: languageName: node linkType: hard -"send@npm:0.17.1": - version: 0.17.1 - resolution: "send@npm:0.17.1" +"send@npm:0.18.0": + version: 0.18.0 + resolution: "send@npm:0.18.0" dependencies: debug: 2.6.9 - depd: ~1.1.2 - destroy: ~1.0.4 + depd: 2.0.0 + destroy: 1.2.0 encodeurl: ~1.0.2 escape-html: ~1.0.3 etag: ~1.8.1 fresh: 0.5.2 - http-errors: ~1.7.2 + http-errors: 2.0.0 mime: 1.6.0 - ms: 2.1.1 - on-finished: ~2.3.0 + ms: 2.1.3 + on-finished: 2.4.1 range-parser: ~1.2.1 - statuses: ~1.5.0 - checksum: d214c2fa42e7fae3f8fc1aa3931eeb3e6b78c2cf141574e09dbe159915c1e3a337269fc6b7512e7dfddcd7d6ff5974cb62f7c3637ba86a55bde20a92c18bdca0 + statuses: 2.0.1 + checksum: 74fc07ebb58566b87b078ec63e5a3e41ecd987e4272ba67b7467e86c6ad51bc6b0b0154133b6d8b08a2ddda360464f71382f7ef864700f34844a76c8027817a8 languageName: node linkType: hard @@ -10441,15 +10655,15 @@ __metadata: languageName: node linkType: hard -"serve-static@npm:1.14.1": - version: 1.14.1 - resolution: "serve-static@npm:1.14.1" +"serve-static@npm:1.15.0": + version: 1.15.0 + resolution: "serve-static@npm:1.15.0" dependencies: encodeurl: ~1.0.2 escape-html: ~1.0.3 parseurl: ~1.3.3 - send: 0.17.1 - checksum: c6b268e8486d39ecd54b86c7f2d0ee4a38cd7514ddd9c92c8d5793bb005afde5e908b12395898ae206782306ccc848193d93daa15b86afb3cbe5a8414806abe8 + send: 0.18.0 + checksum: af57fc13be40d90a12562e98c0b7855cf6e8bd4c107fe9a45c212bf023058d54a1871b1c89511c3958f70626fff47faeb795f5d83f8cf88514dbaeb2b724464d languageName: node linkType: hard @@ -10460,6 +10674,20 @@ __metadata: languageName: node linkType: hard +"set-function-length@npm:^1.2.1": + version: 1.2.1 + resolution: "set-function-length@npm:1.2.1" + dependencies: + define-data-property: ^1.1.2 + es-errors: ^1.3.0 + function-bind: ^1.1.2 + get-intrinsic: ^1.2.3 + gopd: ^1.0.1 + has-property-descriptors: ^1.0.1 + checksum: 23742476d695f2eae86348c069bd164d4f25fa7c26546a46a2b5f370f1f84b98ec64366d2cd17785d5b41bbf16b95855da4b7eb188e7056fe3b0248d61f6afda + languageName: node + linkType: hard + "set-value@npm:^2.0.0, set-value@npm:^2.0.1": version: 2.0.1 resolution: "set-value@npm:2.0.1" @@ -10486,6 +10714,13 @@ __metadata: languageName: node linkType: hard +"setprototypeof@npm:1.2.0": + version: 1.2.0 + resolution: "setprototypeof@npm:1.2.0" + checksum: be18cbbf70e7d8097c97f713a2e76edf84e87299b40d085c6bf8b65314e994cc15e2e317727342fa6996e38e1f52c59720b53fe621e2eb593a6847bf0356db89 + languageName: node + linkType: hard + "shallow-clone@npm:^3.0.0": version: 3.0.1 resolution: "shallow-clone@npm:3.0.1" @@ -10534,6 +10769,18 @@ __metadata: languageName: node linkType: hard +"side-channel@npm:^1.0.4": + version: 1.0.5 + resolution: "side-channel@npm:1.0.5" + dependencies: + call-bind: ^1.0.6 + es-errors: ^1.3.0 + get-intrinsic: ^1.2.4 + object-inspect: ^1.13.1 + checksum: 640446b4e5a9554116ed6f5bec17c6740fa8da2c1a19e4d69c1202191185d4cc24f21ba0dd3ccca140eb6a8ee978d0b5bc5132f09b7962db7f9c4bc7872494ac + languageName: node + linkType: hard + "signal-exit@npm:^3.0.0, signal-exit@npm:^3.0.2": version: 3.0.3 resolution: "signal-exit@npm:3.0.3" @@ -10872,6 +11119,13 @@ __metadata: languageName: node linkType: hard +"statuses@npm:2.0.1": + version: 2.0.1 + resolution: "statuses@npm:2.0.1" + checksum: 18c7623fdb8f646fb213ca4051be4df7efb3484d4ab662937ca6fbef7ced9b9e12842709872eb3020cc3504b93bde88935c9f6417489627a7786f24f8031cbcb + languageName: node + linkType: hard + "statuses@npm:>= 1.4.0 < 2, statuses@npm:>= 1.5.0 < 2, statuses@npm:~1.5.0": version: 1.5.0 resolution: "statuses@npm:1.5.0" @@ -11291,6 +11545,13 @@ __metadata: languageName: node linkType: hard +"toidentifier@npm:1.0.1": + version: 1.0.1 + resolution: "toidentifier@npm:1.0.1" + checksum: 952c29e2a85d7123239b5cfdd889a0dde47ab0497f0913d70588f19c53f7e0b5327c95f4651e413c74b785147f9637b17410ac8c846d5d4a20a5a33eb6dc3a45 + languageName: node + linkType: hard + "tough-cookie@npm:~2.5.0": version: 2.5.0 resolution: "tough-cookie@npm:2.5.0" From 07441fb5263e1e01ec2b379114883b064297da17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:50:32 +0000 Subject: [PATCH 137/158] Bump qs from 6.5.2 to 6.5.3 Bumps [qs](https://github.com/ljharb/qs) from 6.5.2 to 6.5.3. - [Release notes](https://github.com/ljharb/qs/releases) - [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/qs/compare/v6.5.2...v6.5.3) --- updated-dependencies: - dependency-name: qs dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d74f90cb5..c0d92fd94 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9752,9 +9752,9 @@ __metadata: linkType: hard "qs@npm:~6.5.2": - version: 6.5.2 - resolution: "qs@npm:6.5.2" - checksum: 24af7b9928ba2141233fba2912876ff100403dba1b08b20c3b490da9ea6c636760445ea2211a079e7dfa882a5cf8f738337b3748c8bdd0f93358fa8881d2db8f + version: 6.5.3 + resolution: "qs@npm:6.5.3" + checksum: 6f20bf08cabd90c458e50855559539a28d00b2f2e7dddcb66082b16a43188418cb3cb77cbd09268bcef6022935650f0534357b8af9eeb29bf0f27ccb17655692 languageName: node linkType: hard From 541b4f0ac9e0fef2084b57e49837614a8477acc1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:51:03 +0000 Subject: [PATCH 138/158] Bump json5 from 1.0.1 to 1.0.2 Bumps [json5](https://github.com/json5/json5) from 1.0.1 to 1.0.2. - [Release notes](https://github.com/json5/json5/releases) - [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md) - [Commits](https://github.com/json5/json5/compare/v1.0.1...v1.0.2) --- updated-dependencies: - dependency-name: json5 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d74f90cb5..1b7dd5893 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6941,13 +6941,13 @@ __metadata: linkType: hard "json5@npm:^1.0.1": - version: 1.0.1 - resolution: "json5@npm:1.0.1" + version: 1.0.2 + resolution: "json5@npm:1.0.2" dependencies: minimist: ^1.2.0 bin: json5: lib/cli.js - checksum: e76ea23dbb8fc1348c143da628134a98adf4c5a4e8ea2adaa74a80c455fc2cdf0e2e13e6398ef819bfe92306b610ebb2002668ed9fc1af386d593691ef346fc3 + checksum: 866458a8c58a95a49bef3adba929c625e82532bcff1fe93f01d29cb02cac7c3fe1f4b79951b7792c2da9de0b32871a8401a6e3c5b36778ad852bf5b8a61165d7 languageName: node linkType: hard From c8b661e09253deb281bf75966129c1fe7a24290c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:52:29 +0000 Subject: [PATCH 139/158] Bump karma from 6.3.4 to 6.3.16 Bumps [karma](https://github.com/karma-runner/karma) from 6.3.4 to 6.3.16. - [Release notes](https://github.com/karma-runner/karma/releases) - [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md) - [Commits](https://github.com/karma-runner/karma/compare/v6.3.4...v6.3.16) --- updated-dependencies: - dependency-name: karma dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 219 +++++++++++++++++++++++++++------------------------ 2 files changed, 115 insertions(+), 106 deletions(-) diff --git a/package.json b/package.json index b903347f8..940b2990d 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@types/node": "^12.11.1", "cypress": "8.3.0", "jasmine-core": "~3.8.0", - "karma": "~6.3.0", + "karma": "~6.3.16", "karma-chrome-launcher": "^3.1.0", "karma-coverage": "~2.0.3", "karma-jasmine": "~4.0.0", diff --git a/yarn.lock b/yarn.lock index d74f90cb5..13521d896 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1875,6 +1875,13 @@ __metadata: languageName: node linkType: hard +"@colors/colors@npm:1.5.0": + version: 1.5.0 + resolution: "@colors/colors@npm:1.5.0" + checksum: d64d5260bed1d5012ae3fc617d38d1afc0329fec05342f4e6b838f46998855ba56e0a73833f4a80fa8378c84810da254f76a8a19c39d038260dc06dc4e007425 + languageName: node + linkType: hard + "@cspotcode/source-map-consumer@npm:0.8.0": version: 0.8.0 resolution: "@cspotcode/source-map-consumer@npm:0.8.0" @@ -2177,6 +2184,13 @@ __metadata: languageName: node linkType: hard +"@socket.io/component-emitter@npm:~3.1.0": + version: 3.1.0 + resolution: "@socket.io/component-emitter@npm:3.1.0" + checksum: db069d95425b419de1514dffe945cc439795f6a8ef5b9465715acf5b8b50798e2c91b8719cbf5434b3fe7de179d6cdcd503c277b7871cb3dd03febb69bdd50fa + languageName: node + linkType: hard + "@tootallnate/once@npm:1": version: 1.1.2 resolution: "@tootallnate/once@npm:1.1.2" @@ -2219,24 +2233,19 @@ __metadata: languageName: node linkType: hard -"@types/component-emitter@npm:^1.2.10": - version: 1.2.10 - resolution: "@types/component-emitter@npm:1.2.10" - checksum: 7589d3a10ef4e1c60f415db0d7ad90680c2d60b589972d198c19ba092f06559988dde501f83c0293e945fe19b989ef2334da07802b802d1a9846b0dde7a34ab1 - languageName: node - linkType: hard - -"@types/cookie@npm:^0.4.0": +"@types/cookie@npm:^0.4.1": version: 0.4.1 resolution: "@types/cookie@npm:0.4.1" checksum: 3275534ed69a76c68eb1a77d547d75f99fedc80befb75a3d1d03662fb08d697e6f8b1274e12af1a74c6896071b11510631ba891f64d30c78528d0ec45a9c1a18 languageName: node linkType: hard -"@types/cors@npm:^2.8.8": - version: 2.8.12 - resolution: "@types/cors@npm:2.8.12" - checksum: 8c45f112c7d1d2d831b4b266f2e6ed33a1887a35dcbfe2a18b28370751fababb7cd045e745ef84a523c33a25932678097bf79afaa367c6cb3fa0daa7a6438257 +"@types/cors@npm:^2.8.12": + version: 2.8.17 + resolution: "@types/cors@npm:2.8.17" + dependencies: + "@types/node": "*" + checksum: 469bd85e29a35977099a3745c78e489916011169a664e97c4c3d6538143b0a16e4cc72b05b407dc008df3892ed7bf595f9b7c0f1f4680e169565ee9d64966bde languageName: node linkType: hard @@ -3087,13 +3096,6 @@ __metadata: languageName: node linkType: hard -"base64-arraybuffer@npm:0.1.4": - version: 0.1.4 - resolution: "base64-arraybuffer@npm:0.1.4" - checksum: d249a929e27b2430d7ba1527e91a36e14da37ae2f80e350c4d696a038257718f8da07577e820e7262f86a0ecd573c283db10c46502080f53ae11bfdd99b6a029 - languageName: node - linkType: hard - "base64-js@npm:^1.2.0, base64-js@npm:^1.3.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" @@ -3779,7 +3781,7 @@ __metadata: languageName: node linkType: hard -"colors@npm:^1.1.2, colors@npm:^1.4.0": +"colors@npm:^1.1.2": version: 1.4.0 resolution: "colors@npm:1.4.0" checksum: 98aa2c2418ad87dedf25d781be69dc5fc5908e279d9d30c34d8b702e586a0474605b3a189511482b9d5ed0d20c867515d22749537f7bc546256c6014f3ebdcec @@ -3837,7 +3839,7 @@ __metadata: languageName: node linkType: hard -"component-emitter@npm:^1.2.1, component-emitter@npm:~1.3.0": +"component-emitter@npm:^1.2.1": version: 1.3.0 resolution: "component-emitter@npm:1.3.0" checksum: b3c46de38ffd35c57d1c02488355be9f218e582aec72d72d1b8bbec95a3ac1b38c96cd6e03ff015577e68f550fbb361a3bfdbd9bb248be9390b7b3745691be6b @@ -4402,17 +4404,10 @@ __metadata: languageName: node linkType: hard -"date-format@npm:^2.1.0": - version: 2.1.0 - resolution: "date-format@npm:2.1.0" - checksum: ff2c80c76021a315409b6ce2f08997f6e4a61ae68042dbf2cefda450207712a804aa30ac52e235f3de495dc915842507249c74e4668659835cc4870892042394 - languageName: node - linkType: hard - -"date-format@npm:^3.0.0": - version: 3.0.0 - resolution: "date-format@npm:3.0.0" - checksum: 9e1d224460d27f28fd0ce9ae72790bfb850a0d71ce97926633968d5ff9a4c86a537ff288edbe60cd4549a3c35bf5ad3b930d57cd5d579ce9da0a7e71605bdd74 +"date-format@npm:^4.0.14": + version: 4.0.14 + resolution: "date-format@npm:4.0.14" + checksum: dfe5139df6af5759b9dd3c007b899b3f60d45a9240ffeee6314ab74e6ab52e9b519a44ccf285888bdd6b626c66ee9b4c8a523075fa1140617b5beb1cbb9b18d1 languageName: node linkType: hard @@ -4453,6 +4448,18 @@ __metadata: languageName: node linkType: hard +"debug@npm:^4.3.4, debug@npm:~4.3.2, debug@npm:~4.3.4": + version: 4.3.4 + resolution: "debug@npm:4.3.4" + dependencies: + ms: 2.1.2 + peerDependenciesMeta: + supports-color: + optional: true + checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 + languageName: node + linkType: hard + "debug@npm:~3.1.0": version: 3.1.0 resolution: "debug@npm:3.1.0" @@ -4786,27 +4793,28 @@ __metadata: languageName: node linkType: hard -"engine.io-parser@npm:~4.0.0": - version: 4.0.3 - resolution: "engine.io-parser@npm:4.0.3" - dependencies: - base64-arraybuffer: 0.1.4 - checksum: 9e2db35acb6f2e8269a7c5cd8ca40d1cd7277e5c6472e7341d0f85a8d09a6788427c1f55cc5a8fa4a44213d89d2bd2494f230d0624605d88f7aae32651a3c44b +"engine.io-parser@npm:~5.2.1": + version: 5.2.2 + resolution: "engine.io-parser@npm:5.2.2" + checksum: 470231215f3136a9259efb1268bc9a71f789af4e8c74da8d3b49ceb149fe3cd5c315bf0cd13d2d8d9c8f0f051c6f93b68e8fa9c89a3b612b9217bf33765c943a languageName: node linkType: hard -"engine.io@npm:~4.1.0": - version: 4.1.1 - resolution: "engine.io@npm:4.1.1" +"engine.io@npm:~6.5.2": + version: 6.5.4 + resolution: "engine.io@npm:6.5.4" dependencies: + "@types/cookie": ^0.4.1 + "@types/cors": ^2.8.12 + "@types/node": ">=10.0.0" accepts: ~1.3.4 base64id: 2.0.0 cookie: ~0.4.1 cors: ~2.8.5 debug: ~4.3.1 - engine.io-parser: ~4.0.0 - ws: ~7.4.2 - checksum: 773fc7be6ecc2b8af95f72e6371feaa44957e481e175e614513a92307b55a33fa779d491a918af7f9071c11ad36fd52133b44d09c996baca88b5524d934ce4f7 + engine.io-parser: ~5.2.1 + ws: ~8.11.0 + checksum: d5b55cbac718c5b1c10800314379923f8c7ef9e3a8a60c6827ed86303d1154b81d354a89fdecf4cbb773515c82c84a98d3c791ff88279393b53625dd67299d30 languageName: node linkType: hard @@ -5513,10 +5521,10 @@ __metadata: languageName: node linkType: hard -"flatted@npm:^2.0.1": - version: 2.0.2 - resolution: "flatted@npm:2.0.2" - checksum: 473c754db7a529e125a22057098f1a4c905ba17b8cc269c3acf77352f0ffa6304c851eb75f6a1845f74461f560e635129ca6b0b8a78fb253c65cea4de3d776f2 +"flatted@npm:^3.2.7": + version: 3.3.1 + resolution: "flatted@npm:3.3.1" + checksum: 85ae7181650bb728c221e7644cbc9f4bf28bc556f2fc89bb21266962bdf0ce1029cc7acc44bb646cd469d9baac7c317f64e841c4c4c00516afa97320cdac7f94 languageName: node linkType: hard @@ -7078,14 +7086,14 @@ __metadata: languageName: node linkType: hard -"karma@npm:~6.3.0": - version: 6.3.4 - resolution: "karma@npm:6.3.4" +"karma@npm:~6.3.16": + version: 6.3.20 + resolution: "karma@npm:6.3.20" dependencies: + "@colors/colors": 1.5.0 body-parser: ^1.19.0 braces: ^3.0.2 chokidar: ^3.5.1 - colors: ^1.4.0 connect: ^3.7.0 di: ^0.0.1 dom-serialize: ^2.2.1 @@ -7094,20 +7102,21 @@ __metadata: http-proxy: ^1.18.1 isbinaryfile: ^4.0.8 lodash: ^4.17.21 - log4js: ^6.3.0 + log4js: ^6.4.1 mime: ^2.5.2 minimatch: ^3.0.4 + mkdirp: ^0.5.5 qjobs: ^1.2.0 range-parser: ^1.2.1 rimraf: ^3.0.2 - socket.io: ^3.1.0 + socket.io: ^4.4.1 source-map: ^0.6.1 tmp: ^0.2.1 - ua-parser-js: ^0.7.28 + ua-parser-js: ^0.7.30 yargs: ^16.1.1 bin: karma: bin/karma - checksum: d8850275a7ba7447e37e19835594584eb112e286dd5db08fea4630cbe519551c0b5b477a2dd7e1583f7371ec54ae26620abcb9c96344118aa12d16bbed3dbb03 + checksum: 7060afc367c49b2ce2e145f6555c428eadfd72bd68a5d4ae392ec51c8d1c0484706fdd52cfd06d69a811c25517fd5129689a69173be850814dc68c3b7eafa6c8 languageName: node linkType: hard @@ -7367,16 +7376,16 @@ __metadata: languageName: node linkType: hard -"log4js@npm:^6.3.0": - version: 6.3.0 - resolution: "log4js@npm:6.3.0" +"log4js@npm:^6.4.1": + version: 6.9.1 + resolution: "log4js@npm:6.9.1" dependencies: - date-format: ^3.0.0 - debug: ^4.1.1 - flatted: ^2.0.1 - rfdc: ^1.1.4 - streamroller: ^2.2.4 - checksum: da2812bbe477d0594154562d63c8b23030d4a31964bbf9d5b708f528eb57adb9e4c2eec4caf087400776b5758e4f5e5a5ef90c1453bec471aba2a8c42ee9176c + date-format: ^4.0.14 + debug: ^4.3.4 + flatted: ^3.2.7 + rfdc: ^1.3.0 + streamroller: ^3.1.5 + checksum: 59d98c37d4163138dab5d9b06ae26965d1353106fece143973d57b1003b3a482791aa21374fd2cca81a953b8837b2f9756ac225404e60cbfa4dd3ab59f082e2e languageName: node linkType: hard @@ -7483,7 +7492,7 @@ __metadata: font-awesome: 4.7.0 jasmine-core: ~3.8.0 jquery: 3.5.0 - karma: ~6.3.0 + karma: ~6.3.16 karma-chrome-launcher: ^3.1.0 karma-coverage: ~2.0.3 karma-jasmine: ~4.0.0 @@ -10165,10 +10174,10 @@ __metadata: languageName: node linkType: hard -"rfdc@npm:^1.1.4": - version: 1.3.0 - resolution: "rfdc@npm:1.3.0" - checksum: fb2ba8512e43519983b4c61bd3fa77c0f410eff6bae68b08614437bc3f35f91362215f7b4a73cbda6f67330b5746ce07db5dd9850ad3edc91271ad6deea0df32 +"rfdc@npm:^1.3.0": + version: 1.3.1 + resolution: "rfdc@npm:1.3.1" + checksum: d5d1e930aeac7e0e0a485f97db1356e388bdbeff34906d206fe524dd5ada76e95f186944d2e68307183fdc39a54928d4426bbb6734851692cfe9195efba58b79 languageName: node linkType: hard @@ -10613,38 +10622,38 @@ __metadata: languageName: node linkType: hard -"socket.io-adapter@npm:~2.1.0": - version: 2.1.0 - resolution: "socket.io-adapter@npm:2.1.0" - checksum: d5b18b1c007066adcfb4737ac835834e4191221179c50334314605b077df2468a37a9ba2d37626f740ecf6b2adef7b6b7bb7dae6e262e5561d36814910a0a8b0 +"socket.io-adapter@npm:~2.5.2": + version: 2.5.4 + resolution: "socket.io-adapter@npm:2.5.4" + dependencies: + debug: ~4.3.4 + ws: ~8.11.0 + checksum: 7dea1d606a039d494f31fe06a9d84e4318704e3e61c1c5b917befe13f03dd9ee1a6564775a5ee92a444e8caaa83555e850e0da855cefa436d18cdbd638b3bb51 languageName: node linkType: hard -"socket.io-parser@npm:~4.0.3": - version: 4.0.4 - resolution: "socket.io-parser@npm:4.0.4" +"socket.io-parser@npm:~4.2.4": + version: 4.2.4 + resolution: "socket.io-parser@npm:4.2.4" dependencies: - "@types/component-emitter": ^1.2.10 - component-emitter: ~1.3.0 + "@socket.io/component-emitter": ~3.1.0 debug: ~4.3.1 - checksum: c173b4f3747c51e2af802eca35212f4dcfa8fe55d7fdc07b9a01da1ecc956791c1bf6591e307952548eab69e6500bcfe27cea8aff1386b860d9bb51f98e4fafb + checksum: 61540ef99af33e6a562b9effe0fad769bcb7ec6a301aba5a64b3a8bccb611a0abdbe25f469933ab80072582006a78ca136bf0ad8adff9c77c9953581285e2263 languageName: node linkType: hard -"socket.io@npm:^3.1.0": - version: 3.1.2 - resolution: "socket.io@npm:3.1.2" +"socket.io@npm:^4.4.1": + version: 4.7.4 + resolution: "socket.io@npm:4.7.4" dependencies: - "@types/cookie": ^0.4.0 - "@types/cors": ^2.8.8 - "@types/node": ">=10.0.0" accepts: ~1.3.4 base64id: ~2.0.0 - debug: ~4.3.1 - engine.io: ~4.1.0 - socket.io-adapter: ~2.1.0 - socket.io-parser: ~4.0.3 - checksum: 3fa5296f9f917c8765ff150030308aac6198baeceb7182f62cfee8d5696fad2c8ebef2364d8bb8910be5e299752394afac68c1819f5ea79abaa524038ed09596 + cors: ~2.8.5 + debug: ~4.3.2 + engine.io: ~6.5.2 + socket.io-adapter: ~2.5.2 + socket.io-parser: ~4.2.4 + checksum: 63bb2b0c1168beb7a79b60541def09d4de23f10f206e2e36e7a1ec1ef3d1f2f3143264878e026ceacdd26b52a37da74606c44e95da6651b4980cad5bfcc291a9 languageName: node linkType: hard @@ -10879,14 +10888,14 @@ __metadata: languageName: node linkType: hard -"streamroller@npm:^2.2.4": - version: 2.2.4 - resolution: "streamroller@npm:2.2.4" +"streamroller@npm:^3.1.5": + version: 3.1.5 + resolution: "streamroller@npm:3.1.5" dependencies: - date-format: ^2.1.0 - debug: ^4.1.1 + date-format: ^4.0.14 + debug: ^4.3.4 fs-extra: ^8.1.0 - checksum: 83060ded804747d2a9f202f142d24680a01f3bc5e36e9bd746b3e530252bbbf29a8030659f3c66e2dcd3d1ce403144bd302d9b4e51be0f9ed7d2f371a13d166b + checksum: c1df5612b785ffa4b6bbf16460590b62994c57265bc55a5166eebeeb0daf648e84bc52dc6d57e0cd4e5c7609bda93076753c63ff54589febd1e0b95590f0e443 languageName: node linkType: hard @@ -11439,10 +11448,10 @@ __metadata: languageName: node linkType: hard -"ua-parser-js@npm:^0.7.28": - version: 0.7.28 - resolution: "ua-parser-js@npm:0.7.28" - checksum: a7da4ad54527211e878ee016c2ef64efad5c2f5a31277d36c9da93b4c89ecaa64f391ad4cf158ada76a9ad8e53004a950705ff1c2f27a52ca8bfb3f1381c39ff +"ua-parser-js@npm:^0.7.30": + version: 0.7.37 + resolution: "ua-parser-js@npm:0.7.37" + checksum: 9e91a66171aa16c74680cfac84af6ed7ecdeb508ff7c90a55222f56c63172da2d98d2478763e9469c940415fe29c45a56ae51fec1c19a498e7a3b293f7b3b874 languageName: node linkType: hard @@ -12003,9 +12012,9 @@ __metadata: languageName: node linkType: hard -"ws@npm:~7.4.2": - version: 7.4.6 - resolution: "ws@npm:7.4.6" +"ws@npm:~8.11.0": + version: 8.11.0 + resolution: "ws@npm:8.11.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -12014,7 +12023,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 3a990b32ed08c72070d5e8913e14dfcd831919205be52a3ff0b4cdd998c8d554f167c9df3841605cde8b11d607768cacab3e823c58c96a5c08c987e093eb767a + checksum: 316b33aba32f317cd217df66dbfc5b281a2f09ff36815de222bc859e3424d83766d9eb2bd4d667de658b6ab7be151f258318fb1da812416b30be13103e5b5c67 languageName: node linkType: hard From 76f298fca301c0fa3125a37ddc4400375c6d5555 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:54:22 +0000 Subject: [PATCH 140/158] Bump nanoid from 3.1.25 to 3.3.7 Bumps [nanoid](https://github.com/ai/nanoid) from 3.1.25 to 3.3.7. - [Release notes](https://github.com/ai/nanoid/releases) - [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md) - [Commits](https://github.com/ai/nanoid/compare/3.1.25...3.3.7) --- updated-dependencies: - dependency-name: nanoid dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index d74f90cb5..f2b95f9aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7925,21 +7925,12 @@ __metadata: languageName: node linkType: hard -"nanoid@npm:^3.1.23": - version: 3.1.25 - resolution: "nanoid@npm:3.1.25" +"nanoid@npm:^3.1.23, nanoid@npm:^3.1.30": + version: 3.3.7 + resolution: "nanoid@npm:3.3.7" bin: nanoid: bin/nanoid.cjs - checksum: e2353828c7d8fde65265e9c981380102e2021f292038a93fd27288bad390339833286e8cbc7531abe1cb2c6b317e55f38b895dcb775151637bb487388558e0ff - languageName: node - linkType: hard - -"nanoid@npm:^3.1.30": - version: 3.1.30 - resolution: "nanoid@npm:3.1.30" - bin: - nanoid: bin/nanoid.cjs - checksum: 276d0d4b0c41c46aeefec5f09f093e4085a2352d06881c845db22b84f8ef72cc8defae6d76bfb1d8a2a128eb2dec42ab148d16582be4e7754c97905806ef57b6 + checksum: d36c427e530713e4ac6567d488b489a36582ef89da1d6d4e3b87eded11eb10d7042a877958c6f104929809b2ab0bafa17652b076cdf84324aa75b30b722204f2 languageName: node linkType: hard From 9a942db72b74cdd81600f044e09ba6778d1c9298 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:54:44 +0000 Subject: [PATCH 141/158] Bump decode-uri-component from 0.2.0 to 0.2.2 Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2. - [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases) - [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2) --- updated-dependencies: - dependency-name: decode-uri-component dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d74f90cb5..c540ffe20 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4470,9 +4470,9 @@ __metadata: linkType: hard "decode-uri-component@npm:^0.2.0": - version: 0.2.0 - resolution: "decode-uri-component@npm:0.2.0" - checksum: f3749344ab9305ffcfe4bfe300e2dbb61fc6359e2b736812100a3b1b6db0a5668cba31a05e4b45d4d63dbf1a18dfa354cd3ca5bb3ededddabb8cd293f4404f94 + version: 0.2.2 + resolution: "decode-uri-component@npm:0.2.2" + checksum: 95476a7d28f267292ce745eac3524a9079058bbb35767b76e3ee87d42e34cd0275d2eb19d9d08c3e167f97556e8a2872747f5e65cbebcac8b0c98d83e285f139 languageName: node linkType: hard From f11e332347df3c5772ab5168a121993475c161ac Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 12:55:25 +0000 Subject: [PATCH 142/158] Bump url-parse from 1.5.3 to 1.5.10 Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.3 to 1.5.10. - [Release notes](https://github.com/unshiftio/url-parse/releases) - [Commits](https://github.com/unshiftio/url-parse/compare/1.5.3...1.5.10) --- updated-dependencies: - dependency-name: url-parse dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d74f90cb5..007b49215 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11583,12 +11583,12 @@ __metadata: linkType: hard "url-parse@npm:^1.4.3, url-parse@npm:^1.5.3": - version: 1.5.3 - resolution: "url-parse@npm:1.5.3" + version: 1.5.10 + resolution: "url-parse@npm:1.5.10" dependencies: querystringify: ^2.1.1 requires-port: ^1.0.0 - checksum: c6b32fff835e43f3b1b4150239f459744f0ab1a908841dbfecbfc79bf67f4d6c8d9af1841d0c6d814d45bfa08525cc29312a0bef31db7aa894306b3db07e4ee0 + checksum: fbdba6b1d83336aca2216bbdc38ba658d9cfb8fc7f665eb8b17852de638ff7d1a162c198a8e4ed66001ddbf6c9888d41e4798912c62b4fd777a31657989f7bdf languageName: node linkType: hard From 6b64523e71c6ff69010080a554e8382cfa1f583a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 13:00:41 +0000 Subject: [PATCH 143/158] Bump follow-redirects from 1.14.2 to 1.15.5 Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.2 to 1.15.5. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.2...v1.15.5) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d74f90cb5..d5849355a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5528,12 +5528,12 @@ __metadata: linkType: hard "follow-redirects@npm:^1.0.0": - version: 1.14.2 - resolution: "follow-redirects@npm:1.14.2" + version: 1.15.5 + resolution: "follow-redirects@npm:1.15.5" peerDependenciesMeta: debug: optional: true - checksum: 53195df4a2f36202177f40a2d59d497d630f3b20e2e51e2b697ee5f9c0a5261985f164b23d3744a574e117618af668d07c0d000c2c5cb0c1546851671585ac4e + checksum: 5ca49b5ce6f44338cbfc3546823357e7a70813cecc9b7b768158a1d32c1e62e7407c944402a918ea8c38ae2e78266312d617dc68783fac502cbb55e1047b34ec languageName: node linkType: hard From 841a8b5feaf630da3a046d4f9f273021239df1ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 13:01:35 +0000 Subject: [PATCH 144/158] Bump async from 2.6.3 to 2.6.4 Bumps [async](https://github.com/caolan/async) from 2.6.3 to 2.6.4. - [Release notes](https://github.com/caolan/async/releases) - [Changelog](https://github.com/caolan/async/blob/v2.6.4/CHANGELOG.md) - [Commits](https://github.com/caolan/async/compare/v2.6.3...v2.6.4) --- updated-dependencies: - dependency-name: async dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d74f90cb5..24547ece0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2951,11 +2951,11 @@ __metadata: linkType: hard "async@npm:^2.6.2": - version: 2.6.3 - resolution: "async@npm:2.6.3" + version: 2.6.4 + resolution: "async@npm:2.6.4" dependencies: lodash: ^4.17.14 - checksum: 5e5561ff8fca807e88738533d620488ac03a5c43fce6c937451f7e35f943d33ad06c24af3f681a48cca3d2b0002b3118faff0a128dc89438a9bf0226f712c499 + checksum: a52083fb32e1ebe1d63e5c5624038bb30be68ff07a6c8d7dfe35e47c93fc144bd8652cbec869e0ac07d57dde387aa5f1386be3559cdee799cb1f789678d88e19 languageName: node linkType: hard From 0e20c75a12e83f874c5dacf928f4405c5d119139 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 13:21:50 +0000 Subject: [PATCH 145/158] Bump log4js from 6.3.0 to 6.9.1 Bumps [log4js](https://github.com/log4js-node/log4js-node) from 6.3.0 to 6.9.1. - [Changelog](https://github.com/log4js-node/log4js-node/blob/master/CHANGELOG.md) - [Commits](https://github.com/log4js-node/log4js-node/compare/v6.3.0...v6.9.1) --- updated-dependencies: - dependency-name: log4js dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 71 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/yarn.lock b/yarn.lock index d74f90cb5..a2efac842 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4402,17 +4402,10 @@ __metadata: languageName: node linkType: hard -"date-format@npm:^2.1.0": - version: 2.1.0 - resolution: "date-format@npm:2.1.0" - checksum: ff2c80c76021a315409b6ce2f08997f6e4a61ae68042dbf2cefda450207712a804aa30ac52e235f3de495dc915842507249c74e4668659835cc4870892042394 - languageName: node - linkType: hard - -"date-format@npm:^3.0.0": - version: 3.0.0 - resolution: "date-format@npm:3.0.0" - checksum: 9e1d224460d27f28fd0ce9ae72790bfb850a0d71ce97926633968d5ff9a4c86a537ff288edbe60cd4549a3c35bf5ad3b930d57cd5d579ce9da0a7e71605bdd74 +"date-format@npm:^4.0.14": + version: 4.0.14 + resolution: "date-format@npm:4.0.14" + checksum: dfe5139df6af5759b9dd3c007b899b3f60d45a9240ffeee6314ab74e6ab52e9b519a44ccf285888bdd6b626c66ee9b4c8a523075fa1140617b5beb1cbb9b18d1 languageName: node linkType: hard @@ -4453,6 +4446,18 @@ __metadata: languageName: node linkType: hard +"debug@npm:^4.3.4": + version: 4.3.4 + resolution: "debug@npm:4.3.4" + dependencies: + ms: 2.1.2 + peerDependenciesMeta: + supports-color: + optional: true + checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 + languageName: node + linkType: hard + "debug@npm:~3.1.0": version: 3.1.0 resolution: "debug@npm:3.1.0" @@ -5513,10 +5518,10 @@ __metadata: languageName: node linkType: hard -"flatted@npm:^2.0.1": - version: 2.0.2 - resolution: "flatted@npm:2.0.2" - checksum: 473c754db7a529e125a22057098f1a4c905ba17b8cc269c3acf77352f0ffa6304c851eb75f6a1845f74461f560e635129ca6b0b8a78fb253c65cea4de3d776f2 +"flatted@npm:^3.2.7": + version: 3.3.1 + resolution: "flatted@npm:3.3.1" + checksum: 85ae7181650bb728c221e7644cbc9f4bf28bc556f2fc89bb21266962bdf0ce1029cc7acc44bb646cd469d9baac7c317f64e841c4c4c00516afa97320cdac7f94 languageName: node linkType: hard @@ -7368,15 +7373,15 @@ __metadata: linkType: hard "log4js@npm:^6.3.0": - version: 6.3.0 - resolution: "log4js@npm:6.3.0" + version: 6.9.1 + resolution: "log4js@npm:6.9.1" dependencies: - date-format: ^3.0.0 - debug: ^4.1.1 - flatted: ^2.0.1 - rfdc: ^1.1.4 - streamroller: ^2.2.4 - checksum: da2812bbe477d0594154562d63c8b23030d4a31964bbf9d5b708f528eb57adb9e4c2eec4caf087400776b5758e4f5e5a5ef90c1453bec471aba2a8c42ee9176c + date-format: ^4.0.14 + debug: ^4.3.4 + flatted: ^3.2.7 + rfdc: ^1.3.0 + streamroller: ^3.1.5 + checksum: 59d98c37d4163138dab5d9b06ae26965d1353106fece143973d57b1003b3a482791aa21374fd2cca81a953b8837b2f9756ac225404e60cbfa4dd3ab59f082e2e languageName: node linkType: hard @@ -10165,10 +10170,10 @@ __metadata: languageName: node linkType: hard -"rfdc@npm:^1.1.4": - version: 1.3.0 - resolution: "rfdc@npm:1.3.0" - checksum: fb2ba8512e43519983b4c61bd3fa77c0f410eff6bae68b08614437bc3f35f91362215f7b4a73cbda6f67330b5746ce07db5dd9850ad3edc91271ad6deea0df32 +"rfdc@npm:^1.3.0": + version: 1.3.1 + resolution: "rfdc@npm:1.3.1" + checksum: d5d1e930aeac7e0e0a485f97db1356e388bdbeff34906d206fe524dd5ada76e95f186944d2e68307183fdc39a54928d4426bbb6734851692cfe9195efba58b79 languageName: node linkType: hard @@ -10879,14 +10884,14 @@ __metadata: languageName: node linkType: hard -"streamroller@npm:^2.2.4": - version: 2.2.4 - resolution: "streamroller@npm:2.2.4" +"streamroller@npm:^3.1.5": + version: 3.1.5 + resolution: "streamroller@npm:3.1.5" dependencies: - date-format: ^2.1.0 - debug: ^4.1.1 + date-format: ^4.0.14 + debug: ^4.3.4 fs-extra: ^8.1.0 - checksum: 83060ded804747d2a9f202f142d24680a01f3bc5e36e9bd746b3e530252bbbf29a8030659f3c66e2dcd3d1ce403144bd302d9b4e51be0f9ed7d2f371a13d166b + checksum: c1df5612b785ffa4b6bbf16460590b62994c57265bc55a5166eebeeb0daf648e84bc52dc6d57e0cd4e5c7609bda93076753c63ff54589febd1e0b95590f0e443 languageName: node linkType: hard From ffa320cb16b168383b0703d026924e703ffc4b76 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 13:19:05 +0000 Subject: [PATCH 146/158] Bump ua-parser-js from 0.7.28 to 0.7.37 Bumps [ua-parser-js](https://github.com/faisalman/ua-parser-js) from 0.7.28 to 0.7.37. - [Release notes](https://github.com/faisalman/ua-parser-js/releases) - [Changelog](https://github.com/faisalman/ua-parser-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/faisalman/ua-parser-js/compare/0.7.28...0.7.37) --- updated-dependencies: - dependency-name: ua-parser-js dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 976932d1d..a277ca26c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11700,7 +11700,7 @@ __metadata: languageName: node linkType: hard -"ua-parser-js@npm:^0.7.30": +"ua-parser-js@npm:^0.7.28": version: 0.7.37 resolution: "ua-parser-js@npm:0.7.37" checksum: 9e91a66171aa16c74680cfac84af6ed7ecdeb508ff7c90a55222f56c63172da2d98d2478763e9469c940415fe29c45a56ae51fec1c19a498e7a3b293f7b3b874 From 093db25f427d335875a272feb8ff3c351007e5db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:27:11 +0000 Subject: [PATCH 147/158] Bump loader-utils from 1.4.0 to 1.4.2 Bumps [loader-utils](https://github.com/webpack/loader-utils) from 1.4.0 to 1.4.2. - [Release notes](https://github.com/webpack/loader-utils/releases) - [Changelog](https://github.com/webpack/loader-utils/blob/v1.4.2/CHANGELOG.md) - [Commits](https://github.com/webpack/loader-utils/compare/v1.4.0...v1.4.2) --- updated-dependencies: - dependency-name: loader-utils dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index d74f90cb5..df76e8213 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7274,13 +7274,13 @@ __metadata: linkType: hard "loader-utils@npm:^1.4.0": - version: 1.4.0 - resolution: "loader-utils@npm:1.4.0" + version: 1.4.2 + resolution: "loader-utils@npm:1.4.2" dependencies: big.js: ^5.2.2 emojis-list: ^3.0.0 json5: ^1.0.1 - checksum: d150b15e7a42ac47d935c8b484b79e44ff6ab4c75df7cc4cb9093350cf014ec0b17bdb60c5d6f91a37b8b218bd63b973e263c65944f58ca2573e402b9a27e717 + checksum: eb6fb622efc0ffd1abdf68a2022f9eac62bef8ec599cf8adb75e94d1d338381780be6278534170e99edc03380a6d29bc7eb1563c89ce17c5fed3a0b17f1ad804 languageName: node linkType: hard From eb5e4930175b6fb060b872e83e97b411e2b1c554 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 23 Feb 2024 16:34:56 +0100 Subject: [PATCH 148/158] Manually bump minimatch to fix #685 --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index cf6ed0275..1ce5cb986 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8247,11 +8247,11 @@ __metadata: linkType: hard "minimatch@npm:3.0.4, minimatch@npm:^3.0.4": - version: 3.0.4 - resolution: "minimatch@npm:3.0.4" + version: 3.0.5 + resolution: "minimatch@npm:3.0.5" dependencies: brace-expansion: ^1.1.7 - checksum: 66ac295f8a7b59788000ea3749938b0970344c841750abd96694f80269b926ebcafad3deeb3f1da2522978b119e6ae3a5869b63b13a7859a456b3408bd18a078 + checksum: a3b84b426eafca947741b864502cee02860c4e7b145de11ad98775cfcf3066fef422583bc0ffce0952ddf4750c1ccf4220b1556430d4ce10139f66247d87d69e languageName: node linkType: hard From a36e16ddd4f6d925c38c6a51c4b0137d85215e14 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 23 Feb 2024 16:39:38 +0100 Subject: [PATCH 149/158] postgresql to 42.6.1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index cfedaf791..0b0715c7e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -7,7 +7,7 @@ hazelcast_hibernate_version=5.1.0 hikaricp_version=5.0.1 liquibase_slf4j_version=4.1.0 liquibase_version=4.22.0 -postgresql_version=42.6.0 +postgresql_version=42.6.1 springdoc_version=1.6.15 spring_boot_version=2.7.15 spring_framework_version=5.3.27 From f2cd6ec0a6672d6060755ce72bb70292a9b5b3f9 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 23 Feb 2024 16:50:29 +0100 Subject: [PATCH 150/158] manual snyk fixes --- build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 3ddc5d791..34e09164b 100644 --- a/build.gradle +++ b/build.gradle @@ -165,10 +165,10 @@ dependencies { implementation group: 'com.google.code.findbugs', name: 'jsr305', version: findbugAnnotationVersion implementation("org.liquibase:liquibase-core:${liquibase_version}") runtimeOnly "com.mattbertolini:liquibase-slf4j:${liquibase_slf4j_version}" - implementation("org.springframework.boot:spring-boot-starter-actuator") + implementation("org.springframework.boot:spring-boot-starter-actuator:3.0.0") implementation("org.springframework.boot:spring-boot-autoconfigure") implementation "org.springframework.boot:spring-boot-starter-mail" - runtimeOnly "org.springframework.boot:spring-boot-starter-logging" + runtimeOnly "org.springframework.boot:spring-boot-starter-logging:3.1.7" runtimeOnly ("org.springframework.boot:spring-boot-starter-data-jpa") { exclude group: 'org.hibernate', module: 'hibernate-entitymanager' } @@ -183,7 +183,7 @@ dependencies { runtimeOnly "org.springframework.boot:spring-boot-starter-security" implementation "org.springframework.security:spring-security-data" - implementation("org.springframework.boot:spring-boot-starter-web") { + implementation("org.springframework.boot:spring-boot-starter-web:3.1.9") { exclude module: 'spring-boot-starter-tomcat' } implementation ("org.springframework.boot:spring-boot-starter-undertow") @@ -199,7 +199,7 @@ dependencies { implementation("org.springframework.session:spring-session-hazelcast") implementation('org.springframework.security.oauth:spring-security-oauth2:2.5.2.RELEASE') - implementation('org.springframework.security:spring-security-web:5.7.8') + implementation('org.springframework.security:spring-security-web:5.8.1') implementation "org.springdoc:springdoc-openapi-ui:${springdoc_version}" runtimeOnly("javax.inject:javax.inject:1") implementation project(':radar-auth') From 0aa808b15b20bd616aeb708aab573d2ff5ae4e4e Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 23 Feb 2024 16:53:56 +0100 Subject: [PATCH 151/158] run yarn install to fix yarn.lock file --- yarn.lock | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1ce5cb986..4f1529caf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2087,6 +2087,13 @@ __metadata: languageName: node linkType: hard +"@colors/colors@npm:1.5.0": + version: 1.5.0 + resolution: "@colors/colors@npm:1.5.0" + checksum: d64d5260bed1d5012ae3fc617d38d1afc0329fec05342f4e6b838f46998855ba56e0a73833f4a80fa8378c84810da254f76a8a19c39d038260dc06dc4e007425 + languageName: node + linkType: hard + "@cspotcode/source-map-consumer@npm:0.8.0": version: 0.8.0 resolution: "@cspotcode/source-map-consumer@npm:0.8.0" @@ -4784,7 +4791,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:^4.3.4": +"debug@npm:^4.3.4, debug@npm:~4.3.2, debug@npm:~4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -6075,7 +6082,7 @@ __metadata: "fsevents@patch:fsevents@^1.2.7#~builtin": version: 1.2.13 - resolution: "fsevents@patch:fsevents@npm%3A1.2.13#~builtin::version=1.2.13&hash=18f3a7" + resolution: "fsevents@patch:fsevents@npm%3A1.2.13#~builtin::version=1.2.13&hash=d11327" dependencies: bindings: ^1.5.0 nan: ^2.12.1 @@ -6085,7 +6092,7 @@ __metadata: "fsevents@patch:fsevents@~2.3.2#~builtin": version: 2.3.2 - resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=18f3a7" + resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" dependencies: node-gyp: latest conditions: os=darwin @@ -10671,7 +10678,7 @@ __metadata: "resolve@patch:resolve@1.20.0#~builtin, resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.14.2#~builtin": version: 1.20.0 - resolution: "resolve@patch:resolve@npm%3A1.20.0#~builtin::version=1.20.0&hash=07638b" + resolution: "resolve@patch:resolve@npm%3A1.20.0#~builtin::version=1.20.0&hash=c3c19d" dependencies: is-core-module: ^2.2.0 path-parse: ^1.0.6 @@ -10950,9 +10957,9 @@ __metadata: languageName: node linkType: hard -"send@npm:0.17.1": - version: 0.17.1 - resolution: "send@npm:0.17.1" +"send@npm:0.18.0": + version: 0.18.0 + resolution: "send@npm:0.18.0" dependencies: debug: 2.6.9 depd: 2.0.0 @@ -12052,7 +12059,7 @@ __metadata: "typescript@patch:typescript@4.3.5#~builtin, typescript@patch:typescript@~4.3.5#~builtin": version: 4.3.5 - resolution: "typescript@patch:typescript@npm%3A4.3.5#~builtin::version=4.3.5&hash=701156" + resolution: "typescript@patch:typescript@npm%3A4.3.5#~builtin::version=4.3.5&hash=dba6d9" bin: tsc: bin/tsc tsserver: bin/tsserver @@ -12060,7 +12067,7 @@ __metadata: languageName: node linkType: hard -"ua-parser-js@npm:^0.7.28": +"ua-parser-js@npm:^0.7.30": version: 0.7.37 resolution: "ua-parser-js@npm:0.7.37" checksum: 9e91a66171aa16c74680cfac84af6ed7ecdeb508ff7c90a55222f56c63172da2d98d2478763e9469c940415fe29c45a56ae51fec1c19a498e7a3b293f7b3b874 From 81d13a6fa0084ceac5df2616da670a89e2492864 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Fri, 23 Feb 2024 17:12:32 +0100 Subject: [PATCH 152/158] snyk fixes --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 34e09164b..11659a8d1 100644 --- a/build.gradle +++ b/build.gradle @@ -168,7 +168,7 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-actuator:3.0.0") implementation("org.springframework.boot:spring-boot-autoconfigure") implementation "org.springframework.boot:spring-boot-starter-mail" - runtimeOnly "org.springframework.boot:spring-boot-starter-logging:3.1.7" + runtimeOnly "org.springframework.boot:spring-boot-starter-logging:3.2.2" runtimeOnly ("org.springframework.boot:spring-boot-starter-data-jpa") { exclude group: 'org.hibernate', module: 'hibernate-entitymanager' } @@ -199,7 +199,7 @@ dependencies { implementation("org.springframework.session:spring-session-hazelcast") implementation('org.springframework.security.oauth:spring-security-oauth2:2.5.2.RELEASE') - implementation('org.springframework.security:spring-security-web:5.8.1') + implementation('org.springframework.security:spring-security-web:5.8.10') implementation "org.springdoc:springdoc-openapi-ui:${springdoc_version}" runtimeOnly("javax.inject:javax.inject:1") implementation project(':radar-auth') From 7ce905cfbcd1e705ffbb4215d4814505e5edcbc1 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 6 Mar 2024 12:51:55 +0100 Subject: [PATCH 153/158] Bump eventsource from 1.1.0 to 1.1.2 --- yarn.lock | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4f1529caf..caf8f2875 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5572,11 +5572,9 @@ __metadata: linkType: hard "eventsource@npm:^1.0.7": - version: 1.1.0 - resolution: "eventsource@npm:1.1.0" - dependencies: - original: ^1.0.0 - checksum: 78338b7e75ec471cb793efb3319e0c4d2bf00fb638a2e3f888ad6d98cd1e3d4492a29f554c0921c7b2ac5130c3a732a1a0056739f6e2f548d714aec685e5da7e + version: 1.1.2 + resolution: "eventsource@npm:1.1.2" + checksum: fe8f2ac3c70b1b63ee3cef5c0a28680cb00b5747bfda1d9835695fab3ed602be41c5c799b1fc997b34b02633573fead25b12b036bdf5212f23a6aa9f59212e9b languageName: node linkType: hard @@ -8983,15 +8981,6 @@ __metadata: languageName: node linkType: hard -"original@npm:^1.0.0": - version: 1.0.2 - resolution: "original@npm:1.0.2" - dependencies: - url-parse: ^1.4.3 - checksum: 8dca9311dab50c8953366127cb86b7c07bf547d6aa6dc6873a75964b7563825351440557e5724d9c652c5e99043b8295624f106af077f84bccf19592e421beb9 - languageName: node - linkType: hard - "os-tmpdir@npm:~1.0.2": version: 1.0.2 resolution: "os-tmpdir@npm:1.0.2" From 84d44c884386390f565cd0c740cf0c973dd74b03 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 6 Mar 2024 13:18:04 +0100 Subject: [PATCH 154/158] version reorganization --- build.gradle | 14 +++++++------- gradle.properties | 14 ++++++++++---- radar-auth/build.gradle | 16 ++++++++-------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/build.gradle b/build.gradle index 11659a8d1..4a90078a2 100644 --- a/build.gradle +++ b/build.gradle @@ -149,15 +149,15 @@ if (project.hasProperty('prod')) { ext.findbugAnnotationVersion = '3.0.2' dependencies { - implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.10") + implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlin_version}") implementation("tech.jhipster:jhipster-framework:${jhipster_server_version}") implementation("tech.jhipster:jhipster-dependencies:${jhipster_server_version}") - implementation("io.micrometer:micrometer-core") - runtimeOnly "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" - implementation "com.fasterxml.jackson.datatype:jackson-datatype-hibernate5" - implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-csv" - implementation "com.fasterxml.jackson.core:jackson-annotations" - implementation "com.fasterxml.jackson.core:jackson-databind" + implementation("io.micrometer:micrometer-core:${micrometer_version}") + runtimeOnly "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:${jackson_version}" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:${jackson_version}" + implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-csv:${jackson_version}" + implementation "com.fasterxml.jackson.core:jackson-annotations:${jackson_version}" + implementation "com.fasterxml.jackson.core:jackson-databind:${jackson_version}" implementation "com.hazelcast:hazelcast:${hazelcast_version}" implementation "com.hazelcast:hazelcast-spring:${hazelcast_version}" runtimeOnly "com.hazelcast:hazelcast-hibernate53:${hazelcast_hibernate_version}" diff --git a/gradle.properties b/gradle.properties index 0b0715c7e..dad6dc5e8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ rootProject.name=management-portal profile=dev assertj_version=3.23.1 jhipster_server_version=7.9.3 -hazelcast_version=5.2.4 +hazelcast_version=5.2.5 hazelcast_hibernate_version=5.1.0 hikaricp_version=5.0.1 liquibase_slf4j_version=4.1.0 @@ -16,7 +16,7 @@ thymeleaf_version=3.1.2.RELEASE spring_session_version=2021.2.0 gatling_version=3.8.4 mapstruct_version=1.5.5.Final -jackson_version=2.15.2 +jackson_version=2.16.1 javax_xml_bind_version=2.3.3 javax_jaxb_core_version=2.3.0.1 javax_jaxb_runtime_version=2.3.8 @@ -29,8 +29,14 @@ oauth_jwt_version=4.4.0 junit_version=5.10.0 okhttp_version=4.10.0 hsqldb_version=2.7.2 -coroutines_version=1.7.3 -ktor_version=2.3.3 +coroutines_version=1.8.0 +ktor_version=2.3.9 +radar_commons_version=1.1.0 +hamcrest_version=2.2 +wiremock_version=3.0.1 +kotlin_version=1.9.10 +micrometer_version=1.12.3 + kotlin.code.style=official org.gradle.vfs.watch=true diff --git a/radar-auth/build.gradle b/radar-auth/build.gradle index 4d4be8380..e8c5cb595 100644 --- a/radar-auth/build.gradle +++ b/radar-auth/build.gradle @@ -17,21 +17,21 @@ description = 'Library for authentication and authorization of JWT tokens issued dependencies { api group: 'com.auth0', name: 'java-jwt', version: oauth_jwt_version api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:$coroutines_version")) - api("org.jetbrains.kotlinx:kotlinx-coroutines-core") + api("org.jetbrains.kotlinx:kotlinx-coroutines-core$coroutines_version") - implementation("org.radarbase:radar-commons-kotlin:1.0.0") + implementation("org.radarbase:radar-commons-kotlin:$radar_commons_version") implementation(platform("io.ktor:ktor-bom:$ktor_version")) - implementation("io.ktor:ktor-client-core") - implementation("io.ktor:ktor-client-cio") - implementation("io.ktor:ktor-client-content-negotiation") - implementation("io.ktor:ktor-serialization-kotlinx-json") + implementation("io.ktor:ktor-client-core:$ktor_version") + implementation("io.ktor:ktor-client-cio:$ktor_version") + implementation("io.ktor:ktor-client-content-negotiation:$ktor_version") + implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version") implementation group: 'org.slf4j', name: 'slf4j-api', version: slf4j_version testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: junit_version - testImplementation group: 'com.github.tomakehurst', name: 'wiremock', version: '2.27.2' - testImplementation group: 'org.hamcrest', name: 'hamcrest', version: '2.2' + testImplementation group: 'com.github.tomakehurst', name: 'wiremock', version: wiremock_version + testImplementation group: 'org.hamcrest', name: 'hamcrest', version: hamcrest_version testRuntimeOnly group: 'ch.qos.logback', name: 'logback-classic', version: logback_version testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: junit_version From 675d8a8c6c1ef1cabaaf1be5b3f9f23696d74717 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 6 Mar 2024 14:14:40 +0100 Subject: [PATCH 155/158] Tests passing --- build.gradle | 36 +++++++++---------- gradle.properties | 5 +-- radar-auth/build.gradle | 2 +- .../security/JwtAuthenticationFilter.kt | 4 +-- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/build.gradle b/build.gradle index 4a90078a2..006a7a507 100644 --- a/build.gradle +++ b/build.gradle @@ -153,11 +153,11 @@ dependencies { implementation("tech.jhipster:jhipster-framework:${jhipster_server_version}") implementation("tech.jhipster:jhipster-dependencies:${jhipster_server_version}") implementation("io.micrometer:micrometer-core:${micrometer_version}") - runtimeOnly "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:${jackson_version}" - implementation "com.fasterxml.jackson.datatype:jackson-datatype-hibernate5:${jackson_version}" - implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-csv:${jackson_version}" - implementation "com.fasterxml.jackson.core:jackson-annotations:${jackson_version}" - implementation "com.fasterxml.jackson.core:jackson-databind:${jackson_version}" + runtimeOnly "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" + implementation "com.fasterxml.jackson.datatype:jackson-datatype-hibernate5" + implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-csv" + implementation "com.fasterxml.jackson.core:jackson-annotations" + implementation "com.fasterxml.jackson.core:jackson-databind" implementation "com.hazelcast:hazelcast:${hazelcast_version}" implementation "com.hazelcast:hazelcast-spring:${hazelcast_version}" runtimeOnly "com.hazelcast:hazelcast-hibernate53:${hazelcast_hibernate_version}" @@ -165,41 +165,41 @@ dependencies { implementation group: 'com.google.code.findbugs', name: 'jsr305', version: findbugAnnotationVersion implementation("org.liquibase:liquibase-core:${liquibase_version}") runtimeOnly "com.mattbertolini:liquibase-slf4j:${liquibase_slf4j_version}" - implementation("org.springframework.boot:spring-boot-starter-actuator:3.0.0") + implementation("org.springframework.boot:spring-boot-starter-actuator") implementation("org.springframework.boot:spring-boot-autoconfigure") implementation "org.springframework.boot:spring-boot-starter-mail" - runtimeOnly "org.springframework.boot:spring-boot-starter-logging:3.2.2" + runtimeOnly "org.springframework.boot:spring-boot-starter-logging" runtimeOnly ("org.springframework.boot:spring-boot-starter-data-jpa") { exclude group: 'org.hibernate', module: 'hibernate-entitymanager' } - implementation "org.hibernate:hibernate-core" + implementation "org.springframework.security:spring-security-data" + + implementation("org.springframework.boot:spring-boot-starter-web") { + exclude module: 'spring-boot-starter-tomcat' + } + runtimeOnly "org.springframework.boot:spring-boot-starter-security" + implementation ("org.springframework.boot:spring-boot-starter-undertow") + implementation "org.hibernate:hibernate-core" implementation "org.hibernate:hibernate-envers" - implementation 'org.hibernate:hibernate-validator:8.0.0.Final' + implementation "org.hibernate:hibernate-validator:${hibernate_validator_version}" runtimeOnly "org.postgresql:postgresql:${postgresql_version}" runtimeOnly "org.hsqldb:hsqldb:${hsqldb_version}" - runtimeOnly "org.springframework.boot:spring-boot-starter-security" - implementation "org.springframework.security:spring-security-data" - - implementation("org.springframework.boot:spring-boot-starter-web:3.1.9") { - exclude module: 'spring-boot-starter-tomcat' - } - implementation ("org.springframework.boot:spring-boot-starter-undertow") // Fix vulnerabilities runtimeOnly("io.undertow:undertow-websockets-jsr:2.2.25.Final") runtimeOnly("io.undertow:undertow-servlet:2.2.25.Final") runtimeOnly("io.undertow:undertow-core:2.2.25.Final") implementation "org.springframework.boot:spring-boot-starter-thymeleaf" - runtimeOnly("org.thymeleaf:thymeleaf-spring5:${thymeleaf_version}") runtimeOnly("org.thymeleaf:thymeleaf:${thymeleaf_version}") + runtimeOnly("org.thymeleaf:thymeleaf-spring5:${thymeleaf_version}") implementation("org.springframework:spring-context-support") implementation("org.springframework.session:spring-session-hazelcast") implementation('org.springframework.security.oauth:spring-security-oauth2:2.5.2.RELEASE') - implementation('org.springframework.security:spring-security-web:5.8.10') + implementation('org.springframework.security:spring-security-web:5.7.8') implementation "org.springdoc:springdoc-openapi-ui:${springdoc_version}" runtimeOnly("javax.inject:javax.inject:1") implementation project(':radar-auth') diff --git a/gradle.properties b/gradle.properties index dad6dc5e8..dada70642 100644 --- a/gradle.properties +++ b/gradle.properties @@ -31,12 +31,13 @@ okhttp_version=4.10.0 hsqldb_version=2.7.2 coroutines_version=1.8.0 ktor_version=2.3.9 -radar_commons_version=1.1.0 +radar_commons_version=1.0.0 hamcrest_version=2.2 wiremock_version=3.0.1 kotlin_version=1.9.10 micrometer_version=1.12.3 - +hibernate_orm_version=6.4.4.Final +hibernate_validator_version=8.0.0.Final kotlin.code.style=official org.gradle.vfs.watch=true diff --git a/radar-auth/build.gradle b/radar-auth/build.gradle index e8c5cb595..90bf4a5bf 100644 --- a/radar-auth/build.gradle +++ b/radar-auth/build.gradle @@ -17,7 +17,7 @@ description = 'Library for authentication and authorization of JWT tokens issued dependencies { api group: 'com.auth0', name: 'java-jwt', version: oauth_jwt_version api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:$coroutines_version")) - api("org.jetbrains.kotlinx:kotlinx-coroutines-core$coroutines_version") + api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version") implementation("org.radarbase:radar-commons-kotlin:$radar_commons_version") diff --git a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt index abc8748fd..456d82b51 100644 --- a/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt +++ b/src/main/java/org/radarbase/management/security/JwtAuthenticationFilter.kt @@ -186,7 +186,7 @@ class JwtAuthenticationFilter @JvmOverloads constructor( * @return set of authority references. */ val User.authorityReferences: Set - get() = roles?.mapTo(HashSet()) { role: Role? -> + get() = roles.mapTo(HashSet()) { role: Role? -> val auth = role?.role val referent = when (auth?.scope) { RoleAuthority.Scope.GLOBAL -> null @@ -195,7 +195,7 @@ class JwtAuthenticationFilter @JvmOverloads constructor( null -> null } AuthorityReference(auth!!, referent) - } ?: setOf() + } From b320efb3aae1e72ae014eda1568a4040d035043c Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Wed, 20 Mar 2024 14:22:32 +0100 Subject: [PATCH 156/158] version to non-snapshot --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 006a7a507..55a05245e 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ apply plugin: 'io.spring.dependency-management' allprojects { group 'org.radarbase' - version '2.1.1-SNAPSHOT' // project version + version '2.1.1' // project version // The comment on the previous line is only there to identify the project version line easily // with a sed command, to auto-update the version number with the prepare-release-branch.sh From b97991f9d60e427fdfd54a6242a60cfddc8447df Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Thu, 21 Mar 2024 10:25:21 +0100 Subject: [PATCH 157/158] fix ci --- .github/workflows/pre-release.yml | 19 +++++++++++++++---- gradle/profile_dev.gradle | 4 ++++ gradle/profile_prod.gradle | 4 ++++ .../config/application-e2e-prod-test.yml | 5 +++++ .../resources/config/application-prod.yml | 18 +++++++++--------- .../integration/entities/permission.spec.ts | 3 ++- yarn.lock | 2 +- 7 files changed, 40 insertions(+), 15 deletions(-) diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml index 095db156c..00ac52e70 100644 --- a/.github/workflows/pre-release.yml +++ b/.github/workflows/pre-release.yml @@ -46,17 +46,28 @@ jobs: ${{ runner.os }}-rc-node- ${{ runner.os }}-node- + - name: Install Yarn dependencies + run: yarn install + + - name: Yarn build + run: yarn build:prod + + - name: Yarn check + run: yarn test + # Compile the code - - name: Install dependencies - run: | - yarn install + - name: Compile java + run: ./gradlew assemble - name: Run full production end to end tests + id: e2e run: | + cp src/test/resources/config/keystore.p12 src/main/resources/config/keystore.p12 docker-compose -f src/main/docker/postgresql.yml up -d - ./gradlew bootRun &>mp.log mp.log { }) it('should remove user with role organization admin', () => { - cy.get('jhi-permissions button.fa-remove').eq(1).click(); + cy.wait(100) + cy.get('jhi-permissions button.fa-remove').eq(1).click({force: true}); cy.get('jhi-permissions tbody tr').should('have.length', 2); }) diff --git a/yarn.lock b/yarn.lock index caf8f2875..a094431ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12213,7 +12213,7 @@ __metadata: languageName: node linkType: hard -"url-parse@npm:^1.4.3, url-parse@npm:^1.5.3": +"url-parse@npm:^1.5.3": version: 1.5.10 resolution: "url-parse@npm:1.5.10" dependencies: From 91b0dc6e45f089a5b22ba42cbc0ebbdf74dad186 Mon Sep 17 00:00:00 2001 From: Bastiaan Date: Thu, 21 Mar 2024 17:22:51 +0100 Subject: [PATCH 158/158] fix ci --- .../e2e/cypress/integration/entities/permission.spec.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/javascript/e2e/cypress/integration/entities/permission.spec.ts b/src/test/javascript/e2e/cypress/integration/entities/permission.spec.ts index 2021ef0cf..9d0c93b09 100644 --- a/src/test/javascript/e2e/cypress/integration/entities/permission.spec.ts +++ b/src/test/javascript/e2e/cypress/integration/entities/permission.spec.ts @@ -20,8 +20,9 @@ describe('Organization Permissions e2e test', () => { }) it('should remove user with role organization admin', () => { - cy.wait(100) - cy.get('jhi-permissions button.fa-remove').eq(1).click({force: true}); + cy.wait(1000) + cy.get('jhi-permissions tbody tr').contains('oadmin').parent().find('button.fa-remove').click(); + cy.wait(1000) cy.get('jhi-permissions tbody tr').should('have.length', 2); })