diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 099826457d..7a24f75e76 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -16,7 +16,7 @@ Release Notes: - [ ] After integration of the pull request, I verified our [bluemix test environment](http://taskana.mybluemix.net/taskana) is not broken ### Verified by the reviewer: -- [ ] Commit message format → (Closes) #: Your commit message. i.e. Closes #2271: Your commit message. +- [ ] Commit message format → (Closes) #<Issue Number>: Your commit message. - [ ] Submitter's update to [documentation](https://taskana.atlassian.net/wiki/spaces/TAS/overview) is sufficient - [ ] SonarCloud analysis meets our standards - [ ] Update of the [current release notes](https://taskana.atlassian.net/wiki/spaces/TAS/pages/1281392672/Current+Release+Notes+Taskana) reflects changes diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 8414a3f302..0e8a7e0fb0 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -13,7 +13,7 @@ concurrency: cancel-in-progress: true env: - JAVA_VERSION: 11 + JAVA_VERSION: 17 NODE_VERSION: 16.14.2 ARTIFACTS_CYPRESS_TESTS_NAME: cypress-tests @@ -38,7 +38,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Git checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} uses: actions/setup-java@v3 with: @@ -67,7 +67,7 @@ jobs: path: ${{ env.ARTIFACTS_TASKANA_JARS_PATH }} if-no-files-found: error - name: Remove taskana artifacts from cache - run: rm -rf ~/.m2/repository/pro/taskana + run: rm -rf ${{ env.ARTIFACTS_TASKANA_JARS_PATH }} - name: Cancel workflow if: failure() uses: andymckay/cancel-action@0.3 @@ -77,14 +77,14 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Git checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} uses: actions/setup-java@v3 with: distribution: adopt java-version: ${{ env.JAVA_VERSION }} - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v4.0.0 with: node-version: ${{ env.NODE_VERSION }} - name: Cache web dependencies @@ -132,9 +132,9 @@ jobs: needs: [ compile_frontend ] steps: - name: Git checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v4.0.0 with: node-version: ${{ env.NODE_VERSION }} - name: Cache web dependencies @@ -174,14 +174,14 @@ jobs: needs: [ compile_frontend, compile_backend ] steps: - name: Git checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} uses: actions/setup-java@v3 with: distribution: adopt java-version: ${{ env.JAVA_VERSION }} - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v3.6.0 + uses: actions/setup-node@v4.0.0 with: node-version: ${{ env.NODE_VERSION }} - name: Cache web dependencies @@ -298,7 +298,7 @@ jobs: database: POSTGRES steps: - name: Git checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} uses: actions/setup-java@v3 with: @@ -348,7 +348,7 @@ jobs: GPG_TTY: $(tty) steps: - name: Git checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 # necessary for push back # NOTE @v2 uses the token as an auth http header. Set it to @@ -418,7 +418,7 @@ jobs: needs: [ test_frontend, test_e2e, test_backend ] steps: - name: Git checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up JDK ${{ env.JAVA_VERSION }} uses: actions/setup-java@v3 with: @@ -455,10 +455,14 @@ jobs: with: creds: '{"clientId":"${{ secrets.CLIENT_ID }}","clientSecret":"${{ secrets.CLIENT_SECRET }}","subscriptionId":"${{ secrets.SUBSCRIPTION_ID }}","tenantId":"${{ secrets.TENANT_ID }}"}' - name: Deploy to Microsoft Azure - uses: Azure/webapps-deploy@v2 + uses: Azure/webapps-deploy@v3 with: app-name: taskana package: rest/taskana-rest-spring-example-boot/target/taskana-rest-spring-example-boot.jar + - name: Wait for Azure for 60 seconds + uses: jakejarvis/wait-action@master + with: + time: '60s' - name: Smoke test documentation run: ci/verify_docs_alive.sh - name: Cancel workflow @@ -473,7 +477,7 @@ jobs: needs: [ test_frontend, test_e2e, test_backend ] steps: - name: Git checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Set up JDK ${{ env.JAVA_VERSION }} diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index 8c79a83ae4..ac184013fc 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -5,14 +5,14 @@ # to you 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. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/README.md b/README.md index 7d61bf13ae..0fff2a68d6 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ TASKANA - The open source task management library TASKANA is a task management component open source library. It can be embedded into your application or be operated standalone if appropriate. Beside the basic task management functionalities, TASKANA adds workbaskets and classifications to control and monitor a large amount of tasks within a larger organization. * Web Site: http://taskana.pro/ -* Demo Environment: https://taskana.mybluemix.net/taskana +* Demo Environment: https://taskana.azurewebsites.net/taskana * Getting Started: https://taskana.atlassian.net/wiki/spaces/TAS/pages/228655109/Getting+started * Issue Tracker: https://taskana.atlassian.net * Contribution Guildelines: https://taskana.atlassian.net/wiki/spaces/TAS/pages/274202625/Contribution+Guide diff --git a/ci/taskana-sonar-test-coverage/pom.xml b/ci/taskana-sonar-test-coverage/pom.xml index acb3c3435d..9e124ec78e 100644 --- a/ci/taskana-sonar-test-coverage/pom.xml +++ b/ci/taskana-sonar-test-coverage/pom.xml @@ -11,7 +11,7 @@ pro.taskana taskana-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../../pom.xml diff --git a/ci/verify_docs_alive.sh b/ci/verify_docs_alive.sh index a06a8387db..c70d215e89 100755 --- a/ci/verify_docs_alive.sh +++ b/ci/verify_docs_alive.sh @@ -1,7 +1,7 @@ #!/bin/bash set -e # fail fast set -x -BASE_URL=https://taskana.mybluemix.net/taskana +BASE_URL=https://taskana.azurewebsites.net/taskana test 200 -eq "$(curl -sw "%{http_code}" -o /dev/null "$BASE_URL/docs/rest/rest-api.html")" test 200 -eq "$(curl -sw "%{http_code}" -o /dev/null "$BASE_URL/docs/rest/simplehistory-rest-api.html")" diff --git a/common/pom.xml b/common/pom.xml index 95bf87dc50..ecee0a2f3d 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -12,7 +12,7 @@ pro.taskana taskana-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../pom.xml diff --git a/common/taskana-common-data/pom.xml b/common/taskana-common-data/pom.xml index d38ab09e4e..c902022744 100644 --- a/common/taskana-common-data/pom.xml +++ b/common/taskana-common-data/pom.xml @@ -10,7 +10,7 @@ pro.taskana taskana-common-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../pom.xml @@ -44,6 +44,7 @@ org.assertj assertj-core + ${version.assertj} test diff --git a/common/taskana-common-data/src/main/resources/sql/clear/clear-db.sql b/common/taskana-common-data/src/main/resources/sql/clear/clear-db.sql index 3221bb90a2..1c9ad0127b 100644 --- a/common/taskana-common-data/src/main/resources/sql/clear/clear-db.sql +++ b/common/taskana-common-data/src/main/resources/sql/clear/clear-db.sql @@ -14,5 +14,6 @@ DELETE FROM OBJECT_REFERENCE; DELETE FROM SCHEDULED_JOB; DELETE FROM USER_INFO; DELETE FROM GROUP_INFO; +DELETE FROM PERMISSION_INFO; INSERT INTO CONFIGURATION (NAME) VALUES ('MASTER'); COMMIT; diff --git a/common/taskana-common-data/src/main/resources/sql/clear/drop-tables.sql b/common/taskana-common-data/src/main/resources/sql/clear/drop-tables.sql index 4c95dd9c7f..447674060a 100644 --- a/common/taskana-common-data/src/main/resources/sql/clear/drop-tables.sql +++ b/common/taskana-common-data/src/main/resources/sql/clear/drop-tables.sql @@ -14,6 +14,7 @@ DROP TABLE OBJECT_REFERENCE; DROP TABLE SCHEDULED_JOB; DROP TABLE USER_INFO; DROP TABLE GROUP_INFO; +DROP TABLE PERMISSION_INFO; DROP SEQUENCE SCHEDULED_JOB_SEQ; DROP SEQUENCE TASKANA_SCHEMA_VERSION_ID_SEQ; COMMIT; diff --git a/common/taskana-common-data/src/main/resources/sql/monitor-data/monitor-sample-data.sql b/common/taskana-common-data/src/main/resources/sql/monitor-data/monitor-sample-data.sql index 359af64bb9..91ceded363 100644 --- a/common/taskana-common-data/src/main/resources/sql/monitor-data/monitor-sample-data.sql +++ b/common/taskana-common-data/src/main/resources/sql/monitor-data/monitor-sample-data.sql @@ -1,10 +1,10 @@ --- WORKBASKET TABLE (ID , KEY , CREATED , MODIFIED , NAME , DOMAIN , TYPE , DESCRIPTION , OWNER , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4 , ORG_LEVEL_1 , ORG_LEVEL_2 , ORG_LEVEL_3 , ORG_LEVEL_4 , MARKED_FOR_DELETION ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000001', 'USER-1-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 1', 'MONITOR_TEST_DOMAIN', 'PERSONAL', 'Monitor Test Postkorb 1', 'John' , '' , '' , '' , '' , 'org1' , '' , '' , '' , FALSE ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000002', 'USER-1-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 2', 'MONITOR_TEST_DOMAIN', 'PERSONAL', 'Monitor Test Postkorb 2', 'John' , '' , '' , '' , '' , '' , '' , '' , '' , FALSE ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000003', 'USER-1-3' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 3', 'MONITOR_TEST_DOMAIN', 'PERSONAL', 'Monitor Test Postkorb 3', 'John' , '' , '' , '' , '' , 'org1' , '' , '' , '' , FALSE ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000004', 'USER-1-4' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 4', 'MONITOR_TEST_DOMAIN', 'PERSONAL', 'Monitor Test Postkorb 4', 'John' , '' , '' , '' , '' , '' , '' , '' , '' , FALSE ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000005', 'GPK-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'GPK GruppenPk 1' , 'MONITOR_TEST_DOMAIN', 'GROUP' , 'Monitor Test Postkorb 5', 'John' , '' , '' , '' , '' , '' , '' , '' , '' , FALSE ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000006', 'TPK-VIP-1', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'TPK VIP 1' , 'MONITOR_TEST_DOMAIN', 'TOPIC' , 'Monitor Test Postkorb 6', 'John' , '' , '' , '' , '' , '' , '' , '' , '' , FALSE ); +-- WORKBASKET TABLE (ID , KEY , CREATED , MODIFIED , NAME , DOMAIN , TYPE , DESCRIPTION , OWNER , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4 , ORG_LEVEL_1 , ORG_LEVEL_2 , ORG_LEVEL_3 , ORG_LEVEL_4 , MARKED_FOR_DELETION , CUSTOM_5 , CUSTOM_6 , CUSTOM_7 , CUSTOM_8 ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000001', 'USER-1-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 1', 'MONITOR_TEST_DOMAIN', 'PERSONAL', 'Monitor Test Postkorb 1', 'John' , '' , '' , '' , '' , 'org1' , '' , '' , '' , FALSE , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000002', 'USER-1-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 2', 'MONITOR_TEST_DOMAIN', 'PERSONAL', 'Monitor Test Postkorb 2', 'John' , '' , '' , '' , '' , '' , '' , '' , '' , FALSE , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000003', 'USER-1-3' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 3', 'MONITOR_TEST_DOMAIN', 'PERSONAL', 'Monitor Test Postkorb 3', 'John' , '' , '' , '' , '' , 'org1' , '' , '' , '' , FALSE , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000004', 'USER-1-4' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 4', 'MONITOR_TEST_DOMAIN', 'PERSONAL', 'Monitor Test Postkorb 4', 'John' , '' , '' , '' , '' , '' , '' , '' , '' , FALSE , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000005', 'GPK-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'GPK GruppenPk 1' , 'MONITOR_TEST_DOMAIN', 'GROUP' , 'Monitor Test Postkorb 5', 'John' , '' , '' , '' , '' , '' , '' , '' , '' , FALSE , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000006', 'TPK-VIP-1', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'TPK VIP 1' , 'MONITOR_TEST_DOMAIN', 'TOPIC' , 'Monitor Test Postkorb 6', 'John' , '' , '' , '' , '' , '' , '' , '' , '' , FALSE , '' , '' , '' , '' ); -- CLASSIFICATION TABLE (ID , KEY , PARENT_ID , PARENT_KEY, CATEGORY , TYPE , DOMAIN , VALID_IN_DOMAIN, CREATED , MODIFIED ,NAME , DESCRIPTION , PRIORITY, SERVICE_LEVEL, APPLICATION_ENTRY_POINT, CUSTOM_1 , CUSTOM_2, CUSTOM_3, CUSTOM_4, CUSTOM_5, CUSTOM_6, CUSTOM_7, CUSTOM_8 ); INSERT INTO CLASSIFICATION VALUES('CLI:000000000000000000000000000000000001', 'L10000', '' , '' , 'EXTERN' , 'TASK' , 'DOMAIN_A' , TRUE , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'OLD-Leistungsfall' , 'OLD-Leistungsfall' , 3 , 'P1D' , '' , 'VNR,RVNR,KOLVNR' , '' , '' , '' , '' , '' , '' , '' ); diff --git a/common/taskana-common-data/src/main/resources/sql/sample-data/workbasket-access-list.sql b/common/taskana-common-data/src/main/resources/sql/sample-data/workbasket-access-list.sql index 1e3a3182c4..3c173fdbae 100644 --- a/common/taskana-common-data/src/main/resources/sql/sample-data/workbasket-access-list.sql +++ b/common/taskana-common-data/src/main/resources/sql/sample-data/workbasket-access-list.sql @@ -1,66 +1,66 @@ -- sample-data is used for rest tests and for the example application ---SERT INTO WORKBASKET_ACCESS_LIST VALUES (ID , WB_ID , ACCESS_ID , ACCESS_NAME , READ , OPEN , APPEND, TRANSFER, DISTRIBUTE, C1 , C2 , C3 , C4 , C5 , C6 , C7 , C8 , C9 , C10 , C11 , C12 ) +--SERT INTO WORKBASKET_ACCESS_LIST VALUES (ID , WB_ID , ACCESS_ID , ACCESS_NAME , READ , OPEN , APPEND, TRANSFER, DISTRIBUTE, C1 , C2 , C3 , C4 , C5 , C6 , C7 , C8 , C9 , C10 , C11 , C12 , READTASKS, EDITTASKS) -- KSC authorizations -- PPKs -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000001', 'WBI:100000000000000000000000000000000004', 'teamlead-1' , 'Titus Toll' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000002', 'WBI:100000000000000000000000000000000005', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000003', 'WBI:100000000000000000000000000000000006', 'user-1-1' , 'Max Mustermann' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000004', 'WBI:100000000000000000000000000000000007', 'user-1-2' , 'Elena Eifrig' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000005', 'WBI:100000000000000000000000000000000008', 'user-2-1' , 'Simone Müller' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000006', 'WBI:100000000000000000000000000000000009', 'user-2-2' , 'Tim Schläfrig' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016201', 'WBI:100000000000000000000000000000000016', 'user-2-1' , 'Simone Müller' , true , true , true , true , true , true , false , false , false , false , false , false , false , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016202', 'WBI:100000000000000000000000000000000016', 'user-2-2' , 'Tim Schläfrig' , true , true , true , true , true , false , true , false , false , false , false , false , false , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016203', 'WBI:100000000000000000000000000000000016', 'user-2-3' , 'Thomas Bach' , true , true , true , true , true , false , false , true , false , false , false , false , false , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016204', 'WBI:100000000000000000000000000000000016', 'user-2-4' , 'Rolf Wieland' , true , true , true , true , true , false , false , false , true , false , false , false , false , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016205', 'WBI:100000000000000000000000000000000016', 'user-2-5' , 'Heike Schmidt' , true , true , true , true , true , false , false , false , false , true , false , false , false , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016206', 'WBI:100000000000000000000000000000000016', 'user-2-6' , 'Kurt Maier' , true , true , true , true , true , false , false , false , false , false , true , false , false , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016207', 'WBI:100000000000000000000000000000000016', 'user-2-7' , 'Wiebke Meyer' , true , true , true , true , true , false , false , false , false , false , false , true , false , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016208', 'WBI:100000000000000000000000000000000016', 'user-2-8' , 'Jana Heeg' , true , true , true , true , true , false , false , false , false , false , false , false , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016209', 'WBI:100000000000000000000000000000000016', 'user-2-9' , 'Nathalie Fuchs' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016210', 'WBI:100000000000000000000000000000000016', 'user-2-10' , 'Johannes Renz' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:B00000000000000000000000000000000014', 'WBI:100000000000000000000000000000000014', 'user-b-1' , 'Bernd Bern' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:B00000000000000000000000000000000015', 'WBI:100000000000000000000000000000000015', 'user-b-2' , 'Brundhilde Bio' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000001', 'WBI:100000000000000000000000000000000004', 'teamlead-1' , 'Titus Toll' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000002', 'WBI:100000000000000000000000000000000005', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000003', 'WBI:100000000000000000000000000000000006', 'user-1-1' , 'Max Mustermann' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000004', 'WBI:100000000000000000000000000000000007', 'user-1-2' , 'Elena Eifrig' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000005', 'WBI:100000000000000000000000000000000008', 'user-2-1' , 'Simone Müller' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000006', 'WBI:100000000000000000000000000000000009', 'user-2-2' , 'Tim Schläfrig' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016201', 'WBI:100000000000000000000000000000000016', 'user-2-1' , 'Simone Müller' , true , true , true , true , true , true , false , false , false , false , false , false , false , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016202', 'WBI:100000000000000000000000000000000016', 'user-2-2' , 'Tim Schläfrig' , true , true , true , true , true , false , true , false , false , false , false , false , false , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016203', 'WBI:100000000000000000000000000000000016', 'user-2-3' , 'Thomas Bach' , true , true , true , true , true , false , false , true , false , false , false , false , false , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016204', 'WBI:100000000000000000000000000000000016', 'user-2-4' , 'Rolf Wieland' , true , true , true , true , true , false , false , false , true , false , false , false , false , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016205', 'WBI:100000000000000000000000000000000016', 'user-2-5' , 'Heike Schmidt' , true , true , true , true , true , false , false , false , false , true , false , false , false , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016206', 'WBI:100000000000000000000000000000000016', 'user-2-6' , 'Kurt Maier' , true , true , true , true , true , false , false , false , false , false , true , false , false , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016207', 'WBI:100000000000000000000000000000000016', 'user-2-7' , 'Wiebke Meyer' , true , true , true , true , true , false , false , false , false , false , false , true , false , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016208', 'WBI:100000000000000000000000000000000016', 'user-2-8' , 'Jana Heeg' , true , true , true , true , true , false , false , false , false , false , false , false , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016209', 'WBI:100000000000000000000000000000000016', 'user-2-9' , 'Nathalie Fuchs' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000016210', 'WBI:100000000000000000000000000000000016', 'user-2-10' , 'Johannes Renz' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:B00000000000000000000000000000000014', 'WBI:100000000000000000000000000000000014', 'user-b-1' , 'Bernd Bern' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:B00000000000000000000000000000000015', 'WBI:100000000000000000000000000000000015', 'user-b-2' , 'Brundhilde Bio' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -- group internal access -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000007', 'WBI:100000000000000000000000000000000004', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000008', 'WBI:100000000000000000000000000000000005', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000009', 'WBI:100000000000000000000000000000000006', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000010', 'WBI:100000000000000000000000000000000007', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000011', 'WBI:100000000000000000000000000000000008', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000012', 'WBI:100000000000000000000000000000000009', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000007', 'WBI:100000000000000000000000000000000004', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000008', 'WBI:100000000000000000000000000000000005', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000009', 'WBI:100000000000000000000000000000000006', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000010', 'WBI:100000000000000000000000000000000007', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000011', 'WBI:100000000000000000000000000000000008', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000012', 'WBI:100000000000000000000000000000000009', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true); -- teamlead substitution -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000013', 'WBI:100000000000000000000000000000000004', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000014', 'WBI:100000000000000000000000000000000005', 'teamlead-1' , 'Titus Toll' , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false , false ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000013', 'WBI:100000000000000000000000000000000004', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000014', 'WBI:100000000000000000000000000000000005', 'teamlead-1' , 'Titus Toll' , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true); -- cross team tranfers -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000015', 'WBI:100000000000000000000000000000000006', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , false, true , false , false , false , false , false , false , false , false , false , false , false , false , false , false ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000016', 'WBI:100000000000000000000000000000000007', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , false, true , false , false , false , false , false , false , false , false , false , false , false , false , false , false ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000017', 'WBI:100000000000000000000000000000000008', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , false, false , false , false , false , false , false , false , false , false , false , false , false , false , false , false ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000018', 'WBI:100000000000000000000000000000000009', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , false, true , false , false , false , false , false , false , false , false , false , false , false , false , false , false ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000015', 'WBI:100000000000000000000000000000000006', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , false, true , false , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000016', 'WBI:100000000000000000000000000000000007', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , false, true , false , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000017', 'WBI:100000000000000000000000000000000008', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , false, false , false , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000018', 'WBI:100000000000000000000000000000000009', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , false, true , false , false , false , false , false , false , false , false , false , false , false , false , false , false ,true , true); ---SERT INTO WORKBASKET_ACCESS_LIST VALUES (ID , WB_ID , ACCESS_ID , ACCESS_NAME , READ , OPEN , APPEND, TRANSFER, DISTRIBUTE, C1 , C2 , C3 , C4 , C5 , C6 , C7 , C8 , C9 , C10 , C11 , C12 ) +--SERT INTO WORKBASKET_ACCESS_LIST VALUES (ID , WB_ID , ACCESS_ID , ACCESS_NAME , READ , OPEN , APPEND, TRANSFER, DISTRIBUTE, C1 , C2 , C3 , C4 , C5 , C6 , C7 , C8 , C9 , C10 , C11 , C12 ,READTASKS, EDITTASKS) -- Team GPK access -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000019', 'WBI:100000000000000000000000000000000002', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000020', 'WBI:100000000000000000000000000000000003', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000019', 'WBI:100000000000000000000000000000000002', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000020', 'WBI:100000000000000000000000000000000003', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -- Cross team GPK access -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000021', 'WBI:100000000000000000000000000000000001', 'teamlead-1' , 'Titus Toll' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000022', 'WBI:100000000000000000000000000000000001', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000021', 'WBI:100000000000000000000000000000000001', 'teamlead-1' , 'Titus Toll' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000022', 'WBI:100000000000000000000000000000000001', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -- TPK access -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000123', 'WBI:100000000000000000000000000000000010', 'teamlead-1' , 'Titus Toll' , true , false, false , false , false , false , false , false , false , false , false , false , false , false , false , false , false ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000123', 'WBI:100000000000000000000000000000000010', 'teamlead-1' , 'Titus Toll' , true , false, false , false , false , false , false , false , false , false , false , false , false , false , false , false , false, true , true); -- Access to other domains -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000023', 'WBI:100000000000000000000000000000000012', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , false, true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000024', 'WBI:100000000000000000000000000000000013', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , false, true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000025', 'WBI:100000000000000000000000000000000014', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000026', 'WBI:100000000000000000000000000000000015', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000023', 'WBI:100000000000000000000000000000000012', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 1', true , false, true , true , false , false , false , false , false , false , false , false , false , false , false , false , false, true , true ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000024', 'WBI:100000000000000000000000000000000013', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , false, true , true , false , false , false , false , false , false , false , false , false , false , false , false , false, true , true ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000025', 'WBI:100000000000000000000000000000000014', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false, true , true ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000026', 'WBI:100000000000000000000000000000000015', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'Organisationseinheit KSC 2', true , true , true , true , false , false , false , false , false , false , false , false , false , false , false , false , false, true , true ); -- Access to workbaskets for sorting test -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000900', 'WBI:000000000000000000000000000000000900', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000901', 'WBI:000000000000000000000000000000000901', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000902', 'WBI:000000000000000000000000000000000902', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000903', 'WBI:000000000000000000000000000000000903', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000904', 'WBI:000000000000000000000000000000000904', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000905', 'WBI:000000000000000000000000000000000905', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000906', 'WBI:000000000000000000000000000000000906', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000907', 'WBI:000000000000000000000000000000000907', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000908', 'WBI:000000000000000000000000000000000908', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000909', 'WBI:000000000000000000000000000000000909', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000900', 'WBI:000000000000000000000000000000000900', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true ); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000901', 'WBI:000000000000000000000000000000000901', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000902', 'WBI:000000000000000000000000000000000902', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000903', 'WBI:000000000000000000000000000000000903', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000904', 'WBI:000000000000000000000000000000000904', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000905', 'WBI:000000000000000000000000000000000905', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000906', 'WBI:000000000000000000000000000000000906', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000907', 'WBI:000000000000000000000000000000000907', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000908', 'WBI:000000000000000000000000000000000908', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000909', 'WBI:000000000000000000000000000000000909', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); diff --git a/common/taskana-common-data/src/main/resources/sql/sample-data/workbasket.sql b/common/taskana-common-data/src/main/resources/sql/sample-data/workbasket.sql index bc9d7d1db0..459bf40e02 100644 --- a/common/taskana-common-data/src/main/resources/sql/sample-data/workbasket.sql +++ b/common/taskana-common-data/src/main/resources/sql/sample-data/workbasket.sql @@ -1,55 +1,55 @@ -- sample-data is used for rest tests and for the example application -- KSC workbaskets --- WORKBASKET TABLE (ID , KEY , CREATED , MODIFIED , NAME , DOMAIN , TYPE , DESCRIPTION , OWNER , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4 , ORG_LEVEL_1 , ORG_LEVEL_2, ORG_LEVEL_3, ORG_LEVEL_4, MARKED_FOR_DELETION ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000000', 'ADMIN' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Postkorb Admin' , 'DOMAIN_A' , 'PERSONAL', 'Postkorb Admin' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000001', 'GPK_KSC' , '2018-02-01 12:00:00', '2018-02-01 12:00:00', 'Gruppenpostkorb KSC' , 'DOMAIN_A' , 'GROUP' , 'Gruppenpostkorb KSC' , 'teamlead-1' , 'ABCQVW' , '' , 'xyz4' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000002', 'GPK_KSC_1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC 1' , 'DOMAIN_A' , 'GROUP' , 'Gruppenpostkorb KSC 1' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000003', 'GPK_KSC_2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC 2' , 'DOMAIN_A' , 'GROUP' , 'Gruppenpostkorb KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000004', 'TEAMLEAD-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK Teamlead KSC 1' , 'DOMAIN_A' , 'PERSONAL', 'PPK Teamlead KSC 1' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000005', 'TEAMLEAD-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK Teamlead KSC 2' , 'DOMAIN_A' , 'PERSONAL', 'PPK Teamlead KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000006', 'USER-1-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 1' , 'DOMAIN_A' , 'PERSONAL', 'PPK User 1 KSC 1' , '' , '' , '' , '' , 'custom4z', '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000007', 'USER-1-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 1' , 'DOMAIN_A' , 'PERSONAL', 'PPK User 2 KSC 1' , 'user-1-2' , 'custom1', 'custom2' , 'custom3', 'custom4' , 'versicherung', 'abteilung', 'projekt' , 'team' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000008', 'USER-2-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 2' , 'DOMAIN_A' , 'PERSONAL', 'PPK User 1 KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000009', 'USER-2-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 2' , 'DOMAIN_A' , 'PERSONAL', 'PPK User 2 KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000010', 'TPK_VIP' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Themenpostkorb VIP' , 'DOMAIN_A' , 'TOPIC' , 'Themenpostkorb VIP' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000016', 'TPK_VIP_2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Themenpostkorb VIP 2' , 'DOMAIN_A' , 'TOPIC' , 'Themenpostkorb VIP' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +-- WORKBASKET TABLE (ID , KEY , CREATED , MODIFIED , NAME , DOMAIN , TYPE , DESCRIPTION , OWNER , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4 , ORG_LEVEL_1 , ORG_LEVEL_2, ORG_LEVEL_3, ORG_LEVEL_4, MARKED_FOR_DELETION , CUSTOM_5 , CUSTOM_6 , CUSTOM_7 , CUSTOM_8 ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000000', 'ADMIN' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Postkorb Admin' , 'DOMAIN_A' , 'PERSONAL', 'Postkorb Admin' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000001', 'GPK_KSC' , '2018-02-01 12:00:00', '2018-02-01 12:00:00', 'Gruppenpostkorb KSC' , 'DOMAIN_A' , 'GROUP' , 'Gruppenpostkorb KSC' , 'teamlead-1' , 'ABCQVW' , '' , 'xyz4' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000002', 'GPK_KSC_1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC 1' , 'DOMAIN_A' , 'GROUP' , 'Gruppenpostkorb KSC 1' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000003', 'GPK_KSC_2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC 2' , 'DOMAIN_A' , 'GROUP' , 'Gruppenpostkorb KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000004', 'TEAMLEAD-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK Teamlead KSC 1' , 'DOMAIN_A' , 'PERSONAL', 'PPK Teamlead KSC 1' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000005', 'TEAMLEAD-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK Teamlead KSC 2' , 'DOMAIN_A' , 'PERSONAL', 'PPK Teamlead KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000006', 'USER-1-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 1' , 'DOMAIN_A' , 'PERSONAL', 'PPK User 1 KSC 1' , '' , '' , '' , '' , 'custom4z', '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000007', 'USER-1-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 1' , 'DOMAIN_A' , 'PERSONAL', 'PPK User 2 KSC 1' , 'user-1-2' , 'custom1', 'custom2' , 'custom3', 'custom4' , 'versicherung', 'abteilung', 'projekt' , 'team' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000008', 'USER-2-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 2' , 'DOMAIN_A' , 'PERSONAL', 'PPK User 1 KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000009', 'USER-2-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 2' , 'DOMAIN_A' , 'PERSONAL', 'PPK User 2 KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000010', 'TPK_VIP' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Themenpostkorb VIP' , 'DOMAIN_A' , 'TOPIC' , 'Themenpostkorb VIP' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000016', 'TPK_VIP_2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Themenpostkorb VIP 2' , 'DOMAIN_A' , 'TOPIC' , 'Themenpostkorb VIP' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000017', 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_key_1', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Testpostkorb' , 'DOMAIN_TEST', 'TOPIC' , null , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000017', 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_key_1', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Testpostkorb' , 'DOMAIN_TEST', 'TOPIC' , null , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); --- WORKBASKET TABLE (ID , KEY , CREATED , MODIFIED , NAME , DOMAIN , TYPE , DESCRIPTION , OWNER , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4 , ORG_LEVEL_1 , ORG_LEVEL_2, ORG_LEVEL_3, ORG_LEVEL_4, MARKED_FOR_DELETION ); +-- WORKBASKET TABLE (ID , KEY , CREATED , MODIFIED , NAME , DOMAIN , TYPE , DESCRIPTION , OWNER , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4 , ORG_LEVEL_1 , ORG_LEVEL_2, ORG_LEVEL_3, ORG_LEVEL_4, MARKED_FOR_DELETION , CUSTOM_5 , CUSTOM_6 , CUSTOM_7 , CUSTOM_8 ); INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000018', 'das_ist_eine_lange_description_und_ein_langer_owner' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Testpostkorb' , 'DOMAIN_TEST', 'TOPIC' , CONCAT('Lorem ipsum dolor sit amet, consetetur sadipscing', CONCAT('sed diam nonumy eirmod tempor invidunt ut labore ', CONCAT('sed diam nonumy eirmod tempor invidunt ut labore ', CONCAT('ore magna aliquyam erat, sed diam voluptua. At ve', - 's et accusam et justo duo dolores abcdfiskdk ekeke')))), 'das_ist_eine_sehr_sehr_sehr_sehr_sehr_lange_user_id', '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000019', 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_key_2', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_Testpostkorbname_ohne_Leerzeichen' , 'DOMAIN_TEST', 'TOPIC' , 'langer Key und langer Name ohne Leerzeichen' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000020', 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_key_3', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'das ist ein sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr langer Testpostkorbname mit Leerzeichen 1' , 'DOMAIN_TEST', 'TOPIC' , 'langer Key und langer Name mit Leerzeichen' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000021', 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_key_4', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'das ist ein sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr langer Testpostkorbname mit Leerzeichen 2' , 'DOMAIN_TEST', 'TOPIC' , 'langer Key, langer Name mit Leerzeichen und lange UserId', 'das_ist_eine_sehr_sehr_sehr_sehr_sehr_lange_user_id', '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000022', 'kurzer_key' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'das ist ein sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr langer Testpostkorbname mit Leerzeichen 3' , 'DOMAIN_TEST', 'TOPIC' , 'kurzer Key und langer Name mit Leerzeichen' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); + 's et accusam et justo duo dolores abcdfiskdk ekeke')))), 'das_ist_eine_sehr_sehr_sehr_sehr_sehr_lange_user_id', '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000019', 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_key_2', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_Testpostkorbname_ohne_Leerzeichen' , 'DOMAIN_TEST', 'TOPIC' , 'langer Key und langer Name ohne Leerzeichen' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000020', 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_key_3', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'das ist ein sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr langer Testpostkorbname mit Leerzeichen 1' , 'DOMAIN_TEST', 'TOPIC' , 'langer Key und langer Name mit Leerzeichen' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000021', 'das_ist_ein_sehr_sehr_sehr_sehr_sehr_sehr_sehr_sehr_langer_key_4', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'das ist ein sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr langer Testpostkorbname mit Leerzeichen 2' , 'DOMAIN_TEST', 'TOPIC' , 'langer Key, langer Name mit Leerzeichen und lange UserId', 'das_ist_eine_sehr_sehr_sehr_sehr_sehr_lange_user_id', '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000022', 'kurzer_key' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'das ist ein sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr langer Testpostkorbname mit Leerzeichen 3' , 'DOMAIN_TEST', 'TOPIC' , 'kurzer Key und langer Name mit Leerzeichen' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000023', 'langer key, langer name, eine lange description, langer owner' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'das ist ein sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr langer Testpostkorbname mit Leerzeichen 4' , 'DOMAIN_TEST', 'TOPIC' , CONCAT('Lorem ipsum dolor sit amet, consetetur sadipscing', CONCAT('sed diam nonumy eirmod tempor invidunt ut labore ', CONCAT('sed diam nonumy eirmod tempor invidunt ut labore ', CONCAT('ore magna aliquyam erat, sed diam voluptua. At ve', - 's et accusam et justo duo dolores abcdfiskdk ekeke')))), 'das_ist_eine_sehr_sehr_sehr_sehr_sehr_lange_user_id', '' , '' , '' , '' , '' , '' , '' , '' , false ); + 's et accusam et justo duo dolores abcdfiskdk ekeke')))), 'das_ist_eine_sehr_sehr_sehr_sehr_sehr_lange_user_id', '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); --- WORKBASKET TABLE (ID , KEY , CREATED , MODIFIED , NAME , DOMAIN , TYPE , DESCRIPTION , OWNER , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4 , ORG_LEVEL_1 , ORG_LEVEL_2, ORG_LEVEL_3, ORG_LEVEL_4, MARKED_FOR_DELETION ); +-- WORKBASKET TABLE (ID , KEY , CREATED , MODIFIED , NAME , DOMAIN , TYPE , DESCRIPTION , OWNER , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4 , ORG_LEVEL_1 , ORG_LEVEL_2, ORG_LEVEL_3, ORG_LEVEL_4, MARKED_FOR_DELETION , CUSTOM_5 , CUSTOM_6 , CUSTOM_7 , CUSTOM_8 ); -- KSC workbaskets Domain_B -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000011', 'GPK_B_KSC' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC B' , 'DOMAIN_B' , 'GROUP' , 'Gruppenpostkorb KSC' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000012', 'GPK_B_KSC_1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC B1' , 'DOMAIN_B' , 'GROUP' , 'Gruppenpostkorb KSC 1' , '' , 'custom1', 'custom2' , 'custom3', 'custom4' , 'orgl1' , 'orgl2' , 'orgl3' , 'aorgl4' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000013', 'GPK_B_KSC_2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC B2' , 'DOMAIN_B' , 'GROUP' , 'Gruppenpostkorb KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000014', 'USER-B-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 1 Domain B' , 'DOMAIN_B' , 'PERSONAL', 'PPK User 1 KSC 1 Domain B' , '' , '' , 'custom20', '' , 'custom4' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000015', 'USER-B-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 1 Domain B' , 'DOMAIN_B' , 'PERSONAL', 'PPK User 1 KSC 1 Domain B' , 'user-1-2' , 'ABCABC' , 'cust2' , 'cust3' , 'cust4' , 'orgl1' , 'orgl2' , 'orgl3' , 'orgl4' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000011', 'GPK_B_KSC' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC B' , 'DOMAIN_B' , 'GROUP' , 'Gruppenpostkorb KSC' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000012', 'GPK_B_KSC_1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC B1' , 'DOMAIN_B' , 'GROUP' , 'Gruppenpostkorb KSC 1' , '' , 'custom1', 'custom2' , 'custom3', 'custom4' , 'orgl1' , 'orgl2' , 'orgl3' , 'aorgl4' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000013', 'GPK_B_KSC_2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC B2' , 'DOMAIN_B' , 'GROUP' , 'Gruppenpostkorb KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000014', 'USER-B-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 1 Domain B' , 'DOMAIN_B' , 'PERSONAL', 'PPK User 1 KSC 1 Domain B' , '' , '' , 'custom20', '' , 'custom4' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000015', 'USER-B-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 1 Domain B' , 'DOMAIN_B' , 'PERSONAL', 'PPK User 1 KSC 1 Domain B' , 'user-1-2' , 'ABCABC' , 'cust2' , 'cust3' , 'cust4' , 'orgl1' , 'orgl2' , 'orgl3' , 'orgl4' , false , '' , '' , '' , '' ); -- Workbaskets for sorting test -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000900', 'sort001' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxet0' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000901', 'Sort002' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Basxet1' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000902', 'sOrt003' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'bAsxet2' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000903', 'soRt004' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'baSxet3' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000904', 'sorT005' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basXet4' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000905', 'Sort006' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxEt5' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000906', 'SOrt007' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxeT6' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000907', 'SoRt008' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BAsxet7' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000908', 'SorT009' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BaSxet8' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000909', 'Sort010' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BasXet9' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000900', 'sort001' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxet0' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000901', 'Sort002' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Basxet1' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000902', 'sOrt003' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'bAsxet2' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000903', 'soRt004' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'baSxet3' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000904', 'sorT005' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basXet4' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000905', 'Sort006' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxEt5' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000906', 'SOrt007' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxeT6' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000907', 'SoRt008' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BAsxet7' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000908', 'SorT009' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BaSxet8' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000909', 'Sort010' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BasXet9' , 'DOMAIN_A' , 'TOPIC' , 'Lorem ipsum dolor sit amet.' , 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); diff --git a/common/taskana-common-data/src/main/resources/sql/test-data/task.sql b/common/taskana-common-data/src/main/resources/sql/test-data/task.sql index d08f034f6f..d3d1dbdc64 100644 --- a/common/taskana-common-data/src/main/resources/sql/test-data/task.sql +++ b/common/taskana-common-data/src/main/resources/sql/test-data/task.sql @@ -29,6 +29,7 @@ INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000021', 'ETI:0000000 INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000022', 'ETI:000000000000000000000000000000000022', '2018-01-29 15:55:22', null , null , '2018-01-29 15:55:22', null , '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'Widerruf' , 'creator_user_id' , 'Widerruf' , null , 2 , -1 , 'READY' , 'EXTERN' , 'L1050' , 'CLI:100000000000000000000000000000000003', 'WBI:100000000000000000000000000000000001' , 'GPK_KSC' , 'DOMAIN_A', 'PI_0000000000022' , 'DOC_0000000000000000022' , null , '00' , 'PASystem' , '00' , 'SDNR' , '11223344' , false , false , null , 'NONE' , null , '' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '' , 'abc' , '' , '' , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ); INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000023', 'ETI:000000000000000000000000000000000023', '2018-01-29 15:55:23', null , null , '2018-01-29 15:55:23', null , '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'Widerruf' , 'creator_user_id' , 'Widerruf' , null , 2 , -1 , 'READY' , 'EXTERN' , 'L1050' , 'CLI:100000000000000000000000000000000003', 'WBI:100000000000000000000000000000000001' , 'GPK_KSC' , 'DOMAIN_A', 'PI_0000000000023' , 'DOC_0000000000000000023' , null , '00' , 'PASystem' , '00' , 'SDNR' , '11223344' , false , false , null , 'NONE' , null , '' , '' , '' , '' , '' , '' , '' , 'lnp' , '' , '' , '' , '' , '' , 'abc' , '' , '' , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ); INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000024', 'ETI:000000000000000000000000000000000024', '2018-01-29 15:55:24', null , null , '2018-01-29 15:55:24', null , '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'Widerruf' , 'creator_user_id' , 'Widerruf' , null , 2 , -1 , 'READY' , 'EXTERN' , 'L1050' , 'CLI:100000000000000000000000000000000003', 'WBI:100000000000000000000000000000000001' , 'GPK_KSC' , 'DOMAIN_A', 'PI_0000000000024' , 'DOC_0000000000000000024' , null , '00' , 'PASystem' , '00' , 'SDNR' , '11223344' , false , false , null , 'NONE' , null , '' , '' , '' , '' , '' , '' , '' , '' , null , '' , '' , '' , '' , 'abc' , '' , '' , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ); +INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000201', 'ETI:000000000000000000000000000000000201', '2023-07-31 15:55:01', '2023-07-31 15:55:00', null , '2023-07-31 15:55:01', null , '2023-07-31 15:55:00', '2023-08-02 15:55:00', 'Task201' , 'creator_user_id' , 'Lorem ipsum was n Quatsch dolor sit amet.', 'Some custom Note' , 2 , -1 , 'READY' , 'EXTERN' , 'L110102' , 'CLI:100000000000000000000000000000000002', 'WBI:100000000000000000000000000000000006' , 'USER-1-1' , 'DOMAIN_A', 'BPI21' , 'PBPI21' , 'user-1-1' , 'MyCompany1', 'MySystem1', 'MyInstance1' , 'MyType1', 'MyValue1' , true , false , null , 'NONE' , null , 'pqr' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '' , '' , 'abc' , '' , '' , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ); -- TASK TABLE (ID , EXTERNAL_ID , CREATED , CLAIMED , COMPLETED , modified , received , planned , due , name , creator , description , note , priority, manual_priority, state , classification_category , classification_key, classification_id , workbasket_id , workbasket_key, domain , business_process_id, parent_business_process_id, owner , por_company , por_system , por_system_instance, por_type , por_value , is_read, is_transferred,callback_info , callback_state , custom_attributes ,custom1 ,custom2, ,custom3, ,custom4 ,custom5 ,custom6 ,custom7 ,custom8 ,custom9 ,custom10 ,custom11, ,custom12 ,custom13 ,custom14 ,custom15 ,custom16 , custom-int-1, custom-int-2, custom-int-3, custom-int-4, custom-int-5, custom-int-6, custom-int-7, custom-int-8 -- Tasks for WorkOnTaskAccTest INSERT INTO TASK VALUES('TKI:000000000000000000000000000000000025', 'ETI:000000000000000000000000000000000025', '2018-01-29 15:55:24', null , null , '2018-01-29 15:55:24', '2018-01-29 15:55:24', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'Widerruf' , 'creator_user_id' , 'Widerruf' , null , 2 , -1 , 'READY' , 'EXTERN' , 'L1050' , 'CLI:100000000000000000000000000000000003', 'WBI:100000000000000000000000000000000007' , 'USER-1-2' , 'DOMAIN_A', 'PI_0000000000025' , 'DOC_0000000000000000025' , null , 'abcd00' , 'PASystem' , '00' , 'SDNR' , '98765432' , false , false , null , 'NONE' , null , '' , '' , '' , '' , '' , '' , '' , '' , '' , 'ert' , 'ert' , 'ert' , 'ert' , 'abc' , 'ert' , 'ert' , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ); diff --git a/common/taskana-common-data/src/main/resources/sql/test-data/workbasket-access-list.sql b/common/taskana-common-data/src/main/resources/sql/test-data/workbasket-access-list.sql index ee47dcdf85..6a3f8edf91 100644 --- a/common/taskana-common-data/src/main/resources/sql/test-data/workbasket-access-list.sql +++ b/common/taskana-common-data/src/main/resources/sql/test-data/workbasket-access-list.sql @@ -1,53 +1,53 @@ -- test-data is used for all tests except for the rest tests --- KSC authorizations (ID , WB_ID , ACCESS_ID , ACCESS_NAME , READ , OPEN , APPEND, TRANSFER, DISTRIBUTE, C1 , C2 , C3 , C4 , C5 , C6 , C7 , C8 , C9 , C10 , C11 , C12) +-- KSC authorizations (ID , WB_ID , ACCESS_ID , ACCESS_NAME , READ , OPEN , APPEND, TRANSFER, DISTRIBUTE, C1 , C2 , C3 , C4 , C5 , C6 , C7 , C8 , C9 , C10 , C11 , C12 ,READTASKS, EDITTASKS) -- PPKs -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000001', 'WBI:100000000000000000000000000000000004', 'teamlead-1' , 'Titus Toll' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000002', 'WBI:100000000000000000000000000000000005', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000003', 'WBI:100000000000000000000000000000000006', 'user-1-1' , 'Max Mustermann' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000004', 'WBI:100000000000000000000000000000000007', 'user-1-2' , 'Elena Eifrig' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000005', 'WBI:100000000000000000000000000000000008', 'user-2-1' , 'Simone Müller' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000006', 'WBI:100000000000000000000000000000000009', 'user-2-2' , 'Tim Schläfrig' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:B00000000000000000000000000000000014', 'WBI:100000000000000000000000000000000014', 'user-b-1' , 'Bernd Bern' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:B00000000000000000000000000000000015', 'WBI:100000000000000000000000000000000015', 'user-b-2' , 'Brundhilde Bio' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000001', 'WBI:100000000000000000000000000000000004', 'teamlead-1' , 'Titus Toll' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000002', 'WBI:100000000000000000000000000000000005', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000003', 'WBI:100000000000000000000000000000000006', 'user-1-1' , 'Max Mustermann' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000004', 'WBI:100000000000000000000000000000000007', 'user-1-2' , 'Elena Eifrig' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000005', 'WBI:100000000000000000000000000000000008', 'user-2-1' , 'Simone Müller' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000006', 'WBI:100000000000000000000000000000000009', 'user-2-2' , 'Tim Schläfrig' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:B00000000000000000000000000000000014', 'WBI:100000000000000000000000000000000014', 'user-b-1' , 'Bernd Bern' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:B00000000000000000000000000000000015', 'WBI:100000000000000000000000000000000015', 'user-b-2' , 'Brundhilde Bio' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -- group internal access -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000007', 'WBI:100000000000000000000000000000000004', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000008', 'WBI:100000000000000000000000000000000005', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000009', 'WBI:100000000000000000000000000000000006', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000010', 'WBI:100000000000000000000000000000000007', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000011', 'WBI:100000000000000000000000000000000008', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000012', 'WBI:100000000000000000000000000000000009', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000007', 'WBI:100000000000000000000000000000000004', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000008', 'WBI:100000000000000000000000000000000005', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000009', 'WBI:100000000000000000000000000000000006', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000010', 'WBI:100000000000000000000000000000000007', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000011', 'WBI:100000000000000000000000000000000008', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000012', 'WBI:100000000000000000000000000000000009', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); -- teamlead substitution -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000013', 'WBI:100000000000000000000000000000000004', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000014', 'WBI:100000000000000000000000000000000005', 'teamlead-1' , 'Titus Toll' , true , true , true , false , false , false, false, false, false, false, false, false, false, false, false, false, false); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000013', 'WBI:100000000000000000000000000000000004', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000014', 'WBI:100000000000000000000000000000000005', 'teamlead-1' , 'Titus Toll' , true , true , true , false , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); -- cross team tranfers -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000015', 'WBI:100000000000000000000000000000000006', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , false, true , false , false , false, false, false, false, false, false, false, false, false, false, false, false); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000016', 'WBI:100000000000000000000000000000000007', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , false, true , false , false , false, false, false, false, false, false, false, false, false, false, false, false); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000017', 'WBI:100000000000000000000000000000000008', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , false, false , false , false , false, false, false, false, false, false, false, false, false, false, false, false); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000018', 'WBI:100000000000000000000000000000000009', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , false, true , false , false , false, false, false, false, false, false, false, false, false, false, false, false); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000015', 'WBI:100000000000000000000000000000000006', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , false, true , false , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000016', 'WBI:100000000000000000000000000000000007', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , false, true , false , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000017', 'WBI:100000000000000000000000000000000008', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , false, false , false , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000018', 'WBI:100000000000000000000000000000000009', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , false, true , false , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); -- Team GPK access -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000019', 'WBI:100000000000000000000000000000000002', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000020', 'WBI:100000000000000000000000000000000003', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000019', 'WBI:100000000000000000000000000000000002', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000020', 'WBI:100000000000000000000000000000000003', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -- Cross team GPK access -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000021', 'WBI:100000000000000000000000000000000001', 'teamlead-1' , 'Titus Toll' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000022', 'WBI:100000000000000000000000000000000001', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000021', 'WBI:100000000000000000000000000000000001', 'teamlead-1' , 'Titus Toll' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000022', 'WBI:100000000000000000000000000000000001', 'teamlead-2' , 'Frauke Faul' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -- TPK access -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000123', 'WBI:100000000000000000000000000000000010', 'teamlead-1' , 'Titus Toll' , true , false, false , false , false , false, false, false, false, false, false, false, false, false, false, false, false); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000123', 'WBI:100000000000000000000000000000000010', 'teamlead-1' , 'Titus Toll' , true , false, false , false , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); -- Access to other domains -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000023', 'WBI:100000000000000000000000000000000012', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , false, true , true , false , false, false, false, false, false, false, false, false, false, false, false, false); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000024', 'WBI:100000000000000000000000000000000013', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , false, true , true , false , false, false, false, false, false, false, false, false, false, false, false, false); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000025', 'WBI:100000000000000000000000000000000014', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000026', 'WBI:100000000000000000000000000000000015', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000023', 'WBI:100000000000000000000000000000000012', 'cn=organisationseinheit ksc 1,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 1' , true , false, true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000024', 'WBI:100000000000000000000000000000000013', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , false, true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000025', 'WBI:100000000000000000000000000000000014', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WAI:100000000000000000000000000000000026', 'WBI:100000000000000000000000000000000015', 'cn=organisationseinheit ksc 2,cn=organisationseinheit ksc,cn=organisation,ou=test,o=taskana', 'KSC 2' , true , true , true , true , false , false, false, false, false, false, false, false, false, false, false, false, false, true , true); -- Access to workbaskets for sorting test -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000900', 'WBI:000000000000000000000000000000000900', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000901', 'WBI:000000000000000000000000000000000901', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000902', 'WBI:000000000000000000000000000000000902', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000903', 'WBI:000000000000000000000000000000000903', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000904', 'WBI:000000000000000000000000000000000904', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000905', 'WBI:000000000000000000000000000000000905', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000906', 'WBI:000000000000000000000000000000000906', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000907', 'WBI:000000000000000000000000000000000907', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000908', 'WBI:000000000000000000000000000000000908', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); -INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000909', 'WBI:000000000000000000000000000000000909', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000900', 'WBI:000000000000000000000000000000000900', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000901', 'WBI:000000000000000000000000000000000901', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000902', 'WBI:000000000000000000000000000000000902', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000903', 'WBI:000000000000000000000000000000000903', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000904', 'WBI:000000000000000000000000000000000904', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000905', 'WBI:000000000000000000000000000000000905', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000906', 'WBI:000000000000000000000000000000000906', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000907', 'WBI:000000000000000000000000000000000907', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000908', 'WBI:000000000000000000000000000000000908', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); +INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('WBI:000000000000000000000000000000000909', 'WBI:000000000000000000000000000000000909', 'user-b-1' , 'Bern, Bernd' , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true , true); diff --git a/common/taskana-common-data/src/main/resources/sql/test-data/workbasket.sql b/common/taskana-common-data/src/main/resources/sql/test-data/workbasket.sql index 580bf5b7bd..a5de604c33 100644 --- a/common/taskana-common-data/src/main/resources/sql/test-data/workbasket.sql +++ b/common/taskana-common-data/src/main/resources/sql/test-data/workbasket.sql @@ -1,34 +1,34 @@ -- test-data is used for all tests except for the rest tests -- KSC workbaskets --- WORKBASKET TABLE (ID , KEY , CREATED , MODIFIED , NAME , DOMAIN , TYPE , DESCRIPTION , OWNER , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4 , ORG_LEVEL_1 , ORG_LEVEL_2 , ORG_LEVEL_3 , ORG_LEVEL_4, MARKED_FOR_DELETION ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000001', 'GPK_KSC' , '2018-02-01 12:00:00', '2018-02-01 12:00:00', 'Gruppenpostkorb KSC' , 'DOMAIN_A', 'GROUP' , 'Gruppenpostkorb KSC' , 'teamlead-1' , 'ABCQVW' , '' , 'xyz4' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000002', 'GPK_KSC_1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC 1' , 'DOMAIN_A', 'GROUP' , 'Gruppenpostkorb KSC 1' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000003', 'GPK_KSC_2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC 2' , 'DOMAIN_A', 'GROUP' , 'Gruppenpostkorb KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000004', 'TEAMLEAD-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK Teamlead KSC 1' , 'DOMAIN_A', 'PERSONAL', 'PPK Teamlead KSC 1' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000005', 'TEAMLEAD-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK Teamlead KSC 2' , 'DOMAIN_A', 'PERSONAL', 'PPK Teamlead KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000006', 'USER-1-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 1' , 'DOMAIN_A', 'PERSONAL', 'PPK User 1 KSC 1' , '' , '' , '' , '' , 'custom4z', '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000007', 'USER-1-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 1' , 'DOMAIN_A', 'PERSONAL', 'PPK User 2 KSC 1' , 'user-1-2' , 'custom1', 'custom2' , 'custom3', 'custom4' , 'versicherung', 'abteilung' , 'projekt' , 'team' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000008', 'USER-2-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 2' , 'DOMAIN_A', 'PERSONAL', 'PPK User 1 KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000009', 'USER-2-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 2' , 'DOMAIN_A', 'PERSONAL', 'PPK User 2 KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000010', 'TPK_VIP' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Themenpostkorb VIP' , 'DOMAIN_A', 'TOPIC' , 'Themenpostkorb VIP' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +-- WORKBASKET TABLE (ID , KEY , CREATED , MODIFIED , NAME , DOMAIN , TYPE , DESCRIPTION , OWNER , CUSTOM_1 , CUSTOM_2 , CUSTOM_3 , CUSTOM_4 , ORG_LEVEL_1 , ORG_LEVEL_2 , ORG_LEVEL_3 , ORG_LEVEL_4, MARKED_FOR_DELETION , CUSTOM_5 , CUSTOM_6 , CUSTOM_7 , CUSTOM_8 ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000001', 'GPK_KSC' , '2018-02-01 12:00:00', '2018-02-01 12:00:00', 'Gruppenpostkorb KSC' , 'DOMAIN_A', 'GROUP' , 'Gruppenpostkorb KSC' , 'teamlead-1' , 'ABCQVW' , '' , 'xyz4' , '' , '' , '' , '' , '' , false , 'XYZ123' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000002', 'GPK_KSC_1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC 1' , 'DOMAIN_A', 'GROUP' , 'Gruppenpostkorb KSC 1' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , 'ABCABC' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000003', 'GPK_KSC_2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC 2' , 'DOMAIN_A', 'GROUP' , 'Gruppenpostkorb KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000004', 'TEAMLEAD-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK Teamlead KSC 1' , 'DOMAIN_A', 'PERSONAL', 'PPK Teamlead KSC 1' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000005', 'TEAMLEAD-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK Teamlead KSC 2' , 'DOMAIN_A', 'PERSONAL', 'PPK Teamlead KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000006', 'USER-1-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 1' , 'DOMAIN_A', 'PERSONAL', 'PPK User 1 KSC 1' , '' , '' , '' , '' , 'custom4z', '' , '' , '' , '' , false , '' , '' , '' , 'cust8z' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000007', 'USER-1-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 1' , 'DOMAIN_A', 'PERSONAL', 'PPK User 2 KSC 1' , 'user-1-2' , 'custom1', 'custom2' , 'custom3', 'custom4' , 'versicherung', 'abteilung' , 'projekt' , 'team' , false , 'custom5', 'custom6', 'custom7', 'custom8' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000008', 'USER-2-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 2' , 'DOMAIN_A', 'PERSONAL', 'PPK User 1 KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000009', 'USER-2-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 2' , 'DOMAIN_A', 'PERSONAL', 'PPK User 2 KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000010', 'TPK_VIP' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Themenpostkorb VIP' , 'DOMAIN_A', 'TOPIC' , 'Themenpostkorb VIP' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); -- KSC workbaskets Domain_B -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000011', 'GPK_B_KSC' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC B' , 'DOMAIN_B', 'GROUP' , 'Gruppenpostkorb KSC' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000012', 'GPK_B_KSC_1', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC B1' , 'DOMAIN_B', 'GROUP' , 'Gruppenpostkorb KSC 1' , '' , 'custom1', 'custom2' , 'custom3', 'custom4' , 'orgl1' , 'orgl2' , 'orgl3' , 'aorgl4' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000013', 'GPK_B_KSC_2', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC B2' , 'DOMAIN_B', 'GROUP' , 'Gruppenpostkorb KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000014', 'USER-B-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 1 Domain B', 'DOMAIN_B', 'PERSONAL', 'PPK User 1 KSC 1 Domain B' , '' , '' , 'custom20', '' , 'custom4' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000015', 'USER-B-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 1 Domain B', 'DOMAIN_B', 'PERSONAL', 'PPK User 1 KSC 1 Domain B' , 'user-1-2' , 'ABCABC' , 'cust2' , 'cust3' , 'cust4' , 'orgl1' , 'orgl2' , 'orgl3' , 'orgl4' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000016', 'MASSNAHMEN' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'TPK Maßnahmen' , 'DOMAIN_B', 'TOPIC' , 'TPK Maßnahmen' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000011', 'GPK_B_KSC' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC B' , 'DOMAIN_B', 'GROUP' , 'Gruppenpostkorb KSC' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000012', 'GPK_B_KSC_1', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC B1' , 'DOMAIN_B', 'GROUP' , 'Gruppenpostkorb KSC 1' , '' , 'custom1', 'custom2' , 'custom3', 'custom4' , 'orgl1' , 'orgl2' , 'orgl3' , 'aorgl4' , false , 'abc123' , '' , 'TSK123' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000013', 'GPK_B_KSC_2', RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Gruppenpostkorb KSC B2' , 'DOMAIN_B', 'GROUP' , 'Gruppenpostkorb KSC 2' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000014', 'USER-B-1' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 1 KSC 1 Domain B', 'DOMAIN_B', 'PERSONAL', 'PPK User 1 KSC 1 Domain B' , '' , '' , 'custom20', '' , 'custom4' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000015', 'USER-B-2' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'PPK User 2 KSC 1 Domain B', 'DOMAIN_B', 'PERSONAL', 'PPK User 1 KSC 1 Domain B' , 'user-1-2' , 'ABCABC' , 'cust2' , 'cust3' , 'cust4' , 'orgl1' , 'orgl2' , 'orgl3' , 'orgl4' , false , '' , 'cust6' , 'cust7' , 'cust8' ); +INSERT INTO WORKBASKET VALUES ('WBI:100000000000000000000000000000000016', 'MASSNAHMEN' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'TPK Maßnahmen' , 'DOMAIN_B', 'TOPIC' , 'TPK Maßnahmen' , '' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); -- Workbaskets for sorting test -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000900', 'sort001' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxet0' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000901', 'Sort002' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Basxet1' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000902', 'sOrt003' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'bAsxet2' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000903', 'soRt004' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'baSxet3' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000904', 'sorT005' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basXet4' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000905', 'Sort006' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxEt5' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000906', 'SOrt007' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxeT6' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000907', 'SoRt008' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BAsxet7' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000908', 'SorT009' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BaSxet8' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); -INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000909', 'Sort010' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BasXet9' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000900', 'sort001' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxet0' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000901', 'Sort002' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'Basxet1' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000902', 'sOrt003' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'bAsxet2' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000903', 'soRt004' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'baSxet3' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000904', 'sorT005' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basXet4' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000905', 'Sort006' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxEt5' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000906', 'SOrt007' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'basxeT6' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000907', 'SoRt008' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BAsxet7' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000908', 'SorT009' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BaSxet8' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); +INSERT INTO WORKBASKET VALUES ('WBI:000000000000000000000000000000000909', 'Sort010' , RELATIVE_DATE(0) , RELATIVE_DATE(0) , 'BasXet9' , 'DOMAIN_A', 'TOPIC' , 'Lorem ipsum dolor sit amet.', 'user-1-3' , '' , '' , '' , '' , '' , '' , '' , '' , false , '' , '' , '' , '' ); diff --git a/common/taskana-common-logging/pom.xml b/common/taskana-common-logging/pom.xml index 0b2b6b5168..fd79390d3c 100644 --- a/common/taskana-common-logging/pom.xml +++ b/common/taskana-common-logging/pom.xml @@ -11,7 +11,7 @@ pro.taskana taskana-common-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT @@ -32,7 +32,7 @@ test - uk.org.lidalia + com.github.valfirst slf4j-test ${version.slf4j-test} test @@ -40,11 +40,12 @@ org.assertj assertj-core + ${version.assertj} test org.mockito - mockito-inline + mockito-core test diff --git a/common/taskana-common-logging/src/test/java/pro/taskana/common/internal/logging/LoggingAspectTest.java b/common/taskana-common-logging/src/test/java/pro/taskana/common/internal/logging/LoggingAspectTest.java index e1a3f465fd..1bb017686f 100644 --- a/common/taskana-common-logging/src/test/java/pro/taskana/common/internal/logging/LoggingAspectTest.java +++ b/common/taskana-common-logging/src/test/java/pro/taskana/common/internal/logging/LoggingAspectTest.java @@ -2,6 +2,9 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.github.valfirst.slf4jtest.LoggingEvent; +import com.github.valfirst.slf4jtest.TestLogger; +import com.github.valfirst.slf4jtest.TestLoggerFactory; import org.assertj.core.api.Condition; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -9,12 +12,9 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.internal.stubbing.answers.CallsRealMethods; +import org.slf4j.event.Level; import outside.of.pro.taskana.OutsideOfProTaskanaPackageLoggingTestClass; import pro.taskana.AtProTaskanaRootPackageLoggingTestClass; -import uk.org.lidalia.slf4jext.Level; -import uk.org.lidalia.slf4jtest.LoggingEvent; -import uk.org.lidalia.slf4jtest.TestLogger; -import uk.org.lidalia.slf4jtest.TestLoggerFactory; @NoLogging class LoggingAspectTest { diff --git a/common/taskana-common-security/pom.xml b/common/taskana-common-security/pom.xml index ac86239f26..13835498c1 100644 --- a/common/taskana-common-security/pom.xml +++ b/common/taskana-common-security/pom.xml @@ -11,7 +11,7 @@ pro.taskana taskana-common-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT diff --git a/common/taskana-common-security/src/main/java/pro/taskana/common/internal/security/CurrentUserContextImpl.java b/common/taskana-common-security/src/main/java/pro/taskana/common/internal/security/CurrentUserContextImpl.java index a18cc80ce5..d6954f3d86 100644 --- a/common/taskana-common-security/src/main/java/pro/taskana/common/internal/security/CurrentUserContextImpl.java +++ b/common/taskana-common-security/src/main/java/pro/taskana/common/internal/security/CurrentUserContextImpl.java @@ -49,7 +49,9 @@ public String getUserid() { } @Override + @SuppressWarnings("removal") public List getGroupIds() { + // TODO replace with Subject.current() when migrating to newer Version than 17 Subject subject = Subject.getSubject(AccessController.getContext()); LOGGER.trace("Subject of caller: {}", subject); if (subject != null) { @@ -125,7 +127,9 @@ private String getUserIdFromWsSubject() { return null; } + @SuppressWarnings("removal") private String getUserIdFromJaasSubject() { + // TODO replace with Subject.current() when migrating to newer Version than 17 Subject subject = Subject.getSubject(AccessController.getContext()); LOGGER.trace("Subject of caller: {}", subject); if (subject != null) { diff --git a/common/taskana-common-test/pom.xml b/common/taskana-common-test/pom.xml index 99d4859e99..7f33b80ae2 100644 --- a/common/taskana-common-test/pom.xml +++ b/common/taskana-common-test/pom.xml @@ -11,7 +11,7 @@ pro.taskana taskana-common-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../pom.xml @@ -52,9 +52,9 @@ jackson-datatype-jsr310 - javax.servlet - javax.servlet-api - ${version.javax.servlet} + jakarta.servlet + jakarta.servlet-api + ${version.jakarta.servlet} org.springframework @@ -150,6 +150,7 @@ org.assertj assertj-core + ${version.assertj} test diff --git a/common/taskana-common/pom.xml b/common/taskana-common/pom.xml index 5d9b32e927..27d7c5e815 100644 --- a/common/taskana-common/pom.xml +++ b/common/taskana-common/pom.xml @@ -11,7 +11,7 @@ pro.taskana taskana-common-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT @@ -54,6 +54,7 @@ org.assertj assertj-core + ${version.assertj} test diff --git a/common/taskana-common/src/main/java/pro/taskana/common/internal/configuration/parser/PropertyParser.java b/common/taskana-common/src/main/java/pro/taskana/common/internal/configuration/parser/PropertyParser.java index 4faaa81915..ee7cdb8fc4 100644 --- a/common/taskana-common/src/main/java/pro/taskana/common/internal/configuration/parser/PropertyParser.java +++ b/common/taskana-common/src/main/java/pro/taskana/common/internal/configuration/parser/PropertyParser.java @@ -36,7 +36,7 @@ public interface PropertyParser { new SimpleParser<>(String.class, Function.identity()), new SimpleParser<>(ZoneId.class, ZoneId::of)) .collect( - Collectors.toUnmodifiableMap(PropertyParser::getTargetClass, Function.identity())); + Collectors.toUnmodifiableMap(PropertyParser::getTargetClass, t -> t)); static PropertyParser getPropertyParser(Class forClass) { forClass = ReflectionUtil.wrap(forClass); diff --git a/common/taskana-common/src/main/java/pro/taskana/common/internal/util/ObjectAttributeChangeDetector.java b/common/taskana-common/src/main/java/pro/taskana/common/internal/util/ObjectAttributeChangeDetector.java index b22a2f8f5c..b995ccb2b5 100644 --- a/common/taskana-common/src/main/java/pro/taskana/common/internal/util/ObjectAttributeChangeDetector.java +++ b/common/taskana-common/src/main/java/pro/taskana/common/internal/util/ObjectAttributeChangeDetector.java @@ -40,7 +40,8 @@ public static String determineChangesInAttributes(T oldObject, T newObject) // this has to be checked after we deal with List data types, because // we want to allow different implementations of the List interface to work as well. - if (!oldObject.getClass().equals(newObject.getClass())) { + if (!oldObject.getClass().equals(newObject.getClass()) + && !oldObject.getClass().isAssignableFrom(newObject.getClass())) { throw new SystemException( String.format( "The classes differ between the oldObject(%s) and newObject(%s). " diff --git a/common/taskana-common/src/main/java/pro/taskana/common/internal/util/SqlProviderUtil.java b/common/taskana-common/src/main/java/pro/taskana/common/internal/util/SqlProviderUtil.java index 0ed7a1979c..0e933fbebb 100644 --- a/common/taskana-common/src/main/java/pro/taskana/common/internal/util/SqlProviderUtil.java +++ b/common/taskana-common/src/main/java/pro/taskana/common/internal/util/SqlProviderUtil.java @@ -24,7 +24,7 @@ public static StringBuilder whereIn(String collection, String column, StringBuil .append("") .append("0=1") .append(""); - if (column.matches("t.CUSTOM_\\d+")) { + if (column.matches("t.CUSTOM_\\d+") || column.matches("t.OWNER")) { sb.append(" OR " + column + " IS NULL "); } return sb.append(") "); diff --git a/common/taskana-common/src/main/java/pro/taskana/common/internal/workingtime/WorkingDayCalculatorImpl.java b/common/taskana-common/src/main/java/pro/taskana/common/internal/workingtime/WorkingDayCalculatorImpl.java new file mode 100644 index 0000000000..ddaf46d8b2 --- /dev/null +++ b/common/taskana-common/src/main/java/pro/taskana/common/internal/workingtime/WorkingDayCalculatorImpl.java @@ -0,0 +1,118 @@ +package pro.taskana.common.internal.workingtime; + +import java.time.DayOfWeek; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.stream.LongStream; +import pro.taskana.common.api.WorkingTimeCalculator; +import pro.taskana.common.api.exceptions.InvalidArgumentException; +import pro.taskana.common.api.exceptions.SystemException; + +public class WorkingDayCalculatorImpl implements WorkingTimeCalculator { + + private final ZoneId zoneId; + private final HolidaySchedule holidaySchedule; + + public WorkingDayCalculatorImpl(HolidaySchedule holidaySchedule, ZoneId zoneId) { + this.holidaySchedule = holidaySchedule; + this.zoneId = zoneId; + } + + @Override + public Instant subtractWorkingTime(Instant workStart, Duration workingTime) + throws InvalidArgumentException { + long days = convertWorkingDaysToDays(workStart, -workingTime.toDays(), ZeroDirection.SUB_DAYS); + return workStart.plus(Duration.ofDays(days)); + } + + @Override + public Instant addWorkingTime(Instant workStart, Duration workingTime) + throws InvalidArgumentException { + long days = convertWorkingDaysToDays(workStart, workingTime.toDays(), ZeroDirection.ADD_DAYS); + return workStart.plus(Duration.ofDays(days)); + } + + @Override + public Duration workingTimeBetween(Instant first, Instant second) + throws InvalidArgumentException { + long days = Duration.between(first, second).abs().toDays(); + Instant firstInstant = first.isBefore(second) ? first : second; + + long workingDaysBetween = + LongStream.range(1, days) + .mapToObj(day -> isWorkingDay(firstInstant.plus(day, ChronoUnit.DAYS))) + .filter(t -> t) + .count(); + return Duration.ofDays(workingDaysBetween); + } + + @Override + public boolean isWorkingDay(Instant instant) { + return !isWeekend(instant) && !isHoliday(instant); + } + + @Override + public boolean isWeekend(Instant instant) { + DayOfWeek dayOfWeek = toDayOfWeek(instant); + return dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY; + } + + @Override + public boolean isHoliday(Instant instant) { + return holidaySchedule.isHoliday(toLocalDate(instant)); + } + + @Override + public boolean isGermanHoliday(Instant instant) { + return holidaySchedule.isGermanHoliday(toLocalDate(instant)); + } + + private long convertWorkingDaysToDays( + final Instant startTime, long numberOfDays, ZeroDirection zeroDirection) { + if (startTime == null) { + throw new SystemException( + "Internal Error: convertWorkingDaysToDays was called with a null startTime"); + } + int direction = calculateDirection(numberOfDays, zeroDirection); + long limit = Math.abs(numberOfDays); + return LongStream.iterate(0, i -> i + direction) + .filter(day -> isWorkingDay(startTime.plus(day, ChronoUnit.DAYS))) + .skip(limit) + .findFirst() + .orElse(0); + } + + private int calculateDirection(long numberOfDays, ZeroDirection zeroDirection) { + if (numberOfDays == 0) { + return zeroDirection.getDirection(); + } else { + return numberOfDays >= 0 ? 1 : -1; + } + } + + private LocalDate toLocalDate(Instant instant) { + return LocalDate.ofInstant(instant, zoneId); + } + + private DayOfWeek toDayOfWeek(Instant instant) { + return toLocalDate(instant).getDayOfWeek(); + } + + private enum ZeroDirection { + SUB_DAYS(-1), + ADD_DAYS(1); + + private final int direction; + + ZeroDirection(int direction) { + this.direction = direction; + } + + public int getDirection() { + return direction; + } + } +} diff --git a/common/taskana-common/src/main/resources/sql/db2/taskana-schema-db2.sql b/common/taskana-common/src/main/resources/sql/db2/taskana-schema-db2.sql index 98425dbd8c..7f5a3600a0 100644 --- a/common/taskana-common/src/main/resources/sql/db2/taskana-schema-db2.sql +++ b/common/taskana-common/src/main/resources/sql/db2/taskana-schema-db2.sql @@ -15,7 +15,7 @@ CREATE SEQUENCE TASKANA_SCHEMA_VERSION_ID_SEQ -- The VERSION value must be equal or higher then the value of TaskanaEngineImpl.MINIMAL_TASKANA_SCHEMA_VERSION INSERT INTO TASKANA_SCHEMA_VERSION (ID, VERSION, CREATED) -VALUES (TASKANA_SCHEMA_VERSION_ID_SEQ.NEXTVAL, '5.10.0', CURRENT_TIMESTAMP); +VALUES (TASKANA_SCHEMA_VERSION_ID_SEQ.NEXTVAL, '7.0.0', CURRENT_TIMESTAMP); CREATE TABLE CLASSIFICATION ( @@ -66,6 +66,10 @@ CREATE TABLE WORKBASKET ORG_LEVEL_3 VARCHAR(255) NULL, ORG_LEVEL_4 VARCHAR(255) NULL, MARKED_FOR_DELETION SMALLINT NOT NULL, + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL, PRIMARY KEY (ID), CONSTRAINT WB_KEY_DOMAIN UNIQUE (KEY, DOMAIN) ); @@ -167,6 +171,8 @@ CREATE TABLE WORKBASKET_ACCESS_LIST PERM_CUSTOM_10 SMALLINT NOT NULL, PERM_CUSTOM_11 SMALLINT NOT NULL, PERM_CUSTOM_12 SMALLINT NOT NULL, + PERM_READTASKS SMALLINT NOT NULL, + PERM_EDITTASKS SMALLINT NOT NULL, PRIMARY KEY (ID), CONSTRAINT UC_ACCESSID_WBID UNIQUE (ACCESS_ID, WORKBASKET_ID), CONSTRAINT ACCESS_LIST_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE CASCADE @@ -355,6 +361,13 @@ CREATE TABLE GROUP_INFO PRIMARY KEY (USER_ID, GROUP_ID) ); +CREATE TABLE PERMISSION_INFO +( + USER_ID VARCHAR(32) NOT NUll, + PERMISSION_ID VARCHAR(256) NOT NULL, + PRIMARY KEY (USER_ID, PERMISSION_ID) +); + CREATE SEQUENCE SCHEDULED_JOB_SEQ MINVALUE 1 START WITH 1 @@ -446,4 +459,8 @@ COMMIT WORK ; CREATE INDEX IDX_OBJECT_REFERE_ACCESS_LIST ON OBJECT_REFERENCE (VALUE ASC, TYPE ASC, SYSTEM_INSTANCE ASC, SYSTEM ASC, COMPANY ASC, ID ASC) ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; +COMMIT WORK ; +CREATE INDEX IDX_TASK_ID_HISTORY_EVENT ON TASK_HISTORY_EVENT + (TASK_ID ASC) + ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; COMMIT WORK ; \ No newline at end of file diff --git a/common/taskana-common/src/main/resources/sql/db2/taskana_schema_update_5.10.0_to_6.2.0_db2.sql b/common/taskana-common/src/main/resources/sql/db2/taskana_schema_update_5.10.0_to_6.2.0_db2.sql new file mode 100644 index 0000000000..e767fab81a --- /dev/null +++ b/common/taskana-common/src/main/resources/sql/db2/taskana_schema_update_5.10.0_to_6.2.0_db2.sql @@ -0,0 +1,19 @@ +-- this script updates the TASKANA database schema from version 5.10.0 to version 6.2.0. +SET SCHEMA %schemaName%; + +INSERT INTO TASKANA_SCHEMA_VERSION (ID, VERSION, CREATED) +VALUES (TASKANA_SCHEMA_VERSION_ID_SEQ.NEXTVAL, '6.2.0', CURRENT_TIMESTAMP); + +ALTER TABLE WORKBASKET_ACCESS_LIST + ADD COLUMN PERM_READTASKS SMALLINT NOT NULL DEFAULT 0; +UPDATE WORKBASKET_ACCESS_LIST +SET PERM_READTASKS=PERM_READ; +ALTER TABLE WORKBASKET_ACCESS_LIST + ALTER COLUMN PERM_READTASKS DROP DEFAULT; + +ALTER TABLE WORKBASKET_ACCESS_LIST + ADD COLUMN PERM_EDITTASKS SMALLINT NOT NULL DEFAULT 0; +UPDATE WORKBASKET_ACCESS_LIST +SET PERM_EDITTASKS=PERM_READ; +ALTER TABLE WORKBASKET_ACCESS_LIST + ALTER COLUMN PERM_EDITTASKS DROP DEFAULT; diff --git a/common/taskana-common/src/main/resources/sql/db2/taskana_schema_update_6.2.0_to_7.0.0_db2.sql b/common/taskana-common/src/main/resources/sql/db2/taskana_schema_update_6.2.0_to_7.0.0_db2.sql new file mode 100644 index 0000000000..84c9b70dbd --- /dev/null +++ b/common/taskana-common/src/main/resources/sql/db2/taskana_schema_update_6.2.0_to_7.0.0_db2.sql @@ -0,0 +1,23 @@ +-- this script updates the TASKANA database schema from version 6.2.0 to version 7.0.0. +SET SCHEMA %schemaName%; + +INSERT INTO TASKANA_SCHEMA_VERSION (ID, VERSION, CREATED) +VALUES (TASKANA_SCHEMA_VERSION_ID_SEQ.NEXTVAL, '7.0.0', CURRENT_TIMESTAMP); + +CREATE TABLE PERMISSION_INFO +( + USER_ID VARCHAR(32) NOT NULL, + PERMISSION_ID VARCHAR(256) NOT NULL, + PRIMARY KEY (USER_ID, PERMISSION_ID) +); + +ALTER TABLE WORKBASKET + ADD COLUMN CUSTOM_5 VARCHAR(255) NULL + ADD COLUMN CUSTOM_6 VARCHAR(255) NULL + ADD COLUMN CUSTOM_7 VARCHAR(255) NULL + ADD COLUMN CUSTOM_8 VARCHAR(255) NULL; + +CREATE INDEX IDX_TASK_ID_HISTORY_EVENT ON TASK_HISTORY_EVENT + (TASK_ID ASC) + ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; +COMMIT WORK ; \ No newline at end of file diff --git a/common/taskana-common/src/main/resources/sql/h2/taskana-schema-h2.sql b/common/taskana-common/src/main/resources/sql/h2/taskana-schema-h2.sql index a447f2e220..a12789a723 100644 --- a/common/taskana-common/src/main/resources/sql/h2/taskana-schema-h2.sql +++ b/common/taskana-common/src/main/resources/sql/h2/taskana-schema-h2.sql @@ -22,7 +22,7 @@ CREATE SEQUENCE TASKANA_SCHEMA_VERSION_ID_SEQ -- The VERSION value must be equal or higher then the value of TaskanaEngineImpl.MINIMAL_TASKANA_SCHEMA_VERSION INSERT INTO TASKANA_SCHEMA_VERSION (ID, VERSION, CREATED) -VALUES (nextval('TASKANA_SCHEMA_VERSION_ID_SEQ'), '5.10.0', CURRENT_TIMESTAMP); +VALUES (nextval('TASKANA_SCHEMA_VERSION_ID_SEQ'), '7.0.0', CURRENT_TIMESTAMP); CREATE TABLE CLASSIFICATION ( @@ -73,6 +73,10 @@ CREATE TABLE WORKBASKET ORG_LEVEL_3 VARCHAR(255) NULL, ORG_LEVEL_4 VARCHAR(255) NULL, MARKED_FOR_DELETION SMALLINT NOT NULL, + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL, PRIMARY KEY (ID), CONSTRAINT WB_KEY_DOMAIN UNIQUE (KEY, DOMAIN) ); @@ -174,6 +178,8 @@ CREATE TABLE WORKBASKET_ACCESS_LIST PERM_CUSTOM_10 SMALLINT NOT NULL, PERM_CUSTOM_11 SMALLINT NOT NULL, PERM_CUSTOM_12 SMALLINT NOT NULL, + PERM_READTASKS SMALLINT NOT NULL, + PERM_EDITTASKS SMALLINT NOT NULL, PRIMARY KEY (ID), CONSTRAINT UC_ACCESSID_WBID UNIQUE (ACCESS_ID, WORKBASKET_ID), CONSTRAINT ACCESS_LIST_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE CASCADE @@ -361,6 +367,13 @@ CREATE TABLE GROUP_INFO PRIMARY KEY (USER_ID, GROUP_ID) ); +CREATE TABLE PERMISSION_INFO +( + USER_ID VARCHAR(32) NOT NULL, + PERMISSION_ID VARCHAR(256) NOT NULL, + PRIMARY KEY (USER_ID, PERMISSION_ID) +); + CREATE SEQUENCE SCHEDULED_JOB_SEQ MINVALUE 1 START WITH 1 @@ -445,4 +458,4 @@ CREATE INDEX IDX_OBJECT_REFERE_FK_TASK_ID ON OBJECT_REFERENCE COMMIT WORK ; CREATE INDEX IDX_OBJECT_REFERE_ACCESS_LIST ON OBJECT_REFERENCE (VALUE ASC, TYPE ASC, SYSTEM_INSTANCE ASC, SYSTEM ASC, COMPANY ASC, ID ASC); -COMMIT WORK ; \ No newline at end of file +COMMIT WORK ; diff --git a/common/taskana-common/src/main/resources/sql/h2/taskana_schema_update_5.10.0_to_6.2.0_h2.sql b/common/taskana-common/src/main/resources/sql/h2/taskana_schema_update_5.10.0_to_6.2.0_h2.sql new file mode 100644 index 0000000000..eeb153e0b3 --- /dev/null +++ b/common/taskana-common/src/main/resources/sql/h2/taskana_schema_update_5.10.0_to_6.2.0_h2.sql @@ -0,0 +1,19 @@ +-- this script updates the TASKANA database schema from version 5.10.0 to version 6.2.0. +SET SCHEMA %schemaName%; + +INSERT INTO TASKANA_SCHEMA_VERSION (ID, VERSION, CREATED) +VALUES (nextval('TASKANA_SCHEMA_VERSION_ID_SEQ'), '6.2.0', CURRENT_TIMESTAMP); + +ALTER TABLE WORKBASKET_ACCESS_LIST + ADD COLUMN PERM_READTASKS SMALLINT NOT NULL DEFAULT 0; +UPDATE WORKBASKET_ACCESS_LIST +SET PERM_READTASKS=PERM_READ; +ALTER TABLE WORKBASKET_ACCESS_LIST + ALTER COLUMN PERM_READTASKS DROP DEFAULT; + +ALTER TABLE WORKBASKET_ACCESS_LIST + ADD COLUMN PERM_EDITTASKS SMALLINT NOT NULL DEFAULT 0; +UPDATE WORKBASKET_ACCESS_LIST +SET PERM_EDITTASKS=PERM_READ; +ALTER TABLE WORKBASKET_ACCESS_LIST + ALTER COLUMN PERM_EDITTASKS DROP DEFAULT; diff --git a/common/taskana-common/src/main/resources/sql/h2/taskana_schema_update_6.2.0_to_7.0.0_h2.sql b/common/taskana-common/src/main/resources/sql/h2/taskana_schema_update_6.2.0_to_7.0.0_h2.sql new file mode 100644 index 0000000000..271e7ebcc7 --- /dev/null +++ b/common/taskana-common/src/main/resources/sql/h2/taskana_schema_update_6.2.0_to_7.0.0_h2.sql @@ -0,0 +1,19 @@ +-- this script updates the TASKANA database schema from version 6.2.0 to version 7.0.0. + +INSERT INTO TASKANA_SCHEMA_VERSION (ID, VERSION, CREATED) +VALUES (nextval('TASKANA_SCHEMA_VERSION_ID_SEQ'), '7.0.0', CURRENT_TIMESTAMP); + +CREATE TABLE PERMISSION_INFO +( + USER_ID VARCHAR(32) NOT NULL, + PERMISSION_ID VARCHAR(256) NOT NULL, + PRIMARY KEY (USER_ID, PERMISSION_ID) +); + +ALTER TABLE WORKBASKET + ADD ( + `CUSTOM_5` VARCHAR(255) NULL, + `CUSTOM_6` VARCHAR(255) NULL, + `CUSTOM_7` VARCHAR(255) NULL, + `CUSTOM_8` VARCHAR(255) NULL + ) AFTER `MARKED_FOR_DELETION`; diff --git a/common/taskana-common/src/main/resources/sql/oracle/taskana-schema-oracle.sql b/common/taskana-common/src/main/resources/sql/oracle/taskana-schema-oracle.sql index 15f70aebaf..8591f0213d 100644 --- a/common/taskana-common/src/main/resources/sql/oracle/taskana-schema-oracle.sql +++ b/common/taskana-common/src/main/resources/sql/oracle/taskana-schema-oracle.sql @@ -14,7 +14,7 @@ CREATE SEQUENCE TASKANA_SCHEMA_VERSION_ID_SEQ -- The VERSION value must be equal or higher then the value of TaskanaEngineImpl.MINIMAL_TASKANA_SCHEMA_VERSION INSERT INTO TASKANA_SCHEMA_VERSION (ID, VERSION, CREATED) -VALUES (TASKANA_SCHEMA_VERSION_ID_SEQ.NEXTVAL, '5.10.0', CURRENT_TIMESTAMP); +VALUES (TASKANA_SCHEMA_VERSION_ID_SEQ.NEXTVAL, '7.0.0', CURRENT_TIMESTAMP); CREATE TABLE CLASSIFICATION ( @@ -65,6 +65,10 @@ CREATE TABLE WORKBASKET ORG_LEVEL_3 VARCHAR2(255) NULL, ORG_LEVEL_4 VARCHAR2(255) NULL, MARKED_FOR_DELETION NUMBER(1) NOT NULL CHECK (MARKED_FOR_DELETION IN (0,1)), + CUSTOM_5 VARCHAR2(255) NULL, + CUSTOM_6 VARCHAR2(255) NULL, + CUSTOM_7 VARCHAR2(255) NULL, + CUSTOM_8 VARCHAR2(255) NULL, CONSTRAINT WORKBASKET_PKEY PRIMARY KEY (ID), CONSTRAINT WB_KEY_DOMAIN UNIQUE (KEY, DOMAIN) ); @@ -166,6 +170,8 @@ CREATE TABLE WORKBASKET_ACCESS_LIST PERM_CUSTOM_10 NUMBER(1) NOT NULL CHECK (PERM_CUSTOM_10 IN (0,1)), PERM_CUSTOM_11 NUMBER(1) NOT NULL CHECK (PERM_CUSTOM_11 IN (0,1)), PERM_CUSTOM_12 NUMBER(1) NOT NULL CHECK (PERM_CUSTOM_12 IN (0,1)), + PERM_READTASKS NUMBER(1) NOT NULL CHECK (PERM_READTASKS IN (0,1)), + PERM_EDITTASKS NUMBER(1) NOT NULL CHECK (PERM_EDITTASKS IN (0,1)), CONSTRAINT WORKBASKET_ACCESS_LIST_PKEY PRIMARY KEY (ID), CONSTRAINT UC_ACCESSID_WBID UNIQUE (ACCESS_ID, WORKBASKET_ID), CONSTRAINT ACCESS_LIST_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET(ID) ON DELETE CASCADE @@ -354,6 +360,13 @@ CREATE TABLE GROUP_INFO CONSTRAINT GROUP_INFO_PKEY PRIMARY KEY (USER_ID, GROUP_ID) ); +CREATE TABLE PERMISSION_INFO +( + USER_ID VARCHAR2(32) NOT NULL, + PERMISSION_ID VARCHAR2(256) NOT NULL, + CONSTRAINT PERMISSION_INFO_PKEY PRIMARY KEY (USER_ID, PERMISSION_ID) +); + CREATE SEQUENCE SCHEDULED_JOB_SEQ START WITH 1 INCREMENT BY 1 @@ -444,4 +457,7 @@ CREATE INDEX IDX_OBJECT_REFERE_FK_TASK_ID ON OBJECT_REFERENCE COMMIT WORK ; CREATE INDEX IDX_OBJECT_REFERE_ACCESS_LIST ON OBJECT_REFERENCE (VALUE ASC, TYPE ASC, SYSTEM_INSTANCE ASC, SYSTEM ASC, COMPANY ASC, ID ASC); +COMMIT WORK ; +CREATE INDEX IDX_TASK_ID_HISTORY_EVENT ON TASK_HISTORY_EVENT + (TASK_ID ASC); COMMIT WORK ; \ No newline at end of file diff --git a/common/taskana-common/src/main/resources/sql/oracle/taskana_schema_update_5.10.0_to_6.2.0_oracle.sql b/common/taskana-common/src/main/resources/sql/oracle/taskana_schema_update_5.10.0_to_6.2.0_oracle.sql new file mode 100644 index 0000000000..55aedcd99d --- /dev/null +++ b/common/taskana-common/src/main/resources/sql/oracle/taskana_schema_update_5.10.0_to_6.2.0_oracle.sql @@ -0,0 +1,20 @@ +-- this script updates the TASKANA database schema from version 5.10.0 to version 6.2.0. +ALTER +SESSION SET CURRENT_SCHEMA = %schemaName%; + +INSERT INTO TASKANA_SCHEMA_VERSION (ID, VERSION, CREATED) +VALUES (TASKANA_SCHEMA_VERSION_ID_SEQ.NEXTVAL, '6.2.0', CURRENT_TIMESTAMP); + +ALTER TABLE WORKBASKET_ACCESS_LIST + ADD PERM_READTASKS NUMBER(1) DEFAULT 0 NOT NULL CHECK (PERM_READTASKS IN (0,1)); +UPDATE WORKBASKET_ACCESS_LIST +SET PERM_READTASKS=PERM_READ; +ALTER TABLE WORKBASKET_ACCESS_LIST + ALTER PERM_READTASKS DROP DEFAULT; + +ALTER TABLE WORKBASKET_ACCESS_LIST + ADD PERM_EDITTASKS NUMBER(1) DEFAULT 0 NOT NULL CHECK (PERM_EDITTASKS IN (0,1)); +UPDATE WORKBASKET_ACCESS_LIST +SET PERM_EDITTASKS=PERM_READ; +ALTER TABLE WORKBASKET_ACCESS_LIST + ALTER PERM_EDITTASKS DROP DEFAULT diff --git a/common/taskana-common/src/main/resources/sql/oracle/taskana_schema_update_6.2.0_to_7.0.0_oracle.sql b/common/taskana-common/src/main/resources/sql/oracle/taskana_schema_update_6.2.0_to_7.0.0_oracle.sql new file mode 100644 index 0000000000..1d21a5b3a4 --- /dev/null +++ b/common/taskana-common/src/main/resources/sql/oracle/taskana_schema_update_6.2.0_to_7.0.0_oracle.sql @@ -0,0 +1,24 @@ +-- this script updates the TASKANA database schema from version 6.2.0 to version 7.0.0. +ALTER SESSION SET CURRENT_SCHEMA = %schemaName%; + +INSERT INTO TASKANA_SCHEMA_VERSION (ID, VERSION, CREATED) +VALUES (nextval('TASKANA_SCHEMA_VERSION_ID_SEQ'), '7.0.0', CURRENT_TIMESTAMP); + +CREATE TABLE PERMISSION_INFO +( + USER_ID VARCHAR2(32) NOT NULL, + PERMISSION_ID VARCHAR2(256) NOT NULL, + CONSTRAINT PERMISSION_INFO_PKEY PRIMARY KEY (USER_ID, PERMISSION_ID) +); + +ALTER TABLE WORKBASKET +ADD ( + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL +); + +CREATE INDEX IDX_TASK_ID_HISTORY_EVENT ON TASK_HISTORY_EVENT + (TASK_ID ASC); +COMMIT WORK ; \ No newline at end of file diff --git a/common/taskana-common/src/main/resources/sql/postgres/taskana-schema-postgres.sql b/common/taskana-common/src/main/resources/sql/postgres/taskana-schema-postgres.sql index 8af466a996..ee8a784a28 100644 --- a/common/taskana-common/src/main/resources/sql/postgres/taskana-schema-postgres.sql +++ b/common/taskana-common/src/main/resources/sql/postgres/taskana-schema-postgres.sql @@ -18,7 +18,7 @@ CREATE SEQUENCE TASKANA_SCHEMA_VERSION_ID_SEQ -- The VERSION value must be equal or higher then the value of TaskanaEngineImpl.MINIMAL_TASKANA_SCHEMA_VERSION INSERT INTO TASKANA_SCHEMA_VERSION (ID, VERSION, CREATED) -VALUES (nextval('TASKANA_SCHEMA_VERSION_ID_SEQ'), '5.10.0', CURRENT_TIMESTAMP); +VALUES (nextval('TASKANA_SCHEMA_VERSION_ID_SEQ'), '7.0.0', CURRENT_TIMESTAMP); CREATE TABLE CLASSIFICATION ( @@ -69,6 +69,10 @@ CREATE TABLE WORKBASKET ORG_LEVEL_3 VARCHAR(255) NULL, ORG_LEVEL_4 VARCHAR(255) NULL, MARKED_FOR_DELETION BOOLEAN NOT NULL, + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL, PRIMARY KEY (ID), CONSTRAINT WB_KEY_DOMAIN UNIQUE (KEY, DOMAIN) ); @@ -170,6 +174,8 @@ CREATE TABLE WORKBASKET_ACCESS_LIST PERM_CUSTOM_10 BOOLEAN NOT NULL, PERM_CUSTOM_11 BOOLEAN NOT NULL, PERM_CUSTOM_12 BOOLEAN NOT NULL, + PERM_READTASKS BOOLEAN NOT NULL, + PERM_EDITTASKS BOOLEAN NOT NULL, PRIMARY KEY (ID), CONSTRAINT UC_ACCESSID_WBID UNIQUE (ACCESS_ID, WORKBASKET_ID), CONSTRAINT ACCESS_LIST_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE CASCADE @@ -358,6 +364,13 @@ CREATE TABLE GROUP_INFO PRIMARY KEY (USER_ID, GROUP_ID) ); +CREATE TABLE PERMISSION_INFO +( + USER_ID VARCHAR(32) NOT NULL, + PERMISSION_ID VARCHAR(256) NOT NULL, + PRIMARY KEY (USER_ID, PERMISSION_ID) +); + CREATE SEQUENCE SCHEDULED_JOB_SEQ MINVALUE 1 START WITH 1 @@ -441,4 +454,7 @@ CREATE INDEX IDX_OBJECT_REFERE_FK_TASK_ID ON OBJECT_REFERENCE COMMIT WORK ; CREATE INDEX IDX_OBJECT_REFERE_ACCESS_LIST ON OBJECT_REFERENCE (VALUE ASC, TYPE ASC, SYSTEM_INSTANCE ASC, SYSTEM ASC, COMPANY ASC, ID ASC); -COMMIT WORK ; \ No newline at end of file +COMMIT WORK ; +CREATE INDEX IDX_TASK_ID_HISTORY_EVENT ON TASK_HISTORY_EVENT + (TASK_ID ASC); +COMMIT WORK ; diff --git a/common/taskana-common/src/main/resources/sql/postgres/taskana_schema_update_5.10.0_to_6.2.0_postgres.sql b/common/taskana-common/src/main/resources/sql/postgres/taskana_schema_update_5.10.0_to_6.2.0_postgres.sql new file mode 100644 index 0000000000..9f15fd9d4f --- /dev/null +++ b/common/taskana-common/src/main/resources/sql/postgres/taskana_schema_update_5.10.0_to_6.2.0_postgres.sql @@ -0,0 +1,20 @@ +-- this script updates the TASKANA database schema from version 5.10.0 to version 6.2.0. +SET +search_path = %schemaName%; + +INSERT INTO TASKANA_SCHEMA_VERSION (ID, VERSION, CREATED) +VALUES (nextval('TASKANA_SCHEMA_VERSION_ID_SEQ'), '6.2.0', CURRENT_TIMESTAMP); + +ALTER TABLE WORKBASKET_ACCESS_LIST + ADD COLUMN PERM_READTASKS BOOLEAN NOT NULL DEFAULT FALSE; +UPDATE WORKBASKET_ACCESS_LIST +SET PERM_READTASKS=PERM_READ; +ALTER TABLE WORKBASKET_ACCESS_LIST + ALTER COLUMN PERM_READTASKS DROP DEFAULT; + +ALTER TABLE WORKBASKET_ACCESS_LIST + ADD COLUMN PERM_EDITTASKS BOOLEAN NOT NULL DEFAULT FALSE; +UPDATE WORKBASKET_ACCESS_LIST +SET PERM_EDITTASKS=PERM_READ; +ALTER TABLE WORKBASKET_ACCESS_LIST + ALTER COLUMN PERM_EDITTASKS DROP DEFAULT; diff --git a/common/taskana-common/src/main/resources/sql/postgres/taskana_schema_update_6.2.0_to_7.0.0_postgres.sql b/common/taskana-common/src/main/resources/sql/postgres/taskana_schema_update_6.2.0_to_7.0.0_postgres.sql new file mode 100644 index 0000000000..e499e4a396 --- /dev/null +++ b/common/taskana-common/src/main/resources/sql/postgres/taskana_schema_update_6.2.0_to_7.0.0_postgres.sql @@ -0,0 +1,23 @@ +-- this script updates the TASKANA database schema from version 6.2.0 to version 7.0.0. + +SET search_path = %schemaName%; + +INSERT INTO TASKANA_SCHEMA_VERSION (ID, VERSION, CREATED) +VALUES (nextval('TASKANA_SCHEMA_VERSION_ID_SEQ'), '7.0.0', CURRENT_TIMESTAMP); + +CREATE TABLE PERMISSION_INFO +( + USER_ID VARCHAR(32) NOT NULL, + PERMISSION_ID VARCHAR(256) NOT NULL, + PRIMARY KEY (USER_ID, PERMISSION_ID) +); + +ALTER TABLE WORKBASKET + ADD COLUMN CUSTOM_5 VARCHAR(255) NULL, + ADD COLUMN CUSTOM_6 VARCHAR(255) NULL, + ADD COLUMN CUSTOM_7 VARCHAR(255) NULL, + ADD COLUMN CUSTOM_8 VARCHAR(255) NULL; + +CREATE INDEX IDX_TASK_ID_HISTORY_EVENT ON TASK_HISTORY_EVENT + (TASK_ID ASC); +COMMIT WORK ; diff --git a/history/pom.xml b/history/pom.xml index c3f274af87..632524e7de 100644 --- a/history/pom.xml +++ b/history/pom.xml @@ -12,7 +12,7 @@ pro.taskana taskana-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../pom.xml diff --git a/history/taskana-loghistory-provider/pom.xml b/history/taskana-loghistory-provider/pom.xml index 43c4f86eda..068cec5a9f 100644 --- a/history/taskana-loghistory-provider/pom.xml +++ b/history/taskana-loghistory-provider/pom.xml @@ -11,7 +11,7 @@ pro.taskana.history taskana-history-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../pom.xml @@ -41,7 +41,7 @@ - uk.org.lidalia + com.github.valfirst slf4j-test ${version.slf4j-test} test @@ -49,6 +49,7 @@ org.assertj assertj-core + ${version.assertj} test @@ -58,7 +59,7 @@ org.mockito - mockito-inline + mockito-core test diff --git a/history/taskana-loghistory-provider/src/test/java/pro/taskana/loghistory/impl/LogfileHistoryServiceImplTest.java b/history/taskana-loghistory-provider/src/test/java/pro/taskana/loghistory/impl/LogfileHistoryServiceImplTest.java index 6dc67bf686..9292fbdb75 100644 --- a/history/taskana-loghistory-provider/src/test/java/pro/taskana/loghistory/impl/LogfileHistoryServiceImplTest.java +++ b/history/taskana-loghistory-provider/src/test/java/pro/taskana/loghistory/impl/LogfileHistoryServiceImplTest.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.github.valfirst.slf4jtest.TestLogger; +import com.github.valfirst.slf4jtest.TestLoggerFactory; import java.time.Instant; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; @@ -17,8 +19,6 @@ import pro.taskana.spi.history.api.events.task.TaskHistoryEventType; import pro.taskana.spi.history.api.events.workbasket.WorkbasketHistoryEvent; import pro.taskana.spi.history.api.events.workbasket.WorkbasketHistoryEventType; -import uk.org.lidalia.slf4jtest.TestLogger; -import uk.org.lidalia.slf4jtest.TestLoggerFactory; class LogfileHistoryServiceImplTest { diff --git a/history/taskana-simplehistory-provider/pom.xml b/history/taskana-simplehistory-provider/pom.xml index 30a29d69f4..3beeba5a47 100644 --- a/history/taskana-simplehistory-provider/pom.xml +++ b/history/taskana-simplehistory-provider/pom.xml @@ -11,7 +11,7 @@ pro.taskana.history taskana-history-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../pom.xml @@ -66,7 +66,7 @@ org.mockito - mockito-inline + mockito-core test @@ -91,7 +91,12 @@ ${version.oracle} test - + + pro.taskana + taskana-test-api + ${project.version} + test + diff --git a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/jobs/HistoryCleanupJob.java b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/jobs/HistoryCleanupJob.java index 77889d8aa4..4c58490f14 100644 --- a/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/jobs/HistoryCleanupJob.java +++ b/history/taskana-simplehistory-provider/src/main/java/pro/taskana/simplehistory/impl/jobs/HistoryCleanupJob.java @@ -14,6 +14,7 @@ import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import pro.taskana.TaskanaConfiguration; import pro.taskana.common.api.ScheduledJob; import pro.taskana.common.api.TaskanaEngine; import pro.taskana.common.api.TimeInterval; @@ -52,6 +53,10 @@ public HistoryCleanupJob( super(taskanaEngine, txProvider, scheduledJob, true); } + public static Duration getLockExpirationPeriod(TaskanaConfiguration taskanaConfiguration) { + return taskanaConfiguration.getSimpleHistoryCleanupJobLockExpirationPeriod(); + } + @Override public void execute() { Instant createdBefore = Instant.now().minus(minimumAge); diff --git a/history/taskana-simplehistory-provider/src/test/java/acceptance/events/task/CreateHistoryEventOnTaskDeletionAccTest.java b/history/taskana-simplehistory-provider/src/test/java/acceptance/events/task/CreateHistoryEventOnTaskDeletionAccTest.java new file mode 100644 index 0000000000..8c70d30229 --- /dev/null +++ b/history/taskana-simplehistory-provider/src/test/java/acceptance/events/task/CreateHistoryEventOnTaskDeletionAccTest.java @@ -0,0 +1,121 @@ +package acceptance.events.task; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import pro.taskana.classification.api.ClassificationService; +import pro.taskana.classification.api.models.ClassificationSummary; +import pro.taskana.common.api.TaskanaEngine; +import pro.taskana.common.test.security.JaasExtension; +import pro.taskana.common.test.security.WithAccessId; +import pro.taskana.simplehistory.impl.SimpleHistoryServiceImpl; +import pro.taskana.spi.history.api.TaskanaHistory; +import pro.taskana.spi.history.api.events.task.TaskHistoryEvent; +import pro.taskana.spi.history.api.events.task.TaskHistoryEventType; +import pro.taskana.task.api.TaskService; +import pro.taskana.task.api.TaskState; +import pro.taskana.task.api.models.Task; +import pro.taskana.testapi.DefaultTestEntities; +import pro.taskana.testapi.TaskanaInject; +import pro.taskana.testapi.TaskanaIntegrationTest; +import pro.taskana.testapi.WithServiceProvider; +import pro.taskana.testapi.builder.TaskBuilder; +import pro.taskana.workbasket.api.WorkbasketService; +import pro.taskana.workbasket.api.models.WorkbasketSummary; + +@WithServiceProvider( + serviceProviderInterface = TaskanaHistory.class, + serviceProviders = SimpleHistoryServiceImpl.class) +@TaskanaIntegrationTest +@ExtendWith(JaasExtension.class) +class CreateHistoryEventOnTaskDeletionAccTest { + @TaskanaInject TaskanaEngine taskanaEngine; + @TaskanaInject TaskService taskService; + @TaskanaInject WorkbasketService workbasketService; + @TaskanaInject ClassificationService classificationService; + ClassificationSummary defaultClassificationSummary; + WorkbasketSummary defaultWorkbasketSummary; + Task task1; + Task task2; + Task task3; + Task task4; + SimpleHistoryServiceImpl historyService; + + @WithAccessId(user = "admin") + @BeforeAll + void setUp() throws Exception { + historyService = new SimpleHistoryServiceImpl(); + historyService.initialize(taskanaEngine); + + defaultClassificationSummary = + DefaultTestEntities.defaultTestClassification() + .buildAndStoreAsSummary(classificationService); + defaultWorkbasketSummary = + DefaultTestEntities.defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + + task1 = createTask().buildAndStore(taskService); + task2 = createTask().state(TaskState.COMPLETED).buildAndStore(taskService); + task3 = createTask().state(TaskState.COMPLETED).buildAndStore(taskService); + task4 = createTask().state(TaskState.COMPLETED).buildAndStore(taskService); + } + + @WithAccessId(user = "admin") + @Test + void should_CreateDeleteHistoryEvent_When_TaskIsDeleted() throws Exception { + historyService.deleteHistoryEventsByTaskIds(List.of(task4.getId())); + + taskService.deleteTask(task4.getId()); + + List events = + historyService.createTaskHistoryQuery().taskIdIn(task4.getId()).list(); + assertThat(events).hasSize(1); + assertDeleteHistoryEvent(events.get(0).getId(), "admin", task4.getId()); + } + + @WithAccessId(user = "admin") + @Test + void should_CreateDeleteHistoryEvent_When_TaskIsForceDeleted() throws Exception { + historyService.deleteHistoryEventsByTaskIds(List.of(task1.getId())); + + taskService.forceDeleteTask(task1.getId()); + + List events = + historyService.createTaskHistoryQuery().taskIdIn(task1.getId()).list(); + assertThat(events).hasSize(1); + assertDeleteHistoryEvent(events.get(0).getId(), "admin", task1.getId()); + } + + @WithAccessId(user = "admin") + @Test + void should_CreateDeleteHistoryEvents_When_MultipleTasksAreDeleted() throws Exception { + List taskIds = List.of(task2.getId(), task3.getId()); + historyService.deleteHistoryEventsByTaskIds(taskIds); + + taskService.deleteTasks(taskIds); + + TaskHistoryEvent eventTask2 = + historyService.createTaskHistoryQuery().taskIdIn(task2.getId()).single(); + TaskHistoryEvent eventTask3 = + historyService.createTaskHistoryQuery().taskIdIn(task3.getId()).single(); + assertDeleteHistoryEvent(eventTask2.getId(), "admin", task2.getId()); + assertDeleteHistoryEvent(eventTask3.getId(), "admin", task3.getId()); + } + + private void assertDeleteHistoryEvent(String eventId, String expectedUser, String taskId) + throws Exception { + TaskHistoryEvent event = historyService.getTaskHistoryEvent(eventId); + assertThat(event.getUserId()).isEqualTo(expectedUser); + assertThat(event.getEventType()).isEqualTo(TaskHistoryEventType.DELETED.getName()); + assertThat(event.getTaskId()).isEqualTo(taskId); + } + + private TaskBuilder createTask() { + return TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(defaultWorkbasketSummary) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()); + } +} diff --git a/history/taskana-simplehistory-provider/src/test/java/acceptance/events/task/DeleteHistoryEventsOnTaskDeletionAccTest.java b/history/taskana-simplehistory-provider/src/test/java/acceptance/events/task/DeleteHistoryEventsOnTaskDeletionAccTest.java index bae80a8677..3647521735 100644 --- a/history/taskana-simplehistory-provider/src/test/java/acceptance/events/task/DeleteHistoryEventsOnTaskDeletionAccTest.java +++ b/history/taskana-simplehistory-provider/src/test/java/acceptance/events/task/DeleteHistoryEventsOnTaskDeletionAccTest.java @@ -15,6 +15,7 @@ import pro.taskana.simplehistory.impl.TaskHistoryQueryImpl; import pro.taskana.simplehistory.impl.task.TaskHistoryQueryMapper; import pro.taskana.spi.history.api.events.task.TaskHistoryEvent; +import pro.taskana.spi.history.api.events.task.TaskHistoryEventType; import pro.taskana.task.api.exceptions.TaskNotFoundException; @ExtendWith(JaasExtension.class) @@ -47,7 +48,8 @@ void should_DeleteHistoryEvents_When_TaskIsDeletedWithHistoryDeletionEnabled() t listEvents = taskHistoryQueryMapper.queryHistoryEvents( (TaskHistoryQueryImpl) historyService.createTaskHistoryQuery().taskIdIn(taskid)); - assertThat(listEvents).isEmpty(); + assertThat(listEvents).hasSize(1); + assertThat(listEvents.get(0).getEventType()).isEqualTo(TaskHistoryEventType.DELETED.getName()); } @Test @@ -87,7 +89,9 @@ void should_DeleteHistoryEvents_When_TasksAreDeletedWithHistoryDeletionEnabled() taskHistoryQueryMapper.queryHistoryEvents( (TaskHistoryQueryImpl) historyService.createTaskHistoryQuery().taskIdIn(taskId_1, taskId_2)); - assertThat(listEvents).isEmpty(); + assertThat(listEvents).hasSize(2); + assertThat(listEvents.get(0).getEventType()).isEqualTo(TaskHistoryEventType.DELETED.getName()); + assertThat(listEvents.get(1).getEventType()).isEqualTo(TaskHistoryEventType.DELETED.getName()); } @Test @@ -119,7 +123,7 @@ void should_NotDeleteHistoryEvents_When_TaskIsDeletedWithHistoryDeletionDisabled listEvents = taskHistoryQueryMapper.queryHistoryEvents( (TaskHistoryQueryImpl) historyService.createTaskHistoryQuery().taskIdIn(taskId)); - assertThat(listEvents).hasSize(2); + assertThat(listEvents).hasSize(3); } @Test @@ -152,7 +156,7 @@ void should_NotDeleteHistoryEvents_When_TasksAreDeletedWithHistoryDeletionDisabl taskHistoryQueryMapper.queryHistoryEvents( (TaskHistoryQueryImpl) historyService.createTaskHistoryQuery().taskIdIn(taskId_1, taskId_2)); - assertThat(listEvents).hasSize(2); + assertThat(listEvents).hasSize(4); } private void createTaskanaEngineWithNewConfig(boolean deleteHistoryOnTaskDeletionEnabled) diff --git a/history/taskana-simplehistory-provider/src/test/resources/taskana.properties b/history/taskana-simplehistory-provider/src/test/resources/taskana.properties index 3663460b9d..c7ac38d55a 100644 --- a/history/taskana-simplehistory-provider/src/test/resources/taskana.properties +++ b/history/taskana-simplehistory-provider/src/test/resources/taskana.properties @@ -29,11 +29,11 @@ taskana.workingTime.timezone=UTC # enable or disable the jobscheduler at all # set it to false and no jobs are running taskana.jobs.scheduler.enabled=false -# wait time before the first job run in millis +# wait time before the first job run taskana.jobs.scheduler.initialStartDelay=100 # sleeping time befor the next job runs taskana.jobs.scheduler.period=12 -# timeunit for the sleeping period +# timeunit for the initial start delay and the sleeping period # Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS taskana.jobs.scheduler.periodTimeUnit=HOURS taskana.jobs.cleanup.task.enable=true diff --git a/history/taskana-simplehistory-rest-spring/pom.xml b/history/taskana-simplehistory-rest-spring/pom.xml index dcbe483dff..d068b159b4 100644 --- a/history/taskana-simplehistory-rest-spring/pom.xml +++ b/history/taskana-simplehistory-rest-spring/pom.xml @@ -11,7 +11,7 @@ pro.taskana.history taskana-history-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../pom.xml @@ -44,13 +44,13 @@ spring-hateoas - javax.servlet - javax.servlet-api + jakarta.servlet + jakarta.servlet-api provided - javax.validation - validation-api + jakarta.validation + jakarta.validation-api com.fasterxml.jackson.core @@ -78,6 +78,7 @@ org.assertj assertj-core + ${version.assertj} test @@ -103,7 +104,7 @@ org.springframework.plugin spring-plugin-core - ${version.spring.core} + ${version.spring.plugin.core} test @@ -192,11 +193,7 @@ capital.scalable.restdocs.jsondoclet.ExtractDocumentationAsJsonDoclet capital.scalable - - spring-auto-restdocs-json-doclet + spring-auto-restdocs-json-doclet-jdk9 ${version.auto-restdocs} generated-javadoc-json diff --git a/history/taskana-simplehistory-rest-spring/src/main/java/pro/taskana/simplehistory/rest/TaskHistoryEventController.java b/history/taskana-simplehistory-rest-spring/src/main/java/pro/taskana/simplehistory/rest/TaskHistoryEventController.java index 2d493a32cf..0bb0604325 100644 --- a/history/taskana-simplehistory-rest-spring/src/main/java/pro/taskana/simplehistory/rest/TaskHistoryEventController.java +++ b/history/taskana-simplehistory-rest-spring/src/main/java/pro/taskana/simplehistory/rest/TaskHistoryEventController.java @@ -1,10 +1,10 @@ package pro.taskana.simplehistory.rest; +import jakarta.servlet.http.HttpServletRequest; import java.beans.ConstructorProperties; import java.sql.SQLException; import java.util.List; import java.util.function.BiConsumer; -import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.hateoas.MediaTypes; import org.springframework.hateoas.config.EnableHypermediaSupport; diff --git a/history/taskana-simplehistory-rest-spring/src/test/resources/application.properties b/history/taskana-simplehistory-rest-spring/src/test/resources/application.properties index 5340f95115..7866939c93 100644 --- a/history/taskana-simplehistory-rest-spring/src/test/resources/application.properties +++ b/history/taskana-simplehistory-rest-spring/src/test/resources/application.properties @@ -26,6 +26,7 @@ taskana.ldap.userOrglevel3Attribute=someDepartement taskana.ldap.userOrglevel4Attribute=orgLevel4 taskana.ldap.userIdAttribute=uid taskana.ldap.userMemberOfGroupAttribute=memberOf +taskana.ldap.userPermissionsAttribute=permission taskana.ldap.groupSearchBase=cn=groups taskana.ldap.groupSearchFilterName=objectclass taskana.ldap.groupSearchFilterValue=groupOfUniqueNames diff --git a/lib/pom.xml b/lib/pom.xml index d675e4fac8..7d66295cb9 100644 --- a/lib/pom.xml +++ b/lib/pom.xml @@ -12,7 +12,7 @@ pro.taskana taskana-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../pom.xml diff --git a/lib/taskana-cdi-example/pom.xml b/lib/taskana-cdi-example/pom.xml index 2d761718a6..07eaa60054 100644 --- a/lib/taskana-cdi-example/pom.xml +++ b/lib/taskana-cdi-example/pom.xml @@ -11,7 +11,7 @@ pro.taskana taskana-lib-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../pom.xml @@ -19,16 +19,29 @@ + + + + org.wildfly.bom + wildfly-ee + ${version.wildfly} + import + pom + + + org.jboss.arquillian + arquillian-bom + ${version.arquillian} + import + pom + + + - pro.taskana - taskana-common-logging - ${project.version} - - - javax - javaee-api - ${version.javaee-api} + jakarta.platform + jakarta.jakartaee-api + ${version.jakartaee-api} provided @@ -36,5 +49,171 @@ taskana-cdi ${project.version} + + + org.slf4j + jcl-over-slf4j + test + + + org.slf4j + slf4j-simple + test + + + org.assertj + assertj-core + ${version.assertj} + test + + + org.awaitility + awaitility + test + + + org.junit.jupiter + junit-jupiter + test + + + org.junit.vintage + junit-vintage-engine + test + + + jakarta.servlet + jakarta.servlet-api + test + + + com.h2database + h2 + test + + + org.jboss.arquillian.junit + arquillian-junit-container + test + + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-impl-maven + test + + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-api-maven + test + + + org.wildfly.arquillian + wildfly-arquillian-container-managed + ${version.arquillian.managed.wildfly} + test + + + + + + org.apache.maven.plugins + maven-dependency-plugin + ${version.maven.dependency} + + + unpack-wildfly + process-test-classes + + unpack + + + + + org.wildfly + wildfly-dist + ${version.wildfly} + zip + false + ${project.build.directory} + + + + + + copy-latest-h2-db-driver + process-test-classes + + copy + + + + + com.h2database + h2 + + ${project.build.directory}/wildfly-${version.wildfly}/modules/system/layers/base/com/h2database/h2/main + + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + ${version.maven.resources} + + + copy-h2-module-xml + process-test-classes + + copy-resources + + + + ${project.build.directory}/wildfly-${version.wildfly}/modules/system/layers/base/com/h2database/h2/main + + + + src/test/resources + + module.xml + + + + + + + copy-wildfly-config-xml + process-test-classes + + copy-resources + + + + ${project.build.directory}/wildfly-${version.wildfly}/standalone/configuration + + + + src/test/resources + + int-test-standalone.xml + + + + + + + + + + + + + jboss + https://repository.jboss.org/nexus/content/groups/public-jboss/ + + diff --git a/lib/taskana-cdi-example/src/main/java/pro/taskana/example/ExampleBootstrap.java b/lib/taskana-cdi-example/src/main/java/pro/taskana/example/ExampleBootstrap.java index 5f2fac7bb9..2e8596855b 100644 --- a/lib/taskana-cdi-example/src/main/java/pro/taskana/example/ExampleBootstrap.java +++ b/lib/taskana-cdi-example/src/main/java/pro/taskana/example/ExampleBootstrap.java @@ -1,57 +1,77 @@ package pro.taskana.example; -import javax.annotation.PostConstruct; -import javax.ejb.EJB; -import javax.enterprise.context.ApplicationScoped; -import javax.enterprise.context.Initialized; -import javax.enterprise.event.Observes; -import pro.taskana.classification.api.exceptions.ClassificationNotFoundException; -import pro.taskana.common.api.exceptions.InvalidArgumentException; -import pro.taskana.task.api.exceptions.AttachmentPersistenceException; -import pro.taskana.task.api.exceptions.InvalidOwnerException; -import pro.taskana.task.api.exceptions.InvalidTaskStateException; -import pro.taskana.task.api.exceptions.ObjectReferencePersistenceException; -import pro.taskana.task.api.exceptions.TaskAlreadyExistException; -import pro.taskana.task.api.exceptions.TaskNotFoundException; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.event.Startup; +import jakarta.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import pro.taskana.classification.api.models.Classification; +import pro.taskana.common.api.exceptions.TaskanaException; import pro.taskana.task.api.models.Task; import pro.taskana.task.internal.models.ObjectReferenceImpl; -import pro.taskana.workbasket.api.exceptions.NotAuthorizedOnWorkbasketException; -import pro.taskana.workbasket.api.exceptions.WorkbasketNotFoundException; +import pro.taskana.workbasket.api.WorkbasketType; +import pro.taskana.workbasket.api.models.Workbasket; /** Example Bootstrap Application. */ @ApplicationScoped public class ExampleBootstrap { - @EJB private TaskanaEjb taskanaEjb; - - @PostConstruct - public void init(@Observes @Initialized(ApplicationScoped.class) Object init) - throws TaskNotFoundException, - WorkbasketNotFoundException, - ClassificationNotFoundException, - InvalidOwnerException, - TaskAlreadyExistException, - InvalidArgumentException, - AttachmentPersistenceException, - ObjectReferencePersistenceException, - NotAuthorizedOnWorkbasketException, - InvalidTaskStateException { - System.out.println("---------------------------> Start App"); - ObjectReferenceImpl objRef = new ObjectReferenceImpl(); - objRef.setCompany("aCompany"); - objRef.setSystem("aSystem"); - objRef.setSystemInstance("anInstance"); - objRef.setType("aType"); - objRef.setValue("aValue"); - Task task = taskanaEjb.getTaskService().newTask(null); - task.setPrimaryObjRef(objRef); - task = taskanaEjb.getTaskService().createTask(task); - System.out.println("---------------------------> Task started: " + task.getId()); - taskanaEjb.getTaskService().claim(task.getId()); - System.out.println( - "---------------------------> Task claimed: " - + taskanaEjb.getTaskService().getTask(task.getId()).getOwner()); - taskanaEjb.getTaskService().completeTask(task.getId()); - System.out.println("---------------------------> Task completed"); + private static final Logger LOGGER = LoggerFactory.getLogger(ExampleBootstrap.class); + + private static final String CDIDOMAIN = "CDIDOMAIN"; + private static final String CLASSIFICATION_TYPE = "T1"; + + private final TaskanaEjb taskanaEjb; + + public ExampleBootstrap() { + this.taskanaEjb = null; + } + + @Inject + public ExampleBootstrap(TaskanaEjb taskanaEjb) { + this.taskanaEjb = taskanaEjb; + } + + /** + * The parameter `@Observes Startup` makes sure that the dependency injection framework calls this + * method on system startup. And to do that, it needs to call `@PostConstruct start()` first. + * + * @param startup just the startup event + * @throws ExampleStartupException in case of task creation fails + */ + public void init(@Observes Startup startup) throws ExampleStartupException { + try { + LOGGER.info("---------------------------> Start App -- {}", startup); + Workbasket workbasket = taskanaEjb.getWorkbasketService().newWorkbasket("KEY", CDIDOMAIN); + workbasket.setName("wb"); + workbasket.setType(WorkbasketType.PERSONAL); + workbasket = taskanaEjb.getWorkbasketService().createWorkbasket(workbasket); + Classification classification = + taskanaEjb + .getClassificationService() + .newClassification("TEST", CDIDOMAIN, CLASSIFICATION_TYPE); + taskanaEjb.getClassificationService().createClassification(classification); + ObjectReferenceImpl objRef = new ObjectReferenceImpl(); + objRef.setCompany("aCompany"); + objRef.setSystem("aSystem"); + objRef.setSystemInstance("anInstance"); + objRef.setType("aType"); + objRef.setValue("aValue"); + Task task = taskanaEjb.getTaskService().newTask(workbasket.getId()); + task.setClassificationKey(classification.getKey()); + task.setName("BootstrapTask"); + task.setPrimaryObjRef(objRef); + task = taskanaEjb.getTaskService().createTask(task); + LOGGER.info("---------------------------> Task started: {}", task.getId()); + taskanaEjb.getTaskService().claim(task.getId()); + LOGGER.info( + "---------------------------> Task claimed: {}", + taskanaEjb.getTaskService().getTask(task.getId()).getOwner()); + taskanaEjb.getTaskService().completeTask(task.getId()); + LOGGER.info("---------------------------> Task completed"); + } catch (TaskanaException e) { + throw new ExampleStartupException(e); + } } } diff --git a/lib/taskana-cdi-example/src/main/java/pro/taskana/example/ExampleStartupException.java b/lib/taskana-cdi-example/src/main/java/pro/taskana/example/ExampleStartupException.java new file mode 100644 index 0000000000..80cc1ba1a2 --- /dev/null +++ b/lib/taskana-cdi-example/src/main/java/pro/taskana/example/ExampleStartupException.java @@ -0,0 +1,8 @@ +package pro.taskana.example; + +public class ExampleStartupException extends RuntimeException { + + public ExampleStartupException(Throwable cause) { + super("Can't bootstrap CDI example application", cause); + } +} diff --git a/lib/taskana-cdi-example/src/main/java/pro/taskana/example/TaskanaEjb.java b/lib/taskana-cdi-example/src/main/java/pro/taskana/example/TaskanaEjb.java index 7e44c94b26..8c18e0b1e4 100644 --- a/lib/taskana-cdi-example/src/main/java/pro/taskana/example/TaskanaEjb.java +++ b/lib/taskana-cdi-example/src/main/java/pro/taskana/example/TaskanaEjb.java @@ -1,16 +1,46 @@ package pro.taskana.example; -import javax.ejb.Stateless; -import javax.inject.Inject; +import jakarta.ejb.Stateless; +import jakarta.inject.Inject; +import pro.taskana.classification.api.ClassificationService; import pro.taskana.task.api.TaskService; +import pro.taskana.workbasket.api.WorkbasketService; /** example Taskana EJB. */ @Stateless public class TaskanaEjb { - @Inject private TaskService taskService; + private final TaskService taskService; + + private final ClassificationService classificationService; + + private final WorkbasketService workbasketService; + + public TaskanaEjb() { + this.taskService = null; + this.classificationService = null; + this.workbasketService = null; + } + + @Inject + public TaskanaEjb( + TaskService taskService, + ClassificationService classificationService, + WorkbasketService workbasketService) { + this.taskService = taskService; + this.classificationService = classificationService; + this.workbasketService = workbasketService; + } public TaskService getTaskService() { return taskService; } + + public ClassificationService getClassificationService() { + return classificationService; + } + + public WorkbasketService getWorkbasketService() { + return workbasketService; + } } diff --git a/lib/taskana-cdi-example/src/main/resources/META-INF/beans.xml b/lib/taskana-cdi-example/src/main/resources/META-INF/beans.xml new file mode 100644 index 0000000000..3235afa2f1 --- /dev/null +++ b/lib/taskana-cdi-example/src/main/resources/META-INF/beans.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/lib/taskana-cdi-example/src/main/resources/taskana.properties b/lib/taskana-cdi-example/src/main/resources/taskana.properties index 61c2f89cda..8c44c99cf3 100644 --- a/lib/taskana-cdi-example/src/main/resources/taskana.properties +++ b/lib/taskana-cdi-example/src/main/resources/taskana.properties @@ -1 +1,19 @@ datasource.jndi=java:jboss/datasources/Taskana +taskana.domains=CDIDOMAIN +taskana.classification.types=T1 +taskana.classification.categories.T1=DEFAULT +# enable or disable the jobscheduler at all +# set it to false and no jobs are running +taskana.jobs.scheduler.enabled=true +# wait time before the first job run +taskana.jobs.scheduler.initialStartDelay=100 +# sleeping time befor the next job runs +taskana.jobs.scheduler.period=1 +# timeunit for the initial start delay and the sleeping period +# Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS +taskana.jobs.scheduler.periodTimeUnit=HOURS +taskana.jobs.cleanup.task.enable=true +taskana.jobs.priority.task.enable=true +taskana.jobs.cleanup.workbasket.enable=true +taskana.jobs.refresh.user.enable=false +taskana.jobs.cleanup.history.simple.enable=false diff --git a/lib/taskana-cdi-example/src/main/webapp/META-INF/MANIFEST.MF b/lib/taskana-cdi-example/src/main/webapp/META-INF/MANIFEST.MF deleted file mode 100644 index 254272e1c0..0000000000 --- a/lib/taskana-cdi-example/src/main/webapp/META-INF/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -Class-Path: - diff --git a/lib/taskana-cdi-example/src/main/webapp/WEB-INF/beans.xml b/lib/taskana-cdi-example/src/main/webapp/WEB-INF/beans.xml deleted file mode 100644 index df8f4fd28e..0000000000 --- a/lib/taskana-cdi-example/src/main/webapp/WEB-INF/beans.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - diff --git a/lib/taskana-cdi-example/src/main/webapp/WEB-INF/web.xml b/lib/taskana-cdi-example/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index a0d739cc77..0000000000 --- a/lib/taskana-cdi-example/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,4 +0,0 @@ - - \ No newline at end of file diff --git a/lib/taskana-cdi-example/src/test/java/pro/taskana/example/ExampleBootstrapTest.java b/lib/taskana-cdi-example/src/test/java/pro/taskana/example/ExampleBootstrapTest.java new file mode 100644 index 0000000000..dd5612ffa2 --- /dev/null +++ b/lib/taskana-cdi-example/src/test/java/pro/taskana/example/ExampleBootstrapTest.java @@ -0,0 +1,111 @@ +package pro.taskana.example; + +import static org.awaitility.Awaitility.await; +import static org.awaitility.Durations.ONE_HUNDRED_MILLISECONDS; +import static org.awaitility.Durations.TWO_SECONDS; +import static org.hamcrest.CoreMatchers.equalTo; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import org.apache.commons.io.FileUtils; +import org.h2.jdbc.JdbcSQLNonTransientConnectionException; +import org.h2.jdbc.JdbcSQLSyntaxErrorException; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.EnterpriseArchive; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jboss.shrinkwrap.resolver.api.maven.Maven; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(Arquillian.class) +public class ExampleBootstrapTest { + + @Deployment(testable = false, order = 10) + public static Archive createDeployment() throws Exception { + EnterpriseArchive deployment = ShrinkWrap.create(EnterpriseArchive.class, "taskana.ear"); + + File[] libs = + Maven.resolver() + .loadPomFromFile("pom.xml") + .importCompileAndRuntimeDependencies() + .resolve() + .withTransitivity() + .asFile(); + deployment.addAsLibraries(libs); + + JavaArchive ejbModule = ShrinkWrap.create(JavaArchive.class, "taskana.jar"); + ejbModule.addClasses(TaskanaEjb.class, ExampleBootstrap.class, ExampleStartupException.class); + ejbModule.addAsResource("taskana.properties"); + deployment.addAsModule(ejbModule); + + deployment.addAsManifestResource("META-INF/beans.xml", "beans.xml"); + return deployment; + } + + @BeforeClass + public static void cleanTaskanaH2DataFolder() throws IOException { + // Delete Taskana folder if exists + Path taskanaH2Data = Path.of(System.getProperty("user.home"), "taskana-h2-data"); + if (Files.exists(taskanaH2Data)) { + FileUtils.deleteDirectory(taskanaH2Data.toFile()); + } + } + + @Test + public void should_count_tasks_after_example_cdi_application_was_deployed() throws Exception { + // this test method is started that fast that the commit + // from pro.taskana.example.ExampleBootstrap.init is not completed + // so we need to wait here a bit + // https://www.baeldung.com/awaitility-testing + await() + .atLeast(ONE_HUNDRED_MILLISECONDS) + .atMost(TWO_SECONDS) + .with() + .pollInterval(ONE_HUNDRED_MILLISECONDS) + .until( + () -> { + try { + return countTasksByName("BootstrapTask"); + } catch (JdbcSQLSyntaxErrorException | JdbcSQLNonTransientConnectionException e) { + // ignore this Exception, because in the beginning the schema is not created + return 0; + } + }, + equalTo(1)); + } + + private Connection getConnection() throws Exception { + return DriverManager.getConnection( + "jdbc:h2:~/taskana-h2-data/testdb;NON_KEYWORDS=KEY,VALUE;AUTO_SERVER=TRUE;" + + "IGNORECASE=TRUE;LOCK_MODE=0", + "sa", + ""); + } + + private int countTasksByName(String taskName) throws Exception { + + Class.forName("org.h2.Driver"); + int resultCount = 0; + try (Connection conn = getConnection(); + PreparedStatement statement = + conn.prepareStatement("SELECT COUNT(ID) FROM TASKANA.TASK WHERE NAME = ?")) { + statement.setString(1, taskName); + ResultSet rs = statement.executeQuery(); + + while (rs.next()) { + resultCount = rs.getInt(1); + } + } + return resultCount; + } +} diff --git a/lib/taskana-cdi-example/src/test/resources/arquillian.xml b/lib/taskana-cdi-example/src/test/resources/arquillian.xml new file mode 100644 index 0000000000..3fcbf32bff --- /dev/null +++ b/lib/taskana-cdi-example/src/test/resources/arquillian.xml @@ -0,0 +1,19 @@ + + + + + target/wildfly-27.0.1.Final + int-test-standalone.xml + + + + + + -Djava.util.logging.manager=org.jboss.logmanager.LogManager + + + + \ No newline at end of file diff --git a/lib/taskana-cdi-example/src/test/resources/int-test-standalone.xml b/lib/taskana-cdi-example/src/test/resources/int-test-standalone.xml new file mode 100644 index 0000000000..e08f36936e --- /dev/null +++ b/lib/taskana-cdi-example/src/test/resources/int-test-standalone.xml @@ -0,0 +1,673 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + h2 + + sa + + + + + + jdbc:h2:~/taskana-h2-data/testdb;NON_KEYWORDS=KEY,VALUE;AUTO_SERVER=TRUE;IGNORECASE=TRUE;LOCK_MODE=0 + + h2 + + sa + + + + + + org.h2.jdbcx.JdbcDataSource + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${jboss.bind.address:127.0.0.1} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/taskana-cdi-example/src/test/resources/module.xml b/lib/taskana-cdi-example/src/test/resources/module.xml new file mode 100644 index 0000000000..933f1e5345 --- /dev/null +++ b/lib/taskana-cdi-example/src/test/resources/module.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/taskana-cdi/README.md b/lib/taskana-cdi/README.md new file mode 100644 index 0000000000..d5a46aa4d8 --- /dev/null +++ b/lib/taskana-cdi/README.md @@ -0,0 +1,168 @@ +# taskana-cdi + +this module is for EJB deployments. + +## Testing procedure + +1. deploy wildfly server locally +2. replace h2 with latest version +3. start wildfly +4. deploy ear +5. test application + +### deploy wildfly server locally + +we extract the wildfly server into the target directory via maven configuration + +```xml + + org.apache.maven.plugins + maven-dependency-plugin + ${version.maven.dependency} + + + unpack-wildfly + process-test-classes + + unpack + + + + + org.wildfly + wildfly-dist + ${version.wildfly} + zip + false + ${project.build.directory} + + + + + . + . + . + + +``` + +### 2. replace h2 with latest version + +for our tests we need the latest h2 version, so we need to replace the h2 jar in wildfly. + +this happens in 2 steps. + +first extract the dependency into the correct directory + +```xml + + org.apache.maven.plugins + maven-dependency-plugin + ${version.maven.dependency} + + . + . + . + + copy-latest-h2-db-driver + process-test-classes + + copy + + + + + com.h2database + h2 + + ${project.build.directory}/wildfly-${version.wildfly}/modules/system/layers/base/com/h2database/h2/main + + + + + + + +``` + +second step is to copy the `src/test/resources/module.xml` to required directory + +```xml + + org.apache.maven.plugins + maven-resources-plugin + ${version.maven.resources} + + + copy-h2-module-xml + process-test-classes + + copy-resources + + + + ${project.build.directory}/wildfly-${version.wildfly}/modules/system/layers/base/com/h2database/h2/main + + + + src/test/resources + + module.xml + + + + + + + +``` + +### 3. start wildfly + +starting and stopping wildfly happens with [arquillian](https://arquillian.org/) + +```java +@RunWith(Arquillian.class) +public class TaskanaProducersTest {} + +``` + +the file `src/test/resources/arquillian.xml` contains additional server start settings. change vm settings here for remote debugging. + +the file `src/test/resources/int-test-standalone.xml` conatins the wildfly server config. Here are the datasources configured, for example. + +### 4. deploy ear + +create the ear deployment happens inside the testcase + +```java + @Deployment(testable = false) + public static Archive createDeployment() throws Exception { + EnterpriseArchive deployment = ShrinkWrap.create(EnterpriseArchive.class, "taskana.ear"); + + File[] libs = + Maven.resolver() + .loadPomFromFile("pom.xml") + .importRuntimeAndTestDependencies() + .resolve() + .withTransitivity() + .asFile(); + deployment.addAsLibraries(libs); + + JavaArchive ejbModule = ShrinkWrap.create(JavaArchive.class, "taskana.jar"); + ejbModule.addClasses(TaskanaProducers.class, TaskanaEjb.class); + ejbModule.addAsResource("taskana.properties"); + deployment.addAsModule(ejbModule); + + WebArchive webArchive = + ShrinkWrap.create(WebArchive.class, "taskana.war") + .addClasses(TaskanaCdiTestRestController.class, RestApplication.class) + .addAsWebInfResource("beans.xml") + .addAsWebInfResource("int-test-jboss-web.xml", "jboss-web.xml"); + deployment.addAsModule(webArchive); + + deployment.addAsManifestResource("beans.xml"); + return deployment; + } +``` + diff --git a/lib/taskana-cdi/pom.xml b/lib/taskana-cdi/pom.xml index c2f354d9e5..6472146684 100644 --- a/lib/taskana-cdi/pom.xml +++ b/lib/taskana-cdi/pom.xml @@ -10,25 +10,39 @@ pro.taskana taskana-lib-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../pom.xml + + + + org.wildfly.bom + wildfly-ee + ${version.wildfly} + import + pom + + + org.jboss.arquillian + arquillian-bom + ${version.arquillian} + import + pom + + + pro.taskana - taskana-common-logging + taskana-core ${project.version} - javax - javaee-api - ${version.javaee-api} - - - pro.taskana - taskana-core - ${project.version} + jakarta.platform + jakarta.jakartaee-api + ${version.jakartaee-api} + provided @@ -45,6 +59,7 @@ org.assertj assertj-core + ${version.assertj} test @@ -58,32 +73,34 @@ test - io.thorntail - jaxrs - ${version.thorntail} + jakarta.servlet + jakarta.servlet-api test - io.thorntail - cdi - ${version.thorntail} + com.h2database + h2 test - com.h2database - h2 + org.jboss.arquillian.junit + arquillian-junit-container test - io.thorntail - arquillian - ${version.thorntail} + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-impl-maven test - org.jboss.arquillian.junit - arquillian-junit-container - ${version.arquillian} + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-api-maven + test + + + org.wildfly.arquillian + wildfly-arquillian-container-managed + ${version.arquillian.managed.wildfly} test @@ -91,14 +108,93 @@ - io.thorntail - thorntail-maven-plugin - ${version.thorntail} + org.apache.maven.plugins + maven-dependency-plugin + ${version.maven.dependency} + unpack-wildfly + process-test-classes + + unpack + + + + + org.wildfly + wildfly-dist + ${version.wildfly} + zip + false + ${project.build.directory} + + + + + + copy-latest-h2-db-driver + process-test-classes + + copy + + + + + com.h2database + h2 + + ${project.build.directory}/wildfly-${version.wildfly}/modules/system/layers/base/com/h2database/h2/main + + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + ${version.maven.resources} + + + copy-h2-module-xml + process-test-classes + + copy-resources + + + + ${project.build.directory}/wildfly-${version.wildfly}/modules/system/layers/base/com/h2database/h2/main + + + + src/test/resources + + module.xml + + + + + + + copy-wildfly-config-xml + process-test-classes - package + copy-resources + + + ${project.build.directory}/wildfly-${version.wildfly}/standalone/configuration + + + + src/test/resources + + int-test-standalone.xml + + + + @@ -108,7 +204,7 @@ jboss - http://repository.jboss.org/nexus/content/groups/public-jboss/ + https://repository.jboss.org/nexus/content/groups/public-jboss/ diff --git a/lib/taskana-cdi/src/main/java/pro/taskana/common/internal/TaskanaCdiStartupException.java b/lib/taskana-cdi/src/main/java/pro/taskana/common/internal/TaskanaCdiStartupException.java new file mode 100644 index 0000000000..a4e716784b --- /dev/null +++ b/lib/taskana-cdi/src/main/java/pro/taskana/common/internal/TaskanaCdiStartupException.java @@ -0,0 +1,8 @@ +package pro.taskana.common.internal; + +public class TaskanaCdiStartupException extends RuntimeException { + + public TaskanaCdiStartupException(Throwable cause) { + super("Can't init TaskanaProducers", cause); + } +} diff --git a/lib/taskana-cdi/src/main/java/pro/taskana/common/internal/TaskanaProducers.java b/lib/taskana-cdi/src/main/java/pro/taskana/common/internal/TaskanaProducers.java index 45f638078f..5e475c1b6e 100644 --- a/lib/taskana-cdi/src/main/java/pro/taskana/common/internal/TaskanaProducers.java +++ b/lib/taskana-cdi/src/main/java/pro/taskana/common/internal/TaskanaProducers.java @@ -1,15 +1,17 @@ package pro.taskana.common.internal; +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.enterprise.event.Startup; +import jakarta.enterprise.inject.Produces; +import jakarta.inject.Inject; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; import java.util.Properties; -import javax.annotation.PostConstruct; -import javax.enterprise.context.ApplicationScoped; -import javax.enterprise.inject.Produces; -import javax.inject.Inject; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; @@ -30,10 +32,31 @@ public class TaskanaProducers { private static final String TASKANA_PROPERTIES = "taskana.properties"; - @Inject private TaskanaEngine taskanaEngine; - + // initalized during post construct private TaskanaConfiguration taskanaConfiguration; + private final TaskanaEngine taskanaEngine; + + public TaskanaProducers() { + this.taskanaEngine = null; + } + + @Inject + public TaskanaProducers(TaskanaEngine taskanaEngine) { + this.taskanaEngine = taskanaEngine; + } + + /** + * The parameter `@Observes Startup` makes sure that the dependency injection framework calls this + * method on system startup. And to do that, it needs to call `@PostConstruct start()` first. + * + * @param startup just the startup event + */ + @SuppressWarnings("unused") + private void forceEagerInitialization(@Observes Startup startup) { + LOGGER.info("startup={}", startup); + } + @PostConstruct public void init() { // Load Properties and get Datasource via Context @@ -57,7 +80,7 @@ public void init() { .initTaskanaProperties() .build(); } catch (NamingException | SQLException | IOException e) { - LOGGER.error("Could not start Taskana: ", e); + throw new TaskanaCdiStartupException(e); } } diff --git a/lib/taskana-cdi/src/main/resources/META-INF/beans.xml b/lib/taskana-cdi/src/main/resources/META-INF/beans.xml index a2425b8d84..3235afa2f1 100644 --- a/lib/taskana-cdi/src/main/resources/META-INF/beans.xml +++ b/lib/taskana-cdi/src/main/resources/META-INF/beans.xml @@ -1,7 +1,3 @@ - - - + + \ No newline at end of file diff --git a/lib/taskana-cdi/src/test/java/pro/taskana/RestApplication.java b/lib/taskana-cdi/src/test/java/pro/taskana/RestApplication.java index 5d2fd74431..cd7d8b3e75 100644 --- a/lib/taskana-cdi/src/test/java/pro/taskana/RestApplication.java +++ b/lib/taskana-cdi/src/test/java/pro/taskana/RestApplication.java @@ -1,7 +1,7 @@ package pro.taskana; -import javax.ws.rs.ApplicationPath; -import javax.ws.rs.core.Application; +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; @ApplicationPath("/rest") public class RestApplication extends Application {} diff --git a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaCdiTestRestController.java b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaCdiTestRestController.java index e1f4971fff..df06ea0bee 100644 --- a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaCdiTestRestController.java +++ b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaCdiTestRestController.java @@ -1,13 +1,12 @@ package pro.taskana; -import javax.ejb.EJB; -import javax.inject.Inject; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.core.Response; +import jakarta.inject.Inject; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.core.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pro.taskana.classification.api.ClassificationService; @@ -24,9 +23,21 @@ public class TaskanaCdiTestRestController { private static final String CDIDOMAIN = "CDIDOMAIN"; private static final String CLASSIFICATION_TYPE = "T1"; - @EJB private TaskanaEjb taskanaEjb; + private final TaskanaEjb taskanaEjb; - @Inject private ClassificationService classificationService; + private final ClassificationService classificationService; + + public TaskanaCdiTestRestController() { + this.taskanaEjb = null; + this.classificationService = null; + } + + @Inject + public TaskanaCdiTestRestController( + TaskanaEjb taskanaEjb, ClassificationService classificationService) { + this.taskanaEjb = taskanaEjb; + this.classificationService = classificationService; + } @GET public Response startTask() throws Exception { diff --git a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaEjb.java b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaEjb.java index 42cf31dc13..8d74d2c3aa 100644 --- a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaEjb.java +++ b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaEjb.java @@ -1,7 +1,7 @@ package pro.taskana; -import javax.ejb.Stateless; -import javax.inject.Inject; +import jakarta.ejb.Stateless; +import jakarta.inject.Inject; import pro.taskana.classification.api.ClassificationService; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.models.Task; @@ -11,11 +11,27 @@ @Stateless public class TaskanaEjb { - @Inject private TaskService taskService; + private final TaskService taskService; - @Inject private ClassificationService classificationService; + private final ClassificationService classificationService; - @Inject private WorkbasketService workbasketService; + private final WorkbasketService workbasketService; + + public TaskanaEjb() { + this.taskService = null; + this.classificationService = null; + this.workbasketService = null; + } + + @Inject + public TaskanaEjb( + TaskService taskService, + ClassificationService classificationService, + WorkbasketService workbasketService) { + this.taskService = taskService; + this.classificationService = classificationService; + this.workbasketService = workbasketService; + } public TaskService getTaskService() { return taskService; diff --git a/lib/taskana-cdi/src/test/java/pro/taskana/common/internal/TaskanaProducersTest.java b/lib/taskana-cdi/src/test/java/pro/taskana/common/internal/TaskanaProducersTest.java index 6f2ba30a38..7fad289d91 100644 --- a/lib/taskana-cdi/src/test/java/pro/taskana/common/internal/TaskanaProducersTest.java +++ b/lib/taskana-cdi/src/test/java/pro/taskana/common/internal/TaskanaProducersTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.io.File; import java.io.IOException; import java.net.URI; import java.net.http.HttpClient; @@ -19,15 +20,21 @@ import org.jboss.arquillian.junit.Arquillian; import org.jboss.shrinkwrap.api.Archive; import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.EnterpriseArchive; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.jboss.shrinkwrap.resolver.api.maven.Maven; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -import org.wildfly.swarm.undertow.WARArchive; +import pro.taskana.RestApplication; +import pro.taskana.TaskanaCdiTestRestController; +import pro.taskana.TaskanaEjb; @RunWith(Arquillian.class) public class TaskanaProducersTest { - private static final String REST_TEST_URL = "http://127.0.0.1:8090/rest/test"; + private static final String REST_TEST_URL = "http://127.0.0.1:8080/taskana/rest/test"; private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder() @@ -37,13 +44,31 @@ public class TaskanaProducersTest { @Deployment(testable = false) public static Archive createDeployment() throws Exception { - WARArchive deployment = ShrinkWrap.create(WARArchive.class); - deployment.addPackage("pro.taskana"); - deployment.addClass(TaskanaProducers.class); - deployment.addAllDependencies(); - deployment.addAsResource("META-INF/beans.xml"); - deployment.addAsResource("taskana.properties"); - deployment.addAsResource("project-defaults.yml"); + EnterpriseArchive deployment = ShrinkWrap.create(EnterpriseArchive.class, "taskana.ear"); + + File[] libs = + Maven.resolver() + .loadPomFromFile("pom.xml") + .importCompileAndRuntimeDependencies() + .resolve() + .withTransitivity() + .asFile(); + deployment.addAsLibraries(libs); + + JavaArchive ejbModule = ShrinkWrap.create(JavaArchive.class, "taskana.jar"); + ejbModule.addClasses( + TaskanaProducers.class, TaskanaEjb.class, TaskanaCdiStartupException.class); + ejbModule.addAsResource("taskana.properties"); + deployment.addAsModule(ejbModule); + + WebArchive webArchive = + ShrinkWrap.create(WebArchive.class, "taskana.war") + .addClasses(TaskanaCdiTestRestController.class, RestApplication.class) + .addAsWebInfResource("META-INF/beans.xml", "beans.xml") + .addAsWebInfResource("int-test-jboss-web.xml", "jboss-web.xml"); + deployment.addAsModule(webArchive); + + deployment.addAsManifestResource("META-INF/beans.xml", "beans.xml"); return deployment; } @@ -85,8 +110,8 @@ private Connection getConnection() throws Exception { return DriverManager.getConnection( "jdbc:h2:~/taskana-h2-data/testdb;NON_KEYWORDS=KEY,VALUE;AUTO_SERVER=TRUE;" + "IGNORECASE=TRUE;LOCK_MODE=0", - "SA", - "SA"); + "sa", + ""); } private int countTasksByName(String taskName) throws Exception { diff --git a/lib/taskana-cdi/src/test/resources/arquillian.xml b/lib/taskana-cdi/src/test/resources/arquillian.xml new file mode 100644 index 0000000000..3fcbf32bff --- /dev/null +++ b/lib/taskana-cdi/src/test/resources/arquillian.xml @@ -0,0 +1,19 @@ + + + + + target/wildfly-27.0.1.Final + int-test-standalone.xml + + + + + + -Djava.util.logging.manager=org.jboss.logmanager.LogManager + + + + \ No newline at end of file diff --git a/lib/taskana-cdi/src/test/resources/int-test-jboss-web.xml b/lib/taskana-cdi/src/test/resources/int-test-jboss-web.xml new file mode 100644 index 0000000000..a4c595ccc8 --- /dev/null +++ b/lib/taskana-cdi/src/test/resources/int-test-jboss-web.xml @@ -0,0 +1,7 @@ + + + /taskana + diff --git a/lib/taskana-cdi/src/test/resources/int-test-standalone.xml b/lib/taskana-cdi/src/test/resources/int-test-standalone.xml new file mode 100644 index 0000000000..356454a3ca --- /dev/null +++ b/lib/taskana-cdi/src/test/resources/int-test-standalone.xml @@ -0,0 +1,673 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + h2 + + sa + + + + + + jdbc:h2:~/taskana-h2-data/testdb;NON_KEYWORDS=KEY,VALUE;AUTO_SERVER=TRUE;IGNORECASE=TRUE;LOCK_MODE=0 + + h2 + + sa + + + + + + org.h2.jdbcx.JdbcDataSource + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${jboss.bind.address:127.0.0.1} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/taskana-cdi/src/test/resources/module.xml b/lib/taskana-cdi/src/test/resources/module.xml new file mode 100644 index 0000000000..933f1e5345 --- /dev/null +++ b/lib/taskana-cdi/src/test/resources/module.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/taskana-cdi/src/test/resources/project-defaults.yml b/lib/taskana-cdi/src/test/resources/project-defaults.yml deleted file mode 100644 index 30950dd300..0000000000 --- a/lib/taskana-cdi/src/test/resources/project-defaults.yml +++ /dev/null @@ -1,16 +0,0 @@ -swarm: - port: - offset: 10 - datasources: - data-sources: - TestDS: - driver-name: myh2 - connection-url: jdbc:h2:~/taskana-h2-data/testdb;NON_KEYWORDS=KEY,VALUE;AUTO_SERVER=TRUE;IGNORECASE=TRUE;LOCK_MODE=0 - user-name: SA - password: SA - jdbc-drivers: - myh2: - driver-class-name: org.h2.Driver - xa-datasource-name: org.h2.jdbcx.JdbcDataSource - driver-module-name: com.h2database.h2 - diff --git a/lib/taskana-cdi/src/test/resources/taskana.properties b/lib/taskana-cdi/src/test/resources/taskana.properties index 799c69696e..1fe7a119e4 100644 --- a/lib/taskana-cdi/src/test/resources/taskana.properties +++ b/lib/taskana-cdi/src/test/resources/taskana.properties @@ -5,11 +5,11 @@ taskana.classification.categories.T1=DEFAULT # enable or disable the jobscheduler at all # set it to false and no jobs are running taskana.jobs.scheduler.enabled=true -# wait time before the first job run in millis +# wait time before the first job run taskana.jobs.scheduler.initialStartDelay=100 # sleeping time befor the next job runs taskana.jobs.scheduler.period=1 -# timeunit for the sleeping period +# timeunit for the initial start delay and the sleeping period # Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS taskana.jobs.scheduler.periodTimeUnit=HOURS taskana.jobs.cleanup.task.enable=true diff --git a/lib/taskana-core-test/pom.xml b/lib/taskana-core-test/pom.xml index 4fe02cf382..5144967ab9 100644 --- a/lib/taskana-core-test/pom.xml +++ b/lib/taskana-core-test/pom.xml @@ -10,7 +10,7 @@ pro.taskana taskana-lib-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../pom.xml @@ -45,6 +45,7 @@ org.assertj assertj-core + ${version.assertj} test diff --git a/lib/taskana-core-test/src/test/java/acceptance/ArchitectureTest.java b/lib/taskana-core-test/src/test/java/acceptance/ArchitectureTest.java index 58d1a19a1a..c3c357e221 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/ArchitectureTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/ArchitectureTest.java @@ -62,6 +62,7 @@ import org.junit.platform.commons.support.AnnotationSupport; import pro.taskana.TaskanaConfiguration; import pro.taskana.common.api.TaskanaEngine; +import pro.taskana.common.api.WorkingTimeCalculator; import pro.taskana.common.api.exceptions.ErrorCode; import pro.taskana.common.api.exceptions.TaskanaException; import pro.taskana.common.api.exceptions.TaskanaRuntimeException; @@ -71,7 +72,6 @@ import pro.taskana.common.internal.jobs.JobScheduler; import pro.taskana.common.internal.logging.LoggingAspect; import pro.taskana.common.internal.workingtime.HolidaySchedule; -import pro.taskana.common.internal.workingtime.WorkingTimeCalculatorImpl; import pro.taskana.testapi.TaskanaIntegrationTest; /** @@ -437,7 +437,7 @@ void classesShouldNotUseWorkingDaysToDaysConverter() { .that() .areNotAssignableFrom(ArchitectureTest.class) .and() - .areNotAssignableTo(WorkingTimeCalculatorImpl.class) + .areNotAssignableTo(WorkingTimeCalculator.class) .and() .areNotAssignableTo(TaskanaEngineImpl.class) .and() diff --git a/lib/taskana-core-test/src/test/java/acceptance/TaskanaConfigurationTest.java b/lib/taskana-core-test/src/test/java/acceptance/TaskanaConfigurationTest.java index 050e2a0f45..21efb159b9 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/TaskanaConfigurationTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/TaskanaConfigurationTest.java @@ -115,7 +115,7 @@ void should_SetDefaultValues() { assertThat(configuration.getLogHistoryLoggerName()).isNull(); // job configuration assertThat(configuration.isJobSchedulerEnabled()).isTrue(); - assertThat(configuration.getJobSchedulerInitialStartDelay()).isEqualTo(100); + assertThat(configuration.getJobSchedulerInitialStartDelay()).isEqualTo(0); assertThat(configuration.getJobSchedulerPeriod()).isEqualTo(5); assertThat(configuration.getJobSchedulerPeriodTimeUnit()).isEqualTo(TimeUnit.MINUTES); assertThat(configuration.getMaxNumberOfJobRetries()).isEqualTo(3); @@ -251,6 +251,7 @@ void should_PopulateEveryTaskanaConfiguration_When_EveryBuilderFunctionIsCalled( Map> expectedClassificationCategories = Map.of("TYPE_A", List.of("CATEGORY_A"), "TYPE_B", List.of("CATEGORY_B")); // working time configuration + boolean expectedUseDetailedWorkingTimeCalculation = false; Map> expectedWorkingTimeSchedule = Map.of(DayOfWeek.MONDAY, Set.of(new LocalTimeInterval(LocalTime.MIN, LocalTime.NOON))); ZoneId expectedWorkingTimeScheduleTimeZone = ZoneId.ofOffset("UTC", ZoneOffset.ofHours(4)); @@ -269,21 +270,27 @@ void should_PopulateEveryTaskanaConfiguration_When_EveryBuilderFunctionIsCalled( int expectedJobBatchSize = 50; Instant expectedJobFirstJun = Instant.MIN; Duration expectedJobRunEvery = Duration.ofDays(2); + Duration expectedJobLockExpirationPeriod = Duration.ofDays(2); boolean expectedTaskCleanupJobEnabled = false; Duration expectedTaskCleanupJobMinimumAge = Duration.ofDays(1); boolean expectedTaskCleanupJobAllCompletedSameParentBusiness = false; + Duration expectedTaskCleanupJobLockExpirationPeriod = Duration.ofDays(2); boolean expectedWorkbasketCleanupJobEnabled = false; + Duration expectedWorkbasketCleanupJobLockExpirationPeriod = Duration.ofDays(2); boolean expectedSimpleHistoryCleanupJobEnabled = true; int expectedSimpleHistoryCleanupJobBatchSize = 16; Duration expectedSimpleHistoryCleanupJobMinimumAge = Duration.ofHours(3); boolean expectedSimpleHistoryCleanupJobAllCompletedSameParentBusiness = false; + Duration expectedSimpleHistoryCleanupJobLockExpirationPeriod = Duration.ofDays(2); boolean expectedTaskUpdatePriorityJobEnabled = true; int expectedPriorityJobBatchSize = 49; Instant expectedPriorityJobFirstRun = Instant.MIN.plus(1, ChronoUnit.DAYS); Duration expectedTaskUpdatePriorityJobRunEvery = Duration.ofMinutes(17); + Duration expectedTaskUpdatePriorityJobLockExpirationPeriod = Duration.ofDays(2); boolean expectedUserInfoRefreshJobEnabled = true; Instant expectedUserRefreshJobFirstRun = Instant.MIN.plus(2, ChronoUnit.DAYS); Duration expectedUserRefreshJobRunEvery = Duration.ofDays(5); + Duration expectedUserRefreshJobLockExpirationPeriod = Duration.ofDays(2); Set expectedJobSchedulerCustomJobs = Set.of("Job_A", "Job_B"); // user configuration boolean expectedAddAdditionalUserInfo = true; @@ -308,6 +315,7 @@ void should_PopulateEveryTaskanaConfiguration_When_EveryBuilderFunctionIsCalled( .classificationTypes(expectedClassificationTypes) .classificationCategoriesByType(expectedClassificationCategories) // working time configuration + .useWorkingTimeCalculation(expectedUseDetailedWorkingTimeCalculation) .workingTimeSchedule(expectedWorkingTimeSchedule) .workingTimeScheduleTimeZone(expectedWorkingTimeScheduleTimeZone) .customHolidays(expectedCustomHolidays) @@ -327,23 +335,32 @@ void should_PopulateEveryTaskanaConfiguration_When_EveryBuilderFunctionIsCalled( .jobBatchSize(expectedJobBatchSize) .jobFirstRun(expectedJobFirstJun) .jobRunEvery(expectedJobRunEvery) + .jobLockExpirationPeriod(expectedJobLockExpirationPeriod) .taskCleanupJobEnabled(expectedTaskCleanupJobEnabled) .taskCleanupJobMinimumAge(expectedTaskCleanupJobMinimumAge) .taskCleanupJobAllCompletedSameParentBusiness( expectedTaskCleanupJobAllCompletedSameParentBusiness) + .taskCleanupJobLockExpirationPeriod(expectedTaskCleanupJobLockExpirationPeriod) .workbasketCleanupJobEnabled(expectedWorkbasketCleanupJobEnabled) + .workbasketCleanupJobLockExpirationPeriod( + expectedWorkbasketCleanupJobLockExpirationPeriod) .simpleHistoryCleanupJobEnabled(expectedSimpleHistoryCleanupJobEnabled) .simpleHistoryCleanupJobBatchSize(expectedSimpleHistoryCleanupJobBatchSize) .simpleHistoryCleanupJobMinimumAge(expectedSimpleHistoryCleanupJobMinimumAge) .simpleHistoryCleanupJobAllCompletedSameParentBusiness( expectedSimpleHistoryCleanupJobAllCompletedSameParentBusiness) + .simpleHistoryCleanupJobLockExpirationPeriod( + expectedSimpleHistoryCleanupJobLockExpirationPeriod) .taskUpdatePriorityJobEnabled(expectedTaskUpdatePriorityJobEnabled) .taskUpdatePriorityJobBatchSize(expectedPriorityJobBatchSize) .taskUpdatePriorityJobFirstRun(expectedPriorityJobFirstRun) .taskUpdatePriorityJobRunEvery(expectedTaskUpdatePriorityJobRunEvery) + .taskUpdatePriorityJobLockExpirationPeriod( + expectedTaskUpdatePriorityJobLockExpirationPeriod) .userInfoRefreshJobEnabled(expectedUserInfoRefreshJobEnabled) .userRefreshJobFirstRun(expectedUserRefreshJobFirstRun) .userRefreshJobRunEvery(expectedUserRefreshJobRunEvery) + .userRefreshJobLockExpirationPeriod(expectedUserRefreshJobLockExpirationPeriod) .customJobs(expectedJobSchedulerCustomJobs) // user configuration .addAdditionalUserInfo(expectedAddAdditionalUserInfo) @@ -368,6 +385,8 @@ void should_PopulateEveryTaskanaConfiguration_When_EveryBuilderFunctionIsCalled( assertThat(configuration.getClassificationCategoriesByType()) .isEqualTo(expectedClassificationCategories); // working time configuration + assertThat(configuration.isUseWorkingTimeCalculation()) + .isEqualTo(expectedUseDetailedWorkingTimeCalculation); assertThat(configuration.getWorkingTimeSchedule()).isEqualTo(expectedWorkingTimeSchedule); assertThat(configuration.getWorkingTimeScheduleTimeZone()) .isEqualTo(expectedWorkingTimeScheduleTimeZone); @@ -442,6 +461,7 @@ void should_PopulateEveryConfigurationProperty_When_UsingCopyConstructor() { .classificationCategoriesByType( Map.of("typeA", List.of("categoryA"), "typeB", List.of("categoryB"))) // working time configuration + .useWorkingTimeCalculation(false) .workingTimeSchedule( Map.of( DayOfWeek.MONDAY, @@ -462,21 +482,27 @@ void should_PopulateEveryConfigurationProperty_When_UsingCopyConstructor() { .jobBatchSize(50) .jobFirstRun(Instant.MIN) .jobRunEvery(Duration.ofDays(2)) + .jobLockExpirationPeriod(Duration.ofDays(2)) .taskCleanupJobEnabled(false) .taskCleanupJobMinimumAge(Duration.ofDays(1)) .taskCleanupJobAllCompletedSameParentBusiness(false) + .taskCleanupJobLockExpirationPeriod(Duration.ofDays(6)) .workbasketCleanupJobEnabled(false) + .workbasketCleanupJobLockExpirationPeriod(Duration.ofDays(7)) .simpleHistoryCleanupJobEnabled(true) .simpleHistoryCleanupJobBatchSize(16) .simpleHistoryCleanupJobMinimumAge(Duration.ofHours(3)) .simpleHistoryCleanupJobAllCompletedSameParentBusiness(false) + .simpleHistoryCleanupJobLockExpirationPeriod(Duration.ofDays(9)) .taskUpdatePriorityJobEnabled(true) .taskUpdatePriorityJobBatchSize(49) .taskUpdatePriorityJobFirstRun(Instant.MIN.plus(1, ChronoUnit.DAYS)) .taskUpdatePriorityJobRunEvery(Duration.ofMinutes(17)) + .taskUpdatePriorityJobLockExpirationPeriod(Duration.ofDays(10)) .userInfoRefreshJobEnabled(true) .userRefreshJobFirstRun(Instant.MIN.plus(2, ChronoUnit.DAYS)) .userRefreshJobRunEvery(Duration.ofDays(5)) + .userRefreshJobLockExpirationPeriod(Duration.ofDays(8)) .customJobs(Set.of("Job_A", "Job_B")) // user configuration .addAdditionalUserInfo(true) diff --git a/lib/taskana-core-test/src/test/java/acceptance/classification/delete/DeleteClassificationAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/classification/delete/DeleteClassificationAccTest.java index 07bffb8759..49042e5b71 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/classification/delete/DeleteClassificationAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/classification/delete/DeleteClassificationAccTest.java @@ -45,6 +45,7 @@ void setup() throws Exception { .accessId("businessadmin") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService, "admin"); } diff --git a/lib/taskana-core-test/src/test/java/acceptance/classification/update/UpdateClassificationAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/classification/update/UpdateClassificationAccTest.java index 64bcc46aea..8caadb52f8 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/classification/update/UpdateClassificationAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/classification/update/UpdateClassificationAccTest.java @@ -46,6 +46,7 @@ import pro.taskana.task.internal.models.TaskImpl; import pro.taskana.testapi.TaskanaInject; import pro.taskana.testapi.TaskanaIntegrationTest; +import pro.taskana.testapi.builder.TaskBuilder; import pro.taskana.testapi.builder.WorkbasketAccessItemBuilder; import pro.taskana.testapi.security.WithAccessId; import pro.taskana.workbasket.api.WorkbasketPermission; @@ -134,6 +135,7 @@ private String createTaskWithExistingClassification(ClassificationSummary classi .accessId(currentUserContext.getUserid()) .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService, "businessadmin"); @@ -156,6 +158,7 @@ private List createTasksWithExistingClassificationInAttachment( .accessId(currentUserContext.getUserid()) .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService, "businessadmin"); ClassificationSummary classificationSummaryWithSpecifiedServiceLevel = @@ -183,6 +186,50 @@ private List createTasksWithExistingClassificationInAttachment( @Nested class UpdatePriorityAndServiceLevelTest { + @WithAccessId(user = "businessadmin") + @Test + void should_ChangeDueDate_When_ServiceLevelOfClassificationHasChanged() throws Exception { + Classification classification = + defaultTestClassification() + .priority(1) + .serviceLevel("P1D") + .buildAndStore(classificationService); + WorkbasketSummary workbasketSummary = + defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(workbasketSummary.getId()) + .accessId(currentUserContext.getUserid()) + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService, "businessadmin"); + + Task task = new TaskBuilder() + .classificationSummary(classification.asSummary()) + .workbasketSummary(workbasketSummary) + .primaryObjRef(defaultTestObjectReference().build()) + .planned(Instant.parse("2021-04-27T15:34:00.000Z")) + .due(null) + .buildAndStore(taskService); + + classificationService.updateClassification(classification); + runAssociatedJobs(); + // read again the task from DB + task = taskService.getTask(task.getId()); + assertThat(task.getClassificationSummary().getServiceLevel()).isEqualTo("P1D"); + assertThat(task.getDue()).isAfterOrEqualTo("2021-04-28T15:33:59.999Z"); + + classification.setServiceLevel("P3D"); + classificationService.updateClassification(classification); + runAssociatedJobs(); + + // read again the task from DB + task = taskService.getTask(task.getId()); + assertThat(task.getClassificationSummary().getServiceLevel()).isEqualTo("P3D"); + assertThat(task.getDue()).isEqualTo("2021-04-30T15:33:59.999Z"); + } + @WithAccessId(user = "businessadmin") @Test void should_NotThrowException_When_UpdatingClassificationWithEmptyServiceLevel() diff --git a/lib/taskana-core-test/src/test/java/acceptance/classification/update/UpdateClassificationWithWorkingDayCalculatorAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/classification/update/UpdateClassificationWithWorkingDayCalculatorAccTest.java new file mode 100644 index 0000000000..c041535993 --- /dev/null +++ b/lib/taskana-core-test/src/test/java/acceptance/classification/update/UpdateClassificationWithWorkingDayCalculatorAccTest.java @@ -0,0 +1,933 @@ +package acceptance.classification.update; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static pro.taskana.testapi.DefaultTestEntities.defaultTestClassification; +import static pro.taskana.testapi.DefaultTestEntities.defaultTestObjectReference; +import static pro.taskana.testapi.DefaultTestEntities.defaultTestWorkbasket; +import static pro.taskana.testapi.builder.TaskBuilder.newTask; + +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.api.TestTemplate; +import org.junit.jupiter.api.function.ThrowingConsumer; +import pro.taskana.TaskanaConfiguration.Builder; +import pro.taskana.classification.api.ClassificationCustomField; +import pro.taskana.classification.api.ClassificationService; +import pro.taskana.classification.api.exceptions.ClassificationNotFoundException; +import pro.taskana.classification.api.models.Classification; +import pro.taskana.classification.api.models.ClassificationSummary; +import pro.taskana.classification.internal.models.ClassificationImpl; +import pro.taskana.common.api.TaskanaEngine; +import pro.taskana.common.api.TaskanaRole; +import pro.taskana.common.api.WorkingTimeCalculator; +import pro.taskana.common.api.exceptions.ConcurrencyException; +import pro.taskana.common.api.exceptions.InvalidArgumentException; +import pro.taskana.common.api.exceptions.NotAuthorizedException; +import pro.taskana.common.api.security.CurrentUserContext; +import pro.taskana.common.internal.jobs.JobRunner; +import pro.taskana.common.internal.util.Pair; +import pro.taskana.task.api.TaskService; +import pro.taskana.task.api.models.Attachment; +import pro.taskana.task.api.models.Task; +import pro.taskana.task.internal.models.TaskImpl; +import pro.taskana.testapi.TaskanaConfigurationModifier; +import pro.taskana.testapi.TaskanaInject; +import pro.taskana.testapi.TaskanaIntegrationTest; +import pro.taskana.testapi.builder.TaskBuilder; +import pro.taskana.testapi.builder.WorkbasketAccessItemBuilder; +import pro.taskana.testapi.security.WithAccessId; +import pro.taskana.workbasket.api.WorkbasketPermission; +import pro.taskana.workbasket.api.WorkbasketService; +import pro.taskana.workbasket.api.models.WorkbasketSummary; + +@TaskanaIntegrationTest +public class UpdateClassificationWithWorkingDayCalculatorAccTest + implements TaskanaConfigurationModifier { + + @TaskanaInject ClassificationService classificationService; + @TaskanaInject TaskanaEngine taskanaEngine; + @TaskanaInject TaskService taskService; + @TaskanaInject WorkbasketService workbasketService; + @TaskanaInject WorkingTimeCalculator workingTimeCalculator; + @TaskanaInject CurrentUserContext currentUserContext; + + @Override + public Builder modify(Builder builder) { + return builder + .workingTimeScheduleTimeZone(ZoneId.of("UTC")) + .useWorkingTimeCalculation(false); // switch to WorkingDayCalculatorImpl + } + + @WithAccessId(user = "businessadmin") + @Test + void should_SetFieldsCorrectly_When_TryingToUpdateClassification() throws Exception { + Classification parentClassification = + defaultTestClassification().buildAndStore(classificationService); + Classification classification = + defaultTestClassification().type("TASK").buildAndStore(classificationService); + final Instant createdBefore = classification.getCreated(); + final Instant modifiedBefore = classification.getModified(); + + classification.setApplicationEntryPoint("newEntrypoint"); + classification.setCategory("PROCESS"); + classification.setCustomField(ClassificationCustomField.CUSTOM_1, "newCustom1"); + classification.setCustomField(ClassificationCustomField.CUSTOM_2, "newCustom2"); + classification.setCustomField(ClassificationCustomField.CUSTOM_3, "newCustom3"); + classification.setCustomField(ClassificationCustomField.CUSTOM_4, "newCustom4"); + classification.setCustomField(ClassificationCustomField.CUSTOM_5, "newCustom5"); + classification.setCustomField(ClassificationCustomField.CUSTOM_6, "newCustom6"); + classification.setCustomField(ClassificationCustomField.CUSTOM_7, "newCustom7"); + classification.setCustomField(ClassificationCustomField.CUSTOM_8, "newCustom8"); + classification.setDescription("newDescription"); + classification.setIsValidInDomain(false); + classification.setName("newName"); + classification.setParentId(parentClassification.getId()); + classification.setParentKey(parentClassification.getKey()); + classification.setPriority(1000); + classification.setServiceLevel("P3D"); + classificationService.updateClassification(classification); + + Classification updatedClassification = + classificationService.getClassification(classification.getKey(), "DOMAIN_A"); + ClassificationImpl expectedClassification = + (ClassificationImpl) + defaultTestClassification() + .type("TASK") + .applicationEntryPoint("newEntrypoint") + .category("PROCESS") + .customAttribute(ClassificationCustomField.CUSTOM_1, "newCustom1") + .customAttribute(ClassificationCustomField.CUSTOM_2, "newCustom2") + .customAttribute(ClassificationCustomField.CUSTOM_3, "newCustom3") + .customAttribute(ClassificationCustomField.CUSTOM_4, "newCustom4") + .customAttribute(ClassificationCustomField.CUSTOM_5, "newCustom5") + .customAttribute(ClassificationCustomField.CUSTOM_6, "newCustom6") + .customAttribute(ClassificationCustomField.CUSTOM_7, "newCustom7") + .customAttribute(ClassificationCustomField.CUSTOM_8, "newCustom8") + .description("newDescription") + .isValidInDomain(false) + .name("newName") + .parentId(parentClassification.getId()) + .parentKey(parentClassification.getKey()) + .priority(1000) + .serviceLevel("P3D") + .created(createdBefore) + .modified(updatedClassification.getModified()) + .buildAndStore(classificationService); + expectedClassification.setKey(updatedClassification.getKey()); + expectedClassification.setId(updatedClassification.getId()); + + assertThat(expectedClassification).hasNoNullFieldsOrProperties(); + assertThat(modifiedBefore).isBefore(classification.getModified()); + assertThat(updatedClassification).isEqualTo(expectedClassification); + } + + private String createTaskWithExistingClassification(ClassificationSummary classificationSummary) + throws Exception { + + WorkbasketSummary workbasketSummary = + defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(workbasketSummary.getId()) + .accessId(currentUserContext.getUserid()) + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService, "businessadmin"); + + return newTask() + .classificationSummary(classificationSummary) + .workbasketSummary(workbasketSummary) + .primaryObjRef(defaultTestObjectReference().build()) + .buildAndStore(taskService) + .getId(); + } + + private List createTasksWithExistingClassificationInAttachment( + ClassificationSummary classificationSummary, String serviceLevel, int priority, int amount) + throws Exception { + List taskList = new ArrayList<>(); + WorkbasketSummary workbasketSummary = + defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(workbasketSummary.getId()) + .accessId(currentUserContext.getUserid()) + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService, "businessadmin"); + ClassificationSummary classificationSummaryWithSpecifiedServiceLevel = + defaultTestClassification() + .serviceLevel(serviceLevel) + .priority(priority) + .buildAndStoreAsSummary(classificationService); + for (int i = 0; i < amount; i++) { + Attachment attachment = taskService.newAttachment(); + attachment.setClassificationSummary(classificationSummary); + attachment.setObjectReference(defaultTestObjectReference().build()); + taskList.add( + newTask() + .classificationSummary(classificationSummaryWithSpecifiedServiceLevel) + .workbasketSummary(workbasketSummary) + .primaryObjRef(defaultTestObjectReference().build()) + .attachments(attachment) + .buildAndStore(taskService) + .getId()); + } + return taskList; + } + + @TestInstance(Lifecycle.PER_CLASS) + @Nested + class UpdatePriorityAndServiceLevelTest { + + @WithAccessId(user = "businessadmin") + @Test + void should_ChangeDueDate_When_ClassificationOfTaskHasChanged() throws Exception { + + final Instant plannedDate = Instant.parse("2021-04-27T15:34:00.000Z"); + final String expectedDue1 = plannedDate.plus(1, ChronoUnit.DAYS).toString(); + final String expectedDue3 = plannedDate.plus(3, ChronoUnit.DAYS).toString(); + + final Classification classificationWithSL1 = + defaultTestClassification() + .priority(1) + .serviceLevel("P1D") + .buildAndStore(classificationService); + final Classification classificationWithSL3 = + defaultTestClassification() + .priority(1) + .serviceLevel("P3D") + .buildAndStore(classificationService); + + WorkbasketSummary workbasketSummary = + defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(workbasketSummary.getId()) + .accessId(currentUserContext.getUserid()) + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService, "businessadmin"); + + Task task = + new TaskBuilder() + .classificationSummary(classificationWithSL1.asSummary()) + .workbasketSummary(workbasketSummary) + .primaryObjRef(defaultTestObjectReference().build()) + .planned(plannedDate) + .due(null) + .buildAndStore(taskService); + + classificationService.updateClassification(classificationWithSL1); + runAssociatedJobs(); + // read again the task from DB + task = taskService.getTask(task.getId()); + assertThat(task.getClassificationSummary().getServiceLevel()).isEqualTo("P1D"); + assertThat(task.getDue()).isAfterOrEqualTo(expectedDue1); + + task.setClassificationKey(classificationWithSL3.getKey()); + taskService.updateTask(task); + + // read again the task from DB + task = taskService.getTask(task.getId()); + assertThat(task.getClassificationSummary().getServiceLevel()).isEqualTo("P3D"); + assertThat(task.getDue()).isEqualTo(expectedDue3); + } + + @WithAccessId(user = "businessadmin") + @Test + void should_ChangeDueDate_When_ServiceLevelOfClassificationHasChanged() throws Exception { + Classification classification = + defaultTestClassification() + .priority(1) + .serviceLevel("P1D") + .buildAndStore(classificationService); + WorkbasketSummary workbasketSummary = + defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(workbasketSummary.getId()) + .accessId(currentUserContext.getUserid()) + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService, "businessadmin"); + + Task task = + new TaskBuilder() + .classificationSummary(classification.asSummary()) + .workbasketSummary(workbasketSummary) + .primaryObjRef(defaultTestObjectReference().build()) + .planned(Instant.parse("2021-04-27T15:34:00.000Z")) + .due(null) + .buildAndStore(taskService); + + classificationService.updateClassification(classification); + runAssociatedJobs(); + // read again the task from DB + task = taskService.getTask(task.getId()); + assertThat(task.getClassificationSummary().getServiceLevel()).isEqualTo("P1D"); + assertThat(task.getDue()).isAfterOrEqualTo("2021-04-28T15:34:00.000Z"); + + classification.setServiceLevel("P3D"); + classificationService.updateClassification(classification); + runAssociatedJobs(); + + // read again the task from DB + task = taskService.getTask(task.getId()); + assertThat(task.getClassificationSummary().getServiceLevel()).isEqualTo("P3D"); + assertThat(task.getDue()).isEqualTo("2021-04-30T15:34:00.000Z"); + } + + @WithAccessId(user = "businessadmin") + @Test + void should_NotThrowException_When_UpdatingClassificationWithEmptyServiceLevel() + throws Exception { + Classification classification = + defaultTestClassification().serviceLevel("P1D").buildAndStore(classificationService); + classification.setServiceLevel(""); + assertThatCode(() -> classificationService.updateClassification(classification)) + .doesNotThrowAnyException(); + assertThat(classificationService.getClassification(classification.getId()).getServiceLevel()) + .isEqualTo("P0D"); + } + + @WithAccessId(user = "businessadmin") + @TestFactory + Stream + should_SetDefaultServiceLevel_When_TryingToUpdateClassificationWithMissingServiceLevel() + throws Exception { + Classification classification = + defaultTestClassification().serviceLevel("P1D").buildAndStore(classificationService); + List> inputList = + List.of(Pair.of(classification, null), Pair.of(classification, "")); + + ThrowingConsumer> test = + input -> { + input.getLeft().setServiceLevel(input.getRight()); + classificationService.updateClassification(input.getLeft()); + assertThat( + classificationService + .getClassification(input.getLeft().getId()) + .getServiceLevel()) + .isEqualTo("P0D"); + }; + + return DynamicTest.stream( + inputList.iterator(), i -> String.format("for %s", i.getRight()), test); + } + + @WithAccessId(user = "businessadmin") + @Test + void should_UpdateTaskServiceLevel_When_UpdateClassificationInTask() throws Exception { + final Instant before = Instant.now(); + Classification classification = + defaultTestClassification() + .priority(1) + .serviceLevel("P13D") + .buildAndStore(classificationService); + final List directLinkedTask = + List.of(createTaskWithExistingClassification(classification.asSummary())); + + classification.setServiceLevel("P15D"); + classificationService.updateClassification(classification); + runAssociatedJobs(); + + validateTaskProperties(before, directLinkedTask, taskService, workingTimeCalculator, 15, 1); + } + + @WithAccessId(user = "businessadmin") + @Test + void should_UpdateTaskPriority_When_UpdateClassificationInTask() throws Exception { + final Instant before = Instant.now(); + Classification classification = + defaultTestClassification() + .priority(1) + .serviceLevel("P13D") + .buildAndStore(classificationService); + final List directLinkedTask = + List.of(createTaskWithExistingClassification(classification.asSummary())); + + classification.setPriority(1000); + classificationService.updateClassification(classification); + runAssociatedJobs(); + + validateTaskProperties( + before, directLinkedTask, taskService, workingTimeCalculator, 13, 1000); + } + + @WithAccessId(user = "businessadmin") + @Test + void should_UpdateTaskPriorityAndServiceLevel_When_UpdateClassificationInTask() + throws Exception { + final Instant before = Instant.now(); + Classification classification = + defaultTestClassification() + .priority(1) + .serviceLevel("P13D") + .buildAndStore(classificationService); + final List directLinkedTask = + List.of(createTaskWithExistingClassification(classification.asSummary())); + + classification.setServiceLevel("P15D"); + classification.setPriority(1000); + classificationService.updateClassification(classification); + runAssociatedJobs(); + + validateTaskProperties( + before, directLinkedTask, taskService, workingTimeCalculator, 15, 1000); + } + + @WithAccessId(user = "businessadmin") + @TestFactory + Stream should_UpdateTaskServiceLevel_When_UpdateClassificationInAttachment() { + List> inputs = + List.of(Pair.of("P5D", 2), Pair.of("P8D", 3), Pair.of("P16D", 4)); + + List> outputs = List.of(Pair.of(1, 2), Pair.of(1, 3), Pair.of(1, 4)); + + List, Pair>> zippedTestInputList = + IntStream.range(0, inputs.size()) + .mapToObj(i -> Pair.of(inputs.get(i), outputs.get(i))) + .collect(Collectors.toList()); + + ThrowingConsumer, Pair>> test = + input -> { + final Instant before = Instant.now(); + Classification classification = + defaultTestClassification() + .priority(1) + .serviceLevel("P15D") + .buildAndStore(classificationService); + ClassificationSummary classificationSummary = classification.asSummary(); + final List indirectLinkedTasks = + createTasksWithExistingClassificationInAttachment( + classificationSummary, + input.getLeft().getLeft(), + input.getLeft().getRight(), + 5); + + classification.setServiceLevel("P1D"); + classificationService.updateClassification(classification); + runAssociatedJobs(); + + validateTaskProperties( + before, + indirectLinkedTasks, + taskService, + workingTimeCalculator, + input.getRight().getLeft(), + input.getRight().getRight()); + }; + + return DynamicTest.stream( + zippedTestInputList.iterator(), + i -> + String.format( + "for Task with ServiceLevel %s and Priority %s", + i.getLeft().getLeft(), i.getLeft().getRight()), + test); + } + + @WithAccessId(user = "businessadmin") + @TestFactory + Stream should_NotUpdateTaskServiceLevel_When_UpdateClassificationInAttachment() { + List> inputs = + List.of(Pair.of("P5D", 2), Pair.of("P8D", 3), Pair.of("P14D", 4)); + + List> outputs = List.of(Pair.of(5, 2), Pair.of(8, 3), Pair.of(14, 4)); + + List, Pair>> zippedTestInputList = + IntStream.range(0, inputs.size()) + .mapToObj(i -> Pair.of(inputs.get(i), outputs.get(i))) + .collect(Collectors.toList()); + + ThrowingConsumer, Pair>> test = + input -> { + final Instant before = Instant.now(); + Classification classification = + defaultTestClassification() + .priority(1) + .serviceLevel("P1D") + .buildAndStore(classificationService); + ClassificationSummary classificationSummary = classification.asSummary(); + final List indirectLinkedTasks = + createTasksWithExistingClassificationInAttachment( + classificationSummary, + input.getLeft().getLeft(), + input.getLeft().getRight(), + 5); + + classification.setServiceLevel("P15D"); + classificationService.updateClassification(classification); + runAssociatedJobs(); + + validateTaskProperties( + before, + indirectLinkedTasks, + taskService, + workingTimeCalculator, + input.getRight().getLeft(), + input.getRight().getRight()); + }; + + return DynamicTest.stream( + zippedTestInputList.iterator(), + i -> + String.format( + "for Task with ServiceLevel %s and Priority %s", + i.getLeft().getLeft(), i.getLeft().getRight()), + test); + } + + @WithAccessId(user = "businessadmin") + @TestFactory + Stream should_UpdateTaskPriority_When_UpdateClassificationInAttachment() { + List> inputs = + List.of(Pair.of("P1D", 1), Pair.of("P8D", 2), Pair.of("P14D", 999)); + + List> outputs = + List.of(Pair.of(1, 1000), Pair.of(8, 1000), Pair.of(14, 1000)); + + List, Pair>> zippedTestInputList = + IntStream.range(0, inputs.size()) + .mapToObj(i -> Pair.of(inputs.get(i), outputs.get(i))) + .collect(Collectors.toList()); + + ThrowingConsumer, Pair>> test = + input -> { + final Instant before = Instant.now(); + Classification classification = + defaultTestClassification() + .priority(1) + .serviceLevel("P13D") + .buildAndStore(classificationService); + ClassificationSummary classificationSummary = classification.asSummary(); + final List indirectLinkedTasks = + createTasksWithExistingClassificationInAttachment( + classificationSummary, + input.getLeft().getLeft(), + input.getLeft().getRight(), + 5); + + classification.setServiceLevel("P15D"); + classification.setPriority(1000); + classificationService.updateClassification(classification); + runAssociatedJobs(); + + validateTaskProperties( + before, + indirectLinkedTasks, + taskService, + workingTimeCalculator, + input.getRight().getLeft(), + input.getRight().getRight()); + }; + + return DynamicTest.stream( + zippedTestInputList.iterator(), + i -> + String.format( + "for Task with ServiceLevel %s and Priority %s", + i.getLeft().getLeft(), i.getLeft().getRight()), + test); + } + + @WithAccessId(user = "businessadmin") + @TestFactory + Stream should_NotUpdateTaskPriority_When_UpdateClassificationInAttachment() { + List> inputs = + List.of(Pair.of("P1D", 2), Pair.of("P8D", 3), Pair.of("P14D", 999)); + + List> outputs = + List.of(Pair.of(1, 2), Pair.of(8, 3), Pair.of(14, 999)); + + List, Pair>> zippedTestInputList = + IntStream.range(0, inputs.size()) + .mapToObj(i -> Pair.of(inputs.get(i), outputs.get(i))) + .collect(Collectors.toList()); + + ThrowingConsumer, Pair>> test = + input -> { + final Instant before = Instant.now(); + Classification classification = + defaultTestClassification() + .priority(1000) + .serviceLevel("P13D") + .buildAndStore(classificationService); + ClassificationSummary classificationSummary = classification.asSummary(); + final List indirectLinkedTasks = + createTasksWithExistingClassificationInAttachment( + classificationSummary, + input.getLeft().getLeft(), + input.getLeft().getRight(), + 5); + + classification.setServiceLevel("P15D"); + classification.setPriority(1); + classificationService.updateClassification(classification); + runAssociatedJobs(); + + validateTaskProperties( + before, + indirectLinkedTasks, + taskService, + workingTimeCalculator, + input.getRight().getLeft(), + input.getRight().getRight()); + }; + + return DynamicTest.stream( + zippedTestInputList.iterator(), + i -> + String.format( + "for Task with ServiceLevel %s and Priority %s", + i.getLeft().getLeft(), i.getLeft().getRight()), + test); + } + + @WithAccessId(user = "businessadmin") + @TestFactory + Stream + should_UpdateTaskPriorityAndServiceLevel_When_UpdateClassificationInAttachment() { + List> inputs = List.of(Pair.of("P1D", 5), Pair.of("P14D", 98)); + + List> outputs = List.of(Pair.of(1, 99), Pair.of(1, 99)); + + List, Pair>> zippedTestInputList = + IntStream.range(0, inputs.size()) + .mapToObj(i -> Pair.of(inputs.get(i), outputs.get(i))) + .collect(Collectors.toList()); + + ThrowingConsumer, Pair>> test = + input -> { + final Instant before = Instant.now(); + Classification classification = + defaultTestClassification() + .priority(1) + .serviceLevel("P13D") + .buildAndStore(classificationService); + ClassificationSummary classificationSummary = classification.asSummary(); + final List indirectLinkedTasks = + createTasksWithExistingClassificationInAttachment( + classificationSummary, + input.getLeft().getLeft(), + input.getLeft().getRight(), + 3); + + classification.setServiceLevel("P1D"); + classification.setPriority(99); + classificationService.updateClassification(classification); + runAssociatedJobs(); + + validateTaskProperties( + before, + indirectLinkedTasks, + taskService, + workingTimeCalculator, + input.getRight().getLeft(), + input.getRight().getRight()); + }; + + return DynamicTest.stream( + zippedTestInputList.iterator(), + i -> + String.format( + "for Task with ServiceLevel %s and Priority %s", + i.getLeft().getLeft(), i.getLeft().getRight()), + test); + } + + @WithAccessId(user = "businessadmin") + @TestFactory + Stream + should_NotUpdateTaskPriorityAndServiceLevel_When_UpdateClassificationInAttachment() { + List> inputs = List.of(Pair.of("P1D", 5), Pair.of("P14D", 98)); + + List> outputs = List.of(Pair.of(1, 5), Pair.of(14, 98)); + + List, Pair>> zippedTestInputList = + IntStream.range(0, inputs.size()) + .mapToObj(i -> Pair.of(inputs.get(i), outputs.get(i))) + .collect(Collectors.toList()); + + ThrowingConsumer, Pair>> test = + input -> { + final Instant before = Instant.now(); + Classification classification = + defaultTestClassification() + .priority(1000) + .serviceLevel("P1D") + .buildAndStore(classificationService); + ClassificationSummary classificationSummary = classification.asSummary(); + final List indirectLinkedTasks = + createTasksWithExistingClassificationInAttachment( + classificationSummary, + input.getLeft().getLeft(), + input.getLeft().getRight(), + 3); + + classification.setServiceLevel("P15D"); + classification.setPriority(1); + classificationService.updateClassification(classification); + runAssociatedJobs(); + + validateTaskProperties( + before, + indirectLinkedTasks, + taskService, + workingTimeCalculator, + input.getRight().getLeft(), + input.getRight().getRight()); + }; + + return DynamicTest.stream( + zippedTestInputList.iterator(), + i -> + String.format( + "for Task with ServiceLevel %s and Priority %s", + i.getLeft().getLeft(), i.getLeft().getRight()), + test); + } + + private void runAssociatedJobs() throws Exception { + Thread.sleep(10); + // run the ClassificationChangedJob + JobRunner runner = new JobRunner(taskanaEngine); + // run the TaskRefreshJob that was scheduled by the ClassificationChangedJob. + runner.runJobs(); + Thread.sleep( + 10); // otherwise the next runJobs call intermittently doesn't find the Job created + // by the previous step (it searches with DueDate < CurrentTime) + runner.runJobs(); + } + + private void validateTaskProperties( + Instant before, + List tasksUpdated, + TaskService taskService, + WorkingTimeCalculator workingTimeCalculator, + int serviceLevel, + int priority) + throws Exception { + for (String taskId : tasksUpdated) { + Task task = taskService.getTask(taskId); + + Instant expDue = + workingTimeCalculator.addWorkingTime(task.getPlanned(), Duration.ofDays(serviceLevel)); + assertThat(task.getModified()) + .describedAs("Task " + task.getId() + " has not been refreshed.") + .isAfter(before); + assertThat(task.getDue()).isEqualTo(expDue); + assertThat(task.getPriority()).isEqualTo(priority); + } + } + } + + @TestInstance(Lifecycle.PER_CLASS) + @Nested + class UpdateClassificationExceptionTest { + /** + * This BeforeAll method is needed for this {@linkplain + * #should_ThrowException_When_UserIsNotAuthorized test} and {@linkplain + * #should_ThrowException_When_UserRoleIsNotAdminOrBusinessAdmin test} since it can't create an + * own classification. + * + * @throws Exception for errors in the building or reading process of entities. + */ + @WithAccessId(user = "businessadmin") + @BeforeAll + void createClassifications() throws Exception { + defaultTestClassification() + .key("BeforeAllClassification") + .buildAndStore(classificationService); + } + + @Test + void should_ThrowException_When_UserIsNotAuthorized() throws Exception { + Classification classification = + classificationService.getClassification("BeforeAllClassification", "DOMAIN_A"); + classification.setCustomField(ClassificationCustomField.CUSTOM_1, "newCustom1"); + + NotAuthorizedException expectedException = + new NotAuthorizedException( + currentUserContext.getUserid(), TaskanaRole.BUSINESS_ADMIN, TaskanaRole.ADMIN); + assertThatThrownBy(() -> classificationService.updateClassification(classification)) + .usingRecursiveComparison() + .isEqualTo(expectedException); + } + + @WithAccessId(user = "taskadmin") + @WithAccessId(user = "user-1-1") + @TestTemplate + void should_ThrowException_When_UserRoleIsNotAdminOrBusinessAdmin() throws Exception { + Classification classification = + classificationService.getClassification("BeforeAllClassification", "DOMAIN_A"); + + classification.setApplicationEntryPoint("updated EntryPoint"); + classification.setName("updated Name"); + + NotAuthorizedException expectedException = + new NotAuthorizedException( + currentUserContext.getUserid(), TaskanaRole.BUSINESS_ADMIN, TaskanaRole.ADMIN); + assertThatThrownBy(() -> classificationService.updateClassification(classification)) + .usingRecursiveComparison() + .isEqualTo(expectedException); + } + + @WithAccessId(user = "businessadmin") + @Test + void should_ThrowException_When_UpdatingClassificationConcurrently() throws Exception { + Classification classification = + defaultTestClassification().buildAndStore(classificationService); + final Classification classificationSecondUpdate = + classificationService.getClassification( + classification.getKey(), classification.getDomain()); + + classification.setApplicationEntryPoint("Application Entry Point"); + classification.setDescription("Description"); + classification.setName("Name"); + Thread.sleep(20); // to avoid identity of modified timestamps between classification and base + classificationService.updateClassification(classification); + classificationSecondUpdate.setName("Name again"); + classificationSecondUpdate.setDescription("Description again"); + + ConcurrencyException expectedException = + new ConcurrencyException(classificationSecondUpdate.getId()); + assertThatThrownBy( + () -> classificationService.updateClassification(classificationSecondUpdate)) + .usingRecursiveComparison() + .isEqualTo(expectedException); + } + + @WithAccessId(user = "businessadmin") + @Test + void should_ThrowException_When_TryingToUpdateClassificationWithInvalidParentId() + throws Exception { + Classification classification = + defaultTestClassification().buildAndStore(classificationService); + + classification.setParentId("NON EXISTING ID"); + + ClassificationNotFoundException expectedException = + new ClassificationNotFoundException("NON EXISTING ID"); + assertThatThrownBy(() -> classificationService.updateClassification(classification)) + .usingRecursiveComparison() + .isEqualTo(expectedException); + } + + @WithAccessId(user = "businessadmin") + @Test + void should_ThrowException_When_TryingToUpdateClassificationWithInvalidParentKey() + throws Exception { + Classification classification = + defaultTestClassification().buildAndStore(classificationService); + + classification.setParentKey("NON EXISTING KEY"); + + ClassificationNotFoundException expectedException = + new ClassificationNotFoundException("NON EXISTING KEY", "DOMAIN_A"); + assertThatThrownBy(() -> classificationService.updateClassification(classification)) + .usingRecursiveComparison() + .isEqualTo(expectedException); + } + + @WithAccessId(user = "businessadmin") + @Test + void should_ThrowException_When_TryingToUpdateClassificationWithOwnKeyAsParentKey() + throws Exception { + Classification classification = + defaultTestClassification().buildAndStore(classificationService); + + classification.setParentKey(classification.getKey()); + + InvalidArgumentException expectedException = + new InvalidArgumentException( + String.format( + "The Classification '%s' has the same key and parent key", + classification.getName())); + assertThatThrownBy(() -> classificationService.updateClassification(classification)) + .usingRecursiveComparison() + .isEqualTo(expectedException); + } + } + + @TestInstance(Lifecycle.PER_CLASS) + @Nested + class UpdateClassificationCategoryTest { + Classification classification; + Task task; + Instant createdBefore; + Instant modifiedBefore; + + @WithAccessId(user = "businessadmin") + @BeforeEach + void createClassificationAndTask() throws Exception { + classification = + defaultTestClassification() + .category("MANUAL") + .type("TASK") + .buildAndStore(classificationService); + createdBefore = classification.getCreated(); + modifiedBefore = classification.getModified(); + String taskId = createTaskWithExistingClassification(classification.asSummary()); + task = taskService.getTask(taskId); + } + + @WithAccessId(user = "businessadmin") + @Test + void should_UpdateTask_When_UpdatingClassificationCategory() throws Exception { + classification.setCategory("PROCESS"); + classificationService.updateClassification(classification); + final Task updatedTask = taskService.getTask(task.getId()); + + TaskImpl expectedUpdatedTask = (TaskImpl) task.copy(); + expectedUpdatedTask.setId(task.getId()); + expectedUpdatedTask.setClassificationCategory("PROCESS"); + expectedUpdatedTask.setClassificationSummary( + classificationService.getClassification(classification.getId()).asSummary()); + expectedUpdatedTask.setExternalId(task.getExternalId()); + assertThat(expectedUpdatedTask) + .usingRecursiveComparison() + .ignoringFields("modified") + .isEqualTo(updatedTask); + assertThat(expectedUpdatedTask.getModified()).isAfterOrEqualTo(modifiedBefore); + } + + @WithAccessId(user = "businessadmin") + @Test + void should_UpdateClassification_When_UpdatingClassificationCategory() throws Exception { + classification.setCategory("PROCESS"); + classificationService.updateClassification(classification); + + Classification updatedClassification = + classificationService.getClassification(classification.getId()); + assertThat(updatedClassification) + .usingRecursiveComparison() + .ignoringFields("modified") + .isEqualTo(classification); + assertThat(updatedClassification.getModified()).isAfterOrEqualTo(modifiedBefore); + } + } +} diff --git a/lib/taskana-core-test/src/test/java/acceptance/jobs/helper/TaskUpdatePriorityWorkerAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/jobs/helper/TaskUpdatePriorityWorkerAccTest.java index 416ffd2b8a..21b58091c7 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/jobs/helper/TaskUpdatePriorityWorkerAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/jobs/helper/TaskUpdatePriorityWorkerAccTest.java @@ -65,6 +65,7 @@ void setUp(ClassificationService classificationService, WorkbasketService workba .workbasketId(workbasketSummary.getId()) .accessId("whatever") .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .buildAndStore(workbasketService); TaskBuilder taskBuilder = diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/ServiceLevelOfAllTasksAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/ServiceLevelOfAllTasksAccTest.java index b28c0853fd..f49d5ebd49 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/ServiceLevelOfAllTasksAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/ServiceLevelOfAllTasksAccTest.java @@ -5,18 +5,26 @@ import static pro.taskana.testapi.DefaultTestEntities.defaultTestObjectReference; import static pro.taskana.testapi.DefaultTestEntities.defaultTestWorkbasket; +import java.time.Duration; import java.time.Instant; import java.util.List; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import pro.taskana.TaskanaConfiguration.Builder; import pro.taskana.classification.api.ClassificationService; import pro.taskana.classification.api.models.ClassificationSummary; import pro.taskana.common.api.BulkOperationResults; +import pro.taskana.common.api.TaskanaEngine; +import pro.taskana.common.api.WorkingTimeCalculator; import pro.taskana.common.api.exceptions.TaskanaException; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.models.Attachment; import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.TaskSummary; +import pro.taskana.testapi.TaskanaConfigurationModifier; import pro.taskana.testapi.TaskanaInject; import pro.taskana.testapi.TaskanaIntegrationTest; import pro.taskana.testapi.builder.TaskAttachmentBuilder; @@ -37,171 +45,364 @@ class ServiceLevelOfAllTasksAccTest { private static final String SMALL_CLASSIFICATION_SERVICE_LEVEL = "P2D"; private static final String GREAT_CLASSIFICATION_SERVICE_LEVEL = "P7D"; - @TaskanaInject TaskService taskService; - @TaskanaInject WorkbasketService workbasketService; - @TaskanaInject ClassificationService classificationService; - - ClassificationSummary classificationSummarySmallServiceLevel; - ClassificationSummary classificationSummaryGreatServiceLevel; - Attachment attachmentSummarySmallServiceLevel; - Attachment attachmentSummaryGreatServiceLevel; - WorkbasketSummary defaultWorkbasketSummary; - ObjectReference defaultObjectReference; - - @WithAccessId(user = "businessadmin") - @BeforeAll - void setup() throws Exception { - classificationSummarySmallServiceLevel = - defaultTestClassification() - .serviceLevel(SMALL_CLASSIFICATION_SERVICE_LEVEL) - .buildAndStoreAsSummary(classificationService); - classificationSummaryGreatServiceLevel = - defaultTestClassification() - .serviceLevel(GREAT_CLASSIFICATION_SERVICE_LEVEL) - .buildAndStoreAsSummary(classificationService); - - defaultObjectReference = defaultTestObjectReference().build(); - - attachmentSummarySmallServiceLevel = - TaskAttachmentBuilder.newAttachment() - .classificationSummary(classificationSummarySmallServiceLevel) - .objectReference(defaultObjectReference) - .build(); - attachmentSummaryGreatServiceLevel = - TaskAttachmentBuilder.newAttachment() - .classificationSummary(classificationSummaryGreatServiceLevel) - .objectReference(defaultObjectReference) - .build(); - - defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); - WorkbasketAccessItemBuilder.newWorkbasketAccessItem() - .workbasketId(defaultWorkbasketSummary.getId()) - .accessId("user-1-1") - .permission(WorkbasketPermission.OPEN) - .permission(WorkbasketPermission.READ) - .permission(WorkbasketPermission.APPEND) - .buildAndStore(workbasketService); - } + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class WithWorkingTimeCalculation { + @TaskanaInject TaskService taskService; + @TaskanaInject WorkbasketService workbasketService; + @TaskanaInject ClassificationService classificationService; - @WithAccessId(user = "user-1-1") - @Test - void should_SetPlannedOnMultipleTasks() throws Exception { - Instant planned = Instant.parse("2020-05-03T07:00:00.000Z"); - TaskSummary task1 = - createDefaultTask() - .classificationSummary(classificationSummarySmallServiceLevel) - .buildAndStoreAsSummary(taskService); - TaskSummary task2 = - createDefaultTask() - .classificationSummary(classificationSummarySmallServiceLevel) - .attachments(attachmentSummaryGreatServiceLevel.copy()) - .buildAndStoreAsSummary(taskService); - TaskSummary task3 = - createDefaultTask() - .classificationSummary(classificationSummaryGreatServiceLevel) - .attachments(attachmentSummarySmallServiceLevel.copy()) - .buildAndStoreAsSummary(taskService); - List taskIds = List.of(task1.getId(), task2.getId(), task3.getId()); - - BulkOperationResults bulkLog = - taskService.setPlannedPropertyOfTasks(planned, taskIds); - - assertThat(bulkLog.containsErrors()).isFalse(); - List result = - taskService.createTaskQuery().idIn(task1.getId(), task2.getId(), task3.getId()).list(); - assertThat(result).extracting(TaskSummary::getPlanned).containsOnly(planned); - } + ClassificationSummary classificationSummarySmallServiceLevel; + ClassificationSummary classificationSummaryGreatServiceLevel; + Attachment attachmentSummarySmallServiceLevel; + Attachment attachmentSummaryGreatServiceLevel; + WorkbasketSummary defaultWorkbasketSummary; + ObjectReference defaultObjectReference; - @WithAccessId(user = "user-1-1") - @Test - void should_ChangeDue_When_SettingPlannedAndClassificationHasSmallerServiceLevel() - throws Exception { - Instant planned = Instant.parse("2020-05-04T07:00:00.000Z"); - TaskSummary task1 = - createDefaultTask() - .classificationSummary(classificationSummarySmallServiceLevel) - .attachments(attachmentSummaryGreatServiceLevel.copy()) - .buildAndStoreAsSummary(taskService); - TaskSummary task2 = - createDefaultTask() - .classificationSummary(classificationSummarySmallServiceLevel) - .buildAndStoreAsSummary(taskService); - List taskIds = List.of(task1.getId(), task2.getId()); - - BulkOperationResults bulkLog = - taskService.setPlannedPropertyOfTasks(planned, taskIds); - - assertThat(bulkLog.containsErrors()).isFalse(); - List result = - taskService.createTaskQuery().idIn(task1.getId(), task2.getId()).list(); - Instant expectedDue = Instant.parse("2020-05-06T06:59:59.999Z"); - assertThat(result).extracting(TaskSummary::getDue).containsOnly(expectedDue); - } + @WithAccessId(user = "businessadmin") + @BeforeAll + void setup() throws Exception { + classificationSummarySmallServiceLevel = + defaultTestClassification() + .serviceLevel(SMALL_CLASSIFICATION_SERVICE_LEVEL) + .buildAndStoreAsSummary(classificationService); + classificationSummaryGreatServiceLevel = + defaultTestClassification() + .serviceLevel(GREAT_CLASSIFICATION_SERVICE_LEVEL) + .buildAndStoreAsSummary(classificationService); - @WithAccessId(user = "user-1-1") - @Test - void should_ChangeDue_When_SettingPlannedAndAttachmentHasSmallerOrEqualServiceLevel() - throws Exception { - Instant planned = Instant.parse("2020-05-04T07:00:00.000Z"); - TaskSummary task1 = - createDefaultTask() - .classificationSummary(classificationSummaryGreatServiceLevel) - .attachments(attachmentSummarySmallServiceLevel.copy()) - .buildAndStoreAsSummary(taskService); - TaskSummary task2 = - createDefaultTask() - .classificationSummary(classificationSummarySmallServiceLevel) - .attachments(attachmentSummarySmallServiceLevel.copy()) - .buildAndStoreAsSummary(taskService); - List taskIds = List.of(task1.getId(), task2.getId()); - - BulkOperationResults bulkLog = - taskService.setPlannedPropertyOfTasks(planned, taskIds); - - assertThat(bulkLog.containsErrors()).isFalse(); - List result = - taskService.createTaskQuery().idIn(task1.getId(), task2.getId()).list(); - Instant expectedDue = Instant.parse("2020-05-06T06:59:59.999Z"); - assertThat(result).extracting(TaskSummary::getDue).containsOnly(expectedDue); - } + defaultObjectReference = defaultTestObjectReference().build(); + + attachmentSummarySmallServiceLevel = + TaskAttachmentBuilder.newAttachment() + .classificationSummary(classificationSummarySmallServiceLevel) + .objectReference(defaultObjectReference) + .build(); + attachmentSummaryGreatServiceLevel = + TaskAttachmentBuilder.newAttachment() + .classificationSummary(classificationSummaryGreatServiceLevel) + .objectReference(defaultObjectReference) + .build(); + + defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(defaultWorkbasketSummary.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_SetPlannedOnMultipleTasks() throws Exception { + Instant planned = Instant.parse("2020-05-03T07:00:00.000Z"); + TaskSummary task1 = + createDefaultTask() + .classificationSummary(classificationSummarySmallServiceLevel) + .buildAndStoreAsSummary(taskService); + TaskSummary task2 = + createDefaultTask() + .classificationSummary(classificationSummarySmallServiceLevel) + .attachments(attachmentSummaryGreatServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + TaskSummary task3 = + createDefaultTask() + .classificationSummary(classificationSummaryGreatServiceLevel) + .attachments(attachmentSummarySmallServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + List taskIds = List.of(task1.getId(), task2.getId(), task3.getId()); + + BulkOperationResults bulkLog = + taskService.setPlannedPropertyOfTasks(planned, taskIds); + + assertThat(bulkLog.containsErrors()).isFalse(); + List result = + taskService.createTaskQuery().idIn(task1.getId(), task2.getId(), task3.getId()).list(); + assertThat(result).extracting(TaskSummary::getPlanned).containsOnly(planned); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ChangeDue_When_SettingPlannedAndClassificationHasSmallerServiceLevel() + throws Exception { + Instant planned = Instant.parse("2020-05-04T07:00:00.000Z"); + TaskSummary task1 = + createDefaultTask() + .classificationSummary(classificationSummarySmallServiceLevel) + .attachments(attachmentSummaryGreatServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + TaskSummary task2 = + createDefaultTask() + .classificationSummary(classificationSummarySmallServiceLevel) + .buildAndStoreAsSummary(taskService); + List taskIds = List.of(task1.getId(), task2.getId()); - @WithAccessId(user = "user-1-1") - @Test - void should_ChangeDue_When_SettingPlannedAndUsingDifferentServiceLevels() throws Exception { - Instant planned = Instant.parse("2020-05-04T07:00:00.000Z"); - TaskSummary task1 = - createDefaultTask() - .classificationSummary(classificationSummaryGreatServiceLevel) - .attachments(attachmentSummarySmallServiceLevel.copy()) - .buildAndStoreAsSummary(taskService); - TaskSummary task2 = - createDefaultTask() - .classificationSummary(classificationSummarySmallServiceLevel) - .attachments(attachmentSummaryGreatServiceLevel.copy()) - .buildAndStoreAsSummary(taskService); - TaskSummary task3 = - createDefaultTask() - .classificationSummary(classificationSummaryGreatServiceLevel) - .attachments(attachmentSummaryGreatServiceLevel.copy()) - .buildAndStoreAsSummary(taskService); - List taskIds = List.of(task1.getId(), task2.getId(), task3.getId()); - - BulkOperationResults bulkLog = - taskService.setPlannedPropertyOfTasks(planned, taskIds); - - assertThat(bulkLog.containsErrors()).isFalse(); - List result = - taskService.createTaskQuery().idIn(task1.getId(), task2.getId(), task3.getId()).list(); - Instant expectedDueSmallServiceLevel = Instant.parse("2020-05-06T06:59:59.999Z"); - Instant expectedDueGreatServiceLevel = Instant.parse("2020-05-13T06:59:59.999Z"); - assertThat(result) - .extracting(TaskSummary::getDue) - .containsOnly(expectedDueSmallServiceLevel, expectedDueGreatServiceLevel); + BulkOperationResults bulkLog = + taskService.setPlannedPropertyOfTasks(planned, taskIds); + + assertThat(bulkLog.containsErrors()).isFalse(); + List result = + taskService.createTaskQuery().idIn(task1.getId(), task2.getId()).list(); + Instant expectedDue = Instant.parse("2020-05-06T06:59:59.999Z"); + assertThat(result).extracting(TaskSummary::getDue).containsOnly(expectedDue); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ChangeDue_When_SettingPlannedAndAttachmentHasSmallerOrEqualServiceLevel() + throws Exception { + Instant planned = Instant.parse("2020-05-04T07:00:00.000Z"); + TaskSummary task1 = + createDefaultTask() + .classificationSummary(classificationSummaryGreatServiceLevel) + .attachments(attachmentSummarySmallServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + TaskSummary task2 = + createDefaultTask() + .classificationSummary(classificationSummarySmallServiceLevel) + .attachments(attachmentSummarySmallServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + List taskIds = List.of(task1.getId(), task2.getId()); + + BulkOperationResults bulkLog = + taskService.setPlannedPropertyOfTasks(planned, taskIds); + + assertThat(bulkLog.containsErrors()).isFalse(); + List result = + taskService.createTaskQuery().idIn(task1.getId(), task2.getId()).list(); + Instant expectedDue = Instant.parse("2020-05-06T06:59:59.999Z"); + assertThat(result).extracting(TaskSummary::getDue).containsOnly(expectedDue); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ChangeDue_When_SettingPlannedAndUsingDifferentServiceLevels() throws Exception { + Instant planned = Instant.parse("2020-05-04T07:00:00.000Z"); + TaskSummary task1 = + createDefaultTask() + .classificationSummary(classificationSummaryGreatServiceLevel) + .attachments(attachmentSummarySmallServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + TaskSummary task2 = + createDefaultTask() + .classificationSummary(classificationSummarySmallServiceLevel) + .attachments(attachmentSummaryGreatServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + TaskSummary task3 = + createDefaultTask() + .classificationSummary(classificationSummaryGreatServiceLevel) + .attachments(attachmentSummaryGreatServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + List taskIds = List.of(task1.getId(), task2.getId(), task3.getId()); + + BulkOperationResults bulkLog = + taskService.setPlannedPropertyOfTasks(planned, taskIds); + + assertThat(bulkLog.containsErrors()).isFalse(); + List result = + taskService.createTaskQuery().idIn(task1.getId(), task2.getId(), task3.getId()).list(); + Instant expectedDueSmallServiceLevel = Instant.parse("2020-05-06T06:59:59.999Z"); + Instant expectedDueGreatServiceLevel = Instant.parse("2020-05-13T06:59:59.999Z"); + assertThat(result) + .extracting(TaskSummary::getDue) + .containsOnly(expectedDueSmallServiceLevel, expectedDueGreatServiceLevel); + } + + private TaskBuilder createDefaultTask() { + return (TaskBuilder.newTask() + .workbasketSummary(defaultWorkbasketSummary) + .primaryObjRef(defaultObjectReference)); + } } - private TaskBuilder createDefaultTask() { - return (TaskBuilder.newTask() - .workbasketSummary(defaultWorkbasketSummary) - .primaryObjRef(defaultObjectReference)); + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class WithWorkingDaysCalculation implements TaskanaConfigurationModifier { + + @TaskanaInject TaskanaEngine taskanaEngine; + @TaskanaInject TaskService taskService; + @TaskanaInject WorkbasketService workbasketService; + @TaskanaInject ClassificationService classificationService; + ClassificationSummary classificationSummarySmallServiceLevel; + ClassificationSummary classificationSummaryGreatServiceLevel; + Attachment attachmentSummarySmallServiceLevel; + Attachment attachmentSummaryGreatServiceLevel; + WorkbasketSummary defaultWorkbasketSummary; + ObjectReference defaultObjectReference; + WorkingTimeCalculator converter; + + @Override + public Builder modify(Builder builder) { + return builder.useWorkingTimeCalculation(false); + } + + @WithAccessId(user = "businessadmin") + @BeforeAll + void setup() throws Exception { + classificationSummarySmallServiceLevel = + defaultTestClassification() + .serviceLevel(SMALL_CLASSIFICATION_SERVICE_LEVEL) + .buildAndStoreAsSummary(classificationService); + classificationSummaryGreatServiceLevel = + defaultTestClassification() + .serviceLevel(GREAT_CLASSIFICATION_SERVICE_LEVEL) + .buildAndStoreAsSummary(classificationService); + + defaultObjectReference = defaultTestObjectReference().build(); + + attachmentSummarySmallServiceLevel = + TaskAttachmentBuilder.newAttachment() + .classificationSummary(classificationSummarySmallServiceLevel) + .objectReference(defaultObjectReference) + .build(); + attachmentSummaryGreatServiceLevel = + TaskAttachmentBuilder.newAttachment() + .classificationSummary(classificationSummaryGreatServiceLevel) + .objectReference(defaultObjectReference) + .build(); + + defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(defaultWorkbasketSummary.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + converter = taskanaEngine.getWorkingTimeCalculator(); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_SetPlannedOnMultipleTasks() throws Exception { + Instant planned = Instant.parse("2020-05-03T07:00:00.000Z"); + TaskSummary task1 = + createDefaultTask() + .classificationSummary(classificationSummarySmallServiceLevel) + .buildAndStoreAsSummary(taskService); + TaskSummary task2 = + createDefaultTask() + .classificationSummary(classificationSummarySmallServiceLevel) + .attachments(attachmentSummaryGreatServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + TaskSummary task3 = + createDefaultTask() + .classificationSummary(classificationSummaryGreatServiceLevel) + .attachments(attachmentSummarySmallServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + List taskIds = List.of(task1.getId(), task2.getId(), task3.getId()); + + BulkOperationResults bulkLog = + taskService.setPlannedPropertyOfTasks(planned, taskIds); + + assertThat(bulkLog.containsErrors()).isFalse(); + List result = + taskService.createTaskQuery().idIn(task1.getId(), task2.getId(), task3.getId()).list(); + assertThat(result).extracting(TaskSummary::getPlanned).containsOnly(planned); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ChangeDue_When_SettingPlannedAndClassificationHasSmallerServiceLevel() + throws Exception { + Instant planned = Instant.parse("2020-05-03T07:00:00.000Z"); + TaskSummary task1 = + createDefaultTask() + .classificationSummary(classificationSummarySmallServiceLevel) + .attachments(attachmentSummaryGreatServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + TaskSummary task2 = + createDefaultTask() + .classificationSummary(classificationSummarySmallServiceLevel) + .buildAndStoreAsSummary(taskService); + List taskIds = List.of(task1.getId(), task2.getId()); + + BulkOperationResults bulkLog = + taskService.setPlannedPropertyOfTasks(planned, taskIds); + + assertThat(bulkLog.containsErrors()).isFalse(); + List result = + taskService.createTaskQuery().idIn(task1.getId(), task2.getId()).list(); + assertThat(result) + .extracting(TaskSummary::getDue) + .containsOnly( + converter.addWorkingTime( + planned, Duration.parse(SMALL_CLASSIFICATION_SERVICE_LEVEL))); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ChangeDue_When_SettingPlannedAndAttachmentHasSmallerOrEqualServiceLevel() + throws Exception { + Instant planned = Instant.parse("2020-05-03T07:00:00.000Z"); + TaskSummary task1 = + createDefaultTask() + .classificationSummary(classificationSummaryGreatServiceLevel) + .attachments(attachmentSummarySmallServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + TaskSummary task2 = + createDefaultTask() + .classificationSummary(classificationSummarySmallServiceLevel) + .attachments(attachmentSummarySmallServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + List taskIds = List.of(task1.getId(), task2.getId()); + + BulkOperationResults bulkLog = + taskService.setPlannedPropertyOfTasks(planned, taskIds); + + assertThat(bulkLog.containsErrors()).isFalse(); + List result = + taskService.createTaskQuery().idIn(task1.getId(), task2.getId()).list(); + assertThat(result) + .extracting(TaskSummary::getDue) + .containsOnly( + converter.addWorkingTime( + planned, Duration.parse(SMALL_CLASSIFICATION_SERVICE_LEVEL))); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ChangeDue_When_SettingPlannedAndUsingDifferentServiceLevels() throws Exception { + Instant planned = Instant.parse("2020-05-03T07:00:00.000Z"); + TaskSummary task1 = + createDefaultTask() + .classificationSummary(classificationSummaryGreatServiceLevel) + .attachments(attachmentSummarySmallServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + TaskSummary task2 = + createDefaultTask() + .classificationSummary(classificationSummarySmallServiceLevel) + .attachments(attachmentSummaryGreatServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + TaskSummary task3 = + createDefaultTask() + .classificationSummary(classificationSummaryGreatServiceLevel) + .attachments(attachmentSummaryGreatServiceLevel.copy()) + .buildAndStoreAsSummary(taskService); + List taskIds = List.of(task1.getId(), task2.getId(), task3.getId()); + + BulkOperationResults bulkLog = + taskService.setPlannedPropertyOfTasks(planned, taskIds); + + assertThat(bulkLog.containsErrors()).isFalse(); + List result = + taskService.createTaskQuery().idIn(task1.getId(), task2.getId(), task3.getId()).list(); + assertThat(result) + .extracting(TaskSummary::getDue) + .containsOnly( + converter.addWorkingTime(planned, Duration.parse(SMALL_CLASSIFICATION_SERVICE_LEVEL)), + converter.addWorkingTime( + planned, Duration.parse(GREAT_CLASSIFICATION_SERVICE_LEVEL))); + } + + private TaskBuilder createDefaultTask() { + return (TaskBuilder.newTask() + .workbasketSummary(defaultWorkbasketSummary) + .primaryObjRef(defaultObjectReference)); + } } } diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/claim/ClaimTaskAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/claim/ClaimTaskAccTest.java index b176d41fb6..dea2c18200 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/claim/ClaimTaskAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/claim/ClaimTaskAccTest.java @@ -8,15 +8,21 @@ import static pro.taskana.testapi.DefaultTestEntities.defaultTestWorkbasket; import java.time.Instant; +import java.util.List; +import java.util.stream.Stream; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.junit.jupiter.api.function.ThrowingConsumer; import pro.taskana.TaskanaConfiguration; import pro.taskana.classification.api.ClassificationService; import pro.taskana.classification.api.models.ClassificationSummary; +import pro.taskana.common.internal.util.Triplet; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.exceptions.InvalidOwnerException; @@ -37,7 +43,7 @@ import pro.taskana.workbasket.api.models.WorkbasketSummary; @TaskanaIntegrationTest -class ClaimTaskAccTest { +class ClaimTaskAccTest implements TaskanaConfigurationModifier { @TaskanaInject TaskService taskService; @TaskanaInject ClassificationService classificationService; @TaskanaInject WorkbasketService workbasketService; @@ -46,6 +52,14 @@ class ClaimTaskAccTest { ClassificationSummary defaultClassificationSummary; WorkbasketSummary defaultWorkbasketSummary; ObjectReference defaultObjectReference; + WorkbasketSummary wbWithoutEditTasks; + WorkbasketSummary wbWithoutReadTasks; + WorkbasketSummary wbWithoutRead; + + @Override + public TaskanaConfiguration.Builder modify(TaskanaConfiguration.Builder builder) { + return builder.addAdditionalUserInfo(true); + } @WithAccessId(user = "businessadmin") @BeforeAll @@ -53,12 +67,44 @@ void setup() throws Exception { defaultClassificationSummary = defaultTestClassification().buildAndStoreAsSummary(classificationService); defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutEditTasks = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutReadTasks = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutRead = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); WorkbasketAccessItemBuilder.newWorkbasketAccessItem() .workbasketId(defaultWorkbasketSummary.getId()) .accessId("user-1-2") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutEditTasks.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutReadTasks.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutRead.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -239,13 +285,58 @@ void should_ForceClaimTask_When_InReviewByAnotherUser() throws Exception { assertThat(claimedTask.getOwner()).isEqualTo("user-1-2"); } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_ThrowException_When_ForceClaimingTaskWithMissingPermission() + throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testClaimTask = + t -> { + String anyUserName = "TestUser28"; + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.CLAIMED) + .owner(anyUserName) + .buildAndStore(taskService, "admin"); + + ThrowingCallable call = () -> taskService.forceClaim(task.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testClaimTask); + } + @WithAccessId(user = "user-taskrouter") @Test - void should_ThrowNotAuthorizedException_When_UserHasNoReadPermissionAndTaskIsReady() + void should_ThrowNotAuthorizedException_When_UserHasNoReadPermissionAndTaskIsReadyForReview() throws Exception { Task task = TaskBuilder.newTask() - .state(TaskState.READY) + .state(TaskState.READY_FOR_REVIEW) .classificationSummary(defaultClassificationSummary) .workbasketSummary(defaultWorkbasketSummary) .primaryObjRef(defaultObjectReference) @@ -257,35 +348,60 @@ void should_ThrowNotAuthorizedException_When_UserHasNoReadPermissionAndTaskIsRea catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); assertThat(e.getCurrentUserId()).isEqualTo("user-taskrouter"); assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasketSummary.getId()); - assertThat(e.getRequiredPermissions()).containsExactlyInAnyOrder(WorkbasketPermission.READ); + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } + + @WithAccessId(user = "user-1-2") + @Test + void should_CancelClaimTask_When_TaskIsClaimed() throws Exception { + Task claimedTask = + TaskBuilder.newTask() + .state(TaskState.CLAIMED) + .claimed(Instant.now()) + .owner("user-1-2") + .ownerLongName("Long Name") + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(defaultWorkbasketSummary) + .primaryObjRef(defaultObjectReference) + .buildAndStore(taskService); - ; + Task unclaimedTask = taskService.cancelClaim(claimedTask.getId()); + + assertThat(unclaimedTask).isNotNull(); + assertThat(unclaimedTask.getState()).isEqualTo(TaskState.READY); + assertThat(unclaimedTask.getClaimed()).isNull(); + assertThat(unclaimedTask.isRead()).isTrue(); + assertThat(unclaimedTask.getOwner()).isNull(); + assertThat(unclaimedTask.getOwnerLongName()).isNull(); } - @WithAccessId(user = "user-taskrouter") + @WithAccessId(user = "user-1-2") @Test - void should_ThrowNotAuthorizedException_When_UserHasNoReadPermissionAndTaskIsReadyForReview() - throws Exception { - Task task = + void should_KeepOwnerAndOwnerLongName_When_CancelClaimWithKeepOwner() throws Exception { + Task claimedTask = TaskBuilder.newTask() - .state(TaskState.READY_FOR_REVIEW) + .state(TaskState.CLAIMED) + .claimed(Instant.now()) + .owner("user-1-2") .classificationSummary(defaultClassificationSummary) .workbasketSummary(defaultWorkbasketSummary) .primaryObjRef(defaultObjectReference) - .buildAndStore(taskService, "user-1-2"); + .buildAndStore(taskService); - ThrowingCallable call = () -> taskService.claim(task.getId()); + Task unclaimedTask = taskService.cancelClaim(claimedTask.getId(), true); - NotAuthorizedOnWorkbasketException e = - catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); - assertThat(e.getCurrentUserId()).isEqualTo("user-taskrouter"); - assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasketSummary.getId()); - assertThat(e.getRequiredPermissions()).containsExactlyInAnyOrder(WorkbasketPermission.READ); + assertThat(unclaimedTask).isNotNull(); + assertThat(unclaimedTask.getState()).isEqualTo(TaskState.READY); + assertThat(unclaimedTask.getClaimed()).isNull(); + assertThat(unclaimedTask.isRead()).isTrue(); + assertThat(unclaimedTask.getOwner()).isEqualTo("user-1-2"); + assertThat(unclaimedTask.getOwnerLongName()).isEqualTo("Long name of user-1-2"); } @WithAccessId(user = "user-1-2") @Test - void should_CancelClaimTask_When_TaskIsClaimed() throws Exception { + void should_KeepOwnerAndOwnerLongName_When_ForceCancelClaimWithKeepOwner() throws Exception { Task claimedTask = TaskBuilder.newTask() .state(TaskState.CLAIMED) @@ -296,13 +412,14 @@ void should_CancelClaimTask_When_TaskIsClaimed() throws Exception { .primaryObjRef(defaultObjectReference) .buildAndStore(taskService); - Task unclaimedTask = taskService.cancelClaim(claimedTask.getId()); + Task unclaimedTask = taskService.forceCancelClaim(claimedTask.getId(), true); assertThat(unclaimedTask).isNotNull(); assertThat(unclaimedTask.getState()).isEqualTo(TaskState.READY); assertThat(unclaimedTask.getClaimed()).isNull(); assertThat(unclaimedTask.isRead()).isTrue(); - assertThat(unclaimedTask.getOwner()).isNull(); + assertThat(unclaimedTask.getOwner()).isEqualTo("user-1-2"); + assertThat(unclaimedTask.getOwnerLongName()).isEqualTo("Long name of user-1-2"); } @WithAccessId(user = "user-1-2") @@ -367,6 +484,51 @@ void should_ThrowException_When_CancelClaimingATaskInReviewByAnotherUser() throw assertThat(e.getTaskId()).isEqualTo(claimedTask.getId()); } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_ThrowException_When_CancelClaimingTaskWithMissingPermission() + throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testCancelClaimTask = + t -> { + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.CLAIMED) + .owner("user-1-2") + .buildAndStore(taskService, "admin"); + + task.setNote("Test Note"); + ThrowingCallable call = () -> taskService.cancelClaim(task.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testCancelClaimTask); + } + @WithAccessId(user = "user-1-2") @Test void should_ForceCancelClaim_When_TaskClaimedByAnotherUser() throws Exception { @@ -411,6 +573,51 @@ void should_ForceCancelClaimTask_When_InReviewByAnotherUser() throws Exception { assertThat(unclaimedTask.getOwner()).isNull(); } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_ThrowException_When_ForceCancelClaimingTaskWithMissingPermission() + throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testCancelClaimTask = + t -> { + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.CLAIMED) + .owner("user-1-2") + .buildAndStore(taskService, "admin"); + + task.setNote("Test Note"); + ThrowingCallable call = () -> taskService.forceCancelClaim(task.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testCancelClaimTask); + } + @WithAccessId(user = "user-1-2") @Test void should_ClaimTask_When_OwnerOfReadyForReviewTaskIsSet() throws Exception { @@ -449,6 +656,51 @@ void should_ClaimTask_When_OwnerOfReadyTaskIsSet() throws Exception { assertThat(taskClaimed.getOwner()).isEqualTo("user-1-2"); } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_ThrowException_When_ClaimingTaskWithMissingPermission() + throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testClaimTask = + t -> { + String anyUserName = "TestUser28"; + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.READY) + .owner(anyUserName) + .buildAndStore(taskService, "admin"); + + ThrowingCallable call = () -> taskService.claim(task.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testClaimTask); + } + @Nested @TestInstance(Lifecycle.PER_CLASS) class WithAdditionalUserInfoEnabled implements TaskanaConfigurationModifier { diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/claim/SetOwnerAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/claim/SetOwnerAccTest.java index 9a3a16bc41..818e334f6b 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/claim/SetOwnerAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/claim/SetOwnerAccTest.java @@ -56,6 +56,8 @@ void setup() throws Exception { .accessId("user-1-2") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -117,7 +119,8 @@ void should_ThrowException_When_SetOwnerViaUpdateTaskIsNotAuthorizedOnWorkbasket catchThrowableOfType(call2, NotAuthorizedOnWorkbasketException.class); assertThat(e2.getWorkbasketId()).isEqualTo(defaultWorkbasketSummary.getId()); assertThat(e2.getCurrentUserId()).isEqualTo("user-1-1"); - assertThat(e2.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); + assertThat(e2.getRequiredPermissions()) + .containsExactly(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); } @WithAccessId(user = "user-1-2") diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/complete/CancelTaskAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/complete/CancelTaskAccTest.java index 99ba22a414..30e8780a0f 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/complete/CancelTaskAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/complete/CancelTaskAccTest.java @@ -6,18 +6,23 @@ import static pro.taskana.testapi.DefaultTestEntities.defaultTestObjectReference; import static pro.taskana.testapi.DefaultTestEntities.defaultTestWorkbasket; +import acceptance.task.complete.CompleteTaskWithSpiAccTest.SetCustomAttributeToEndstate; import java.util.List; import java.util.stream.Stream; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.function.ThrowingConsumer; import pro.taskana.classification.api.ClassificationService; import pro.taskana.classification.api.models.ClassificationSummary; import pro.taskana.common.internal.util.Triplet; +import pro.taskana.spi.task.api.TaskEndstatePreprocessor; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.exceptions.InvalidTaskStateException; @@ -26,6 +31,7 @@ import pro.taskana.testapi.DefaultTestEntities; import pro.taskana.testapi.TaskanaInject; import pro.taskana.testapi.TaskanaIntegrationTest; +import pro.taskana.testapi.WithServiceProvider; import pro.taskana.testapi.builder.TaskBuilder; import pro.taskana.testapi.builder.WorkbasketAccessItemBuilder; import pro.taskana.testapi.security.WithAccessId; @@ -58,6 +64,7 @@ void setup() throws Exception { .accessId("user-1-2") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -130,7 +137,8 @@ void should_ThrowException_When_UserNotAuthorized() throws Exception { NotAuthorizedOnWorkbasketException e = catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); - assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); + assertThat(e.getRequiredPermissions()) + .containsExactly(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); assertThat(e.getCurrentUserId()).isEqualTo("user-taskrouter"); assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasketSummary.getId()); } @@ -180,4 +188,33 @@ Stream should_ThrowException_When_CancellingATaskInEndState() throw }; return DynamicTest.stream(list.iterator(), Triplet::getLeft, testCancelTask); } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + @WithServiceProvider( + serviceProviderInterface = TaskEndstatePreprocessor.class, + serviceProviders = SetCustomAttributeToEndstate.class) + class ServiceProviderSetsCustomAttributeToCancelled { + + @TaskanaInject TaskService taskService; + + @WithAccessId(user = "user-1-2") + @Test + void should_SetCustomAttribute_When_UserCancelsTask() throws Exception { + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(defaultWorkbasketSummary) + .state(TaskState.CLAIMED) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .buildAndStore(taskService); + Task processedTask = taskService.cancelTask(task.getId()); + assertThat(processedTask.getState()).isEqualTo(TaskState.CANCELLED); + assertThat(processedTask.getCustomAttributeMap()) + .containsEntry( + "camunda:attribute1", + "{\"valueInfo\":{\"objectTypeName\":\"java.lang.String\"}," + + "\"type\":\"String\",\"value\":\"CANCELLED\"}"); + } + } } diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskAccTest.java index 77065f6045..d02b569440 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskAccTest.java @@ -11,10 +11,14 @@ import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.List; +import java.util.stream.Stream; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.TestTemplate; +import org.junit.jupiter.api.function.ThrowingConsumer; import pro.taskana.TaskanaConfiguration; import pro.taskana.classification.api.ClassificationService; import pro.taskana.classification.api.models.ClassificationSummary; @@ -24,6 +28,7 @@ import pro.taskana.common.api.exceptions.TaskanaException; import pro.taskana.common.api.security.CurrentUserContext; import pro.taskana.common.internal.util.EnumUtil; +import pro.taskana.common.internal.util.Triplet; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.exceptions.InvalidOwnerException; @@ -58,6 +63,9 @@ class CompleteTaskAccTest implements TaskanaConfigurationModifier { ClassificationSummary defaultClassificationSummary; WorkbasketSummary defaultWorkbasketSummary; ObjectReference defaultObjectReference; + WorkbasketSummary wbWithoutEditTasks; + WorkbasketSummary wbWithoutReadTasks; + WorkbasketSummary wbWithoutRead; @Override public TaskanaConfiguration.Builder modify(TaskanaConfiguration.Builder builder) { @@ -71,11 +79,43 @@ void setup(ClassificationService classificationService, WorkbasketService workba defaultClassificationSummary = defaultTestClassification().buildAndStoreAsSummary(classificationService); defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutEditTasks = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutReadTasks = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutRead = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); WorkbasketAccessItemBuilder.newWorkbasketAccessItem() .workbasketId(defaultWorkbasketSummary.getId()) .accessId("user-1-1") .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutEditTasks.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutReadTasks.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutRead.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -192,6 +232,52 @@ void should_ForceCompleteTask_When_TaskIsReadyForReview() throws Exception { assertTaskIsComplete(before, completedTask); } + @WithAccessId(user = "user-1-1") + @TestFactory + Stream should_ThrowException_When_ForceCompleteTaskWithMissingPermission() + throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testCompleteTask = + t -> { + String anyUserName = "TestUser28"; + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.READY_FOR_REVIEW) + .owner(anyUserName) + .buildAndStore(taskService, "admin"); + + ThrowingCallable call = () -> taskService.forceCompleteTask(task.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-1"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testCompleteTask); + } + @WithAccessId(user = "user-1-1") @Test void should_ThrowException_When_CompletingNonExistingTask() { @@ -217,7 +303,8 @@ void should_ThrowException_When_UserIsNotAuthorizedOnTask() throws Exception { assertThat(e.getCurrentUserId()).isEqualTo(currentUserContext.getUserid()); WorkbasketSummary workbasket = claimedTask.getWorkbasketSummary(); assertThat(e.getWorkbasketId()).isEqualTo(workbasket.getId()); - assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); + assertThat(e.getRequiredPermissions()) + .containsExactly(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); } @WithAccessId(user = "user-1-1") @@ -686,6 +773,50 @@ void should_OnlyClaimTasksWhichAreNotClaimed_When_BulkForceCompletingTasks() thr assertTaskIsComplete(beforeBulkComplete, completedTask2); } + @WithAccessId(user = "user-1-1") + @TestFactory + Stream should_ThrowException_When_CompleteTaskWithMissingPermission() + throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testCompleteTask = + t -> { + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.CLAIMED) + .claimed(Instant.now()) + .owner("user-1-1") + .buildAndStore(taskService, "admin"); + + ThrowingCallable call = () -> taskService.completeTask(task.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactly(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-1"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testCompleteTask); + } + private void assertTaskIsComplete(Instant before, Task completedTask) { assertThat(completedTask).isNotNull(); assertThat(completedTask.getState()).isEqualTo(TaskState.COMPLETED); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskWithSpiAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskWithSpiAccTest.java index ccba830e0e..740811c349 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskWithSpiAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/complete/CompleteTaskWithSpiAccTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; @@ -17,6 +18,7 @@ import pro.taskana.classification.api.ClassificationService; import pro.taskana.classification.api.models.ClassificationSummary; import pro.taskana.spi.task.api.ReviewRequiredProvider; +import pro.taskana.spi.task.api.TaskEndstatePreprocessor; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.models.ObjectReference; @@ -54,6 +56,8 @@ void setup(ClassificationService classificationService, WorkbasketService workba .workbasketId(defaultWorkbasketSummary.getId()) .accessId("user-1-1") .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -89,6 +93,21 @@ public boolean reviewRequired(Task task) { } } + static class SetCustomAttributeToEndstate implements TaskEndstatePreprocessor { + @Override + public Task processTaskBeforeEndstate(Task task) { + String endstate = task.getState().toString(); + task.getCustomAttributeMap() + .put( + "camunda:attribute1", + "{\"valueInfo\":{\"objectTypeName\":\"java.lang.String\"}," + + "\"type\":\"String\",\"value\":\"" + + endstate + + "\"}"); + return task; + } + } + @Nested @TestInstance(Lifecycle.PER_CLASS) @WithServiceProvider( @@ -169,4 +188,27 @@ Stream should_RequestReview_When_UserTriesToCompleteTask() throws E tasks.iterator(), t -> "Try to complete " + t.getState().name() + " Task", test); } } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + @WithServiceProvider( + serviceProviderInterface = TaskEndstatePreprocessor.class, + serviceProviders = SetCustomAttributeToEndstate.class) + class ServiceProviderSetsCustomAttributeToCompleted { + + @TaskanaInject TaskService taskService; + + @WithAccessId(user = "user-1-1") + @Test + void should_SetCustomAttribute_When_UserCompletesTask() throws Exception { + Task task = createTaskClaimedByUser("user-1-1").buildAndStore(taskService); + Task processedTask = taskService.completeTask(task.getId()); + assertThat(processedTask.getState()).isEqualTo(TaskState.COMPLETED); + assertThat(processedTask.getCustomAttributeMap()) + .containsEntry( + "camunda:attribute1", + "{\"valueInfo\":{\"objectTypeName\":\"java.lang.String\"}," + + "\"type\":\"String\",\"value\":\"COMPLETED\"}"); + } + } } diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/complete/TerminateTaskAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/complete/TerminateTaskAccTest.java index c951a85e16..8895e80788 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/complete/TerminateTaskAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/complete/TerminateTaskAccTest.java @@ -5,12 +5,17 @@ import static pro.taskana.testapi.DefaultTestEntities.defaultTestClassification; import static pro.taskana.testapi.DefaultTestEntities.defaultTestWorkbasket; +import acceptance.task.complete.CompleteTaskWithSpiAccTest.SetCustomAttributeToEndstate; import java.util.List; import java.util.stream.Stream; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.function.ThrowingConsumer; import pro.taskana.classification.api.ClassificationService; @@ -19,6 +24,7 @@ import pro.taskana.common.api.exceptions.NotAuthorizedException; import pro.taskana.common.api.security.CurrentUserContext; import pro.taskana.common.internal.util.Triplet; +import pro.taskana.spi.task.api.TaskEndstatePreprocessor; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.exceptions.InvalidTaskStateException; @@ -26,6 +32,7 @@ import pro.taskana.testapi.DefaultTestEntities; import pro.taskana.testapi.TaskanaInject; import pro.taskana.testapi.TaskanaIntegrationTest; +import pro.taskana.testapi.WithServiceProvider; import pro.taskana.testapi.builder.TaskBuilder; import pro.taskana.testapi.builder.WorkbasketAccessItemBuilder; import pro.taskana.testapi.security.WithAccessId; @@ -157,4 +164,33 @@ Stream should_ThrowException_When_TerminateTaskInEndState() throws return DynamicTest.stream(testValues.iterator(), Triplet::getLeft, test); } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + @WithServiceProvider( + serviceProviderInterface = TaskEndstatePreprocessor.class, + serviceProviders = SetCustomAttributeToEndstate.class) + class ServiceProviderSetsCustomAttributeToTerminated { + + @TaskanaInject TaskService taskService; + + @WithAccessId(user = "admin") + @Test + void should_SetCustomAttribute_When_UserTerminatesTask() throws Exception { + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(defaultWorkbasketSummary) + .state(TaskState.READY) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .buildAndStore(taskService); + Task processedTask = taskService.terminateTask(task.getId()); + assertThat(processedTask.getState()).isEqualTo(TaskState.TERMINATED); + assertThat(processedTask.getCustomAttributeMap()) + .containsEntry( + "camunda:attribute1", + "{\"valueInfo\":{\"objectTypeName\":\"java.lang.String\"}," + + "\"type\":\"String\",\"value\":\"TERMINATED\"}"); + } + } } diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/create/CreateTaskAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/create/CreateTaskAccTest.java index 64d1548b19..cc54ccea4e 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/create/CreateTaskAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/create/CreateTaskAccTest.java @@ -85,6 +85,7 @@ void setup() throws Exception { .accessId("user-1-2") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); defaultObjectReference = defaultTestObjectReference().build(); @@ -332,12 +333,11 @@ void should_CreateTask_When_MultipleAttachmentsAreSpecified() throws Exception { Instant earlierInstant = Instant.parse("2018-01-12T00:00:00Z"); Instant laterInstant = Instant.parse("2018-01-15T00:00:00Z"); Task task = createDefaultTask(); + Attachment attachment = TaskAttachmentBuilder.newAttachment() .objectReference(defaultObjectReference) .classificationSummary(defaultClassificationSummary) - .created(Instant.now()) - .modified(Instant.now()) .received(laterInstant) .channel("E-MAIL") .build(); @@ -345,8 +345,6 @@ void should_CreateTask_When_MultipleAttachmentsAreSpecified() throws Exception { TaskAttachmentBuilder.newAttachment() .objectReference(defaultObjectReference) .classificationSummary(defaultClassificationSummary) - .created(Instant.now()) - .modified(Instant.now()) .received(earlierInstant) .channel("E-MAIL") .build(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/create/CreateTaskWithSorAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/create/CreateTaskWithSorAccTest.java index b309fe3572..263f45b4e2 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/create/CreateTaskWithSorAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/create/CreateTaskWithSorAccTest.java @@ -56,6 +56,7 @@ void setup() throws Exception { .accessId("user-1-1") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); defaultObjectReference = defaultTestObjectReference().build(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/delete/DeleteTaskAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/delete/DeleteTaskAccTest.java index 068b36f7e5..440e243e8c 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/delete/DeleteTaskAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/delete/DeleteTaskAccTest.java @@ -64,6 +64,7 @@ void setup() throws Exception { .accessId("user-1-2") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); task1 = diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/delete/DeleteTaskWithSorAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/delete/DeleteTaskWithSorAccTest.java index c7ba3c291b..e5f3e1525e 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/delete/DeleteTaskWithSorAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/delete/DeleteTaskWithSorAccTest.java @@ -56,6 +56,7 @@ void setup() throws Exception { .accessId("user-1-1") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); defaultObjectReference = defaultTestObjectReference().build(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/get/GetTaskAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/get/GetTaskAccTest.java index 674c94c1ad..3a62b94a7e 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/get/GetTaskAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/get/GetTaskAccTest.java @@ -52,8 +52,12 @@ class GetTaskAccTest { ClassificationSummary defaultClassificationSummary; WorkbasketSummary defaultWorkbasketSummary; + WorkbasketSummary wbWithoutReadTasksPerm; + WorkbasketSummary wbWithoutReadPerm; ObjectReference defaultObjectReference; Task task; + Task task2; + Task task3; Map callbackInfo; @WithAccessId(user = "admin") @@ -62,6 +66,8 @@ void setup() throws Exception { defaultClassificationSummary = defaultTestClassification().buildAndStoreAsSummary(classificationService); defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutReadTasksPerm = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutReadPerm = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); defaultObjectReference = defaultTestObjectReference().build(); callbackInfo = createSimpleCustomPropertyMap(3); @@ -70,6 +76,21 @@ void setup() throws Exception { .accessId("user-1-1") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutReadTasksPerm.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutReadPerm.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -123,6 +144,20 @@ void setup() throws Exception { .workbasketSummary(defaultWorkbasketSummary) .primaryObjRef(defaultObjectReference) .buildAndStore(taskService); + + task2 = + TaskBuilder.newTask() + .workbasketSummary(wbWithoutReadTasksPerm) + .classificationSummary(defaultClassificationSummary) + .primaryObjRef(defaultObjectReference) + .buildAndStore(taskService); + + task3 = + TaskBuilder.newTask() + .workbasketSummary(wbWithoutReadPerm) + .classificationSummary(defaultClassificationSummary) + .primaryObjRef(defaultObjectReference) + .buildAndStore(taskService); } @WithAccessId(user = "user-1-1") @@ -183,6 +218,34 @@ void should_ReturnTask_When_RequestingTaskByTaskId() throws Exception { .hasNoNullFieldsOrPropertiesExcept("ownerLongName", "completed", "groupByCount"); } + @WithAccessId(user = "user-1-1") + @Test + void should_ThrowException_When_NoReadTasksPerm() { + ThrowingCallable call = () -> taskService.getTask(task2.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + assertThat(e.getCurrentUserId()).isEqualTo("user-1-1"); + assertThat(e.getWorkbasketId()).isEqualTo(wbWithoutReadTasksPerm.getId()); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ThrowException_When_UserHasReadTasksButNoReadPerm() { + ThrowingCallable call = () -> taskService.getTask(task3.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + assertThat(e.getCurrentUserId()).isEqualTo("user-1-1"); + assertThat(e.getWorkbasketId()).isEqualTo(wbWithoutReadPerm.getId()); + } + @WithAccessId(user = "user-1-1") @Test void should_ThrowException_When_RequestedTaskByIdIsNotExisting() { diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/get/GetTaskWithSorAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/get/GetTaskWithSorAccTest.java index 340fc40296..99d2bb0d94 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/get/GetTaskWithSorAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/get/GetTaskWithSorAccTest.java @@ -45,6 +45,7 @@ void setup() throws Exception { .accessId("user-1-1") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); defaultObjectReference = defaultTestObjectReference().build(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplAccTest.java index f2514cfe78..9d7608b612 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplAccTest.java @@ -47,6 +47,7 @@ import pro.taskana.testapi.security.WithAccessId; import pro.taskana.workbasket.api.WorkbasketPermission; import pro.taskana.workbasket.api.WorkbasketService; +import pro.taskana.workbasket.api.exceptions.NotAuthorizedToQueryWorkbasketException; import pro.taskana.workbasket.api.models.WorkbasketSummary; @TaskanaIntegrationTest @@ -93,6 +94,7 @@ private void persistPermission(WorkbasketSummary workbasketSummary) throws Excep .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) .permission(WorkbasketPermission.APPEND) + .permission(WorkbasketPermission.READTASKS) .buildAndStore(workbasketService, "businessadmin"); } @@ -102,11 +104,17 @@ class PermissionsTest { WorkbasketSummary wb1; WorkbasketSummary wb2; WorkbasketSummary wbWithoutPermissions; + WorkbasketSummary wbWithoutReadTasksPerm; + WorkbasketSummary wbWithoutReadPerm; + WorkbasketSummary wbWithoutOpenPerm; TaskSummary taskSummary1; TaskSummary taskSummary2; TaskSummary taskSummary3; TaskSummary taskSummary4; TaskSummary taskSummary5; + TaskSummary taskSummary6; + TaskSummary taskSummary7; + TaskSummary taskSummary8; @WithAccessId(user = "user-1-1") @BeforeAll @@ -115,6 +123,34 @@ void setup() throws Exception { wb2 = createWorkbasketWithPermission(); wbWithoutPermissions = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService, "businessadmin"); + wbWithoutReadTasksPerm = + defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService, "businessadmin"); + wbWithoutReadPerm = + defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService, "businessadmin"); + wbWithoutOpenPerm = + defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService, "businessadmin"); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutReadTasksPerm.getId()) + .accessId(currentUserContext.getUserid()) + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService, "businessadmin"); + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutReadPerm.getId()) + .accessId(currentUserContext.getUserid()) + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService, "businessadmin"); + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutOpenPerm.getId()) + .accessId(currentUserContext.getUserid()) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService, "businessadmin"); taskSummary1 = taskInWorkbasket(wb1).buildAndStoreAsSummary(taskService); taskSummary2 = taskInWorkbasket(wb2).buildAndStoreAsSummary(taskService); @@ -124,6 +160,12 @@ void setup() throws Exception { taskInWorkbasket(wbWithoutPermissions).buildAndStoreAsSummary(taskService, "admin"); taskSummary5 = taskInWorkbasket(wbWithoutPermissions).buildAndStoreAsSummary(taskService, "admin"); + taskSummary6 = + taskInWorkbasket(wbWithoutReadTasksPerm).buildAndStoreAsSummary(taskService, "admin"); + taskSummary7 = + taskInWorkbasket(wbWithoutReadPerm).buildAndStoreAsSummary(taskService, "admin"); + taskSummary8 = + taskInWorkbasket(wbWithoutOpenPerm).buildAndStoreAsSummary(taskService, "admin"); } @WithAccessId(user = "admin") @@ -167,6 +209,66 @@ void should_OnlyReturnTasksFromCorrectWorkbaskets_When_UserHasNoPermissionToOneW .contains(taskSummary1, taskSummary2) .doesNotContain(taskSummary3, taskSummary4, taskSummary5); } + + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnEmptyList_When_WorkbasketOfTaskHasNoReadTasksPerm() { + List list = taskService.createTaskQuery().idIn(taskSummary3.getId()).list(); + + assertThat(list).isEmpty(); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ThrowException_When_QueryByWorkbasketThatHasOpenReadButNoReadTasksPermission() { + ThrowingCallable call = + () -> taskService.createTaskQuery().workbasketIdIn(wbWithoutReadTasksPerm.getId()).list(); + assertThatThrownBy(call).isInstanceOf(NotAuthorizedToQueryWorkbasketException.class); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnEmptyList_When_WorkbasketOfTaskHasReadTasksButNoReadPerm() { + List list = taskService.createTaskQuery().idIn(taskSummary7.getId()).list(); + + assertThat(list).isEmpty(); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_QueryByTaskId_When_WorkbasketHasReadAndReadTasksButNoOpenPerm() { + List list = taskService.createTaskQuery().idIn(taskSummary8.getId()).list(); + + assertThat(list).containsOnly(taskSummary8); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_OnlyReturnTaskFromWorkbasketWithoutOpenPerm_When_OthersHasNoReadOrReadTasksPerm() { + List list = + taskService + .createTaskQuery() + .idIn(taskSummary6.getId(), taskSummary7.getId(), taskSummary8.getId()) + .list(); + + assertThat(list).containsOnly(taskSummary8); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ThrowException_When_QueryByWbIdAndWorkbasketHasReadTasksButNoReadPerm() { + ThrowingCallable call = + () -> taskService.createTaskQuery().workbasketIdIn(wbWithoutReadPerm.getId()).list(); + assertThatThrownBy(call).isInstanceOf(NotAuthorizedToQueryWorkbasketException.class); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ThrowException_When_QueryByWbIdAndWorkbasketHasReadAndReadTasksButNoOpenPerm() { + ThrowingCallable call = + () -> taskService.createTaskQuery().workbasketIdIn(wbWithoutOpenPerm.getId()).list(); + assertThatThrownBy(call).isInstanceOf(NotAuthorizedToQueryWorkbasketException.class); + } } @Nested @@ -697,9 +799,7 @@ void setup() throws Exception { taskInWorkbasket(wb) .completed(Instant.parse("2020-02-01T00:00:00Z")) .buildAndStoreAsSummary(taskService); - taskInWorkbasket(wb) - .completed(null) - .buildAndStoreAsSummary(taskService); + taskInWorkbasket(wb).completed(null).buildAndStoreAsSummary(taskService); } @WithAccessId(user = "user-1-1") @@ -1714,6 +1814,7 @@ class Owner { TaskSummary taskSummary1; TaskSummary taskSummary2; TaskSummary taskSummary3; + TaskSummary taskSummary4; @WithAccessId(user = "user-1-1") @BeforeAll @@ -1722,6 +1823,7 @@ void setup() throws Exception { taskSummary1 = taskInWorkbasket(wb).owner("user-2-1").buildAndStoreAsSummary(taskService); taskSummary2 = taskInWorkbasket(wb).owner("user-1-2").buildAndStoreAsSummary(taskService); taskSummary3 = taskInWorkbasket(wb).owner("user-1-3").buildAndStoreAsSummary(taskService); + taskSummary4 = taskInWorkbasket(wb).owner(null).buildAndStoreAsSummary(taskService); } @WithAccessId(user = "user-1-1") @@ -1759,6 +1861,29 @@ void should_ApplyFilter_When_QueryingForOwnerNotLike() { assertThat(list).containsExactly(taskSummary1); } + + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnTaskWithOwnerNull_When_QueryingForOwnerIn() { + String[] nullArray = {null}; + List list = + taskService.createTaskQuery().workbasketIdIn(wb.getId()).ownerIn(nullArray).list(); + + assertThat(list).containsExactly(taskSummary4); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnTaskWithOwnerNullAndUser11_When_QueryingForOwnerIn() { + List list = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .ownerIn("user-1-2", null) + .list(); + + assertThat(list).containsExactlyInAnyOrder(taskSummary2, taskSummary4); + } } @Nested diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplGroupByAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplGroupByAccTest.java index 6c3c842ecc..34432c9cbf 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplGroupByAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/query/TaskQueryImplGroupByAccTest.java @@ -125,30 +125,6 @@ void setup() throws Exception { taskInWorkbasket(createWorkbasketWithPermission()).buildAndStore(taskService); } - private TaskBuilder taskInWorkbasket(WorkbasketSummary wb) { - return TaskBuilder.newTask() - .classificationSummary(defaultClassificationSummary) - .primaryObjRef(defaultTestObjectReference().build()) - .workbasketSummary(wb); - } - - private WorkbasketSummary createWorkbasketWithPermission() throws Exception { - WorkbasketSummary workbasketSummary = - defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService, "businessadmin"); - persistPermission(workbasketSummary); - return workbasketSummary; - } - - private void persistPermission(WorkbasketSummary workbasketSummary) throws Exception { - WorkbasketAccessItemBuilder.newWorkbasketAccessItem() - .workbasketId(workbasketSummary.getId()) - .accessId(currentUserContext.getUserid()) - .permission(WorkbasketPermission.OPEN) - .permission(WorkbasketPermission.READ) - .permission(WorkbasketPermission.APPEND) - .buildAndStore(workbasketService, "businessadmin"); - } - @WithAccessId(user = "user-1-1") @Test void should_GroupByPor_When_OrderingByName() { @@ -331,4 +307,29 @@ void should_Count_When_GroupingBySor() { .count(); assertThat(numberOfTasks).isEqualTo(1); } + + private TaskBuilder taskInWorkbasket(WorkbasketSummary wb) { + return TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .primaryObjRef(defaultTestObjectReference().build()) + .workbasketSummary(wb); + } + + private WorkbasketSummary createWorkbasketWithPermission() throws Exception { + WorkbasketSummary workbasketSummary = + defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService, "businessadmin"); + persistPermission(workbasketSummary); + return workbasketSummary; + } + + private void persistPermission(WorkbasketSummary workbasketSummary) throws Exception { + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(workbasketSummary.getId()) + .accessId(currentUserContext.getUserid()) + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService, "businessadmin"); + } } diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesAccTest.java index d66ec742ed..a5c191e95e 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesAccTest.java @@ -55,6 +55,7 @@ void setup(ClassificationService classificationService, WorkbasketService workba .workbasketId(defaultWorkbasketSummary.getId()) .accessId("user-1-1") .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -143,7 +144,8 @@ void should_ThrowException_When_UserHasNoWorkbasketPermission() throws Exception NotAuthorizedOnWorkbasketException e = catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); - assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); + assertThat(e.getRequiredPermissions()) + .containsExactly(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasketSummary.getId()); assertThat(e.getDomain()).isNull(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithAfterSpiAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithAfterSpiAccTest.java index eb1fc7757c..ffc121bea6 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithAfterSpiAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithAfterSpiAccTest.java @@ -60,6 +60,8 @@ void setup(ClassificationService classificationService, WorkbasketService workba .workbasketId(defaultWorkbasketSummary.getId()) .accessId("user-1-1") .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .permission(WorkbasketPermission.TRANSFER) .buildAndStore(workbasketService); @@ -68,6 +70,8 @@ void setup(ClassificationService classificationService, WorkbasketService workba .workbasketId(newWorkbasket.getId()) .accessId("user-1-1") .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -263,9 +267,9 @@ void should_RollbackTransaction_When_SpiThrowsAnException() throws Exception { assertThatThrownBy(call) .isInstanceOf(SystemException.class) - .getCause() // unwrap the "wrap" within "call" + .cause() // unwrap the "wrap" within "call" .hasMessage("service provider '%s' threw an exception", ExceptionThrower.class.getName()) - .getCause() // unwrap the "wrap" from the service provider manager + .cause() // unwrap the "wrap" from the service provider manager .hasMessage("I AM THE EXCEPTION THROWER (*_*)"); Task persistentTask = taskService.getTask(task.getId()); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithBeforeSpiAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithBeforeSpiAccTest.java index e244eed616..76e005e74f 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithBeforeSpiAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/requestchanges/RequestChangesWithBeforeSpiAccTest.java @@ -57,6 +57,8 @@ void setup(ClassificationService classificationService, WorkbasketService workba .workbasketId(defaultWorkbasketSummary.getId()) .accessId("user-1-1") .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .permission(WorkbasketPermission.TRANSFER) .buildAndStore(workbasketService); @@ -298,9 +300,9 @@ void should_RollbackTransaction_When_SpiThrowsAnException() throws Exception { assertThatThrownBy(call) .isInstanceOf(SystemException.class) - .getCause() // unwrap the "wrap" within "call" + .cause() // unwrap the "wrap" within "call" .hasMessage("service provider '%s' threw an exception", ExceptionThrower.class.getName()) - .getCause() // unwrap the "wrap" from the service provider manager + .cause() // unwrap the "wrap" from the service provider manager .hasMessage("I AM THE EXCEPTION THROWER (*_*)"); Task persistentTask = taskService.getTask(task.getId()); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewAccTest.java index 2b2a2cda12..cedf97ff37 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewAccTest.java @@ -55,6 +55,7 @@ void setup(ClassificationService classificationService, WorkbasketService workba .workbasketId(defaultWorkbasketSummary.getId()) .accessId("user-1-1") .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -172,7 +173,8 @@ void should_ThrowException_When_UserHasNoWorkbasketPermission() throws Exception NotAuthorizedOnWorkbasketException e = catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); - assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); + assertThat(e.getRequiredPermissions()) + .containsExactly(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasketSummary.getId()); assertThat(e.getDomain()).isNull(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithAfterSpiAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithAfterSpiAccTest.java index 3f70f5a325..9817c24e18 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithAfterSpiAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithAfterSpiAccTest.java @@ -61,6 +61,8 @@ void setup(ClassificationService classificationService, WorkbasketService workba .workbasketId(defaultWorkbasketSummary.getId()) .accessId("user-1-1") .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .permission(WorkbasketPermission.TRANSFER) .buildAndStore(workbasketService); @@ -69,6 +71,8 @@ void setup(ClassificationService classificationService, WorkbasketService workba .workbasketId(newWorkbasket.getId()) .accessId("user-1-1") .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -264,9 +268,9 @@ void should_RollbackTransaction_When_SpiThrowsAnException() throws Exception { assertThatThrownBy(call) .isInstanceOf(SystemException.class) - .getCause() // unwrap the "wrap" within "call" + .cause() // unwrap the "wrap" within "call" .hasMessage("service provider '%s' threw an exception", ExceptionThrower.class.getName()) - .getCause() // unwrap the "wrap" from the service provider manager + .cause() // unwrap the "wrap" from the service provider manager .hasMessage("I AM THE EXCEPTION THROWER (*_*)"); Task persistentTask = taskService.getTask(task.getId()); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithBeforeSpiAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithBeforeSpiAccTest.java index 234e67e34b..b6ae524eb4 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithBeforeSpiAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/requestreview/RequestReviewWithBeforeSpiAccTest.java @@ -58,6 +58,8 @@ void setup(ClassificationService classificationService, WorkbasketService workba .workbasketId(defaultWorkbasketSummary.getId()) .accessId("user-1-1") .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .permission(WorkbasketPermission.TRANSFER) .buildAndStore(workbasketService); @@ -299,9 +301,9 @@ void should_RollbackTransaction_When_SpiThrowsAnException() throws Exception { assertThatThrownBy(call) .isInstanceOf(SystemException.class) - .getCause() // unwrap the "wrap" within "call" + .cause() // unwrap the "wrap" within "call" .hasMessage("service provider '%s' threw an exception", ExceptionThrower.class.getName()) - .getCause() // unwrap the "wrap" from the service provider manager + .cause() // unwrap the "wrap" from the service provider manager .hasMessage("I AM THE EXCEPTION THROWER (*_*)"); Task persistentTask = taskService.getTask(task.getId()); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityAccTest.java index 928c2c5256..d5136e77c9 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityAccTest.java @@ -53,6 +53,8 @@ void setup() throws Exception { .accessId("user-1-1") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); defaultObjectReference = defaultTestObjectReference().build(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityWithSpiAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityWithSpiAccTest.java index ff084a9085..2cf2f6629d 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityWithSpiAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateManualPriorityWithSpiAccTest.java @@ -74,6 +74,8 @@ void setup() throws Exception { .accessId("user-1-1") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); defaultObjectReference = defaultTestObjectReference().build(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskAccTest.java index 78f1620bbf..ee6c57cec7 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskAccTest.java @@ -38,21 +38,26 @@ import pro.taskana.common.api.exceptions.ConcurrencyException; import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.internal.util.Pair; +import pro.taskana.common.internal.util.Triplet; import pro.taskana.task.api.TaskCustomField; import pro.taskana.task.api.TaskService; +import pro.taskana.task.api.TaskState; import pro.taskana.task.api.exceptions.TaskNotFoundException; import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; import pro.taskana.task.api.models.TaskSummary; import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.internal.models.TaskImpl; +import pro.taskana.testapi.DefaultTestEntities; import pro.taskana.testapi.TaskanaConfigurationModifier; import pro.taskana.testapi.TaskanaInject; import pro.taskana.testapi.TaskanaIntegrationTest; import pro.taskana.testapi.builder.ObjectReferenceBuilder; import pro.taskana.testapi.builder.TaskBuilder; +import pro.taskana.testapi.builder.UserBuilder; import pro.taskana.testapi.builder.WorkbasketAccessItemBuilder; import pro.taskana.testapi.security.WithAccessId; +import pro.taskana.user.api.UserService; import pro.taskana.workbasket.api.WorkbasketPermission; import pro.taskana.workbasket.api.WorkbasketService; import pro.taskana.workbasket.api.exceptions.NotAuthorizedOnWorkbasketException; @@ -61,12 +66,17 @@ @TaskanaIntegrationTest public class UpdateTaskAccTest { @TaskanaInject TaskService taskService; + @TaskanaInject UserService userService; + @TaskanaInject ClassificationService classificationService; @TaskanaInject WorkbasketService workbasketService; ClassificationSummary defaultClassificationSummary; WorkbasketSummary defaultWorkbasketSummary; ObjectReference defaultObjectReference; + WorkbasketSummary wbWithoutEditTasks; + WorkbasketSummary wbWithoutReadTasks; + WorkbasketSummary wbWithoutRead; @WithAccessId(user = "businessadmin") @BeforeAll @@ -76,12 +86,44 @@ void setup() throws Exception { .serviceLevel("P1D") .buildAndStoreAsSummary(classificationService); defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutEditTasks = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutReadTasks = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + wbWithoutRead = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); WorkbasketAccessItemBuilder.newWorkbasketAccessItem() .workbasketId(defaultWorkbasketSummary.getId()) .accessId("user-1-2") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutEditTasks.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutReadTasks.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.EDITTASKS) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(wbWithoutRead.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -244,7 +286,8 @@ void should_ThrowException_When_UserIsNotAuthorized() throws Exception { catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); assertThat(e.getCurrentUserId()).isEqualTo("user-taskrouter"); assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasketSummary.getId()); - assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); } @WithAccessId(user = "user-1-2") @@ -442,6 +485,42 @@ void should_UpdateNoTasks_When_UpdateTasksWithUnmatchedObjectReferenceWasCalled( assertThat(taskIds).isEmpty(); } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_UpdateNoTasksWithPor_When_UserHasMissingPermission() throws Exception { + List> list = + List.of( + Pair.of("With Missing Read Permission", wbWithoutRead), + Pair.of("With Missing ReadTasks Permission", wbWithoutReadTasks), + Pair.of("With Missing EditTasks Permission", wbWithoutEditTasks)); + ThrowingConsumer> testUpdateTask = + t -> { + ObjectReference objectReference = + ObjectReferenceBuilder.newObjectReference() + .company("00") + .system("PASystem") + .systemInstance("00") + .type("VNR") + .value("22334455") + .build(); + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getRight()) + .primaryObjRef(objectReference) + .buildAndStore(taskService, "admin"); + Map customProperties = new HashMap<>(); + customProperties.put(CUSTOM_7, "This is modifiedValue 7"); + customProperties.put(CUSTOM_14, null); + customProperties.put(CUSTOM_3, "This is modifiedValue 3"); + customProperties.put(CUSTOM_16, "This is modifiedValue 16"); + + List taskIds = taskService.updateTasks(objectReference, customProperties); + + assertThat(taskIds).isEmpty(); + }; + return DynamicTest.stream(list.iterator(), Pair::getLeft, testUpdateTask); + } + @WithAccessId(user = "user-1-2") @Test void should_UpdateTasks_When_MatchingPrimaryObjectReferenceWasChanged() throws Exception { @@ -519,6 +598,36 @@ void should_UpdateTaskCustomAttributes_When_UpdateTasksIsCalled() throws Excepti } } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_UpdateNoTasksWithTaskId_When_UserHasMissingPermission() + throws Exception { + List> list = + List.of( + Pair.of("With Missing Read Permission", wbWithoutRead), + Pair.of("With Missing ReadTasks Permission", wbWithoutReadTasks), + Pair.of("With Missing EditTasks Permission", wbWithoutEditTasks)); + ThrowingConsumer> testUpdateTask = + t -> { + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getRight()) + .primaryObjRef(defaultObjectReference) + .buildAndStore(taskService, "admin"); + Map customProperties = new HashMap<>(); + customProperties.put(CUSTOM_7, "This is modifiedValue 7"); + customProperties.put(CUSTOM_14, null); + customProperties.put(CUSTOM_3, "This is modifiedValue 3"); + customProperties.put(CUSTOM_16, "This is modifiedValue 16"); + + List taskIds = taskService.updateTasks(List.of(task.getId()), customProperties); + + assertThat(taskIds).isEmpty(); + }; + return DynamicTest.stream(list.iterator(), Pair::getLeft, testUpdateTask); + } + @WithAccessId(user = "user-1-2") @Test void should_UpdateCallbackInfo() throws Exception { @@ -556,6 +665,51 @@ void should_UpdateRetrieved_When_UpdateTaskIsCalled() throws Exception { assertThat(retrievedUpdatedTask).extracting(TaskSummary::getReceived).isEqualTo(retrievedTime); } + @WithAccessId(user = "user-1-2") + @TestFactory + Stream should_ThrowException_When_MissingOneOfThePermissions() throws Exception { + List> list = + List.of( + Triplet.of("With Missing Read Permission", wbWithoutRead, WorkbasketPermission.READ), + Triplet.of( + "With Missing ReadTasks Permission", + wbWithoutReadTasks, + WorkbasketPermission.READTASKS), + Triplet.of( + "With Missing EditTasks Permission", + wbWithoutEditTasks, + WorkbasketPermission.EDITTASKS)); + ThrowingConsumer> testUpdateTask = + t -> { + String anyUserName = "TestUser28"; + Task task = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(t.getMiddle()) + .primaryObjRef(DefaultTestEntities.defaultTestObjectReference().build()) + .state(TaskState.READY) + .owner(anyUserName) + .buildAndStore(taskService, "admin"); + + task.setNote("Test Note"); + ThrowingCallable call = () -> taskService.updateTask(task); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + if (t.getRight() != WorkbasketPermission.EDITTASKS) { + assertThat(e.getRequiredPermissions()) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, WorkbasketPermission.READTASKS); + } else { + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.EDITTASKS); + } + assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); + assertThat(e.getWorkbasketId()).isEqualTo(t.getMiddle().getId()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testUpdateTask); + } + private ObjectReferenceImpl createObjectReference( String company, String system, String systemInstance, String type, String value) { ObjectReferenceImpl objectReference = new ObjectReferenceImpl(); @@ -569,12 +723,30 @@ private ObjectReferenceImpl createObjectReference( @Nested @TestInstance(Lifecycle.PER_CLASS) - class WithEnforceServiceLevelDisabled implements TaskanaConfigurationModifier { + class WithEnforceServiceLevelDisabledAndAdditionalUserInfoEnabled + implements TaskanaConfigurationModifier { @TaskanaInject TaskService taskService; @Override public TaskanaConfiguration.Builder modify(TaskanaConfiguration.Builder builder) { - return builder.enforceServiceLevel(false); + return builder.addAdditionalUserInfo(true).enforceServiceLevel(false); + } + + @WithAccessId(user = "businessadmin") + @BeforeAll + void setup() throws Exception { + UserBuilder.newUser() + .id("user-1-2") + .firstName("Max") + .lastName("Mustermann") + .longName("Max Mustermann") + .buildAndStore(userService, "businessadmin"); + UserBuilder.newUser() + .id("user-1-1") + .firstName("Ella") + .lastName("Mustermann") + .longName("Ella Mustermann") + .buildAndStore(userService, "businessadmin"); } @WithAccessId(user = "user-1-2") @@ -596,5 +768,42 @@ void should_AllowTimestampServiceLevelMismatch_When_ConfigurationAllowsIt() thro assertThat(updatedTask.getPlanned()).isEqualTo(planned); assertThat(updatedTask.getDue()).isEqualTo(due); } + + @WithAccessId(user = "user-1-2") + @Test + void should_SetOwnerLongName_When_NotChangingOwner() throws Exception { + Task task = + TaskBuilder.newTask() + .owner("user-1-2") + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(defaultWorkbasketSummary) + .primaryObjRef(defaultObjectReference) + .buildAndStore(taskService); + + task.setNote("New Note"); + Task updatedTask = taskService.updateTask(task); + + assertThat(updatedTask.getNote()).isEqualTo("New Note"); + assertThat(updatedTask.getOwner()).isEqualTo("user-1-2"); + assertThat(updatedTask.getOwnerLongName()).isEqualTo("Max Mustermann"); + } + + @WithAccessId(user = "user-1-2") + @Test + void should_SetOwnerLongName_When_ChangingOwner() throws Exception { + Task task = + TaskBuilder.newTask() + .owner("user-1-2") + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(defaultWorkbasketSummary) + .primaryObjRef(defaultObjectReference) + .buildAndStore(taskService); + + task.setOwner("user-1-1"); + Task updatedTask = taskService.updateTask(task); + + assertThat(updatedTask.getOwner()).isEqualTo("user-1-1"); + assertThat(updatedTask.getOwnerLongName()).isEqualTo("Ella Mustermann"); + } } } diff --git a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskWithSorAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskWithSorAccTest.java index ec22b30658..78567c8ca1 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskWithSorAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/task/update/UpdateTaskWithSorAccTest.java @@ -46,6 +46,8 @@ void setup() throws Exception { .accessId("user-1-1") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) + .permission(WorkbasketPermission.EDITTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); defaultObjectReference = defaultTestObjectReference().build(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/taskcomment/create/CreateTaskCommentAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/taskcomment/create/CreateTaskCommentAccTest.java index 3e575ced23..1ac49a834f 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/taskcomment/create/CreateTaskCommentAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/taskcomment/create/CreateTaskCommentAccTest.java @@ -50,6 +50,7 @@ void setup() throws Exception { .accessId("user-1-1") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); @@ -104,7 +105,8 @@ void should_FailToCreateTaskComment_When_UserHasNoWorkbasketPermission() { catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasket.getId()); - assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); + assertThat(e.getRequiredPermissions()) + .containsExactly(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); } @WithAccessId(user = "user-1-1") diff --git a/lib/taskana-core-test/src/test/java/acceptance/taskcomment/get/GetTaskCommentAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/taskcomment/get/GetTaskCommentAccTest.java index 318598b0f6..0d04830893 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/taskcomment/get/GetTaskCommentAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/taskcomment/get/GetTaskCommentAccTest.java @@ -61,6 +61,7 @@ void setup() throws Exception { .accessId("user-1-1") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); task1 = @@ -134,7 +135,8 @@ void should_FailToReturnTaskComments_When_TaskIsNotVisible() { catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); - assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); + assertThat(e.getRequiredPermissions()) + .containsExactly(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasket.getId()); } @@ -154,7 +156,8 @@ void should_FailToReturnTaskComment_When_TaskIsNotVisible() throws Exception { catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); assertThat(e.getCurrentUserId()).isEqualTo("user-1-2"); - assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); + assertThat(e.getRequiredPermissions()) + .containsExactly(WorkbasketPermission.READ, WorkbasketPermission.READTASKS); assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasket.getId()); } diff --git a/lib/taskana-core-test/src/test/java/acceptance/taskcomment/update/UpdateTaskCommentAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/taskcomment/update/UpdateTaskCommentAccTest.java index cca3c506bb..99d02c726e 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/taskcomment/update/UpdateTaskCommentAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/taskcomment/update/UpdateTaskCommentAccTest.java @@ -53,6 +53,7 @@ void setup() throws Exception { .accessId("user-1-1") .permission(WorkbasketPermission.OPEN) .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.READTASKS) .permission(WorkbasketPermission.APPEND) .buildAndStore(workbasketService); defaultObjectReference = defaultTestObjectReference().build(); diff --git a/lib/taskana-core-test/src/test/java/acceptance/user/UserServiceAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/user/UserServiceAccTest.java index 0aab0b5b61..610eee2255 100644 --- a/lib/taskana-core-test/src/test/java/acceptance/user/UserServiceAccTest.java +++ b/lib/taskana-core-test/src/test/java/acceptance/user/UserServiceAccTest.java @@ -202,6 +202,59 @@ void should_DetermineDomains_When_WorkbasketPermissionsExistForUsers() throws Ex domains -> Set.of(workbasketDomainB.getDomain()).equals(domains), "DOMAIN_B")); } + @WithAccessId(user = "user-1-1") + @Test + void should_DetermineDomains_When_WorkbasketPermissionsExistForUsersWithPermissions() + throws Exception { + Workbasket workbasketDomainA = + defaultTestWorkbasket().buildAndStore(workbasketService, "businessadmin"); + createAccessItem( + "permissions-domaina", + workbasketDomainA, + WorkbasketPermission.READ, + WorkbasketPermission.OPEN); + Workbasket workbasketDomainB = + defaultTestWorkbasket() + .domain("DOMAIN_B") + .buildAndStore(workbasketService, "businessadmin"); + createAccessItem( + "permissions-domainb", + workbasketDomainB, + WorkbasketPermission.READ, + WorkbasketPermission.OPEN); + Set users = new HashSet<>(); + for (int i = 0; i < 6; i++) { + users.add( + randomTestUser() + .permissions(Set.of("test1", "test2", "permissions-domaina")) + .buildAndStore(userService, "businessadmin")); + } + for (int i = 0; i < 4; i++) { + users.add( + randomTestUser() + .permissions(Set.of("test1", "test2", "permissions-domainb")) + .buildAndStore(userService, "businessadmin")); + } + Set userIds = users.stream().map(User::getId).collect(Collectors.toSet()); + + List returnedUsers = userService.getUsers(userIds); + + assertThat(returnedUsers) + .extracting(User::getDomains) + .areExactly( + 6, + new Condition<>( + domains -> + Set.of(workbasketDomainA.getDomain()) + .equals(domains), "DOMAIN_A")) + .areExactly( + 4, + new Condition<>( + domains -> + Set.of(workbasketDomainB.getDomain()) + .equals(domains), "DOMAIN_B")); + } + @WithAccessId(user = "user-1-1") @Test void should_ReturnAllUsers_When_TryingToGetUsersWithIdsExistingInCaps() throws Exception { @@ -312,6 +365,20 @@ void should_InsertUserInDatabase_When_CreatingUserWithGroups() throws Exception assertThat(userToCreate).isNotSameAs(userInDatabase).isEqualTo(userInDatabase); } + @WithAccessId(user = "businessadmin") + @Test + void should_InsertUserInDatabase_When_CreatingUserWithPermissions() throws Exception { + User userToCreate = userService.newUser(); + userToCreate.setId("anton4"); + userToCreate.setFirstName("Anton"); + userToCreate.setLastName("Miller"); + userToCreate.setPermissions(Set.of("perm1", "perm2")); + userService.createUser(userToCreate); + + User userInDatabase = userService.getUser(userToCreate.getId()); + assertThat(userToCreate).isNotSameAs(userInDatabase).isEqualTo(userInDatabase); + } + @WithAccessId(user = "businessadmin") @TestFactory Stream @@ -483,12 +550,15 @@ void should_MakeAccessIdsLowerCase_When_ConfigurationPropertyIsSet() throws Exce userToCreate.setFirstName("firstName"); userToCreate.setLastName("lastName"); userToCreate.setGroups(Set.of("GROUP1-ID-WITH-CAPS", "Group2-Id-With-Caps")); + userToCreate.setPermissions(Set.of("PERMISSION1-ID-WITH-CAPS", "Permission2-Id-With-Caps")); User userInDatabase = userService.createUser(userToCreate); assertThat(userInDatabase.getId()).isEqualTo("user-id-with-caps"); assertThat(userInDatabase.getGroups()) .containsExactlyInAnyOrder("group1-id-with-caps", "group2-id-with-caps"); + assertThat(userInDatabase.getPermissions()) + .containsExactlyInAnyOrder("permission1-id-with-caps", "permission2-id-with-caps"); } } @@ -549,6 +619,36 @@ Stream should_UpdateGroups() { return DynamicTest.stream(testCases, Triplet::getLeft, test); } + @WithAccessId(user = "businessadmin") + @TestFactory + Stream should_UpdatePermissions() { + Stream, Set>> testCases = + Stream.of( + Triplet.of( + "User has no permissions before updating", Set.of(), Set.of("perm1", "perm2")), + Triplet.of("new permissions differ all", Set.of("perm1"), Set.of("perm2", "perm3")), + Triplet.of("some new permissions differ", Set.of("perm1"), Set.of("perm1", "perm2")), + Triplet.of("new permissions are all the same", Set.of("perm1"), Set.of("perm1"))); + + ThrowingConsumer, Set>> test = + t -> { + Set existingPerms = t.getMiddle(); + Set newPerms = t.getMiddle(); + User userToUpdate = randomTestUser() + .permissions(existingPerms) + .buildAndStore(userService); + + userToUpdate.setPermissions(newPerms); + userService.updateUser(userToUpdate); + + User userInDatabase = userService.getUser(userToUpdate.getId()); + assertThat(userInDatabase.getPermissions()) + .containsExactlyInAnyOrderElementsOf(newPerms); + }; + + return DynamicTest.stream(testCases, Triplet::getLeft, test); + } + @WithAccessId(user = "user-1-1") @Test void should_ThrowNotAuthorizedException_When_TryingToUpdateUserWithNoAdminRole() @@ -722,6 +822,19 @@ void should_MakeGroupIdsLowerCase_When_UpdatingUserWithUpperCaseGroups() throws .containsExactlyInAnyOrder("group1-id-with-caps", "group2-id-with-caps"); } + @WithAccessId(user = "businessadmin") + @Test + void should_MakePermissionsIdsLowerCase_When_UpdatingUserWithUpperCasePermissions() + throws Exception { + User userToUpdate = randomTestUser().buildAndStore(userService); + userToUpdate.setPermissions(Set.of("PERM1-ID-WITH-CAPS", "Permission2-Id-With-Caps")); + + User updatedUser = userService.updateUser(userToUpdate); + + assertThat(updatedUser.getPermissions()) + .containsExactlyInAnyOrder("perm1-id-with-caps", "permission2-id-with-caps"); + } + @WithAccessId(user = "businessadmin") @Test void should_ThrowInvalidArgumentException_When_TryingToUpdateUserWithFirstNameNull() { @@ -826,6 +939,22 @@ void should_DeleteGroupsFromDatabase_When_UserHadGroups() throws Exception { assertThat(userInDatabase.getGroups()).isEmpty(); } + @WithAccessId(user = "businessadmin") + @Test + void should_DeletePermissionsFromDatabase_When_UserHadPermissions() throws Exception { + User userToDelete = + randomTestUser() + .permissions(Set.of("permission1", "permission2")) + .buildAndStore(userService); + + userService.deleteUser(userToDelete.getId()); + + // verify that groups are deleted by creating a new user with the same id and check its groups + User newUserWithSameId = randomTestUser().id(userToDelete.getId()).buildAndStore(userService); + User userInDatabase = userService.getUser(newUserWithSameId.getId()); + assertThat(userInDatabase.getPermissions()).isEmpty(); + } + @WithAccessId(user = "businessadmin") @Test void should_ThrowUserNotFoundException_When_TryingToDeleteUserWithNonExistingId() { @@ -913,6 +1042,25 @@ void should_ReturnOneDomain_When_GroupHasSufficientMinimalPermissionsToAssignDom assertThat(userInDatabase.getDomains()).containsExactly(workbasket.getDomain()); } + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnOneDomain_When_PermissionHasSufficientMinimalPermissionsToAssignDomains() + throws Exception { + String permissionsId = UUID.randomUUID().toString(); + User user = + randomTestUser() + .permissions(Set.of(permissionsId)) + .buildAndStore(userService, "businessadmin"); + Workbasket workbasket = + defaultTestWorkbasket().buildAndStore(workbasketService, "businessadmin"); + createAccessItem(permissionsId, + workbasket, WorkbasketPermission.OPEN, WorkbasketPermission.READ); + + User userInDatabase = userService.getUser(user.getId()); + + assertThat(userInDatabase.getDomains()).containsExactly(workbasket.getDomain()); + } + @WithAccessId(user = "user-1-1") @Test void should_ReturnEmptyDomains_When_UserHasSufficientPermissionsWhichThenGetRevoked() @@ -961,6 +1109,29 @@ void should_ReturnEmptyDomains_When_GroupHasSufficientPermissionsAndThenGroupIsU assertThat(userInDatabase.getDomains()).isEmpty(); } + @WithAccessId(user = "businessadmin") + @Test + void should_ReturnEmptyDomains_When_GroupHasSufficientPermissionsAndThenPermissionIsUpdated() + throws Exception { + String groupId = UUID.randomUUID().toString(); + User user = randomTestUser().permissions(Set.of(groupId)).buildAndStore(userService); + Workbasket workbasket = defaultTestWorkbasket().buildAndStore(workbasketService); + createAccessItem(groupId, workbasket, WorkbasketPermission.OPEN, WorkbasketPermission.READ); + + User userInDatabase = userService.getUser(user.getId()); + + assertThat(userInDatabase.getDomains()).containsExactly(workbasket.getDomain()); + + // then user is updated and other group is assigned + + user.setPermissions(Set.of("new group")); + userService.updateUser(user); + + userInDatabase = userService.getUser(user.getId()); + + assertThat(userInDatabase.getDomains()).isEmpty(); + } + @WithAccessId(user = "user-1-1") @Test void should_ReturnMultipleDomains_When_UserHasSufficientMinimalPermissionsForMultipleDomains() @@ -1007,6 +1178,32 @@ void should_ReturnMultipleDomains_When_UserHasSufficientMinimalPermissionsForMul .containsExactlyInAnyOrder(workbasket1.getDomain(), workbasket2.getDomain()); } + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnMultipleDomains_When_UserAndPermHaveSufficientMinimalPermsForMultipleDomains() + throws Exception { + String permissionId = UUID.randomUUID().toString(); + User user = + randomTestUser() + .permissions(Set.of(permissionId)) + .buildAndStore(userService, "businessadmin"); + Workbasket workbasket1 = + defaultTestWorkbasket().buildAndStore(workbasketService, "businessadmin"); + Workbasket workbasket2 = + defaultTestWorkbasket() + .domain("DOMAIN_B") + .buildAndStore(workbasketService, "businessadmin"); + createAccessItem( + user.getId(), workbasket1, WorkbasketPermission.OPEN, WorkbasketPermission.READ); + createAccessItem( + permissionId, workbasket2, WorkbasketPermission.OPEN, WorkbasketPermission.READ); + + User userInDatabase = userService.getUser(user.getId()); + + assertThat(userInDatabase.getDomains()) + .containsExactlyInAnyOrder(workbasket1.getDomain(), workbasket2.getDomain()); + } + @Nested @TestInstance(Lifecycle.PER_CLASS) class DifferentMinimalPermissionsToAssignDomains implements TaskanaConfigurationModifier { @@ -1050,6 +1247,27 @@ void should_ReturnEmptyDomains_When_GroupHasInsufficientMinimalPermissionsToAssi assertThat(userInDatabase.getDomains()).isEmpty(); } + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnEmptyDomains_When_PermHasInsufficientMinimalPermissionsToAssignDomains() + throws Exception { + String permissionId = UUID.randomUUID().toString(); + User user = + randomTestUser() + .permissions(Set.of(permissionId)) + .buildAndStore(userService, "businessadmin"); + Workbasket workbasket = + defaultTestWorkbasket().buildAndStore(workbasketService, "businessadmin"); + createAccessItem(permissionId, + workbasket, + WorkbasketPermission.OPEN, + WorkbasketPermission.READ); + + User userInDatabase = userService.getUser(user.getId()); + + assertThat(userInDatabase.getDomains()).isEmpty(); + } + @WithAccessId(user = "user-1-1") @Test void should_ReturnOneDomain_When_UserHasSufficientMinimalPermissionsToAssignDomains() @@ -1081,6 +1299,7 @@ void should_ReturnOneDomain_When_GroupHasSufficientMinimalPermissionsToAssignDom assertThat(userInDatabase.getDomains()).containsExactly(workbasket.getDomain()); } + } @Nested @@ -1124,6 +1343,27 @@ void should_ReturnEmptyDomains_When_PropertyIsNotSetAndGroupHasPermission() thro assertThat(userInDatabase.getDomains()).isEmpty(); } + + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnEmptyDomains_When_PropertyIsNotSetAndPermission() + throws Exception { + String permissionId = UUID.randomUUID().toString(); + User user = + randomTestUser() + .permissions(Set.of(permissionId)) + .buildAndStore(userService, "businessadmin"); + Workbasket workbasket = + defaultTestWorkbasket().buildAndStore(workbasketService, "businessadmin"); + createAccessItem(permissionId, + workbasket, + WorkbasketPermission.OPEN, + WorkbasketPermission.READ); + + User userInDatabase = userService.getUser(user.getId()); + + assertThat(userInDatabase.getDomains()).isEmpty(); + } } } } diff --git a/lib/taskana-core-test/src/test/java/acceptance/workbasket/get/GetWorkbasketAccTest.java b/lib/taskana-core-test/src/test/java/acceptance/workbasket/get/GetWorkbasketAccTest.java new file mode 100644 index 0000000000..9567217993 --- /dev/null +++ b/lib/taskana-core-test/src/test/java/acceptance/workbasket/get/GetWorkbasketAccTest.java @@ -0,0 +1,204 @@ +package acceptance.workbasket.get; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowableOfType; +import static pro.taskana.testapi.DefaultTestEntities.defaultTestClassification; +import static pro.taskana.testapi.DefaultTestEntities.defaultTestObjectReference; +import static pro.taskana.workbasket.api.WorkbasketCustomField.CUSTOM_1; +import static pro.taskana.workbasket.api.WorkbasketCustomField.CUSTOM_2; +import static pro.taskana.workbasket.api.WorkbasketCustomField.CUSTOM_3; +import static pro.taskana.workbasket.api.WorkbasketCustomField.CUSTOM_4; +import static pro.taskana.workbasket.api.WorkbasketCustomField.CUSTOM_5; +import static pro.taskana.workbasket.api.WorkbasketCustomField.CUSTOM_6; +import static pro.taskana.workbasket.api.WorkbasketCustomField.CUSTOM_7; +import static pro.taskana.workbasket.api.WorkbasketCustomField.CUSTOM_8; + +import java.util.List; +import java.util.stream.Stream; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DynamicTest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.TestTemplate; +import org.junit.jupiter.api.function.ThrowingConsumer; +import pro.taskana.classification.api.ClassificationService; +import pro.taskana.classification.api.models.ClassificationSummary; +import pro.taskana.common.internal.util.Triplet; +import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.testapi.TaskanaInject; +import pro.taskana.testapi.TaskanaIntegrationTest; +import pro.taskana.testapi.builder.WorkbasketAccessItemBuilder; +import pro.taskana.testapi.builder.WorkbasketBuilder; +import pro.taskana.testapi.security.WithAccessId; +import pro.taskana.workbasket.api.WorkbasketPermission; +import pro.taskana.workbasket.api.WorkbasketService; +import pro.taskana.workbasket.api.WorkbasketType; +import pro.taskana.workbasket.api.exceptions.NotAuthorizedOnWorkbasketException; +import pro.taskana.workbasket.api.exceptions.WorkbasketNotFoundException; +import pro.taskana.workbasket.api.models.Workbasket; +import pro.taskana.workbasket.api.models.WorkbasketSummary; + +@TaskanaIntegrationTest +class GetWorkbasketAccTest { + @TaskanaInject ClassificationService classificationService; + @TaskanaInject WorkbasketService workbasketService; + ClassificationSummary defaultClassificationSummary; + WorkbasketSummary defaultWorkbasketSummary; + ObjectReference defaultObjectReference; + + @WithAccessId(user = "businessadmin") + @BeforeAll + void setup() throws Exception { + defaultClassificationSummary = + defaultTestClassification().buildAndStoreAsSummary(classificationService); + defaultWorkbasketSummary = + WorkbasketBuilder.newWorkbasket() + .domain("DOMAIN_A") + .description("PPK User 2 KSC 1") + .name("PPK User 2 KSC 1") + .key("USER-1-2") + .type(WorkbasketType.PERSONAL) + .owner("user-1-2") + .orgLevel1("versicherung") + .orgLevel2("abteilung") + .orgLevel3("projekt") + .orgLevel4("team") + .customAttribute(CUSTOM_1, "custom1") + .customAttribute(CUSTOM_2, "custom2") + .customAttribute(CUSTOM_3, "custom3") + .customAttribute(CUSTOM_4, "custom4") + .customAttribute(CUSTOM_5, "custom5") + .customAttribute(CUSTOM_6, "custom6") + .customAttribute(CUSTOM_7, "custom7") + .customAttribute(CUSTOM_8, "custom8") + .buildAndStoreAsSummary(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(defaultWorkbasketSummary.getId()) + .accessId("user-1-2") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.TRANSFER) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + + defaultObjectReference = defaultTestObjectReference().build(); + } + + @WithAccessId(user = "user-1-2") + @Test + void should_ReturnWorkbasketWithId_When_IdIsValidAndUserHasPermissions() throws Exception { + Workbasket workbasket = workbasketService.getWorkbasket(defaultWorkbasketSummary.getId()); + + assertThat(workbasket.asSummary()).isEqualTo(defaultWorkbasketSummary); + } + + @WithAccessId(user = "admin") + @WithAccessId(user = "businessadmin") + @WithAccessId(user = "taskadmin") + @TestTemplate + void should_ReturnWorkbasketById_When_NoExplicitPermissionsButUserIsInAdministrativeRole() + throws Exception { + Workbasket workbasket = workbasketService.getWorkbasket(defaultWorkbasketSummary.getId()); + + assertThat(workbasket.asSummary()).isEqualTo(defaultWorkbasketSummary); + } + + @WithAccessId(user = "user-1-1", groups = "user-1-2") + @Test + void should_ReturnWorkbasketPermissions_When_IdIsValidAndUserHasPermissions() { + List permissions = + workbasketService.getPermissionsForWorkbasket(defaultWorkbasketSummary.getId()); + + assertThat(permissions) + .containsExactlyInAnyOrder( + WorkbasketPermission.READ, + WorkbasketPermission.APPEND, + WorkbasketPermission.TRANSFER, + WorkbasketPermission.OPEN); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnNoWorkbasketPermissions_When_ProvidingAnInvalidId() { + List permissions = + workbasketService.getPermissionsForWorkbasket("WBI:invalid"); + + assertThat(permissions).isEmpty(); + } + + @WithAccessId(user = "user-1-2") + @Test + void should_ReturnWorkbasketSummary_When_IdIsValidAndSummaryIsRequested() throws Exception { + WorkbasketSummary workbasketSummary = + workbasketService.getWorkbasket(defaultWorkbasketSummary.getId()).asSummary(); + + assertThat(workbasketSummary).isEqualTo(defaultWorkbasketSummary); + } + + @Test + void should_ThrowException_When_ProvidingAnInvalidId() { + ThrowingCallable call = () -> workbasketService.getWorkbasket("INVALID_ID"); + + WorkbasketNotFoundException e = catchThrowableOfType(call, WorkbasketNotFoundException.class); + + assertThat(e.getId()).isEqualTo("INVALID_ID"); + } + + @TestFactory + Stream should_ThrowException_When_KeyOrDomainIsInvalid() { + List> list = + List.of( + Triplet.of("With Invalid Domain", "USER-1-2", "INVALID_DOMAIN"), + Triplet.of("With Invalid Key", "INVALID_ID", "DOMAIN_A"), + Triplet.of("With Invalid Key and Domain", "INAVLID_ID", "INVALID_DOMAIN")); + ThrowingConsumer> testGetWorkbasket = + t -> { + ThrowingCallable call = + () -> workbasketService.getWorkbasket(t.getMiddle(), t.getRight()); + + WorkbasketNotFoundException e = + catchThrowableOfType(call, WorkbasketNotFoundException.class); + + assertThat(e.getKey()).isEqualTo(t.getMiddle()); + assertThat(e.getDomain()).isEqualTo(t.getRight()); + }; + return DynamicTest.stream(list.iterator(), Triplet::getLeft, testGetWorkbasket); + } + + @Test + void should_ThrowException_When_TryingToGetByIdWithoutPermissions() { + ThrowingCallable call = () -> workbasketService.getWorkbasket(defaultWorkbasketSummary.getId()); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + assertThat(e.getWorkbasketId()).isEqualTo(defaultWorkbasketSummary.getId()); + assertThat(e.getCurrentUserId()).isNull(); + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); + } + + @Test + void should_ThrowException_When_TryingToGetByKeyAndDomainWithoutPermissions() { + ThrowingCallable call = () -> workbasketService.getWorkbasket("USER-1-2", "DOMAIN_A"); + + NotAuthorizedOnWorkbasketException e = + catchThrowableOfType(call, NotAuthorizedOnWorkbasketException.class); + + assertThat(e.getWorkbasketKey()).isEqualTo("USER-1-2"); + assertThat(e.getDomain()).isEqualTo("DOMAIN_A"); + assertThat(e.getCurrentUserId()).isNull(); + assertThat(e.getRequiredPermissions()).containsExactly(WorkbasketPermission.READ); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ThrowException_When_TryingToGetWithAnInvalidId() { + ThrowingCallable call = () -> workbasketService.getWorkbasket("NOT EXISTING ID"); + + WorkbasketNotFoundException e = catchThrowableOfType(call, WorkbasketNotFoundException.class); + + assertThat(e.getId()).isEqualTo("NOT EXISTING ID"); + } +} diff --git a/lib/taskana-core-test/src/test/resources/fullTaskana.properties b/lib/taskana-core-test/src/test/resources/fullTaskana.properties index a3b672bd25..6bedd867aa 100644 --- a/lib/taskana-core-test/src/test/resources/fullTaskana.properties +++ b/lib/taskana-core-test/src/test/resources/fullTaskana.properties @@ -13,6 +13,7 @@ taskana.classification.types=TASK | document taskana.classification.categories.task=EXTERNAL| manual| autoMAtic| Process taskana.classification.categories.document=EXTERNAL # working time configuration +taskana.workingTime.useWorkingTimeCalculation=false taskana.workingTime.schedule.MONDAY=09:00-18:00 taskana.workingTime.schedule.TUESDAY=09:00-18:00 taskana.workingTime.schedule.WEDNESDAY=09:00-18:00 @@ -34,21 +35,27 @@ taskana.jobs.maxRetries=4 taskana.jobs.batchSize=50 taskana.jobs.firstRunAt=2018-07-25T08:00:00Z taskana.jobs.runEvery=P2D +taskana.jobs.lockExpirationPeriod=PT7M taskana.jobs.cleanup.task.enable=false taskana.jobs.cleanup.task.minimumAge=P15D taskana.jobs.cleanup.task.allCompletedSameParentBusiness=false +taskana.jobs.cleanup.task.lockExpirationPeriod=PT4M taskana.jobs.cleanup.workbasket.enable=false +taskana.jobs.cleanup.workbasket.lockExpirationPeriod=PT3M taskana.jobs.cleanup.history.simple.enable=true taskana.jobs.cleanup.history.simple.batchSize=50 taskana.jobs.cleanup.history.simple.minimumAge=P17D taskana.jobs.cleanup.history.simple.allCompletedSameParentBusiness=false +taskana.jobs.cleanup.history.simple.lockExpirationPeriod=PT2M taskana.jobs.priority.task.enable=true taskana.jobs.priority.task.batchSize=50 taskana.jobs.priority.task.firstRunAt=2018-07-25T08:00:00Z taskana.jobs.priority.task.runEvery=P3D +taskana.jobs.priority.task.lockExpirationPeriod=PT8M taskana.jobs.refresh.user.enable=true taskana.jobs.refresh.user.firstRunAt=2018-07-25T08:00:00Z taskana.jobs.refresh.user.runEvery=P4D +taskana.jobs.refresh.user.lockExpirationPeriod=PT5M taskana.jobs.customJobs=A | B | C # user configuration taskana.user.addAdditionalUserInfo=true diff --git a/lib/taskana-core-test/src/test/resources/taskana.properties b/lib/taskana-core-test/src/test/resources/taskana.properties index 7d024174d1..18165d337c 100644 --- a/lib/taskana-core-test/src/test/resources/taskana.properties +++ b/lib/taskana-core-test/src/test/resources/taskana.properties @@ -22,11 +22,11 @@ taskana.query.includeLongName=false # enable or disable the jobscheduler at all # set it to false and no jobs are running taskana.jobs.scheduler.enabled=true -# wait time before the first job run in millis +# wait time before the first job run taskana.jobs.scheduler.initialStartDelay=100000 # sleeping time befor the next job runs taskana.jobs.scheduler.period=12 -# timeunit for the sleeping period +# timeunit for the initial start delay and the sleeping period # Possible values: MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS taskana.jobs.scheduler.periodTimeUnit=HOURS taskana.jobs.cleanup.task.enable=false diff --git a/lib/taskana-core/pom.xml b/lib/taskana-core/pom.xml index 532131b417..2f73212fed 100644 --- a/lib/taskana-core/pom.xml +++ b/lib/taskana-core/pom.xml @@ -10,7 +10,7 @@ pro.taskana taskana-lib-parent - 6.1.1-SNAPSHOT + 8.0.1-SNAPSHOT ../pom.xml @@ -60,11 +60,12 @@ org.assertj assertj-core + ${version.assertj} test org.mockito - mockito-inline + mockito-core test diff --git a/lib/taskana-core/src/main/java/pro/taskana/TaskanaConfiguration.java b/lib/taskana-core/src/main/java/pro/taskana/TaskanaConfiguration.java index a4ce66fce6..3759ba81af 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/TaskanaConfiguration.java +++ b/lib/taskana-core/src/main/java/pro/taskana/TaskanaConfiguration.java @@ -73,6 +73,7 @@ public class TaskanaConfiguration { // endregion // region working time configuration + private final boolean useWorkingTimeCalculation; private final Map> workingTimeSchedule; private final ZoneId workingTimeScheduleTimeZone; private final Set customHolidays; @@ -94,26 +95,30 @@ public class TaskanaConfiguration { private final int jobBatchSize; private final Instant jobFirstRun; private final Duration jobRunEvery; - + private final Duration jobLockExpirationPeriod; private final boolean taskCleanupJobEnabled; private final Duration taskCleanupJobMinimumAge; private final boolean taskCleanupJobAllCompletedSameParentBusiness; + private final Duration taskCleanupJobLockExpirationPeriod; private final boolean workbasketCleanupJobEnabled; + private final Duration workbasketCleanupJobLockExpirationPeriod; private final boolean simpleHistoryCleanupJobEnabled; private final int simpleHistoryCleanupJobBatchSize; private final Duration simpleHistoryCleanupJobMinimumAge; private final boolean simpleHistoryCleanupJobAllCompletedSameParentBusiness; - + private final Duration simpleHistoryCleanupJobLockExpirationPeriod; private final boolean taskUpdatePriorityJobEnabled; private final int taskUpdatePriorityJobBatchSize; private final Instant taskUpdatePriorityJobFirstRun; private final Duration taskUpdatePriorityJobRunEvery; + private final Duration taskUpdatePriorityJobLockExpirationPeriod; private final boolean userInfoRefreshJobEnabled; private final Instant userRefreshJobFirstRun; private final Duration userRefreshJobRunEvery; + private final Duration userRefreshJobLockExpirationPeriod; private final Set customJobs; // endregion @@ -153,6 +158,7 @@ private TaskanaConfiguration(Builder builder) { Collectors.toUnmodifiableMap( Entry::getKey, e -> Collections.unmodifiableList(e.getValue()))); // working time configuration + this.useWorkingTimeCalculation = builder.useWorkingTimeCalculation; this.workingTimeSchedule = builder.workingTimeSchedule.entrySet().stream() .collect( @@ -176,23 +182,32 @@ private TaskanaConfiguration(Builder builder) { this.jobBatchSize = builder.jobBatchSize; this.jobFirstRun = builder.jobFirstRun; this.jobRunEvery = builder.jobRunEvery; + this.jobLockExpirationPeriod = builder.jobLockExpirationPeriod; this.taskCleanupJobEnabled = builder.taskCleanupJobEnabled; this.taskCleanupJobMinimumAge = builder.taskCleanupJobMinimumAge; this.taskCleanupJobAllCompletedSameParentBusiness = builder.taskCleanupJobAllCompletedSameParentBusiness; + this.taskCleanupJobLockExpirationPeriod = builder.taskCleanupJobLockExpirationPeriod; this.workbasketCleanupJobEnabled = builder.workbasketCleanupJobEnabled; + this.workbasketCleanupJobLockExpirationPeriod = + builder.workbasketCleanupJobLockExpirationPeriod; this.simpleHistoryCleanupJobEnabled = builder.simpleHistoryCleanupJobEnabled; this.simpleHistoryCleanupJobBatchSize = builder.simpleHistoryCleanupJobBatchSize; this.simpleHistoryCleanupJobMinimumAge = builder.simpleHistoryCleanupJobMinimumAge; this.simpleHistoryCleanupJobAllCompletedSameParentBusiness = builder.simpleHistoryCleanupJobAllCompletedSameParentBusiness; + this.simpleHistoryCleanupJobLockExpirationPeriod = + builder.simpleHistoryCleanupJobLockExpirationPeriod; this.taskUpdatePriorityJobEnabled = builder.taskUpdatePriorityJobEnabled; this.taskUpdatePriorityJobBatchSize = builder.taskUpdatePriorityJobBatchSize; this.taskUpdatePriorityJobFirstRun = builder.taskUpdatePriorityJobFirstRun; this.taskUpdatePriorityJobRunEvery = builder.taskUpdatePriorityJobRunEvery; + this.taskUpdatePriorityJobLockExpirationPeriod = + builder.taskUpdatePriorityJobLockExpirationPeriod; this.userInfoRefreshJobEnabled = builder.userInfoRefreshJobEnabled; this.userRefreshJobFirstRun = builder.userRefreshJobFirstRun; this.userRefreshJobRunEvery = builder.userRefreshJobRunEvery; + this.userRefreshJobLockExpirationPeriod = builder.userRefreshJobLockExpirationPeriod; this.customJobs = Collections.unmodifiableSet(builder.customJobs); // user configuration this.addAdditionalUserInfo = builder.addAdditionalUserInfo; @@ -262,6 +277,10 @@ public List getClassificationTypes() { return classificationTypes; } + public boolean isUseWorkingTimeCalculation() { + return useWorkingTimeCalculation; + } + public Map> getWorkingTimeSchedule() { return workingTimeSchedule; } @@ -322,6 +341,10 @@ public Duration getJobRunEvery() { return jobRunEvery; } + public Duration getJobLockExpirationPeriod() { + return jobLockExpirationPeriod; + } + public boolean isTaskCleanupJobEnabled() { return taskCleanupJobEnabled; } @@ -334,10 +357,18 @@ public boolean isTaskCleanupJobAllCompletedSameParentBusiness() { return taskCleanupJobAllCompletedSameParentBusiness; } + public Duration getTaskCleanupJobLockExpirationPeriod() { + return taskCleanupJobLockExpirationPeriod; + } + public boolean isWorkbasketCleanupJobEnabled() { return workbasketCleanupJobEnabled; } + public Duration getWorkbasketCleanupJobLockExpirationPeriod() { + return workbasketCleanupJobLockExpirationPeriod; + } + public boolean isSimpleHistoryCleanupJobEnabled() { return simpleHistoryCleanupJobEnabled; } @@ -354,6 +385,10 @@ public boolean isSimpleHistoryCleanupJobAllCompletedSameParentBusiness() { return simpleHistoryCleanupJobAllCompletedSameParentBusiness; } + public Duration getSimpleHistoryCleanupJobLockExpirationPeriod() { + return simpleHistoryCleanupJobLockExpirationPeriod; + } + public boolean isTaskUpdatePriorityJobEnabled() { return taskUpdatePriorityJobEnabled; } @@ -370,6 +405,10 @@ public Duration getTaskUpdatePriorityJobRunEvery() { return taskUpdatePriorityJobRunEvery; } + public Duration getTaskUpdatePriorityJobLockExpirationPeriod() { + return taskUpdatePriorityJobLockExpirationPeriod; + } + public boolean isUserInfoRefreshJobEnabled() { return userInfoRefreshJobEnabled; } @@ -382,6 +421,10 @@ public Duration getUserRefreshJobRunEvery() { return userRefreshJobRunEvery; } + public Duration getUserRefreshJobLockExpirationPeriod() { + return userRefreshJobLockExpirationPeriod; + } + public Set getCustomJobs() { return customJobs; } @@ -412,6 +455,7 @@ public Map getProperties() { // endregion // region hashCode, equals + toString + @Override public int hashCode() { return Objects.hash( @@ -424,6 +468,7 @@ public int hashCode() { roleMap, classificationTypes, classificationCategoriesByType, + useWorkingTimeCalculation, workingTimeSchedule, workingTimeScheduleTimeZone, customHolidays, @@ -439,21 +484,27 @@ public int hashCode() { jobBatchSize, jobFirstRun, jobRunEvery, + jobLockExpirationPeriod, taskCleanupJobEnabled, taskCleanupJobMinimumAge, taskCleanupJobAllCompletedSameParentBusiness, + taskCleanupJobLockExpirationPeriod, workbasketCleanupJobEnabled, + workbasketCleanupJobLockExpirationPeriod, simpleHistoryCleanupJobEnabled, simpleHistoryCleanupJobBatchSize, simpleHistoryCleanupJobMinimumAge, simpleHistoryCleanupJobAllCompletedSameParentBusiness, + simpleHistoryCleanupJobLockExpirationPeriod, taskUpdatePriorityJobEnabled, taskUpdatePriorityJobBatchSize, taskUpdatePriorityJobFirstRun, taskUpdatePriorityJobRunEvery, + taskUpdatePriorityJobLockExpirationPeriod, userInfoRefreshJobEnabled, userRefreshJobFirstRun, userRefreshJobRunEvery, + userRefreshJobLockExpirationPeriod, customJobs, addAdditionalUserInfo, minimalPermissionsToAssignDomains, @@ -473,6 +524,7 @@ public boolean equals(Object obj) { return useManagedTransactions == other.useManagedTransactions && securityEnabled == other.securityEnabled && enforceServiceLevel == other.enforceServiceLevel + && useWorkingTimeCalculation == other.useWorkingTimeCalculation && germanPublicHolidaysEnabled == other.germanPublicHolidaysEnabled && germanPublicHolidaysCorpusChristiEnabled == other.germanPublicHolidaysCorpusChristiEnabled @@ -492,10 +544,10 @@ public boolean equals(Object obj) { && simpleHistoryCleanupJobAllCompletedSameParentBusiness == other.simpleHistoryCleanupJobAllCompletedSameParentBusiness && taskUpdatePriorityJobEnabled == other.taskUpdatePriorityJobEnabled - && useSpecificDb2Taskquery == other.useSpecificDb2Taskquery && taskUpdatePriorityJobBatchSize == other.taskUpdatePriorityJobBatchSize && userInfoRefreshJobEnabled == other.userInfoRefreshJobEnabled && addAdditionalUserInfo == other.addAdditionalUserInfo + && useSpecificDb2Taskquery == other.useSpecificDb2Taskquery && Objects.equals(dataSource, other.dataSource) && Objects.equals(schemaName, other.schemaName) && Objects.equals(domains, other.domains) @@ -509,13 +561,27 @@ public boolean equals(Object obj) { && jobSchedulerPeriodTimeUnit == other.jobSchedulerPeriodTimeUnit && Objects.equals(jobFirstRun, other.jobFirstRun) && Objects.equals(jobRunEvery, other.jobRunEvery) + && Objects.equals(jobLockExpirationPeriod, other.jobLockExpirationPeriod) && Objects.equals(taskCleanupJobMinimumAge, other.taskCleanupJobMinimumAge) + && Objects.equals( + taskCleanupJobLockExpirationPeriod, other.taskCleanupJobLockExpirationPeriod) + && Objects.equals( + workbasketCleanupJobLockExpirationPeriod, + other.workbasketCleanupJobLockExpirationPeriod) && Objects.equals( simpleHistoryCleanupJobMinimumAge, other.simpleHistoryCleanupJobMinimumAge) + && Objects.equals( + simpleHistoryCleanupJobLockExpirationPeriod, + other.simpleHistoryCleanupJobLockExpirationPeriod) && Objects.equals(taskUpdatePriorityJobFirstRun, other.taskUpdatePriorityJobFirstRun) && Objects.equals(taskUpdatePriorityJobRunEvery, other.taskUpdatePriorityJobRunEvery) + && Objects.equals( + taskUpdatePriorityJobLockExpirationPeriod, + other.taskUpdatePriorityJobLockExpirationPeriod) && Objects.equals(userRefreshJobFirstRun, other.userRefreshJobFirstRun) && Objects.equals(userRefreshJobRunEvery, other.userRefreshJobRunEvery) + && Objects.equals( + userRefreshJobLockExpirationPeriod, other.userRefreshJobLockExpirationPeriod) && Objects.equals(customJobs, other.customJobs) && Objects.equals( minimalPermissionsToAssignDomains, other.minimalPermissionsToAssignDomains) @@ -524,12 +590,14 @@ public boolean equals(Object obj) { @Override public String toString() { - return "TaskanaConfiguration [dataSource=" + return "TaskanaConfiguration{" + + "dataSource=" + dataSource + ", useManagedTransactions=" + useManagedTransactions - + ", schemaName=" + + ", schemaName='" + schemaName + + '\'' + ", securityEnabled=" + securityEnabled + ", domains=" @@ -542,6 +610,8 @@ public String toString() { + classificationTypes + ", classificationCategoriesByType=" + classificationCategoriesByType + + ", useWorkingTimeCalculation=" + + useWorkingTimeCalculation + ", workingTimeSchedule=" + workingTimeSchedule + ", workingTimeScheduleTimeZone=" @@ -554,8 +624,9 @@ public String toString() { + germanPublicHolidaysCorpusChristiEnabled + ", deleteHistoryEventsOnTaskDeletionEnabled=" + deleteHistoryEventsOnTaskDeletionEnabled - + ", logHistoryLoggerName=" + + ", logHistoryLoggerName='" + logHistoryLoggerName + + '\'' + ", jobSchedulerEnabled=" + jobSchedulerEnabled + ", jobSchedulerInitialStartDelay=" @@ -572,14 +643,20 @@ public String toString() { + jobFirstRun + ", jobRunEvery=" + jobRunEvery + + ", jobLockExpirationPeriod=" + + jobLockExpirationPeriod + ", taskCleanupJobEnabled=" + taskCleanupJobEnabled + ", taskCleanupJobMinimumAge=" + taskCleanupJobMinimumAge + ", taskCleanupJobAllCompletedSameParentBusiness=" + taskCleanupJobAllCompletedSameParentBusiness + + ", taskCleanupJobLockExpirationPeriod=" + + taskCleanupJobLockExpirationPeriod + ", workbasketCleanupJobEnabled=" + workbasketCleanupJobEnabled + + ", workbasketCleanupJobLockExpirationPeriod=" + + workbasketCleanupJobLockExpirationPeriod + ", simpleHistoryCleanupJobEnabled=" + simpleHistoryCleanupJobEnabled + ", simpleHistoryCleanupJobBatchSize=" @@ -588,6 +665,8 @@ public String toString() { + simpleHistoryCleanupJobMinimumAge + ", simpleHistoryCleanupJobAllCompletedSameParentBusiness=" + simpleHistoryCleanupJobAllCompletedSameParentBusiness + + ", simpleHistoryCleanupJobLockExpirationPeriod=" + + simpleHistoryCleanupJobLockExpirationPeriod + ", taskUpdatePriorityJobEnabled=" + taskUpdatePriorityJobEnabled + ", taskUpdatePriorityJobBatchSize=" @@ -596,12 +675,16 @@ public String toString() { + taskUpdatePriorityJobFirstRun + ", taskUpdatePriorityJobRunEvery=" + taskUpdatePriorityJobRunEvery + + ", taskUpdatePriorityJobLockExpirationPeriod=" + + taskUpdatePriorityJobLockExpirationPeriod + ", userInfoRefreshJobEnabled=" + userInfoRefreshJobEnabled + ", userRefreshJobFirstRun=" + userRefreshJobFirstRun + ", userRefreshJobRunEvery=" + userRefreshJobRunEvery + + ", userRefreshJobLockExpirationPeriod=" + + userRefreshJobLockExpirationPeriod + ", customJobs=" + customJobs + ", addAdditionalUserInfo=" @@ -612,7 +695,7 @@ public String toString() { + useSpecificDb2Taskquery + ", properties=" + properties - + "]"; + + '}'; } // endregion @@ -650,6 +733,10 @@ public static class Builder { // endregion // region working time configuration + + @TaskanaProperty("taskana.workingTime.useWorkingTimeCalculation") + private boolean useWorkingTimeCalculation = true; + @TaskanaProperty("taskana.workingTime.schedule") private Map> workingTimeSchedule = initDefaultWorkingTimeSchedule(); @@ -680,7 +767,7 @@ public static class Builder { private boolean jobSchedulerEnabled = true; @TaskanaProperty("taskana.jobs.scheduler.initialStartDelay") - private long jobSchedulerInitialStartDelay = 100; + private long jobSchedulerInitialStartDelay = 0; @TaskanaProperty("taskana.jobs.scheduler.period") private long jobSchedulerPeriod = 5; @@ -700,6 +787,9 @@ public static class Builder { @TaskanaProperty("taskana.jobs.runEvery") private Duration jobRunEvery = Duration.ofDays(1); + @TaskanaProperty("taskana.jobs.lockExpirationPeriod") + private Duration jobLockExpirationPeriod = Duration.ofMinutes(30); + @TaskanaProperty("taskana.jobs.cleanup.task.enable") private boolean taskCleanupJobEnabled = true; @@ -709,9 +799,15 @@ public static class Builder { @TaskanaProperty("taskana.jobs.cleanup.task.allCompletedSameParentBusiness") private boolean taskCleanupJobAllCompletedSameParentBusiness = true; + @TaskanaProperty("taskana.jobs.cleanup.task.lockExpirationPeriod") + private Duration taskCleanupJobLockExpirationPeriod = Duration.ofMinutes(30); + @TaskanaProperty("taskana.jobs.cleanup.workbasket.enable") private boolean workbasketCleanupJobEnabled = true; + @TaskanaProperty("taskana.jobs.cleanup.workbasket.lockExpirationPeriod") + private Duration workbasketCleanupJobLockExpirationPeriod = Duration.ofMinutes(30); + @TaskanaProperty("taskana.jobs.cleanup.history.simple.enable") private boolean simpleHistoryCleanupJobEnabled = false; @@ -724,6 +820,9 @@ public static class Builder { @TaskanaProperty("taskana.jobs.cleanup.history.simple.allCompletedSameParentBusiness") private boolean simpleHistoryCleanupJobAllCompletedSameParentBusiness = true; + @TaskanaProperty("taskana.jobs.cleanup.history.simple.lockExpirationPeriod") + private Duration simpleHistoryCleanupJobLockExpirationPeriod = Duration.ofMinutes(30); + @TaskanaProperty("taskana.jobs.priority.task.enable") private boolean taskUpdatePriorityJobEnabled = false; @@ -736,6 +835,9 @@ public static class Builder { @TaskanaProperty("taskana.jobs.priority.task.runEvery") private Duration taskUpdatePriorityJobRunEvery = Duration.ofDays(1); + @TaskanaProperty("taskana.jobs.priority.task.lockExpirationPeriod") + private Duration taskUpdatePriorityJobLockExpirationPeriod = Duration.ofMinutes(30); + @TaskanaProperty("taskana.jobs.refresh.user.enable") private boolean userInfoRefreshJobEnabled = false; @@ -745,6 +847,9 @@ public static class Builder { @TaskanaProperty("taskana.jobs.refresh.user.runEvery") private Duration userRefreshJobRunEvery = Duration.ofDays(1); + @TaskanaProperty("taskana.jobs.refresh.user.lockExpirationPeriod") + private Duration userRefreshJobLockExpirationPeriod = Duration.ofMinutes(30); + @TaskanaProperty("taskana.jobs.customJobs") private Set customJobs = new HashSet<>(); // endregion @@ -826,6 +931,7 @@ public Builder( this.classificationTypes = conf.classificationTypes; this.classificationCategoriesByType = conf.classificationCategoriesByType; // working time configuration + this.useWorkingTimeCalculation = conf.useWorkingTimeCalculation; this.workingTimeSchedule = conf.workingTimeSchedule; this.workingTimeScheduleTimeZone = conf.workingTimeScheduleTimeZone; this.customHolidays = conf.customHolidays; @@ -843,23 +949,31 @@ public Builder( this.jobBatchSize = conf.jobBatchSize; this.jobFirstRun = conf.jobFirstRun; this.jobRunEvery = conf.jobRunEvery; + this.jobLockExpirationPeriod = conf.jobLockExpirationPeriod; this.taskCleanupJobEnabled = conf.taskCleanupJobEnabled; this.taskCleanupJobMinimumAge = conf.taskCleanupJobMinimumAge; this.taskCleanupJobAllCompletedSameParentBusiness = conf.taskCleanupJobAllCompletedSameParentBusiness; + this.taskCleanupJobLockExpirationPeriod = conf.taskCleanupJobLockExpirationPeriod; this.workbasketCleanupJobEnabled = conf.workbasketCleanupJobEnabled; + this.workbasketCleanupJobLockExpirationPeriod = conf.workbasketCleanupJobLockExpirationPeriod; this.simpleHistoryCleanupJobEnabled = conf.simpleHistoryCleanupJobEnabled; this.simpleHistoryCleanupJobBatchSize = conf.simpleHistoryCleanupJobBatchSize; this.simpleHistoryCleanupJobMinimumAge = conf.simpleHistoryCleanupJobMinimumAge; this.simpleHistoryCleanupJobAllCompletedSameParentBusiness = conf.simpleHistoryCleanupJobAllCompletedSameParentBusiness; + this.simpleHistoryCleanupJobLockExpirationPeriod = + conf.simpleHistoryCleanupJobLockExpirationPeriod; this.taskUpdatePriorityJobEnabled = conf.taskUpdatePriorityJobEnabled; this.taskUpdatePriorityJobBatchSize = conf.taskUpdatePriorityJobBatchSize; this.taskUpdatePriorityJobFirstRun = conf.taskUpdatePriorityJobFirstRun; this.taskUpdatePriorityJobRunEvery = conf.taskUpdatePriorityJobRunEvery; + this.taskUpdatePriorityJobLockExpirationPeriod = + conf.taskUpdatePriorityJobLockExpirationPeriod; this.userInfoRefreshJobEnabled = conf.userInfoRefreshJobEnabled; this.userRefreshJobFirstRun = conf.userRefreshJobFirstRun; this.userRefreshJobRunEvery = conf.userRefreshJobRunEvery; + this.userRefreshJobLockExpirationPeriod = conf.userRefreshJobLockExpirationPeriod; this.customJobs = conf.customJobs; // user configuration this.addAdditionalUserInfo = conf.addAdditionalUserInfo; @@ -964,6 +1078,11 @@ public Builder classificationCategoriesByType( // region working time configuration + public Builder useWorkingTimeCalculation(boolean useWorkingTimeCalculation) { + this.useWorkingTimeCalculation = useWorkingTimeCalculation; + return this; + } + public Builder workingTimeSchedule(Map> workingTimeSchedule) { this.workingTimeSchedule = workingTimeSchedule; return this; @@ -1054,6 +1173,11 @@ public Builder taskCleanupJobEnabled(boolean taskCleanupJobEnabled) { return this; } + public Builder jobLockExpirationPeriod(Duration jobLockExpirationPeriod) { + this.jobLockExpirationPeriod = jobLockExpirationPeriod; + return this; + } + public Builder taskCleanupJobMinimumAge(Duration taskCleanupJobMinimumAge) { this.taskCleanupJobMinimumAge = taskCleanupJobMinimumAge; return this; @@ -1066,11 +1190,22 @@ public Builder taskCleanupJobAllCompletedSameParentBusiness( return this; } + public Builder taskCleanupJobLockExpirationPeriod(Duration taskCleanupJobLockExpirationPeriod) { + this.taskCleanupJobLockExpirationPeriod = taskCleanupJobLockExpirationPeriod; + return this; + } + public Builder workbasketCleanupJobEnabled(boolean workbasketCleanupJobEnabled) { this.workbasketCleanupJobEnabled = workbasketCleanupJobEnabled; return this; } + public Builder workbasketCleanupJobLockExpirationPeriod( + Duration workbasketCleanupJobLockExpirationPeriod) { + this.workbasketCleanupJobLockExpirationPeriod = workbasketCleanupJobLockExpirationPeriod; + return this; + } + public Builder simpleHistoryCleanupJobEnabled(boolean simpleHistoryCleanupJobEnabled) { this.simpleHistoryCleanupJobEnabled = simpleHistoryCleanupJobEnabled; return this; @@ -1093,6 +1228,13 @@ public Builder simpleHistoryCleanupJobAllCompletedSameParentBusiness( return this; } + public Builder simpleHistoryCleanupJobLockExpirationPeriod( + Duration simpleHistoryCleanupJobLockExpirationPeriod) { + this.simpleHistoryCleanupJobLockExpirationPeriod = + simpleHistoryCleanupJobLockExpirationPeriod; + return this; + } + public Builder taskUpdatePriorityJobEnabled(boolean taskUpdatePriorityJobEnabled) { this.taskUpdatePriorityJobEnabled = taskUpdatePriorityJobEnabled; return this; @@ -1113,6 +1255,12 @@ public Builder taskUpdatePriorityJobRunEvery(Duration taskUpdatePriorityJobRunEv return this; } + public Builder taskUpdatePriorityJobLockExpirationPeriod( + Duration taskUpdatePriorityJobLockExpirationPeriod) { + this.taskUpdatePriorityJobLockExpirationPeriod = taskUpdatePriorityJobLockExpirationPeriod; + return this; + } + public Builder userInfoRefreshJobEnabled(boolean userInfoRefreshJobEnabled) { this.userInfoRefreshJobEnabled = userInfoRefreshJobEnabled; return this; @@ -1128,6 +1276,11 @@ public Builder userRefreshJobRunEvery(Duration userRefreshJobRunEvery) { return this; } + public Builder userRefreshJobLockExpirationPeriod(Duration userRefreshJobLockExpirationPeriod) { + this.userRefreshJobLockExpirationPeriod = userRefreshJobLockExpirationPeriod; + return this; + } + public Builder customJobs(Set customJobs) { this.customJobs = customJobs; return this; diff --git a/lib/taskana-core/src/main/java/pro/taskana/classification/internal/ClassificationServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/classification/internal/ClassificationServiceImpl.java index a4016cbb6f..6b2ec9ab77 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/classification/internal/ClassificationServiceImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/classification/internal/ClassificationServiceImpl.java @@ -179,11 +179,8 @@ public void deleteClassification(String classificationKey, String domain) @Override public Classification createClassification(Classification classification) - throws ClassificationAlreadyExistException, - DomainNotFoundException, - InvalidArgumentException, - MalformedServiceLevelException, - NotAuthorizedException { + throws ClassificationAlreadyExistException, DomainNotFoundException, InvalidArgumentException, + MalformedServiceLevelException, NotAuthorizedException { taskanaEngine.getEngine().checkRoleMembership(TaskanaRole.BUSINESS_ADMIN, TaskanaRole.ADMIN); if (!taskanaEngine.domainExists(classification.getDomain()) && !MASTER_DOMAIN.equals(classification.getDomain())) { @@ -222,7 +219,9 @@ public Classification createClassification(Classification classification) } if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Method createClassification created classification {}.", classificationImpl); + LOGGER.debug( + "Method createClassification created classification {}.", + LogSanitizer.stripLineBreakingChars(classificationImpl)); } if (!classification.getDomain().isEmpty()) { @@ -236,11 +235,8 @@ public Classification createClassification(Classification classification) @Override public Classification updateClassification(Classification classification) - throws ConcurrencyException, - ClassificationNotFoundException, - InvalidArgumentException, - MalformedServiceLevelException, - NotAuthorizedException { + throws ConcurrencyException, ClassificationNotFoundException, InvalidArgumentException, + MalformedServiceLevelException, NotAuthorizedException { taskanaEngine.getEngine().checkRoleMembership(TaskanaRole.BUSINESS_ADMIN, TaskanaRole.ADMIN); ClassificationImpl classificationImpl; try { @@ -283,7 +279,8 @@ public Classification updateClassification(Classification classification) } if (LOGGER.isDebugEnabled()) { LOGGER.debug( - "Method updateClassification() updated the classification {}.", classificationImpl); + "Method updateClassification() updated the classification {}.", + LogSanitizer.stripLineBreakingChars(classificationImpl)); } return classification; } finally { diff --git a/lib/taskana-core/src/main/java/pro/taskana/common/api/TaskanaEngine.java b/lib/taskana-core/src/main/java/pro/taskana/common/api/TaskanaEngine.java index 38948b3c06..d67b0e62b7 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/common/api/TaskanaEngine.java +++ b/lib/taskana-core/src/main/java/pro/taskana/common/api/TaskanaEngine.java @@ -16,7 +16,7 @@ /** The TaskanaEngine represents an overall set of all needed services. */ public interface TaskanaEngine { - String MINIMAL_TASKANA_SCHEMA_VERSION = "5.2.0"; + String MINIMAL_TASKANA_SCHEMA_VERSION = "7.0.0"; /** * Returns a {@linkplain TaskService} initialized with the current TaskanaEngine. {@linkplain diff --git a/lib/taskana-core/src/main/java/pro/taskana/common/internal/InternalTaskanaEngine.java b/lib/taskana-core/src/main/java/pro/taskana/common/internal/InternalTaskanaEngine.java index 3f67f91d5f..dda149d16b 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/common/internal/InternalTaskanaEngine.java +++ b/lib/taskana-core/src/main/java/pro/taskana/common/internal/InternalTaskanaEngine.java @@ -12,6 +12,7 @@ import pro.taskana.spi.task.internal.BeforeRequestReviewManager; import pro.taskana.spi.task.internal.CreateTaskPreprocessorManager; import pro.taskana.spi.task.internal.ReviewRequiredManager; +import pro.taskana.spi.task.internal.TaskEndstatePreprocessorManager; /** * FOR INTERNAL USE ONLY. @@ -144,4 +145,11 @@ default void executeInDatabaseConnection(Runnable runnable) { * @return the {@linkplain AfterRequestChangesManager} instance */ AfterRequestChangesManager getAfterRequestChangesManager(); + + /** + * Retrieves the {@linkplain pro.taskana.spi.task.internal.TaskEndstatePreprocessorManager}. + * + * @return the {@linkplain pro.taskana.spi.task.internal.TaskEndstatePreprocessorManager} instance + */ + TaskEndstatePreprocessorManager getTaskEndstatePreprocessorManager(); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/common/internal/JobServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/common/internal/JobServiceImpl.java index 206941adf9..49ec0a4f30 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/common/internal/JobServiceImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/common/internal/JobServiceImpl.java @@ -1,18 +1,20 @@ package pro.taskana.common.internal; +import java.lang.reflect.InvocationTargetException; import java.time.Duration; import java.time.Instant; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import pro.taskana.TaskanaConfiguration; import pro.taskana.common.api.JobService; import pro.taskana.common.api.ScheduledJob; +import pro.taskana.common.api.exceptions.SystemException; /** Controls all job activities. */ public class JobServiceImpl implements JobService { public static final int JOB_DEFAULT_PRIORITY = 50; - private static final Duration JOB_DEFAULT_LOCK_EXPIRATION_PERIOD = Duration.ofSeconds(60); private static final Logger LOGGER = LoggerFactory.getLogger(JobServiceImpl.class); private final JobMapper jobMapper; @@ -43,7 +45,27 @@ public void deleteJobs(String jobType) { public ScheduledJob lockJob(ScheduledJob job, String owner) { job.setLockedBy(owner); - job.setLockExpires(Instant.now().plus(JOB_DEFAULT_LOCK_EXPIRATION_PERIOD)); + Class jobClass = null; + try { + jobClass = Thread.currentThread().getContextClassLoader().loadClass(job.getType()); + job.setLockExpires( + Instant.now() + .plus( + (Duration) + jobClass + .getMethod("getLockExpirationPeriod", TaskanaConfiguration.class) + .invoke(null, taskanaEngineImpl.getEngine().getConfiguration()))); + } catch (ClassNotFoundException | NoSuchMethodException e) { + throw new SystemException( + String.format( + "Job '%s' does not have a method matching ('getLockExpirationPeriod', %s", + jobClass, TaskanaConfiguration.class)); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new SystemException( + String.format( + "Caught Exception while invoking method 'getLockExpirationPeriod' by reflection")); + } + job.setRetryCount(job.getRetryCount() - 1); taskanaEngineImpl.executeInDatabaseConnection(() -> jobMapper.update(job)); if (LOGGER.isDebugEnabled()) { diff --git a/lib/taskana-core/src/main/java/pro/taskana/common/internal/TaskanaEngineImpl.java b/lib/taskana-core/src/main/java/pro/taskana/common/internal/TaskanaEngineImpl.java index 0220d50365..73d5da160a 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/common/internal/TaskanaEngineImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/common/internal/TaskanaEngineImpl.java @@ -51,6 +51,7 @@ import pro.taskana.common.internal.persistence.StringTypeHandler; import pro.taskana.common.internal.security.CurrentUserContextImpl; import pro.taskana.common.internal.workingtime.HolidaySchedule; +import pro.taskana.common.internal.workingtime.WorkingDayCalculatorImpl; import pro.taskana.common.internal.workingtime.WorkingTimeCalculatorImpl; import pro.taskana.monitor.api.MonitorService; import pro.taskana.monitor.internal.MonitorMapper; @@ -64,6 +65,7 @@ import pro.taskana.spi.task.internal.BeforeRequestReviewManager; import pro.taskana.spi.task.internal.CreateTaskPreprocessorManager; import pro.taskana.spi.task.internal.ReviewRequiredManager; +import pro.taskana.spi.task.internal.TaskEndstatePreprocessorManager; import pro.taskana.task.api.TaskService; import pro.taskana.task.internal.AttachmentMapper; import pro.taskana.task.internal.ObjectReferenceMapper; @@ -97,6 +99,8 @@ public class TaskanaEngineImpl implements TaskanaEngine { private final AfterRequestReviewManager afterRequestReviewManager; private final BeforeRequestChangesManager beforeRequestChangesManager; private final AfterRequestChangesManager afterRequestChangesManager; + private final TaskEndstatePreprocessorManager taskEndstatePreprocessorManager; + private final InternalTaskanaEngineImpl internalTaskanaEngineImpl; private final WorkingTimeCalculator workingTimeCalculator; private final HistoryEventManager historyEventManager; @@ -128,11 +132,18 @@ protected TaskanaEngineImpl( taskanaConfiguration.isGermanPublicHolidaysEnabled(), taskanaConfiguration.isGermanPublicHolidaysCorpusChristiEnabled(), taskanaConfiguration.getCustomHolidays()); - workingTimeCalculator = - new WorkingTimeCalculatorImpl( - holidaySchedule, - taskanaConfiguration.getWorkingTimeSchedule(), - taskanaConfiguration.getWorkingTimeScheduleTimeZone()); + if (taskanaConfiguration.isUseWorkingTimeCalculation()) { + workingTimeCalculator = + new WorkingTimeCalculatorImpl( + holidaySchedule, + taskanaConfiguration.getWorkingTimeSchedule(), + taskanaConfiguration.getWorkingTimeScheduleTimeZone()); + } else { + workingTimeCalculator = + new WorkingDayCalculatorImpl( + holidaySchedule, taskanaConfiguration.getWorkingTimeScheduleTimeZone()); + } + currentUserContext = new CurrentUserContextImpl(TaskanaConfiguration.shouldUseLowerCaseForAccessIds()); createTransactionFactory(taskanaConfiguration.isUseManagedTransactions()); @@ -168,6 +179,7 @@ protected TaskanaEngineImpl( afterRequestReviewManager = new AfterRequestReviewManager(this); beforeRequestChangesManager = new BeforeRequestChangesManager(this); afterRequestChangesManager = new AfterRequestChangesManager(this); + taskEndstatePreprocessorManager = new TaskEndstatePreprocessorManager(); // don't remove, to reset possible explicit mode this.mode = connectionManagementMode; @@ -616,5 +628,10 @@ public BeforeRequestChangesManager getBeforeRequestChangesManager() { public AfterRequestChangesManager getAfterRequestChangesManager() { return afterRequestChangesManager; } + + @Override + public TaskEndstatePreprocessorManager getTaskEndstatePreprocessorManager() { + return taskEndstatePreprocessorManager; + } } } diff --git a/lib/taskana-core/src/main/java/pro/taskana/common/internal/jobs/AbstractTaskanaJob.java b/lib/taskana-core/src/main/java/pro/taskana/common/internal/jobs/AbstractTaskanaJob.java index 1805c87ac2..eae36bad2f 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/common/internal/jobs/AbstractTaskanaJob.java +++ b/lib/taskana-core/src/main/java/pro/taskana/common/internal/jobs/AbstractTaskanaJob.java @@ -4,6 +4,7 @@ import java.lang.reflect.InvocationTargetException; import java.time.Duration; import java.time.Instant; +import pro.taskana.TaskanaConfiguration; import pro.taskana.common.api.ScheduledJob; import pro.taskana.common.api.TaskanaEngine; import pro.taskana.common.api.exceptions.SystemException; @@ -42,8 +43,7 @@ public static TaskanaJob createFromScheduledJob( try { jobClass = Thread.currentThread().getContextClassLoader().loadClass(job.getType()); } catch (ClassNotFoundException e) { - throw new SystemException( - String.format("Can't load class '%s'", job.getType())); + throw new SystemException(String.format("Can't load class '%s'", job.getType())); } return initTaskanaJob(engine, jobClass, txProvider, job); @@ -76,6 +76,46 @@ public static void initializeSchedule(TaskanaEngine taskanaEngine, Class jobC job.scheduleNextJob(); } + public boolean isAsync() { + return async; + } + + public Instant getFirstRun() { + return firstRun; + } + + public Duration getRunEvery() { + return runEvery; + } + + public static Duration getLockExpirationPeriod(TaskanaConfiguration taskanaConfiguration) { + return taskanaConfiguration.getJobLockExpirationPeriod(); + } + + protected abstract String getType(); + + protected abstract void execute() throws TaskanaException; + + protected Instant getNextDueForJob() { + Instant nextRun = firstRun; + if (scheduledJob != null && scheduledJob.getDue() != null) { + nextRun = scheduledJob.getDue(); + } + + while (nextRun.isBefore(Instant.now())) { + nextRun = nextRun.plus(runEvery); + } + + return nextRun; + } + + protected void scheduleNextJob() { + ScheduledJob job = new ScheduledJob(); + job.setType(getType()); + job.setDue(getNextDueForJob()); + taskanaEngineImpl.getJobService().createJob(job); + } + private static AbstractTaskanaJob initTaskanaJob( TaskanaEngine taskanaEngine, Class jobClass, @@ -120,40 +160,4 @@ private static AbstractTaskanaJob initTaskanaJob( } return job; } - - public boolean isAsync() { - return async; - } - - public Instant getFirstRun() { - return firstRun; - } - - public Duration getRunEvery() { - return runEvery; - } - - protected abstract String getType(); - - protected abstract void execute() throws TaskanaException; - - protected Instant getNextDueForJob() { - Instant nextRun = firstRun; - if (scheduledJob != null && scheduledJob.getDue() != null) { - nextRun = scheduledJob.getDue(); - } - - while (nextRun.isBefore(Instant.now())) { - nextRun = nextRun.plus(runEvery); - } - - return nextRun; - } - - protected void scheduleNextJob() { - ScheduledJob job = new ScheduledJob(); - job.setType(getType()); - job.setDue(getNextDueForJob()); - taskanaEngineImpl.getJobService().createJob(job); - } } diff --git a/lib/taskana-core/src/main/java/pro/taskana/spi/history/api/events/task/TaskDeletedEvent.java b/lib/taskana-core/src/main/java/pro/taskana/spi/history/api/events/task/TaskDeletedEvent.java new file mode 100644 index 0000000000..4010aa6789 --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/spi/history/api/events/task/TaskDeletedEvent.java @@ -0,0 +1,18 @@ +package pro.taskana.spi.history.api.events.task; + +import java.time.Instant; +import pro.taskana.task.api.models.TaskSummary; + +public class TaskDeletedEvent extends TaskHistoryEvent { + + public TaskDeletedEvent( + String id, + TaskSummary taskSummary, + String taskId, + String userId) { + super(id, taskSummary, userId, null); + eventType = TaskHistoryEventType.DELETED.getName(); + created = Instant.now(); + super.taskId = taskId; + } +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/spi/history/api/events/task/TaskHistoryEventType.java b/lib/taskana-core/src/main/java/pro/taskana/spi/history/api/events/task/TaskHistoryEventType.java index 6ed98104d2..96576bb4a8 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/spi/history/api/events/task/TaskHistoryEventType.java +++ b/lib/taskana-core/src/main/java/pro/taskana/spi/history/api/events/task/TaskHistoryEventType.java @@ -10,7 +10,8 @@ public enum TaskHistoryEventType { COMPLETED("COMPLETED"), CANCELLED("CANCELLED"), TERMINATED("TERMINATED"), - TRANSFERRED("TRANSFERRED"); + TRANSFERRED("TRANSFERRED"), + DELETED("DELETED"); private String name; diff --git a/lib/taskana-core/src/main/java/pro/taskana/spi/history/api/events/workbasket/WorkbasketHistoryEvent.java b/lib/taskana-core/src/main/java/pro/taskana/spi/history/api/events/workbasket/WorkbasketHistoryEvent.java index b91662691f..53d1678994 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/spi/history/api/events/workbasket/WorkbasketHistoryEvent.java +++ b/lib/taskana-core/src/main/java/pro/taskana/spi/history/api/events/workbasket/WorkbasketHistoryEvent.java @@ -23,6 +23,10 @@ public class WorkbasketHistoryEvent { protected String custom2; protected String custom3; protected String custom4; + protected String custom5; + protected String custom6; + protected String custom7; + protected String custom8; protected String orgLevel1; protected String orgLevel2; protected String orgLevel3; @@ -45,6 +49,10 @@ public WorkbasketHistoryEvent( custom2 = workbasket.getCustomField(WorkbasketCustomField.CUSTOM_2); custom3 = workbasket.getCustomField(WorkbasketCustomField.CUSTOM_3); custom4 = workbasket.getCustomField(WorkbasketCustomField.CUSTOM_4); + custom5 = workbasket.getCustomField(WorkbasketCustomField.CUSTOM_5); + custom6 = workbasket.getCustomField(WorkbasketCustomField.CUSTOM_6); + custom7 = workbasket.getCustomField(WorkbasketCustomField.CUSTOM_7); + custom8 = workbasket.getCustomField(WorkbasketCustomField.CUSTOM_8); orgLevel1 = workbasket.getOrgLevel1(); orgLevel2 = workbasket.getOrgLevel2(); orgLevel3 = workbasket.getOrgLevel3(); @@ -65,6 +73,18 @@ public void setCustomAttribute(WorkbasketCustomField customField, String value) case CUSTOM_4: custom4 = value; break; + case CUSTOM_5: + custom5 = value; + break; + case CUSTOM_6: + custom6 = value; + break; + case CUSTOM_7: + custom7 = value; + break; + case CUSTOM_8: + custom8 = value; + break; default: throw new SystemException("Unknown customField '" + customField + "'"); } @@ -80,6 +100,14 @@ public String getCustomAttribute(WorkbasketCustomField customField) { return custom3; case CUSTOM_4: return custom4; + case CUSTOM_5: + return custom5; + case CUSTOM_6: + return custom6; + case CUSTOM_7: + return custom7; + case CUSTOM_8: + return custom8; default: throw new SystemException("Unknown customField '" + customField + "'"); } @@ -213,6 +241,10 @@ public int hashCode() { custom2, custom3, custom4, + custom5, + custom6, + custom7, + custom8, getOrgLevel1(), getOrgLevel2(), getOrgLevel3(), @@ -242,6 +274,10 @@ public boolean equals(Object obj) { && Objects.equals(custom2, other.custom2) && Objects.equals(custom3, other.custom3) && Objects.equals(custom4, other.custom4) + && Objects.equals(custom5, other.custom5) + && Objects.equals(custom6, other.custom6) + && Objects.equals(custom7, other.custom7) + && Objects.equals(custom8, other.custom8) && Objects.equals(getOrgLevel1(), other.getOrgLevel1()) && Objects.equals(getOrgLevel2(), other.getOrgLevel2()) && Objects.equals(getOrgLevel3(), other.getOrgLevel3()) @@ -277,6 +313,14 @@ public String toString() { + custom3 + ", custom4=" + custom4 + + ", custom5=" + + custom5 + + ", custom6=" + + custom6 + + ", custom7=" + + custom7 + + ", custom8=" + + custom8 + ", orgLevel1=" + orgLevel1 + ", orgLevel2=" diff --git a/lib/taskana-core/src/main/java/pro/taskana/spi/task/api/TaskEndstatePreprocessor.java b/lib/taskana-core/src/main/java/pro/taskana/spi/task/api/TaskEndstatePreprocessor.java new file mode 100644 index 0000000000..66657dc4b6 --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/spi/task/api/TaskEndstatePreprocessor.java @@ -0,0 +1,34 @@ +package pro.taskana.spi.task.api; + +import pro.taskana.task.api.models.Task; + +/** + * The TaskEndstatePreprocessor allows to implement customized behaviour before the given + * {@linkplain Task} goes into an {@linkplain pro.taskana.task.api.TaskState#END_STATES end state} + * (cancelled, terminated or completed). + */ +public interface TaskEndstatePreprocessor { + + /** + * Perform any action before a {@linkplain Task} goes into an {@linkplain + * pro.taskana.task.api.TaskState#END_STATES end state}. A {@linkplain Task} goes into an end + * state at the end of the following methods: {@linkplain + * pro.taskana.task.api.TaskService#completeTask(String)}, {@linkplain + * pro.taskana.task.api.TaskService#cancelTask(String)}, {@linkplain + * pro.taskana.task.api.TaskService#terminateTask(String)}. + * + *

This SPI is executed within the same transaction staple as {@linkplain + * pro.taskana.task.api.TaskService#completeTask(String)}, {@linkplain + * pro.taskana.task.api.TaskService#cancelTask(String)}, {@linkplain + * pro.taskana.task.api.TaskService#terminateTask(String)}. + * + *

This SPI is executed with the same {@linkplain + * pro.taskana.common.api.security.UserPrincipal} and {@linkplain + * pro.taskana.common.api.security.GroupPrincipal} as in the methods mentioned above. + * + * @param taskToProcess the {@linkplain Task} to preprocess + * @return the modified {@linkplain Task}. IMPORTANT: persistent changes to the {@linkplain + * Task} have to be managed by the service provider + */ + Task processTaskBeforeEndstate(Task taskToProcess); +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/spi/task/internal/TaskEndstatePreprocessorManager.java b/lib/taskana-core/src/main/java/pro/taskana/spi/task/internal/TaskEndstatePreprocessorManager.java new file mode 100644 index 0000000000..5873e68ba9 --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/spi/task/internal/TaskEndstatePreprocessorManager.java @@ -0,0 +1,39 @@ +package pro.taskana.spi.task.internal; + +import static pro.taskana.common.internal.util.CheckedConsumer.wrap; + +import java.util.List; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import pro.taskana.common.internal.util.SpiLoader; +import pro.taskana.spi.task.api.TaskEndstatePreprocessor; +import pro.taskana.task.api.models.Task; + +public class TaskEndstatePreprocessorManager { + + private static final Logger LOGGER = + LoggerFactory.getLogger(TaskEndstatePreprocessorManager.class); + private final List taskEndstatePreprocessors; + + public TaskEndstatePreprocessorManager() { + taskEndstatePreprocessors = SpiLoader.load(TaskEndstatePreprocessor.class); + for (TaskEndstatePreprocessor preprocessor : taskEndstatePreprocessors) { + LOGGER.info( + "Registered TaskEndstatePreprocessor provider: {}", preprocessor.getClass().getName()); + } + if (taskEndstatePreprocessors.isEmpty()) { + LOGGER.info("No TaskEndstatePreprocessor found. Running without TaskEndstatePreprocessor."); + } + } + + public Task processTaskBeforeEndstate(Task taskToProcess) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Sending task to TaskEndstatePreprocessor providers: {}", taskToProcess); + } + taskEndstatePreprocessors.forEach( + wrap( + taskEndstatePreprocessor -> + taskEndstatePreprocessor.processTaskBeforeEndstate(taskToProcess))); + return taskToProcess; + } +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java index b7eaf07b3b..d83214238c 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java @@ -221,22 +221,58 @@ Task cancelClaim(String taskId) InvalidTaskStateException; /** - * Cancel the claim of an existing {@linkplain Task} even if it was claimed by another user. + * Cancel the claim of an existing {@linkplain Task} if it was claimed by the current user before. * * @param taskId the {@linkplain Task#getId() id} of the {@linkplain Task} which should be * unclaimed + * @param keepOwner If set to true, will keep the {@linkplain Task#getOwner()} and {@linkplain + * Task#getOwnerLongName()} * @return the unclaimed {@linkplain Task} * @throws TaskNotFoundException if the {@linkplain Task} with taskId was not found * @throws InvalidTaskStateException if the {@linkplain Task} is already in one of the {@linkplain * TaskState#END_STATES} + * @throws InvalidOwnerException if the {@linkplain Task} is claimed by another user * @throws NotAuthorizedOnWorkbasketException if the current user has no {@linkplain * WorkbasketPermission#READ} for the {@linkplain Workbasket} the {@linkplain Task} is in */ - Task forceCancelClaim(String taskId) + Task cancelClaim(String taskId, boolean keepOwner) throws TaskNotFoundException, + InvalidOwnerException, NotAuthorizedOnWorkbasketException, InvalidTaskStateException; + /** + * Cancel the claim of an existing {@linkplain Task} even if it was claimed by another user. + * + * @param taskId the {@linkplain Task#getId() id} of the {@linkplain Task} which should be + * unclaimed + * @param keepOwner If set to true, will keep the {@linkplain Task#getOwner()} and {@linkplain + * Task#getOwnerLongName()} + * @return the unclaimed {@linkplain Task} + * @throws TaskNotFoundException if the {@linkplain Task} with taskId was not found + * @throws InvalidTaskStateException if the {@linkplain Task} is already in one of the {@linkplain + * TaskState#END_STATES} + * @throws NotAuthorizedOnWorkbasketException if the current user has no {@linkplain + * WorkbasketPermission#READ} for the {@linkplain Workbasket} the {@linkplain Task} is in + */ + Task forceCancelClaim(String taskId, boolean keepOwner) + throws TaskNotFoundException, NotAuthorizedOnWorkbasketException, InvalidTaskStateException; + + /** + * Cancel the claim of an existing {@linkplain Task} even if it was claimed by another user. + * + * @param taskId the {@linkplain Task#getId() id} of the {@linkplain Task} which should be + * unclaimed + * @return the unclaimed {@linkplain Task} + * @throws TaskNotFoundException if the {@linkplain Task} with taskId was not found + * @throws InvalidTaskStateException if the {@linkplain Task} is already in one of the {@linkplain + * TaskState#END_STATES} + * @throws NotAuthorizedOnWorkbasketException if the current user has no {@linkplain + * WorkbasketPermission#READ} for the {@linkplain Workbasket} the {@linkplain Task} is in + */ + Task forceCancelClaim(String taskId) + throws TaskNotFoundException, NotAuthorizedOnWorkbasketException, InvalidTaskStateException; + /** * Request review for an existing {@linkplain Task} that is in {@linkplain TaskState#CLAIMED}. * @@ -643,7 +679,8 @@ Task updateTask(Task task) /** * Updates specified {@linkplain TaskCustomField TaskCustomFields} of {@linkplain Task Tasks} - * associated with the given {@linkplain Task#getPrimaryObjRef() primaryObjRef}. + * associated with the given {@linkplain Task#getPrimaryObjRef() primaryObjRef}. Tasks in + * Workbaskets without EDITTASKS permission will be ignored and not updated. * * @param selectionCriteria the {@linkplain Task#getPrimaryObjRef() primaryObjRef} of the * searched-for {@linkplain Task Tasks}. diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/ServiceLevelHandler.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/ServiceLevelHandler.java index 5f140930b8..028bd70a78 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/ServiceLevelHandler.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/ServiceLevelHandler.java @@ -303,7 +303,8 @@ private boolean plannedHasChanged(Task newTask, Task oldTask) { private Instant calculateDue(Instant planned, Duration duration) { Instant dueExclusive = workingTimeCalculator.addWorkingTime(planned, duration); - if (!planned.equals(dueExclusive)) { + if (taskanaEngine.getEngine().getConfiguration().isUseWorkingTimeCalculation() + && !planned.equals(dueExclusive)) { // Calculation is exclusive, but we want due date to be inclusive. Hence, we subtract a // millisecond // If planned and dueExclusive are the same values, we don't want due to be before planned. @@ -320,7 +321,11 @@ private Instant calculatePlanned(Instant due, Duration duration) { return due; } else { // due is inclusive, but calculation happens exclusive. - return workingTimeCalculator.subtractWorkingTime(due.plusMillis(1), duration); + Instant normalize = + taskanaEngine.getEngine().getConfiguration().isUseWorkingTimeCalculation() + ? due.plusMillis(1) + : due; + return workingTimeCalculator.subtractWorkingTime(normalize, duration); } } @@ -328,9 +333,13 @@ private Instant normalizeDue(Instant due) { // plusMillis since due is inclusive, but calculation happens exclusive. // minusMillis since we calculated a due date // Without that some edge case fail (e.g. due is exactly the start of weekend) - return workingTimeCalculator - .subtractWorkingTime(due.plusMillis(1), Duration.ZERO) - .minusMillis(1); + if (taskanaEngine.getEngine().getConfiguration().isUseWorkingTimeCalculation()) { + return workingTimeCalculator + .subtractWorkingTime(due.plusMillis(1), Duration.ZERO) + .minusMillis(1); + } + + return workingTimeCalculator.subtractWorkingTime(due, Duration.ZERO); } private Instant normalizePlanned(Instant instant) { @@ -625,9 +634,9 @@ private boolean isPriorityAndDurationAlreadyCorrect(TaskImpl newTaskImpl, TaskIm } // TODO Do we need to compare Key and Id or could we simply compare ClassificationSummary only? final boolean isClassificationKeyChanged = - Objects.equals(newTaskImpl.getClassificationKey(), oldTaskImpl.getClassificationKey()); + !Objects.equals(newTaskImpl.getClassificationKey(), oldTaskImpl.getClassificationKey()); final boolean isClassificationIdChanged = - Objects.equals(newTaskImpl.getClassificationId(), oldTaskImpl.getClassificationId()); + !Objects.equals(newTaskImpl.getClassificationId(), oldTaskImpl.getClassificationId()); final boolean isManualPriorityChanged = newTaskImpl.getManualPriority() != oldTaskImpl.getManualPriority(); diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQueryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQueryImpl.java index 3fbab64c6f..1f27043688 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQueryImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQueryImpl.java @@ -140,6 +140,7 @@ public class TaskQueryImpl implements TaskQuery { private String[] parentBusinessProcessIdLike; private String[] parentBusinessProcessIdNotLike; private String[] ownerIn; + private boolean ownerInContainsNull; private String[] ownerNotIn; private String[] ownerLike; private String[] ownerNotLike; @@ -865,7 +866,15 @@ public TaskQuery orderByParentBusinessProcessId(SortDirection sortDirection) { @Override public TaskQuery ownerIn(String... owners) { - this.ownerIn = owners; + List conditionList = new ArrayList<>(Arrays.asList(owners)); + boolean containsNull = conditionList.contains(null); + if (containsNull) { + conditionList.remove(null); + ownerInContainsNull = true; + this.ownerIn = conditionList.toArray(new String[owners.length - 1]); + } else { + this.ownerIn = owners; + } return this; } @@ -1983,7 +1992,7 @@ public List list() { return taskanaEngine.executeInDatabaseConnection( () -> { checkForIllegalParamCombinations(); - checkOpenAndReadPermissionForSpecifiedWorkbaskets(); + checkOpenReadAndReadTasksPermissionForSpecifiedWorkbaskets(); setupJoinAndOrderParameters(); setupAccessIds(); List tasks = @@ -1999,7 +2008,7 @@ public List list(int offset, int limit) { try { taskanaEngine.openConnection(); checkForIllegalParamCombinations(); - checkOpenAndReadPermissionForSpecifiedWorkbaskets(); + checkOpenReadAndReadTasksPermissionForSpecifiedWorkbaskets(); setupAccessIds(); setupJoinAndOrderParameters(); RowBounds rowBounds = new RowBounds(offset, limit); @@ -2031,7 +2040,7 @@ public List listValues(TaskQueryColumnName columnName, SortDirection sor this.orderByInner.clear(); this.addOrderCriteria(columnName.toString(), sortDirection); checkForIllegalParamCombinations(); - checkOpenAndReadPermissionForSpecifiedWorkbaskets(); + checkOpenReadAndReadTasksPermissionForSpecifiedWorkbaskets(); setupAccessIds(); if (columnName.equals(TaskQueryColumnName.CLASSIFICATION_NAME)) { @@ -2067,7 +2076,7 @@ public TaskSummary single() { TaskSummary result; try { taskanaEngine.openConnection(); - checkOpenAndReadPermissionForSpecifiedWorkbaskets(); + checkOpenReadAndReadTasksPermissionForSpecifiedWorkbaskets(); setupAccessIds(); setupJoinAndOrderParameters(); TaskSummaryImpl taskSummaryImpl = @@ -2092,7 +2101,7 @@ public long count() { Long rowCount; try { taskanaEngine.openConnection(); - checkOpenAndReadPermissionForSpecifiedWorkbaskets(); + checkOpenReadAndReadTasksPermissionForSpecifiedWorkbaskets(); setupAccessIds(); setupJoinAndOrderParameters(); rowCount = taskanaEngine.getSqlSession().selectOne(getLinkToCounterTaskScript(), this); @@ -2223,7 +2232,7 @@ private void setupAccessIds() { } } - private void checkOpenAndReadPermissionForSpecifiedWorkbaskets() { + private void checkOpenReadAndReadTasksPermissionForSpecifiedWorkbaskets() { if (taskanaEngine.getEngine().isUserInRole(TaskanaRole.ADMIN, TaskanaRole.TASK_ADMIN)) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Skipping permissions check since user is in role ADMIN or TASK_ADMIN."); @@ -2234,13 +2243,13 @@ private void checkOpenAndReadPermissionForSpecifiedWorkbaskets() { if (this.workbasketIdIn != null && this.workbasketIdIn.length > 0) { filterByAccessIdIn = false; for (String workbasketId : workbasketIdIn) { - checkOpenAndReadPermissionById(workbasketId); + checkOpenReadAndReadTasksPermissionById(workbasketId); } } if (workbasketKeyDomainIn != null && workbasketKeyDomainIn.length > 0) { filterByAccessIdIn = false; for (KeyDomain keyDomain : workbasketKeyDomainIn) { - checkOpenAndReadPermissionByKeyDomain(keyDomain); + checkOpenReadAndReadTasksPermissionByKeyDomain(keyDomain); } } } catch (NotAuthorizedOnWorkbasketException e) { @@ -2248,20 +2257,24 @@ private void checkOpenAndReadPermissionForSpecifiedWorkbaskets() { } } - private void checkOpenAndReadPermissionById(String workbasketId) + private void checkOpenReadAndReadTasksPermissionById(String workbasketId) throws NotAuthorizedOnWorkbasketException { try { taskanaEngine .getEngine() .getWorkbasketService() - .checkAuthorization(workbasketId, WorkbasketPermission.OPEN, WorkbasketPermission.READ); + .checkAuthorization( + workbasketId, + WorkbasketPermission.OPEN, + WorkbasketPermission.READ, + WorkbasketPermission.READTASKS); } catch (WorkbasketNotFoundException e) { LOGGER.warn( String.format("The workbasket with the ID ' %s ' does not exist.", workbasketId), e); } } - private void checkOpenAndReadPermissionByKeyDomain(KeyDomain keyDomain) + private void checkOpenReadAndReadTasksPermissionByKeyDomain(KeyDomain keyDomain) throws NotAuthorizedOnWorkbasketException { try { taskanaEngine @@ -2271,7 +2284,8 @@ private void checkOpenAndReadPermissionByKeyDomain(KeyDomain keyDomain) keyDomain.getKey(), keyDomain.getDomain(), WorkbasketPermission.OPEN, - WorkbasketPermission.READ); + WorkbasketPermission.READ, + WorkbasketPermission.READTASKS); } catch (WorkbasketNotFoundException e) { LOGGER.warn( String.format( diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQuerySqlProvider.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQuerySqlProvider.java index f282b027ec..867994f952 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQuerySqlProvider.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQuerySqlProvider.java @@ -70,9 +70,11 @@ public static String queryTaskSummaries() { + "ORDER BY ${item}" + " " + " " - + "FETCH FIRST ROW ONLY FOR UPDATE" + + "FETCH FIRST ROW ONLY FOR UPDATE " + "" - + "WITH RS USE AND KEEP UPDATE LOCKS " + + "WITH RS USE " + + "AND KEEP UPDATE LOCKS " + + "WITH UR " + CLOSING_SCRIPT_TAG; } @@ -126,7 +128,8 @@ public static String queryTaskSummariesDb2() { + "s.ACCESS_ID IN " + "(#{item}) " + "and " - + "s.WORKBASKET_ID = X.WORKBASKET_ID AND s.perm_read = 1 fetch first 1 rows only" + + "s.WORKBASKET_ID = X.WORKBASKET_ID AND s.perm_read = 1 AND s.perm_readtasks = 1" + + " fetch first 1 rows only" + "" + " " + "VALUES(1)" @@ -269,7 +272,8 @@ public static String countQueryTasksDb2() { + "WHERE s.ACCESS_ID IN " + "(#{item}) " + "and " - + "s.WORKBASKET_ID = X.WORKBASKET_ID AND s.perm_read = 1 fetch first 1 rows only " + + "s.WORKBASKET_ID = X.WORKBASKET_ID AND s.perm_read = 1 AND s.perm_readtasks = 1" + + " fetch first 1 rows only " + " " + "" + "VALUES(1)" @@ -385,16 +389,18 @@ private static String checkForAuthorization() { + "FROM (" + "" + "" - + "SELECT WORKBASKET_ID as WID, MAX(PERM_READ) as MAX_READ " + + "SELECT WORKBASKET_ID as WID, MAX(PERM_READ) as MAX_READ, " + + "MAX(PERM_READTASKS) as MAX_READTASKS " + "" + "" - + "SELECT WORKBASKET_ID as WID, MAX(PERM_READ::int) as MAX_READ " + + "SELECT WORKBASKET_ID as WID, MAX(PERM_READ::int) as MAX_READ, " + + "MAX(PERM_READTASKS::int) as MAX_READTASKS " + "" + "" + "FROM WORKBASKET_ACCESS_LIST s where ACCESS_ID IN " + "(#{item}) " + "GROUP by WORKBASKET_ID) f " - + "WHERE MAX_READ = 1) " + + "WHERE MAX_READ = 1 AND MAX_READTASKS = 1) " + ""; } @@ -429,9 +435,7 @@ private static String groupBySorIfActive() { } private static String openOuterClauseForGroupByPorOrSor() { - return " " - + "SELECT * FROM (" - + " "; + return " " + "SELECT * FROM (" + " "; } private static String closeOuterClauseForGroupByPor() { diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java index 4fe06b386f..2ee0394554 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java @@ -46,6 +46,7 @@ import pro.taskana.spi.history.api.events.task.TaskClaimedEvent; import pro.taskana.spi.history.api.events.task.TaskCompletedEvent; import pro.taskana.spi.history.api.events.task.TaskCreatedEvent; +import pro.taskana.spi.history.api.events.task.TaskDeletedEvent; import pro.taskana.spi.history.api.events.task.TaskRequestChangesEvent; import pro.taskana.spi.history.api.events.task.TaskRequestReviewEvent; import pro.taskana.spi.history.api.events.task.TaskTerminatedEvent; @@ -58,6 +59,7 @@ import pro.taskana.spi.task.internal.BeforeRequestReviewManager; import pro.taskana.spi.task.internal.CreateTaskPreprocessorManager; import pro.taskana.spi.task.internal.ReviewRequiredManager; +import pro.taskana.spi.task.internal.TaskEndstatePreprocessorManager; import pro.taskana.task.api.CallbackState; import pro.taskana.task.api.TaskCommentQuery; import pro.taskana.task.api.TaskCustomField; @@ -123,6 +125,7 @@ public class TaskServiceImpl implements TaskService { private final AfterRequestReviewManager afterRequestReviewManager; private final BeforeRequestChangesManager beforeRequestChangesManager; private final AfterRequestChangesManager afterRequestChangesManager; + private final TaskEndstatePreprocessorManager taskEndstatePreprocessorManager; public TaskServiceImpl( InternalTaskanaEngine taskanaEngine, @@ -146,6 +149,7 @@ public TaskServiceImpl( this.afterRequestReviewManager = taskanaEngine.getAfterRequestReviewManager(); this.beforeRequestChangesManager = taskanaEngine.getBeforeRequestChangesManager(); this.afterRequestChangesManager = taskanaEngine.getAfterRequestChangesManager(); + this.taskEndstatePreprocessorManager = taskanaEngine.getTaskEndstatePreprocessorManager(); this.taskTransferrer = new TaskTransferrer(taskanaEngine, taskMapper, this); this.taskCommentService = new TaskCommentServiceImpl(taskanaEngine, taskCommentMapper, userMapper, this); @@ -179,14 +183,33 @@ public Task cancelClaim(String taskId) InvalidOwnerException, NotAuthorizedOnWorkbasketException, InvalidTaskStateException { - return this.cancelClaim(taskId, false); + return this.cancelClaim(taskId, false, false); } @Override public Task forceCancelClaim(String taskId) throws TaskNotFoundException, InvalidTaskStateException, NotAuthorizedOnWorkbasketException { try { - return this.cancelClaim(taskId, true); + return this.cancelClaim(taskId, true, false); + } catch (InvalidOwnerException e) { + throw new SystemException("this should not have happened. You've discovered a new bug!", e); + } + } + + @Override + public Task cancelClaim(String taskId, boolean keepOwner) + throws TaskNotFoundException, + InvalidOwnerException, + NotAuthorizedOnWorkbasketException, + InvalidTaskStateException { + return this.cancelClaim(taskId, false, keepOwner); + } + + @Override + public Task forceCancelClaim(String taskId, boolean keepOwner) + throws TaskNotFoundException, InvalidTaskStateException, NotAuthorizedOnWorkbasketException { + try { + return this.cancelClaim(taskId, true, keepOwner); } catch (InvalidOwnerException e) { throw new SystemException("this should not have happened. You've discovered a new bug!", e); } @@ -381,12 +404,14 @@ public Task getTask(String id) throws NotAuthorizedOnWorkbasketException, TaskNo WorkbasketQueryImpl query = (WorkbasketQueryImpl) workbasketService.createWorkbasketQuery(); query.setUsedToAugmentTasks(true); String workbasketId = resultTask.getWorkbasketSummary().getId(); - List workbaskets = query.idIn(workbasketId).list(); + List workbaskets = + query.idIn(workbasketId).callerHasPermissions(WorkbasketPermission.READTASKS).list(); if (workbaskets.isEmpty()) { throw new NotAuthorizedOnWorkbasketException( taskanaEngine.getEngine().getCurrentUserContext().getUserid(), workbasketId, - WorkbasketPermission.READ); + WorkbasketPermission.READ, + WorkbasketPermission.READTASKS); } else { resultTask.setWorkbasketSummary(workbaskets.get(0)); } @@ -542,6 +567,12 @@ public Task updateTask(Task task) TaskImpl oldTaskImpl = (TaskImpl) getTask(newTaskImpl.getId()); checkConcurrencyAndSetModified(newTaskImpl, oldTaskImpl); + if (!checkEditTasksPerm(oldTaskImpl)) { + throw new NotAuthorizedOnWorkbasketException( + taskanaEngine.getEngine().getCurrentUserContext().getUserid(), + oldTaskImpl.getWorkbasketSummary().getId(), + WorkbasketPermission.EDITTASKS); + } attachmentHandler.insertAndDeleteAttachmentsOnTaskUpdate(newTaskImpl, oldTaskImpl); objectReferenceHandler.insertAndDeleteObjectReferencesOnTaskUpdate(newTaskImpl, oldTaskImpl); @@ -622,11 +653,18 @@ public void forceDeleteTask(String taskId) } @Override - public Optional selectAndClaim(TaskQuery taskQuery) { + public Optional selectAndClaim(TaskQuery taskQuery) + throws NotAuthorizedOnWorkbasketException { ((TaskQueryImpl) taskQuery).selectAndClaimEquals(true); - return taskanaEngine.executeInDatabaseConnection( - () -> - Optional.ofNullable(taskQuery.single()).map(TaskSummary::getId).map(wrap(this::claim))); + try { + return taskanaEngine.executeInDatabaseConnection( + () -> + Optional.ofNullable(taskQuery.single()) + .map(TaskSummary::getId) + .map(wrap(this::claim))); + } catch (Exception e) { + return Optional.empty(); + } } @Override @@ -667,6 +705,9 @@ public BulkOperationResults deleteTasks(List t .isDeleteHistoryEventsOnTaskDeletionEnabled()) { historyEventManager.deleteEvents(taskIds); } + if (historyEventManager.isEnabled()) { + taskIds.forEach(this::createTaskDeletedEvent); + } } return bulkLog; } finally { @@ -702,9 +743,17 @@ public List updateTasks( // use query in order to find only those tasks that are visible to the current user List taskSummaries = getTasksToChange(selectionCriteria); + List tasksWithPermissions = new ArrayList<>(); + for (TaskSummary taskSummary : taskSummaries) { + if (checkEditTasksPerm(taskSummary)) { + tasksWithPermissions.add(taskSummary); + } + } + List changedTasks = new ArrayList<>(); - if (!taskSummaries.isEmpty()) { - changedTasks = taskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList()); + if (!tasksWithPermissions.isEmpty()) { + changedTasks = + tasksWithPermissions.stream().map(TaskSummary::getId).collect(Collectors.toList()); taskMapper.updateTasks(changedTasks, updated, fieldSelector); if (LOGGER.isDebugEnabled()) { LOGGER.debug("updateTasks() updated the following tasks: {} ", changedTasks); @@ -736,9 +785,17 @@ public List updateTasks( // use query in order to find only those tasks that are visible to the current user List taskSummaries = getTasksToChange(taskIds); + List tasksWithPermissions = new ArrayList<>(); + for (TaskSummary taskSummary : taskSummaries) { + if (checkEditTasksPerm(taskSummary)) { + tasksWithPermissions.add(taskSummary); + } + } + List changedTasks = new ArrayList<>(); - if (!taskSummaries.isEmpty()) { - changedTasks = taskSummaries.stream().map(TaskSummary::getId).collect(Collectors.toList()); + if (!tasksWithPermissions.isEmpty()) { + changedTasks = + tasksWithPermissions.stream().map(TaskSummary::getId).collect(Collectors.toList()); taskMapper.updateTasks(changedTasks, updatedTask, fieldSelector); if (LOGGER.isDebugEnabled()) { LOGGER.debug("updateTasks() updated the following tasks: {} ", changedTasks); @@ -889,12 +946,35 @@ public BulkOperationResults setPlannedPropertyOfTasks( public Task cancelTask(String taskId) throws TaskNotFoundException, NotAuthorizedOnWorkbasketException, InvalidTaskStateException { - Task cancelledTask; + TaskImpl cancelledTask; try { taskanaEngine.openConnection(); - cancelledTask = terminateCancelCommonActions(taskId, TaskState.CANCELLED); + if (taskId == null || taskId.isEmpty()) { + throw new TaskNotFoundException(taskId); + } + cancelledTask = (TaskImpl) getTask(taskId); + TaskState state = cancelledTask.getState(); + if (state.isEndState()) { + throw new InvalidTaskStateException( + taskId, + state, + TaskState.READY, + TaskState.CLAIMED, + TaskState.READY_FOR_REVIEW, + TaskState.IN_REVIEW); + } + terminateCancelCommonActions(cancelledTask, TaskState.CANCELLED); + cancelledTask = + (TaskImpl) taskEndstatePreprocessorManager.processTaskBeforeEndstate(cancelledTask); + taskMapper.update(cancelledTask); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "Task '{}' cancelled by user '{}'.", + taskId, + taskanaEngine.getEngine().getCurrentUserContext().getUserid()); + } if (historyEventManager.isEnabled()) { historyEventManager.createEvent( new TaskCancelledEvent( @@ -918,12 +998,35 @@ public Task terminateTask(String taskId) taskanaEngine.getEngine().checkRoleMembership(TaskanaRole.ADMIN, TaskanaRole.TASK_ADMIN); - Task terminatedTask; + TaskImpl terminatedTask; try { taskanaEngine.openConnection(); - terminatedTask = terminateCancelCommonActions(taskId, TaskState.TERMINATED); + if (taskId == null || taskId.isEmpty()) { + throw new TaskNotFoundException(taskId); + } + terminatedTask = (TaskImpl) getTask(taskId); + TaskState state = terminatedTask.getState(); + if (state.isEndState()) { + throw new InvalidTaskStateException( + taskId, + state, + TaskState.READY, + TaskState.CLAIMED, + TaskState.READY_FOR_REVIEW, + TaskState.IN_REVIEW); + } + terminateCancelCommonActions(terminatedTask, TaskState.TERMINATED); + terminatedTask = + (TaskImpl) taskEndstatePreprocessorManager.processTaskBeforeEndstate(terminatedTask); + taskMapper.update(terminatedTask); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "Task '{}' cancelled by user '{}'.", + taskId, + taskanaEngine.getEngine().getCurrentUserContext().getUserid()); + } if (historyEventManager.isEnabled()) { historyEventManager.createEvent( new TaskTerminatedEvent( @@ -1225,35 +1328,11 @@ private void checkConcurrencyAndSetModified(TaskImpl newTaskImpl, TaskImpl oldTa newTaskImpl.setModified(Instant.now()); } - private TaskImpl terminateCancelCommonActions(String taskId, TaskState targetState) - throws TaskNotFoundException, NotAuthorizedOnWorkbasketException, InvalidTaskStateException { - if (taskId == null || taskId.isEmpty()) { - throw new TaskNotFoundException(taskId); - } - TaskImpl task = (TaskImpl) getTask(taskId); - TaskState state = task.getState(); - if (state.isEndState()) { - throw new InvalidTaskStateException( - taskId, - state, - TaskState.READY, - TaskState.CLAIMED, - TaskState.READY_FOR_REVIEW, - TaskState.IN_REVIEW); - } - + private static void terminateCancelCommonActions(TaskImpl task, TaskState targetState) { Instant now = Instant.now(); task.setModified(now); task.setCompleted(now); task.setState(targetState); - taskMapper.update(task); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug( - "Task '{}' cancelled by user '{}'.", - taskId, - taskanaEngine.getEngine().getCurrentUserContext().getUserid()); - } - return task; } private Task claim(String taskId, boolean forceClaim) @@ -1420,8 +1499,12 @@ private static void claimActionsOnTask( } } - private static void cancelClaimActionsOnTask(TaskSummaryImpl task, Instant now) { - task.setOwner(null); + private static void cancelClaimActionsOnTask( + TaskSummaryImpl task, Instant now, boolean keepOwner) { + if (!keepOwner) { + task.setOwner(null); + task.setOwnerLongName(null); + } task.setModified(now); task.setClaimed(null); task.setRead(true); @@ -1440,7 +1523,7 @@ private static void completeActionsOnTask(TaskSummaryImpl task, String userId, I } private void checkPreconditionsForClaimTask(TaskSummary task, boolean forced) - throws InvalidOwnerException, InvalidTaskStateException { + throws InvalidOwnerException, InvalidTaskStateException, NotAuthorizedOnWorkbasketException { TaskState state = task.getState(); if (state.isEndState()) { throw new InvalidTaskStateException( @@ -1453,6 +1536,12 @@ private void checkPreconditionsForClaimTask(TaskSummary task, boolean forced) && !task.getOwner().equals(userId)) { throw new InvalidOwnerException(userId, task.getId()); } + if (!checkEditTasksPerm(task)) { + throw new NotAuthorizedOnWorkbasketException( + taskanaEngine.getEngine().getCurrentUserContext().getUserid(), + task.getWorkbasketSummary().getId(), + WorkbasketPermission.EDITTASKS); + } } private static boolean taskIsNotClaimed(TaskSummary task) { @@ -1471,7 +1560,7 @@ private static void checkIfTaskIsTerminatedOrCancelled(TaskSummary task) } private void checkPreconditionsForCompleteTask(TaskSummary task) - throws InvalidOwnerException, InvalidTaskStateException { + throws InvalidOwnerException, InvalidTaskStateException, NotAuthorizedOnWorkbasketException { if (taskIsNotClaimed(task)) { throw new InvalidTaskStateException( task.getId(), task.getState(), TaskState.CLAIMED, TaskState.IN_REVIEW); @@ -1484,9 +1573,15 @@ private void checkPreconditionsForCompleteTask(TaskSummary task) throw new InvalidOwnerException( taskanaEngine.getEngine().getCurrentUserContext().getUserid(), task.getId()); } + if (!checkEditTasksPerm(task)) { + throw new NotAuthorizedOnWorkbasketException( + taskanaEngine.getEngine().getCurrentUserContext().getUserid(), + task.getWorkbasketSummary().getId(), + WorkbasketPermission.EDITTASKS); + } } - private Task cancelClaim(String taskId, boolean forceUnclaim) + private Task cancelClaim(String taskId, boolean forceUnclaim, boolean keepOwner) throws TaskNotFoundException, InvalidOwnerException, NotAuthorizedOnWorkbasketException, @@ -1496,10 +1591,15 @@ private Task cancelClaim(String taskId, boolean forceUnclaim) try { taskanaEngine.openConnection(); task = (TaskImpl) getTask(taskId); - TaskImpl oldTask = duplicateTaskExactly(task); TaskState state = task.getState(); + if (!checkEditTasksPerm(task)) { + throw new NotAuthorizedOnWorkbasketException( + taskanaEngine.getEngine().getCurrentUserContext().getUserid(), + task.getWorkbasketSummary().getId(), + WorkbasketPermission.EDITTASKS); + } if (state.isEndState()) { throw new InvalidTaskStateException( taskId, state, EnumUtil.allValuesExceptFor(TaskState.END_STATES)); @@ -1510,7 +1610,7 @@ private Task cancelClaim(String taskId, boolean forceUnclaim) throw new InvalidOwnerException(userId, taskId); } Instant now = Instant.now(); - cancelClaimActionsOnTask(task, now); + cancelClaimActionsOnTask(task, now, keepOwner); taskMapper.update(task); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Task '{}' unclaimed by user '{}'.", taskId, userId); @@ -1560,6 +1660,7 @@ private Task completeTask(String taskId, boolean isForced) Instant now = Instant.now(); completeActionsOnTask(task, userId, now); + task = (TaskImpl) taskEndstatePreprocessorManager.processTaskBeforeEndstate(task); taskMapper.update(task); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Task '{}' completed by user '{}'.", taskId, userId); @@ -1612,6 +1713,10 @@ private void deleteTask(String taskId, boolean forceDelete) historyEventManager.deleteEvents(Collections.singletonList(taskId)); } + if (historyEventManager.isEnabled()) { + createTaskDeletedEvent(taskId); + } + if (LOGGER.isDebugEnabled()) { LOGGER.debug("Task {} deleted.", taskId); } @@ -2110,6 +2215,12 @@ private void standardUpdateActions(TaskImpl oldTaskImpl, TaskImpl newTaskImpl) throw new InvalidTaskStateException( oldTaskImpl.getId(), oldTaskImpl.getState(), TaskState.READY, TaskState.READY_FOR_REVIEW); } + if (isOwnerChanged && taskanaEngine.getEngine().getConfiguration().isAddAdditionalUserInfo()) { + User user = userMapper.findById(newTaskImpl.getOwner()); + if (user != null) { + newTaskImpl.setOwnerLongName(user.getLongName()); + } + } } private void updateClassificationSummary(TaskImpl newTaskImpl, TaskImpl oldTaskImpl) @@ -2138,6 +2249,15 @@ private void createTasksCompletedEvents(List taskSummarie taskanaEngine.getEngine().getCurrentUserContext().getUserid()))); } + private void createTaskDeletedEvent(String taskId) { + historyEventManager.createEvent( + new TaskDeletedEvent( + IdGenerator.generateWithPrefix(IdGenerator.ID_PREFIX_TASK_HISTORY_EVENT), + newTask().asSummary(), + taskId, + taskanaEngine.getEngine().getCurrentUserContext().getUserid())); + } + private TaskImpl duplicateTaskExactly(TaskImpl task) { TaskImpl oldTask = task.copy(); oldTask.setId(task.getId()); @@ -2146,4 +2266,12 @@ private TaskImpl duplicateTaskExactly(TaskImpl task) { oldTask.setSecondaryObjectReferences(task.getSecondaryObjectReferences()); return oldTask; } + + private boolean checkEditTasksPerm(TaskSummary task) { + WorkbasketQueryImpl query = (WorkbasketQueryImpl) workbasketService.createWorkbasketQuery(); + String workbasketId = task.getWorkbasketSummary().getId(); + WorkbasketSummary workbasket = + query.idIn(workbasketId).callerHasPermissions(WorkbasketPermission.EDITTASKS).single(); + return workbasket != null; + } } diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/jobs/TaskCleanupJob.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/jobs/TaskCleanupJob.java index ea6ea3d4a1..a49def5386 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/jobs/TaskCleanupJob.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/jobs/TaskCleanupJob.java @@ -11,6 +11,7 @@ import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import pro.taskana.TaskanaConfiguration; import pro.taskana.common.api.BaseQuery.SortDirection; import pro.taskana.common.api.BulkOperationResults; import pro.taskana.common.api.ScheduledJob; @@ -64,6 +65,10 @@ public void execute() { } } + public static Duration getLockExpirationPeriod(TaskanaConfiguration taskanaConfiguration) { + return taskanaConfiguration.getTaskCleanupJobLockExpirationPeriod(); + } + @Override protected String getType() { return TaskCleanupJob.class.getName(); diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/jobs/TaskUpdatePriorityJob.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/jobs/TaskUpdatePriorityJob.java index 468cad90f5..76b2c735b4 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/jobs/TaskUpdatePriorityJob.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/jobs/TaskUpdatePriorityJob.java @@ -2,8 +2,10 @@ import static pro.taskana.common.internal.util.CollectionUtil.partitionBasedOnSize; +import java.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import pro.taskana.TaskanaConfiguration; import pro.taskana.common.api.ScheduledJob; import pro.taskana.common.api.TaskanaEngine; import pro.taskana.common.api.exceptions.SystemException; @@ -45,6 +47,10 @@ public void execute() { } } + public static Duration getLockExpirationPeriod(TaskanaConfiguration taskanaConfiguration) { + return taskanaConfiguration.getTaskUpdatePriorityJobLockExpirationPeriod(); + } + public int getBatchSize() { return batchSize; } diff --git a/lib/taskana-core/src/main/java/pro/taskana/user/api/models/User.java b/lib/taskana-core/src/main/java/pro/taskana/user/api/models/User.java index 7e820efc78..f415d56ea0 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/user/api/models/User.java +++ b/lib/taskana-core/src/main/java/pro/taskana/user/api/models/User.java @@ -34,6 +34,20 @@ public interface User { */ void setGroups(Set groups); + /** + * Returns the permissions of the User. + * + * @return permissions + */ + Set getPermissions(); + + /** + * Sets the permissions of the User. + * + * @param permissions the permissions of the User + */ + void setPermissions(Set permissions); + /** * Returns the first name of the User. * diff --git a/lib/taskana-core/src/main/java/pro/taskana/user/internal/UserMapper.java b/lib/taskana-core/src/main/java/pro/taskana/user/internal/UserMapper.java index 08de1c9fad..c3115ffb3f 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/user/internal/UserMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/user/internal/UserMapper.java @@ -16,6 +16,8 @@ public interface UserMapper { @SelectProvider(type = UserMapperSqlProvider.class, method = "findById") @Result(property = "id", column = "USER_ID") @Result(property = "groups", column = "USER_ID", many = @Many(select = "findGroupsById")) + @Result(property = "permissions", column = "USER_ID", + many = @Many(select = "findPermissionsById")) @Result(property = "firstName", column = "FIRST_NAME") @Result(property = "lastName", column = "LASTNAME") @Result(property = "fullName", column = "FULL_NAME") @@ -32,6 +34,8 @@ public interface UserMapper { @Result(property = "id", column = "USER_ID") @Result(property = "groups", column = "USER_ID", many = @Many(select = "findGroupsById")) + @Result(property = "permissions", column = "USER_ID", + many = @Many(select = "findPermissionsById")) @Result(property = "firstName", column = "FIRST_NAME") @Result(property = "lastName", column = "LASTNAME") @Result(property = "fullName", column = "FULL_NAME") @@ -50,6 +54,9 @@ public interface UserMapper { @SelectProvider(type = UserMapperSqlProvider.class, method = "findGroupsById") Set findGroupsById(String id); + @SelectProvider(type = UserMapperSqlProvider.class, method = "findPermissionsById") + Set findPermissionsById(String id); + @InsertProvider(type = UserMapperSqlProvider.class, method = "insert") void insert(User user); @@ -60,6 +67,13 @@ public interface UserMapper { @InsertProvider(type = UserMapperSqlProvider.class, method = "insertGroups") void insertGroups(User user); + @InsertProvider( + type = UserMapperSqlProvider.class, + method = "insertPermissionsOracle", + databaseId = "oracle") + @InsertProvider(type = UserMapperSqlProvider.class, method = "insertPermissions") + void insertPermissions(User user); + @UpdateProvider(type = UserMapperSqlProvider.class, method = "update") void update(User user); @@ -68,4 +82,7 @@ public interface UserMapper { @DeleteProvider(type = UserMapperSqlProvider.class, method = "deleteGroups") void deleteGroups(String id); + + @DeleteProvider(type = UserMapperSqlProvider.class, method = "deletePermissions") + void deletePermissions(String id); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/user/internal/UserMapperSqlProvider.java b/lib/taskana-core/src/main/java/pro/taskana/user/internal/UserMapperSqlProvider.java index 94b03c0e43..a25fe73f9a 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/user/internal/UserMapperSqlProvider.java +++ b/lib/taskana-core/src/main/java/pro/taskana/user/internal/UserMapperSqlProvider.java @@ -42,6 +42,13 @@ public static String findGroupsById() { + CLOSING_SCRIPT_TAG; } + public static String findPermissionsById() { + return OPENING_SCRIPT_TAG + + "SELECT PERMISSION_ID FROM PERMISSION_INFO WHERE USER_ID = #{id} " + + DB2_WITH_UR + + CLOSING_SCRIPT_TAG; + } + public static String insert() { return "INSERT INTO USER_INFO ( " + USER_INFO_COLUMNS + ") VALUES(" + USER_INFO_VALUES + ")"; } @@ -65,6 +72,26 @@ public static String insertGroupsOracle() { + CLOSING_SCRIPT_TAG; } + public static String insertPermissions() { + return OPENING_SCRIPT_TAG + + "INSERT INTO PERMISSION_INFO (USER_ID, PERMISSION_ID) VALUES " + + "" + + "#{id}, #{permission}" + + " " + + CLOSING_SCRIPT_TAG; + } + + public static String insertPermissionsOracle() { + return OPENING_SCRIPT_TAG + + "INSERT ALL " + + "" + + "INTO PERMISSION_INFO (USER_ID, PERMISSION_ID) VALUES ( #{id}, #{permission} )" + + " " + + "SELECT 1 FROM DUAL" + + CLOSING_SCRIPT_TAG; + } + public static String update() { return "UPDATE USER_INFO " + "SET FIRST_NAME = #{firstName}, " @@ -82,4 +109,8 @@ public static String delete() { public static String deleteGroups() { return "DELETE FROM GROUP_INFO WHERE USER_ID = #{id} "; } + + public static String deletePermissions() { + return "DELETE FROM PERMISSION_INFO WHERE USER_ID = #{id} "; + } } diff --git a/lib/taskana-core/src/main/java/pro/taskana/user/internal/UserServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/user/internal/UserServiceImpl.java index d1bacbf8fb..5455e20a7b 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/user/internal/UserServiceImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/user/internal/UserServiceImpl.java @@ -16,6 +16,7 @@ import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.api.exceptions.NotAuthorizedException; import pro.taskana.common.internal.InternalTaskanaEngine; +import pro.taskana.common.internal.util.LogSanitizer; import pro.taskana.user.api.UserService; import pro.taskana.user.api.exceptions.UserAlreadyExistException; import pro.taskana.user.api.exceptions.UserNotFoundException; @@ -103,7 +104,9 @@ public User createUser(User userToCreate) ((UserImpl) userToCreate).setDomains(determineDomains(userToCreate)); if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Method createUser() created User '{}'.", userToCreate); + LOGGER.debug( + "Method createUser() created User '{}'.", + LogSanitizer.stripLineBreakingChars(userToCreate)); } return userToCreate; } @@ -119,15 +122,24 @@ public User updateUser(User userToUpdate) internalTaskanaEngine.executeInDatabaseConnection(() -> userMapper.update(userToUpdate)); internalTaskanaEngine.executeInDatabaseConnection( - () -> userMapper.deleteGroups(userToUpdate.getId())); + () -> { + userMapper.deleteGroups(userToUpdate.getId()); + userMapper.deletePermissions(userToUpdate.getId()); + }); if (userToUpdate.getGroups() != null && !userToUpdate.getGroups().isEmpty()) { internalTaskanaEngine.executeInDatabaseConnection( () -> userMapper.insertGroups(userToUpdate)); } + if (userToUpdate.getPermissions() != null && !userToUpdate.getPermissions().isEmpty()) { + internalTaskanaEngine.executeInDatabaseConnection( + () -> userMapper.insertPermissions(userToUpdate)); + } ((UserImpl) userToUpdate).setDomains(determineDomains(userToUpdate)); if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Method updateUser() updated User '{}'.", userToUpdate); + LOGGER.debug( + "Method updateUser() updated User '{}'.", + LogSanitizer.stripLineBreakingChars(userToUpdate)); } return userToUpdate; @@ -145,6 +157,7 @@ public void deleteUser(String id) () -> { userMapper.delete(id); userMapper.deleteGroups(id); + userMapper.deletePermissions(id); }); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Method deleteUser() deleted User with id '{}'.", id); @@ -153,6 +166,7 @@ public void deleteUser(String id) private Set determineDomains(User user) { Set accessIds = new HashSet<>(user.getGroups()); + accessIds.addAll(user.getPermissions()); accessIds.add(user.getId()); if (minimalWorkbasketPermissions != null && !minimalWorkbasketPermissions.isEmpty()) { // since WorkbasketService#accessIdsHavePermissions requires some role permissions we have to @@ -181,6 +195,9 @@ private void insertIntoDatabase(User userToCreate) throws UserAlreadyExistExcept if (userToCreate.getGroups() != null && !userToCreate.getGroups().isEmpty()) { userMapper.insertGroups(userToCreate); } + if (userToCreate.getPermissions() != null && !userToCreate.getPermissions().isEmpty()) { + userMapper.insertPermissions(userToCreate); + } } catch (PersistenceException e) { throw new UserAlreadyExistException(userToCreate.getId(), e); } finally { @@ -209,6 +226,8 @@ private void standardCreateActions(User user) { user.setId(user.getId().toLowerCase()); user.setGroups( user.getGroups().stream().map((String::toLowerCase)).collect(Collectors.toSet())); + user.setPermissions( + user.getPermissions().stream().map((String::toLowerCase)).collect(Collectors.toSet())); } } @@ -230,6 +249,8 @@ private void standardUpdateActions(User oldUser, User newUser) { newUser.setId(newUser.getId().toLowerCase()); newUser.setGroups( newUser.getGroups().stream().map((String::toLowerCase)).collect(Collectors.toSet())); + newUser.setPermissions( + newUser.getPermissions().stream().map((String::toLowerCase)).collect(Collectors.toSet())); } } } diff --git a/lib/taskana-core/src/main/java/pro/taskana/user/internal/models/UserImpl.java b/lib/taskana-core/src/main/java/pro/taskana/user/internal/models/UserImpl.java index fbb6997688..0ef53abd44 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/user/internal/models/UserImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/user/internal/models/UserImpl.java @@ -8,6 +8,7 @@ public class UserImpl implements User { private String id; private Set groups = Collections.emptySet(); + private Set permissions = Collections.emptySet(); private String firstName; private String lastName; private String fullName; @@ -27,6 +28,7 @@ public UserImpl() {} protected UserImpl(UserImpl copyFrom) { this.id = copyFrom.id; this.groups = copyFrom.groups; + this.permissions = copyFrom.permissions; this.firstName = copyFrom.firstName; this.lastName = copyFrom.lastName; this.fullName = copyFrom.fullName; @@ -62,6 +64,16 @@ public void setGroups(Set groups) { this.groups = groups; } + @Override + public Set getPermissions() { + return permissions; + } + + @Override + public void setPermissions(Set permissions) { + this.permissions = permissions; + } + @Override public String getFirstName() { return firstName; @@ -201,6 +213,7 @@ public int hashCode() { return Objects.hash( id, groups, + permissions, firstName, lastName, fullName, @@ -230,6 +243,7 @@ public boolean equals(Object obj) { UserImpl other = (UserImpl) obj; return Objects.equals(id, other.id) && Objects.equals(groups, other.groups) + && Objects.equals(permissions, other.permissions) && Objects.equals(firstName, other.firstName) && Objects.equals(lastName, other.lastName) && Objects.equals(fullName, other.fullName) @@ -251,6 +265,8 @@ public String toString() { + id + ", groups=" + groups + + ", permissions=" + + permissions + ", firstName=" + firstName + ", lastName=" diff --git a/lib/taskana-core/src/main/java/pro/taskana/workbasket/api/WorkbasketCustomField.java b/lib/taskana-core/src/main/java/pro/taskana/workbasket/api/WorkbasketCustomField.java index 5c4c207ad6..6db2e86db0 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/workbasket/api/WorkbasketCustomField.java +++ b/lib/taskana-core/src/main/java/pro/taskana/workbasket/api/WorkbasketCustomField.java @@ -4,5 +4,9 @@ public enum WorkbasketCustomField { CUSTOM_1, CUSTOM_2, CUSTOM_3, - CUSTOM_4 + CUSTOM_4, + CUSTOM_5, + CUSTOM_6, + CUSTOM_7, + CUSTOM_8 } diff --git a/lib/taskana-core/src/main/java/pro/taskana/workbasket/api/WorkbasketPermission.java b/lib/taskana-core/src/main/java/pro/taskana/workbasket/api/WorkbasketPermission.java index 9c75d5a390..86d75e8f6d 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/workbasket/api/WorkbasketPermission.java +++ b/lib/taskana-core/src/main/java/pro/taskana/workbasket/api/WorkbasketPermission.java @@ -5,6 +5,8 @@ /** This enum contains all permission values for the {@linkplain Workbasket Workbaskets}. */ public enum WorkbasketPermission { READ, + READTASKS, + EDITTASKS, OPEN, APPEND, TRANSFER, diff --git a/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketAccessMapper.java b/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketAccessMapper.java index e8b0e2b4e9..c24279d16b 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketAccessMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketAccessMapper.java @@ -20,6 +20,8 @@ public interface WorkbasketAccessMapper { @Result(property = "accessId", column = "ACCESS_ID") @Result(property = "accessName", column = "ACCESS_NAME") @Result(property = "permRead", column = "PERM_READ") + @Result(property = "permReadTasks", column = "PERM_READTASKS") + @Result(property = "permEditTasks", column = "PERM_EDITTASKS") @Result(property = "permOpen", column = "PERM_OPEN") @Result(property = "permAppend", column = "PERM_APPEND") @Result(property = "permTransfer", column = "PERM_TRANSFER") @@ -45,6 +47,8 @@ public interface WorkbasketAccessMapper { @Result(property = "accessId", column = "ACCESS_ID") @Result(property = "accessName", column = "ACCESS_NAME") @Result(property = "permRead", column = "PERM_READ") + @Result(property = "permReadTasks", column = "PERM_READTASKS") + @Result(property = "permEditTasks", column = "PERM_EDITTASKS") @Result(property = "permOpen", column = "PERM_OPEN") @Result(property = "permAppend", column = "PERM_APPEND") @Result(property = "permTransfer", column = "PERM_TRANSFER") @@ -70,6 +74,8 @@ public interface WorkbasketAccessMapper { @Result(property = "accessId", column = "ACCESS_ID") @Result(property = "accessName", column = "ACCESS_NAME") @Result(property = "permRead", column = "PERM_READ") + @Result(property = "permReadTasks", column = "PERM_READTASKS") + @Result(property = "permEditTasks", column = "PERM_EDITTASKS") @Result(property = "permOpen", column = "PERM_OPEN") @Result(property = "permAppend", column = "PERM_APPEND") @Result(property = "permTransfer", column = "PERM_TRANSFER") @@ -112,6 +118,8 @@ public interface WorkbasketAccessMapper { @Result(property = "accessId", column = "ACCESS_ID") @Result(property = "accessName", column = "ACCESS_NAME") @Result(property = "permRead", column = "PERM_READ") + @Result(property = "permReadTasks", column = "PERM_READTASKS") + @Result(property = "permEditTasks", column = "PERM_EDITTASKS") @Result(property = "permOpen", column = "PERM_OPEN") @Result(property = "permAppend", column = "PERM_APPEND") @Result(property = "permTransfer", column = "PERM_TRANSFER") @@ -138,6 +146,8 @@ WorkbasketAccessItemImpl findByWorkbasketAndAccessId( @Result(property = "accessId", column = "ACCESS_ID") @Result(property = "accessName", column = "ACCESS_NAME") @Result(property = "permRead", column = "PERM_READ") + @Result(property = "permReadTasks", column = "PERM_READTASKS") + @Result(property = "permEditTasks", column = "PERM_EDITTASKS") @Result(property = "permOpen", column = "PERM_OPEN") @Result(property = "permAppend", column = "PERM_APPEND") @Result(property = "permTransfer", column = "PERM_TRANSFER") diff --git a/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketAccessSqlProvider.java b/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketAccessSqlProvider.java index 60d233a1be..73e73107ab 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketAccessSqlProvider.java +++ b/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketAccessSqlProvider.java @@ -21,6 +21,8 @@ public class WorkbasketAccessSqlProvider { private static final List> PERMISSIONS = Arrays.asList( Pair.of("PERM_READ", "#{workbasketAccessItem.permRead}"), + Pair.of("PERM_READTASKS", "#{workbasketAccessItem.permReadTasks}"), + Pair.of("PERM_EDITTASKS", "#{workbasketAccessItem.permEditTasks}"), Pair.of("PERM_OPEN", "#{workbasketAccessItem.permOpen}"), Pair.of("PERM_APPEND", "#{workbasketAccessItem.permAppend}"), Pair.of("PERM_TRANSFER", "#{workbasketAccessItem.permTransfer}"), diff --git a/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketMapper.java b/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketMapper.java index f98506150b..0713915c75 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketMapper.java @@ -34,6 +34,10 @@ public interface WorkbasketMapper { @Result(property = "orgLevel3", column = "ORG_LEVEL_3") @Result(property = "orgLevel4", column = "ORG_LEVEL_4") @Result(property = "markedForDeletion", column = "MARKED_FOR_DELETION") + @Result(property = "custom5", column = "CUSTOM_5") + @Result(property = "custom6", column = "CUSTOM_6") + @Result(property = "custom7", column = "CUSTOM_7") + @Result(property = "custom8", column = "CUSTOM_8") WorkbasketImpl findById(@Param("id") String id); @SelectProvider(type = WorkbasketSqlProvider.class, method = "findByKeyAndDomain") @@ -55,6 +59,10 @@ public interface WorkbasketMapper { @Result(property = "orgLevel3", column = "ORG_LEVEL_3") @Result(property = "orgLevel4", column = "ORG_LEVEL_4") @Result(property = "markedForDeletion", column = "MARKED_FOR_DELETION") + @Result(property = "custom5", column = "CUSTOM_5") + @Result(property = "custom6", column = "CUSTOM_6") + @Result(property = "custom7", column = "CUSTOM_7") + @Result(property = "custom8", column = "CUSTOM_8") WorkbasketImpl findByKeyAndDomain(@Param("key") String key, @Param("domain") String domain); @SelectProvider(type = WorkbasketSqlProvider.class, method = "findDistributionTargets") @@ -73,6 +81,10 @@ public interface WorkbasketMapper { @Result(property = "orgLevel2", column = "ORG_LEVEL_2") @Result(property = "orgLevel3", column = "ORG_LEVEL_3") @Result(property = "orgLevel4", column = "ORG_LEVEL_4") + @Result(property = "custom5", column = "CUSTOM_5") + @Result(property = "custom6", column = "CUSTOM_6") + @Result(property = "custom7", column = "CUSTOM_7") + @Result(property = "custom8", column = "CUSTOM_8") List findDistributionTargets(@Param("id") String id); @SelectProvider(type = WorkbasketSqlProvider.class, method = "findDistributionSources") @@ -91,6 +103,10 @@ public interface WorkbasketMapper { @Result(property = "orgLevel2", column = "ORG_LEVEL_2") @Result(property = "orgLevel3", column = "ORG_LEVEL_3") @Result(property = "orgLevel4", column = "ORG_LEVEL_4") + @Result(property = "custom5", column = "CUSTOM_5") + @Result(property = "custom6", column = "CUSTOM_6") + @Result(property = "custom7", column = "CUSTOM_7") + @Result(property = "custom8", column = "CUSTOM_8") List findDistributionSources(@Param("id") String id); @SelectProvider(type = WorkbasketSqlProvider.class, method = "findSummaryById") @@ -109,6 +125,10 @@ public interface WorkbasketMapper { @Result(property = "orgLevel2", column = "ORG_LEVEL_2") @Result(property = "orgLevel3", column = "ORG_LEVEL_3") @Result(property = "orgLevel4", column = "ORG_LEVEL_4") + @Result(property = "custom5", column = "CUSTOM_5") + @Result(property = "custom6", column = "CUSTOM_6") + @Result(property = "custom7", column = "CUSTOM_7") + @Result(property = "custom8", column = "CUSTOM_8") List findSummaryById(@Param("key") String id); @SelectProvider(type = WorkbasketSqlProvider.class, method = "findAll") @@ -127,6 +147,10 @@ public interface WorkbasketMapper { @Result(property = "orgLevel2", column = "ORG_LEVEL_2") @Result(property = "orgLevel3", column = "ORG_LEVEL_3") @Result(property = "orgLevel4", column = "ORG_LEVEL_4") + @Result(property = "custom5", column = "CUSTOM_5") + @Result(property = "custom6", column = "CUSTOM_6") + @Result(property = "custom7", column = "CUSTOM_7") + @Result(property = "custom8", column = "CUSTOM_8") List findAll(); @InsertProvider(type = WorkbasketSqlProvider.class, method = "insert") diff --git a/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketQueryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketQueryImpl.java index bdf56c594c..bd253fef76 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketQueryImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketQueryImpl.java @@ -59,6 +59,14 @@ public class WorkbasketQueryImpl implements WorkbasketQuery { private String[] custom3Like; private String[] custom4In; private String[] custom4Like; + private String[] custom5In; + private String[] custom5Like; + private String[] custom6In; + private String[] custom6Like; + private String[] custom7In; + private String[] custom7Like; + private String[] custom8In; + private String[] custom8Like; private String[] orgLevel1In; private String[] orgLevel1Like; private String[] orgLevel2In; @@ -271,6 +279,18 @@ public WorkbasketQuery customAttributeIn( case CUSTOM_4: custom4In = searchArguments; break; + case CUSTOM_5: + custom5In = searchArguments; + break; + case CUSTOM_6: + custom6In = searchArguments; + break; + case CUSTOM_7: + custom7In = searchArguments; + break; + case CUSTOM_8: + custom8In = searchArguments; + break; default: throw new SystemException("Unknown customField '" + customField + "'"); } @@ -293,6 +313,18 @@ public WorkbasketQuery customAttributeLike( case CUSTOM_4: custom4Like = toLowerCopy(searchArguments); break; + case CUSTOM_5: + custom5Like = toLowerCopy(searchArguments); + break; + case CUSTOM_6: + custom6Like = toLowerCopy(searchArguments); + break; + case CUSTOM_7: + custom7Like = toLowerCopy(searchArguments); + break; + case CUSTOM_8: + custom8Like = toLowerCopy(searchArguments); + break; default: throw new SystemException("Unknown customField '" + customField + "'"); } @@ -512,6 +544,38 @@ public String[] getCustom4Like() { return custom4Like; } + public String[] getCustom5In() { + return custom5In; + } + + public String[] getCustom5Like() { + return custom5Like; + } + + public String[] getCustom6In() { + return custom6In; + } + + public String[] getCustom6Like() { + return custom6Like; + } + + public String[] getCustom7In() { + return custom7In; + } + + public String[] getCustom7Like() { + return custom7Like; + } + + public String[] getCustom8In() { + return custom8In; + } + + public String[] getCustom8Like() { + return custom8Like; + } + public String[] getOrgLevel1In() { return orgLevel1In; } @@ -702,6 +766,22 @@ public String toString() { + Arrays.toString(custom4In) + ", custom4Like=" + Arrays.toString(custom4Like) + + ", custom5In=" + + Arrays.toString(custom5In) + + ", custom5Like=" + + Arrays.toString(custom5Like) + + ", custom6In=" + + Arrays.toString(custom6In) + + ", custom6Like=" + + Arrays.toString(custom6Like) + + ", custom7In=" + + Arrays.toString(custom7In) + + ", custom7Like=" + + Arrays.toString(custom7Like) + + ", custom8In=" + + Arrays.toString(custom8In) + + ", custom8Like=" + + Arrays.toString(custom8Like) + ", orgLevel1In=" + Arrays.toString(orgLevel1In) + ", orgLevel1Like=" diff --git a/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketQueryMapper.java b/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketQueryMapper.java index 4cea03abb9..a69e4bea08 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketQueryMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/workbasket/internal/WorkbasketQueryMapper.java @@ -14,17 +14,17 @@ public interface WorkbasketQueryMapper { @Select( "