Merge branch 'master' of github.com:Alfresco/alfresco-community-repo into feature/MNT-24127-EndpointToCalculateFolderSize

# Conflicts:
#	remote-api/src/test/java/org/alfresco/AppContext04TestSuite.java
This commit is contained in:
mohit-singh4
2024-10-07 13:02:01 +05:30
92 changed files with 7416 additions and 1519 deletions

View File

@@ -42,9 +42,16 @@ jobs:
!contains(github.event.head_commit.message, '[force') !contains(github.event.head_commit.message, '[force')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 with:
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 fetch-depth: 0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- id: changed-files
uses: Alfresco/alfresco-build-tools/.github/actions/github-list-changes@v7.1.0
with:
write-list-to-env: true
- uses: Alfresco/alfresco-build-tools/.github/actions/pre-commit@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- name: "Prepare maven cache and check compilation" - name: "Prepare maven cache and check compilation"
@@ -62,12 +69,12 @@ jobs:
!contains(github.event.head_commit.message, '[force') !contains(github.event.head_commit.message, '[force')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- uses: Alfresco/alfresco-build-tools/.github/actions/veracode@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/veracode@v7.1.0
continue-on-error: true continue-on-error: true
with: with:
srcclr-api-token: ${{ secrets.SRCCLR_API_TOKEN }} srcclr-api-token: ${{ secrets.SRCCLR_API_TOKEN }}
@@ -85,10 +92,10 @@ jobs:
!contains(github.event.head_commit.message, '[force') !contains(github.event.head_commit.message, '[force')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/github-download-file@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/github-download-file@v7.1.0
with: with:
token: ${{ secrets.BOT_GITHUB_TOKEN }} token: ${{ secrets.BOT_GITHUB_TOKEN }}
repository: "Alfresco/veracode-baseline-archive" repository: "Alfresco/veracode-baseline-archive"
@@ -135,10 +142,10 @@ jobs:
!contains(github.event.head_commit.message, '[skip tests]') && !contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]') !contains(github.event.head_commit.message, '[force]')
steps: steps:
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- uses: Alfresco/ya-pmd-scan@v4.0.0 - uses: Alfresco/ya-pmd-scan@v4.1.0
with: with:
classpath-build-command: "mvn test-compile -ntp -Pags -pl \"-:alfresco-community-repo-docker\"" classpath-build-command: "mvn test-compile -ntp -Pags -pl \"-:alfresco-community-repo-docker\""
@@ -168,14 +175,14 @@ jobs:
testAttributes: "-Dtest=AllMmtUnitTestSuite" testAttributes: "-Dtest=AllMmtUnitTestSuite"
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testModule }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testModule }}
@@ -206,7 +213,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.run-tests.outcome }} tests-outcome: ${{ steps.run-tests.outcome }}
@@ -248,9 +255,9 @@ jobs:
REQUIRES_INSTALLED_ARTIFACTS: true REQUIRES_INSTALLED_ARTIFACTS: true
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Build" - name: "Build"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: | run: |
@@ -259,10 +266,11 @@ jobs:
- name: "Set transformers tag" - name: "Set transformers tag"
run: echo "TRANSFORMERS_TAG=$(mvn help:evaluate -Dexpression=dependency.alfresco-transform-core.version -q -DforceStdout)" >> $GITHUB_ENV run: echo "TRANSFORMERS_TAG=$(mvn help:evaluate -Dexpression=dependency.alfresco-transform-core.version -q -DforceStdout)" >> $GITHUB_ENV
- name: "Set up the environment" - name: "Set up the environment"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile ${{ matrix.compose-profile }} up -d run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile ${{ matrix.compose-profile }} up -d
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testSuite }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testSuite }}
@@ -283,7 +291,7 @@ jobs:
env: env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }} RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: | run: |
eval "args=($RP_OPTS)" eval "args=($RP_OPTS)"
mvn -B test -pl remote-api -Dtest=${{ matrix.testSuite }} -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}" mvn -B test -pl remote-api -Dtest=${{ matrix.testSuite }} -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}"
continue-on-error: true continue-on-error: true
- name: "Update GitHub Step Summary" - name: "Update GitHub Step Summary"
@@ -293,7 +301,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.run-tests.outcome }} tests-outcome: ${{ steps.run-tests.outcome }}
@@ -326,9 +334,9 @@ jobs:
version: ['10.2.18', '10.4', '10.5'] version: ['10.2.18', '10.4', '10.5']
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- name: Run MariaDB ${{ matrix.version }} database - name: Run MariaDB ${{ matrix.version }} database
@@ -337,7 +345,7 @@ jobs:
MARIADB_VERSION: ${{ matrix.version }} MARIADB_VERSION: ${{ matrix.version }}
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.version }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.version }}
@@ -368,7 +376,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.run-tests.outcome }} tests-outcome: ${{ steps.run-tests.outcome }}
@@ -397,9 +405,9 @@ jobs:
!contains(github.event.head_commit.message, '[force') !contains(github.event.head_commit.message, '[force')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- name: "Run MariaDB 10.6 database" - name: "Run MariaDB 10.6 database"
@@ -408,7 +416,7 @@ jobs:
MARIADB_VERSION: 10.6 MARIADB_VERSION: 10.6
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
@@ -439,7 +447,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.run-tests.outcome }} tests-outcome: ${{ steps.run-tests.outcome }}
@@ -468,9 +476,9 @@ jobs:
!contains(github.event.head_commit.message, '[force') !contains(github.event.head_commit.message, '[force')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- name: "Run MySQL 8 database" - name: "Run MySQL 8 database"
@@ -479,7 +487,7 @@ jobs:
MYSQL_VERSION: 8 MYSQL_VERSION: 8
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
@@ -500,7 +508,7 @@ jobs:
env: env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }} RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: | run: |
eval "args=($RP_OPTS)" eval "args=($RP_OPTS)"
mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=com.mysql.jdbc.Driver -Ddb.name=alfresco -Ddb.url=jdbc:mysql://localhost:3307/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}" mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=com.mysql.jdbc.Driver -Ddb.name=alfresco -Ddb.url=jdbc:mysql://localhost:3307/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}"
continue-on-error: true continue-on-error: true
- name: "Update GitHub Step Summary" - name: "Update GitHub Step Summary"
@@ -510,7 +518,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.run-tests.outcome }} tests-outcome: ${{ steps.run-tests.outcome }}
@@ -538,9 +546,9 @@ jobs:
!contains(github.event.head_commit.message, '[force') !contains(github.event.head_commit.message, '[force')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- name: "Run PostgreSQL 13.12 database" - name: "Run PostgreSQL 13.12 database"
@@ -549,7 +557,7 @@ jobs:
POSTGRES_VERSION: 13.12 POSTGRES_VERSION: 13.12
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
@@ -570,7 +578,7 @@ jobs:
env: env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }} RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: | run: |
eval "args=($RP_OPTS)" eval "args=($RP_OPTS)"
mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}" mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}"
continue-on-error: true continue-on-error: true
- name: "Update GitHub Step Summary" - name: "Update GitHub Step Summary"
@@ -580,7 +588,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.run-tests.outcome }} tests-outcome: ${{ steps.run-tests.outcome }}
@@ -608,9 +616,9 @@ jobs:
!contains(github.event.head_commit.message, '[force') !contains(github.event.head_commit.message, '[force')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- name: "Run PostgreSQL 14.9 database" - name: "Run PostgreSQL 14.9 database"
@@ -619,7 +627,7 @@ jobs:
POSTGRES_VERSION: 14.9 POSTGRES_VERSION: 14.9
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
@@ -640,7 +648,7 @@ jobs:
env: env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }} RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: | run: |
eval "args=($RP_OPTS)" eval "args=($RP_OPTS)"
mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}" mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}"
continue-on-error: true continue-on-error: true
- name: "Update GitHub Step Summary" - name: "Update GitHub Step Summary"
@@ -650,7 +658,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.run-tests.outcome }} tests-outcome: ${{ steps.run-tests.outcome }}
@@ -678,9 +686,9 @@ jobs:
!contains(github.event.head_commit.message, '[force') !contains(github.event.head_commit.message, '[force')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- name: "Run PostgreSQL 15.4 database" - name: "Run PostgreSQL 15.4 database"
@@ -689,7 +697,7 @@ jobs:
POSTGRES_VERSION: 15.4 POSTGRES_VERSION: 15.4
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
@@ -710,7 +718,7 @@ jobs:
env: env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }} RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: | run: |
eval "args=($RP_OPTS)" eval "args=($RP_OPTS)"
mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}" mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}"
continue-on-error: true continue-on-error: true
- name: "Update GitHub Step Summary" - name: "Update GitHub Step Summary"
@@ -720,7 +728,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.run-tests.outcome }} tests-outcome: ${{ steps.run-tests.outcome }}
@@ -746,16 +754,16 @@ jobs:
!contains(github.event.head_commit.message, '[force') !contains(github.event.head_commit.message, '[force')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- name: "Run ActiveMQ" - name: "Run ActiveMQ"
run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile activemq up -d run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile activemq up -d
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
@@ -786,7 +794,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.run-tests.outcome }} tests-outcome: ${{ steps.run-tests.outcome }}
@@ -846,9 +854,9 @@ jobs:
mvn-options: '-Dencryption.ssl.keystore.location=${CI_WORKSPACE}/keystores/alfresco/alfresco.keystore -Dencryption.ssl.truststore.location=${CI_WORKSPACE}/keystores/alfresco/alfresco.truststore' mvn-options: '-Dencryption.ssl.keystore.location=${CI_WORKSPACE}/keystores/alfresco/alfresco.keystore -Dencryption.ssl.truststore.location=${CI_WORKSPACE}/keystores/alfresco/alfresco.truststore'
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- name: "Set transformers tag" - name: "Set transformers tag"
@@ -867,10 +875,11 @@ jobs:
echo "HOSTNAME_VERIFICATION_DISABLED=false" >> "$GITHUB_ENV" echo "HOSTNAME_VERIFICATION_DISABLED=false" >> "$GITHUB_ENV"
fi fi
- name: "Set up the environment" - name: "Set up the environment"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile ${{ matrix.compose-profile }} up -d run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile ${{ matrix.compose-profile }} up -d
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testSuite }} ${{ matrix.idp }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testSuite }} ${{ matrix.idp }}
@@ -901,7 +910,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.run-tests.outcome }} tests-outcome: ${{ steps.run-tests.outcome }}
@@ -959,15 +968,16 @@ jobs:
REQUIRES_LOCAL_IMAGES: true REQUIRES_LOCAL_IMAGES: true
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Build" - name: "Build"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: | run: |
bash ./scripts/ci/init.sh bash ./scripts/ci/init.sh
bash ./scripts/ci/build.sh bash ./scripts/ci/build.sh
- name: "Set up the environment" - name: "Set up the environment"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: | run: |
${{ env.TAS_SCRIPTS }}/start-compose.sh ${{ env.TAS_ENVIRONMENT }}/docker-compose-minimal+transforms.yml ${{ env.TAS_SCRIPTS }}/start-compose.sh ${{ env.TAS_ENVIRONMENT }}/docker-compose-minimal+transforms.yml
${{ env.TAS_SCRIPTS }}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco" ${{ env.TAS_SCRIPTS }}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
@@ -976,7 +986,7 @@ jobs:
run: mvn install -pl :alfresco-community-repo-integration-test -am -DskipTests -Pall-tas-tests run: mvn install -pl :alfresco-community-repo-integration-test -am -DskipTests -Pall-tas-tests
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.test-name }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.test-name }}
@@ -1014,7 +1024,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.tests.outcome }} tests-outcome: ${{ steps.tests.outcome }}
@@ -1040,16 +1050,16 @@ jobs:
!contains(github.event.head_commit.message, '[force') !contains(github.event.head_commit.message, '[force')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- name: "Run Postgres 15.4 database" - name: "Run Postgres 15.4 database"
run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile postgres up -d run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile postgres up -d
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
@@ -1080,7 +1090,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.run-tests.outcome }} tests-outcome: ${{ steps.run-tests.outcome }}
@@ -1114,9 +1124,9 @@ jobs:
REQUIRES_INSTALLED_ARTIFACTS: true REQUIRES_INSTALLED_ARTIFACTS: true
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Build" - name: "Build"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: | run: |
@@ -1124,7 +1134,7 @@ jobs:
bash ./scripts/ci/build.sh bash ./scripts/ci/build.sh
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} 0${{ matrix.part }} - (PostgreSQL) ${{ matrix.test-name }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} 0${{ matrix.part }} - (PostgreSQL) ${{ matrix.test-name }}
@@ -1160,9 +1170,9 @@ jobs:
REQUIRES_INSTALLED_ARTIFACTS: true REQUIRES_INSTALLED_ARTIFACTS: true
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Build" - name: "Build"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: | run: |
@@ -1170,7 +1180,7 @@ jobs:
bash ./scripts/ci/build.sh bash ./scripts/ci/build.sh
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} 0${{ matrix.part }} - (MySQL) ${{ matrix.test-name }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} 0${{ matrix.part }} - (MySQL) ${{ matrix.test-name }}
@@ -1202,9 +1212,9 @@ jobs:
REQUIRES_LOCAL_IMAGES: true REQUIRES_LOCAL_IMAGES: true
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Build" - name: "Build"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: | run: |
@@ -1218,7 +1228,7 @@ jobs:
mvn -B install -pl :alfresco-governance-services-automation-community-rest-api -am -Pags -Pall-tas-tests -DskipTests mvn -B install -pl :alfresco-governance-services-automation-community-rest-api -am -Pags -Pall-tas-tests -DskipTests
- name: "Prepare Report Portal" - name: "Prepare Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v7.1.0
id: rp-prepare id: rp-prepare
with: with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
@@ -1250,7 +1260,7 @@ jobs:
continue-on-error: true continue-on-error: true
- name: "Summarize Report Portal" - name: "Summarize Report Portal"
if: github.ref_name == 'master' if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.0.0 uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v7.1.0
id: rp-summarize id: rp-summarize
with: with:
tests-outcome: ${{ steps.run-tests.outcome }} tests-outcome: ${{ steps.run-tests.outcome }}
@@ -1292,9 +1302,9 @@ jobs:
!contains(github.event.head_commit.message, '[force]') !contains(github.event.head_commit.message, '[force]')
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Build" - name: "Build"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: | run: |

View File

@@ -34,12 +34,12 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
persist-credentials: false persist-credentials: false
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- uses: Alfresco/alfresco-build-tools/.github/actions/configure-git-author@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/configure-git-author@v7.1.0
with: with:
username: ${{ env.GIT_USERNAME }} username: ${{ env.GIT_USERNAME }}
email: ${{ env.GIT_EMAIL }} email: ${{ env.GIT_EMAIL }}
@@ -63,12 +63,12 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
persist-credentials: false persist-credentials: false
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.1.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.1.0
- name: "Init" - name: "Init"
run: bash ./scripts/ci/init.sh run: bash ./scripts/ci/init.sh
- uses: Alfresco/alfresco-build-tools/.github/actions/configure-git-author@v7.0.0 - uses: Alfresco/alfresco-build-tools/.github/actions/configure-git-author@v7.1.0
with: with:
username: ${{ env.GIT_USERNAME }} username: ${{ env.GIT_USERNAME }}
email: ${{ env.GIT_EMAIL }} email: ${{ env.GIT_EMAIL }}

14
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,14 @@
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.5.0
hooks:
- id: detect-secrets
args: ["--baseline", ".secrets.baseline"]
- repo: local
hooks:
- id: check-format-and-headers
name: Check format and headers and fix if necessary
entry: ./scripts/hooks/check-format-and-headers.sh
language: script
files: ".*.java"
pass_filenames: false

1892
.secrets.baseline Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,52 @@ Thanks for your interest in contributing to this project!
The following is a set of guidelines for contributing to this library. Most of them will make the life of the reviewer easier and therefore decrease the time required for the patch be included in the next version. The following is a set of guidelines for contributing to this library. Most of them will make the life of the reviewer easier and therefore decrease the time required for the patch be included in the next version.
The project uses [pre-commit](https://pre-commit.com/) to format code (with [Spotless](https://github.com/diffplug/spotless)), validate license headers and check for secrets (with [detect-secrets](https://github.com/Yelp/detect-secrets)). To install the pre-commit hooks then first install pre-commit and then run:
```shell
pre-commit install
```
When you make a commit then these hooks will run and check the modified files. If it makes changes then you can review them and then `git commit` again to accept the changes.
#### Code Quality
This project uses `spotless` that enforces `alfresco-formatter.xml` to ensure code quality.
To check code-style violations you can use:
```bash
mvn spotless:check
```
To reformat files you can use:
```bash
mvn spotless:apply
```
#### Secret Detection
We are using [detect-secrets](https://github.com/Yelp/detect-secrets) to try to avoid accidentally publishing secret keys.
If you have pre-commit installed then this should run automatically when making a commit. Usually there should be no issues,
but if it finds a potential issue (e.g. a high entropy string) then you will see the following:
```shell
Detect secrets...........................................................Failed
- hook id: detect-secrets
- exit code: 1
ERROR: Potential secrets about to be committed to git repo!
Secret Type: Secret Keyword
Location: test.txt:1
```
If this is a false positive and you actually want to commit the string then run these two commands:
```shell
detect-secrets scan --baseline .secrets.baseline
detect-secrets audit .secrets.baseline
```
This will update the baseline file to include your new code and then allow you to review the detected secret and mark it as a false positive.
Once you are finished then you can add `.secrets.baseline` to the staged changes and you should be able to create a commit.
Because this project forms a part of Alfresco Content Services, the guidelines are hosted in the [Alfresco Social Community](https://hub.alfresco.com/t5/alfresco-content-services-ecm/ct-p/ECM-software) where they can be referenced from multiple projects. Because this project forms a part of Alfresco Content Services, the guidelines are hosted in the [Alfresco Social Community](https://hub.alfresco.com/t5/alfresco-content-services-ecm/ct-p/ECM-software) where they can be referenced from multiple projects.
You can report an issue in the ALF project of the [Alfresco issue tracker](http://issues.alfresco.com). You can report an issue in the ALF project of the [Alfresco issue tracker](http://issues.alfresco.com).

401
alfresco-formatter.xml Normal file
View File

@@ -0,0 +1,401 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="23">
<profile kind="CodeFormatterProfile" name="Spotless" version="23">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.javadoc_do_not_separate_block_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="999"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_if_empty"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="next_line"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="999"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
</profile>
</profiles>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId> <artifactId>alfresco-community-repo-amps</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<modules> <modules>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId> <artifactId>alfresco-governance-services-community-parent</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<modules> <modules>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-automation-community-repo</artifactId> <artifactId>alfresco-governance-services-automation-community-repo</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<build> <build>
@@ -98,7 +98,7 @@
<dependency> <dependency>
<groupId>com.github.docker-java</groupId> <groupId>com.github.docker-java</groupId>
<artifactId>docker-java</artifactId> <artifactId>docker-java</artifactId>
<version>3.3.6</version> <version>3.4.0</version>
<exclusions> <exclusions>
<exclusion> <exclusion>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId> <artifactId>alfresco-governance-services-community-parent</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<modules> <modules>

View File

@@ -1,3 +1,3 @@
SOLR6_TAG=2.0.11 SOLR6_TAG=2.0.12
POSTGRES_TAG=15.4 POSTGRES_TAG=15.4
ACTIVEMQ_TAG=5.18.3-jre17-rockylinux8 ACTIVEMQ_TAG=5.18.3-jre17-rockylinux8

View File

@@ -8,7 +8,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-repo-parent</artifactId> <artifactId>alfresco-governance-services-community-repo-parent</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<properties> <properties>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-repo-parent</artifactId> <artifactId>alfresco-governance-services-community-repo-parent</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<build> <build>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId> <artifactId>alfresco-community-repo</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<modules> <modules>

View File

@@ -8,7 +8,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId> <artifactId>alfresco-community-repo-amps</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<properties> <properties>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId> <artifactId>alfresco-community-repo</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<dependencies> <dependencies>

View File

@@ -27,4 +27,9 @@ public class HttpClientException extends AlfrescoRuntimeException
{ {
super(msgId); super(msgId);
} }
public HttpClientException(String msgId, Throwable cause)
{
super(msgId, cause);
}
} }

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId> <artifactId>alfresco-community-repo</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<properties> <properties>
@@ -132,7 +132,7 @@
<dependency> <dependency>
<groupId>com.fasterxml.woodstox</groupId> <groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId> <artifactId>woodstox-core</artifactId>
<version>6.5.1</version> <version>7.0.0</version>
</dependency> </dependency>
<!-- the cxf libs were updated, see dependencyManagement section --> <!-- the cxf libs were updated, see dependencyManagement section -->

View File

@@ -238,6 +238,17 @@ public interface CustomModelService
*/ */
public NodeRef createDownloadNode(String modelName, boolean withAssociatedForm); public NodeRef createDownloadNode(String modelName, boolean withAssociatedForm);
/**
* Creates a downloadable archive file containing the custom model file and
* if specified, its associated Share extension module file.
*
* @param modelName the model name to be exported
* @param withAssociatedForm whether Share extension module file should be
* included or not
* @return reference to the node which will contain the archive file
*/
NodeRef createDownloadNode(String modelName, boolean withAssociatedForm, String downloadNodeName);
/** /**
* Compiles the {@link M2Model}. * Compiles the {@link M2Model}.
* *

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId> <artifactId>alfresco-community-repo</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<dependencies> <dependencies>

View File

@@ -9,6 +9,6 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId> <artifactId>alfresco-community-repo-packaging</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
</project> </project>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId> <artifactId>alfresco-community-repo-packaging</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<properties> <properties>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId> <artifactId>alfresco-community-repo</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<modules> <modules>

View File

@@ -1,3 +1,3 @@
SOLR6_TAG=2.0.11 SOLR6_TAG=2.0.12
POSTGRES_TAG=15.4 POSTGRES_TAG=15.4
ACTIVEMQ_TAG=5.18.3-jre17-rockylinux8 ACTIVEMQ_TAG=5.18.3-jre17-rockylinux8

View File

@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId> <artifactId>alfresco-community-repo-packaging</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<modules> <modules>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId> <artifactId>alfresco-community-repo-tests</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<organization> <organization>

View File

@@ -9,7 +9,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId> <artifactId>alfresco-community-repo-tests</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<developers> <developers>

View File

@@ -9,7 +9,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId> <artifactId>alfresco-community-repo-tests</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<developers> <developers>

View File

@@ -8,7 +8,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId> <artifactId>alfresco-community-repo-tests</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<properties> <properties>
@@ -17,7 +17,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<rest.api.explorer.branch>master</rest.api.explorer.branch> <rest.api.explorer.branch>master</rest.api.explorer.branch>
<httpclient-osgi-version>4.5.6</httpclient-osgi-version> <httpclient-osgi-version>4.5.6</httpclient-osgi-version>
<commons-lang3.version>3.14.0</commons-lang3.version> <commons-lang3.version>3.17.0</commons-lang3.version>
<scribejava-apis.version>8.3.3</scribejava-apis.version> <scribejava-apis.version>8.3.3</scribejava-apis.version>
<java.version>17</java.version> <java.version>17</java.version>
</properties> </properties>

View File

@@ -36,22 +36,22 @@ public class RestPersonFavoritesModel extends TestModel implements IRestModel<Re
{ {
@JsonProperty(value = "entry") @JsonProperty(value = "entry")
RestPersonFavoritesModel model; RestPersonFavoritesModel model;
@Override @Override
public RestPersonFavoritesModel onModel() public RestPersonFavoritesModel onModel()
{ {
return model; return model;
} }
private String targetGuid; private String targetGuid;
private String createdAt; private String createdAt;
private List<String> aspectNames;
private List<String> allowableOperations; private List<String> allowableOperations;
private RestTargetModel target; private RestTargetModel target;
public RestPersonFavoritesModel() public RestPersonFavoritesModel()
{ {}
}
public RestPersonFavoritesModel(String targetGuid, String createdAt) public RestPersonFavoritesModel(String targetGuid, String createdAt)
{ {
@@ -69,7 +69,7 @@ public class RestPersonFavoritesModel extends TestModel implements IRestModel<Re
{ {
this.targetGuid = targetGuid; this.targetGuid = targetGuid;
} }
public RestTargetModel getTarget() public RestTargetModel getTarget()
{ {
return target; return target;
@@ -90,11 +90,23 @@ public class RestPersonFavoritesModel extends TestModel implements IRestModel<Re
this.createdAt = createdAt; this.createdAt = createdAt;
} }
public List<String> getAllowableOperations() { public List<String> getAspectNames()
{
return aspectNames;
}
public void setAspectNames(List<String> aspectNames)
{
this.aspectNames = aspectNames;
}
public List<String> getAllowableOperations()
{
return allowableOperations; return allowableOperations;
} }
public void setAllowableOperations(List<String> allowableOperations) { public void setAllowableOperations(List<String> allowableOperations)
{
this.allowableOperations = allowableOperations; this.allowableOperations = allowableOperations;
} }
} }

View File

@@ -0,0 +1,97 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.repo.resource.cache.MultiKeyResourceMap;
import org.alfresco.rest.repo.resource.category.RepoCategoryCreator;
import org.alfresco.rest.repo.resource.category.RepoCategoryModifier;
import org.alfresco.rest.repo.resource.general.Modifier;
import org.alfresco.rest.repo.resource.general.Specifier;
import org.alfresco.utility.data.DataUser;
import org.alfresco.utility.model.UserModel;
/**
* Helper class simplifying things related with repository categories management.
*/
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Categories implements ResourceManager<RestCategoryModel, Specifier.CategoriesSpecifier, Modifier.CategoryModifier>
{
public static final String CATEGORY_NAME_PREFIX = "category";
private static final String ROOT_CATEGORY_ID = "-root-";
public static final RestCategoryModel ROOT_CATEGORY = RestCategoryModel.builder().id(ROOT_CATEGORY_ID).create();
private final RestWrapper restClient;
private final UserModel user;
private final Map<String, RestCategoryModel> categoriesCache = new MultiKeyResourceMap<>(RestCategoryModel::getId, RestCategoryModel::getName);
public Categories(RestWrapper restClient, UserModel user)
{
this.restClient = restClient;
this.user = user;
}
@Autowired
public Categories(RestWrapper restClient, DataUser dataUser)
{
this(restClient, dataUser.getAdminUser());
}
@Override
public Specifier.CategoriesSpecifier add()
{
return (Specifier.CategoriesSpecifier) new RepoCategoryCreator(restClient, categoriesCache)
.underCategory(ROOT_CATEGORY).asUser(user);
}
@Override
public RestCategoryModel get(String key)
{
return categoriesCache.get(key);
}
@Override
public Modifier.CategoryModifier modify(RestCategoryModel category)
{
return new RepoCategoryModifier(restClient, category, categoriesCache).asUser(user);
}
@Override
public void delete(RestCategoryModel category)
{
new RepoCategoryModifier(restClient, category, categoriesCache).asUser(user).delete();
}
}

View File

@@ -0,0 +1,105 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.repo.resource.cache.MultiKeyResourceMap;
import org.alfresco.rest.repo.resource.content.PlainFileCreator;
import org.alfresco.rest.repo.resource.content.PlainFileModifier;
import org.alfresco.rest.repo.resource.general.Modifier;
import org.alfresco.rest.repo.resource.general.Specifier;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.data.DataSite;
import org.alfresco.utility.data.DataUser;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
/**
* Helper class simplifying things related with repository files management.
*/
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Files implements ResourceManager<FileModel, Specifier.FileSpecifier, Modifier.FileModifier>
{
public static final String FILE_NAME_PREFIX = "file";
private final DataContent dataContent;
private final RestWrapper restClient;
private final SiteModel site;
private final UserModel user;
private final Map<String, FileModel> filesCache = new MultiKeyResourceMap<>(FileModel::getNodeRef, FileModel::getName);
public Files(DataContent dataContent, RestWrapper restClient, UserModel user, SiteModel site)
{
this.dataContent = dataContent;
this.restClient = restClient;
this.user = user;
this.site = site;
}
public Files(DataContent dataContent, RestWrapper restClient, DataUser dataUser)
{
this(dataContent, restClient, dataUser.getAdminUser(), null);
}
@Autowired
public Files(DataContent dataContent, RestWrapper restClient, DataUser dataUser, DataSite dataSite)
{
this(dataContent, restClient, dataUser.getAdminUser(), dataSite.usingUser(dataUser.getAdminUser()).createPrivateRandomSite());
}
@Override
public Specifier.FileSpecifier add()
{
return (Specifier.FileSpecifier) new PlainFileCreator(dataContent, filesCache).withinSite(site).asUser(user);
}
@Override
public FileModel get(String id)
{
return filesCache.get(id);
}
@Override
public Modifier.FileModifier modify(FileModel file)
{
return new PlainFileModifier(dataContent, restClient, file, filesCache).withinSite(site).asUser(user);
}
@Override
public void delete(FileModel file)
{
new PlainFileModifier(dataContent, restClient, file, filesCache).withinSite(site).asUser(user).delete();
}
}

View File

@@ -0,0 +1,113 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.repo.resource.cache.MultiKeyResourceMap;
import org.alfresco.rest.repo.resource.content.RepoFolderCreator;
import org.alfresco.rest.repo.resource.content.RepoFolderModifier;
import org.alfresco.rest.repo.resource.general.Modifier;
import org.alfresco.rest.repo.resource.general.Specifier;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.data.DataSite;
import org.alfresco.utility.data.DataUser;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
/**
* Helper class simplifying things related with repository folders management.
*/
@Component
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class Folders implements ResourceManager<FolderModel, Specifier.FolderSpecifier, Modifier.FolderModifier>
{
public static final String FOLDER_NAME_PREFIX = "folder";
private final DataContent dataContent;
private final RestWrapper restClient;
private final SiteModel site;
private final UserModel user;
private final Files files;
private final Map<String, FolderModel> foldersCache = new MultiKeyResourceMap<>(FolderModel::getNodeRef, FolderModel::getName);
public Folders(DataContent dataContent, RestWrapper restClient, UserModel user, SiteModel site, Files files)
{
this.dataContent = dataContent;
this.restClient = restClient;
this.site = site;
this.user = user;
this.files = files;
}
public Folders(DataContent dataContent, RestWrapper restClient, UserModel user, SiteModel site)
{
this(dataContent, restClient, user, site, new Files(dataContent, restClient, user, site));
}
public Folders(DataContent dataContent, RestWrapper restClient, DataUser dataUser)
{
this(dataContent, restClient, dataUser.getAdminUser(), null);
}
@Autowired
public Folders(DataContent dataContent, RestWrapper restClient, DataUser dataUser, DataSite dataSite)
{
this(dataContent, restClient, dataUser.getAdminUser(), dataSite.usingUser(dataUser.getAdminUser()).createPrivateRandomSite());
}
@Override
public Specifier.FolderSpecifier add()
{
return (Specifier.FolderSpecifier) new RepoFolderCreator(dataContent, foldersCache).withinSite(site).asUser(user);
}
@Override
public FolderModel get(String key)
{
return foldersCache.get(key);
}
@Override
public Modifier.FolderModifier modify(FolderModel folder)
{
return new RepoFolderModifier(dataContent, restClient, folder, files, foldersCache).withinSite(site).asUser(user);
}
@Override
public void delete(FolderModel folder)
{
new RepoFolderModifier(dataContent, restClient, folder, files, foldersCache).withinSite(site).asUser(user).delete();
}
}

View File

@@ -0,0 +1,61 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource;
import org.alfresco.rest.repo.resource.general.Modifier;
import org.alfresco.rest.repo.resource.general.ResourceIntroducer;
import org.alfresco.rest.repo.resource.general.Specifier;
import org.alfresco.utility.model.TestModel;
/**
* Declares operations introducing new, or allowing to manage repository resources like: folders, files, categories, associations, etc.
*
* @param <RESOURCE>>
* repository resource, e.g. folder, file, category, etc.
* @param <SPECIFIER>
* repository resource specifier, see {@link Specifier}
* @param <MODIFIER>>
* repository resource modifier, see {@link Modifier}
*/
public interface ResourceManager<RESOURCE extends TestModel, SPECIFIER extends Specifier, MODIFIER extends Modifier<RESOURCE, ?>>
extends ResourceIntroducer<SPECIFIER>
{
RESOURCE get(String id);
MODIFIER modify(RESOURCE resource);
default MODIFIER modify(String id)
{
return modify(get(id));
}
void delete(RESOURCE resource);
default void delete(String id)
{
delete(get(id));
}
}

View File

@@ -0,0 +1,129 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.cache;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.alfresco.utility.model.TestModel;
/**
* Allows to store data in map and find it using three keys - id, name and alias.
*
* @param <RESOURCE>
* repository resource, e.g. folder, category, etc.
*/
public class MultiKeyResourceMap<RESOURCE extends TestModel> extends HashMap<String, RESOURCE>
{
private static final String UUID_PATTERN = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$";
private final Map<String, String> keys = new HashMap<>();
private final Function<RESOURCE, String> idSupplier;
private final Function<RESOURCE, String> nameSupplier;
public MultiKeyResourceMap(Function<RESOURCE, String> idSupplier, Function<RESOURCE, String> nameSupplier)
{
super();
this.idSupplier = idSupplier;
this.nameSupplier = nameSupplier;
}
@Override
public RESOURCE put(String alias, RESOURCE resource)
{
String id = idSupplier.apply(resource);
String name = nameSupplier.apply(resource);
if (StringUtils.isEmpty(id))
{
throw new IllegalArgumentException("ID of entity with name: " + name + " and alias: " + alias + " cannot be empty!");
}
if (StringUtils.isEmpty(name))
{
throw new IllegalArgumentException("Name of entity with ID: " + id + " and alias: " + alias + " cannot be empty!");
}
if (StringUtils.isNotEmpty(alias))
{
if (keys.containsKey(alias))
{
throw new IllegalStateException("Entity with alias: " + alias + " already exists in cache!");
}
keys.put(alias, id);
}
if (StringUtils.isNotEmpty(name))
{
keys.put(name, id);
}
return super.put(id, resource);
}
@Override
public RESOURCE get(Object key)
{
return super.get(findKey(key));
}
@Override
public RESOURCE remove(Object key)
{
RESOURCE resource = this.get(key);
if (resource == null)
{
return null;
}
String id = idSupplier.apply(resource);
findKeysFor(id).forEach(keys::remove);
return super.remove(id);
}
private Object findKey(Object key)
{
Object realKey = key;
if (key instanceof String k && (!Pattern.compile(UUID_PATTERN).matcher(k).matches() || !super.containsKey(k)))
{
realKey = keys.getOrDefault(k, k);
}
return realKey;
}
public Set<String> findKeysFor(Object id)
{
return keys.entrySet()
.stream()
.filter(entry -> id.equals(entry.getValue()))
.map(Entry::getKey)
.collect(Collectors.toSet());
}
}

View File

@@ -0,0 +1,64 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.category;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.model.RestCategoryModel;
public class NestedCategoriesCreator extends SerialCategoriesCreator
{
public NestedCategoriesCreator(RestWrapper restClient, Map<String, RestCategoryModel> categories)
{
super(restClient, categories);
}
@Override
public List<RestCategoryModel> create()
{
return createNestedCategories(parent, names, 0);
}
private List<RestCategoryModel> createNestedCategories(RestCategoryModel parent, List<String> categoryNames, int index)
{
List<RestCategoryModel> createdCategories = new ArrayList<>();
categoryNames.stream().findFirst().ifPresent(categoryName -> {
RestCategoryModel createdCategory = createCategory(categoryName, getOrNull(aliases, index), parent);
createdCategories.add(createdCategory);
List<String> remainingNames = categoryNames.stream().skip(1).toList();
if (!remainingNames.isEmpty())
{
createdCategories.addAll(createNestedCategories(createdCategory, remainingNames, index + 1));
}
});
return createdCategories;
}
}

View File

@@ -0,0 +1,154 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.category;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.alfresco.rest.repo.resource.Categories.CATEGORY_NAME_PREFIX;
import static org.alfresco.rest.repo.resource.Categories.ROOT_CATEGORY;
import java.util.Map;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.repo.resource.general.Creator;
import org.alfresco.rest.repo.resource.general.MultiCreator;
import org.alfresco.rest.repo.resource.general.ResourceCreator;
import org.alfresco.rest.repo.resource.general.Specifier;
public class RepoCategoryCreator
extends ResourceCreator<RestCategoryModel, Creator.CategoryCreator>
implements Creator.CategoryCreator, Specifier.CategoriesSpecifier
{
private final RestWrapper restClient;
private RestCategoryModel parent = ROOT_CATEGORY;
private final Map<String, RestCategoryModel> categoriesCache;
public RepoCategoryCreator(RestWrapper restClient, Map<String, RestCategoryModel> categoriesCache)
{
super();
this.restClient = restClient;
this.categoriesCache = categoriesCache;
}
@Override
protected CategoryCreator self()
{
return this;
}
@Override
public CategoryCreator category(String name)
{
return this.withName(name);
}
@Override
public CategoryCreator randomCategory()
{
return this.withRandomName();
}
@Override
public CategoryCreator randomCategory(String prefix)
{
return this.withRandomName(prefix);
}
@Override
public MultiCreator.CategoriesCreator categories(String... names)
{
return new SerialCategoriesCreator(restClient, categoriesCache).withNames(names).underCategory(parent).asUser(user);
}
@Override
public MultiCreator.CategoriesCreator randomCategories(String... prefixes)
{
return new SerialCategoriesCreator(restClient, categoriesCache).withRandomNames(prefixes).underCategory(parent).asUser(user);
}
@Override
public MultiCreator.CategoriesCreator randomCategories(int quantity)
{
return new SerialCategoriesCreator(restClient, categoriesCache).withRandomNames(quantity).underCategory(parent).asUser(user);
}
@Override
public MultiCreator.CategoriesCreator nestedCategories(String... names)
{
return new NestedCategoriesCreator(restClient, categoriesCache).withNames(names).underCategory(parent).asUser(user);
}
@Override
public MultiCreator.CategoriesCreator nestedRandomCategories(String... prefixes)
{
return new NestedCategoriesCreator(restClient, categoriesCache).withRandomNames(prefixes).underCategory(parent).asUser(user);
}
@Override
public MultiCreator.CategoriesCreator nestedRandomCategories(int depth)
{
return new NestedCategoriesCreator(restClient, categoriesCache).withRandomNames(depth).underCategory(parent).asUser(user);
}
@Override
public CategoryCreator withRandomName(String prefix)
{
withAlias(prefix);
return super.withRandomName(prefix);
}
@Override
public CategoryCreator underCategory(RestCategoryModel parent)
{
this.parent = parent;
return this;
}
@Override
public RestCategoryModel create()
{
RestCategoryModel category = restClient.authenticateUser(user).withCoreAPI().usingCategory(parent)
.createSingleCategory(RestCategoryModel.builder().name(name).create());
categoriesCache.put(alias, category);
return category;
}
@Override
protected String generateRandomName()
{
return this.generateRandomNameWith(EMPTY);
}
@Override
protected String generateRandomNameWith(String prefix)
{
return super.generateRandomNameWith(CATEGORY_NAME_PREFIX + prefix + "_");
}
}

View File

@@ -0,0 +1,85 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.category;
import java.util.Map;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.repo.resource.general.Modifier;
import org.alfresco.rest.repo.resource.general.ResourceModifier;
import org.alfresco.rest.repo.resource.general.Specifier;
import org.alfresco.utility.model.UserModel;
public class RepoCategoryModifier
extends ResourceModifier<RestCategoryModel, Modifier.CategoryModifier>
implements Modifier.CategoryModifier
{
private final RestWrapper restClient;
private final RestCategoryModel category;
private final Map<String, RestCategoryModel> categoriesCache;
public RepoCategoryModifier(RestWrapper restClient, RestCategoryModel category, Map<String, RestCategoryModel> categoriesCache)
{
super();
this.restClient = restClient;
this.category = category;
this.categoriesCache = categoriesCache;
}
@Override
protected CategoryModifier self()
{
return this;
}
@Override
public Specifier.CategoriesSpecifier add()
{
return (Specifier.CategoriesSpecifier) new RepoCategoryCreator(restClient, categoriesCache)
.underCategory(category).asUser(user);
}
@Override
public RestCategoryModel get(String id)
{
return buildCategoryRestRequest(restClient, user, RestCategoryModel.builder().id(id).create())
.getCategory();
}
@Override
public void delete()
{
categoriesCache.remove(category.getId());
buildCategoryRestRequest(restClient, user, category).deleteCategory();
}
private static org.alfresco.rest.requests.Categories buildCategoryRestRequest(RestWrapper restClient, UserModel user, RestCategoryModel category)
{
return restClient.authenticateUser(user).withCoreAPI().usingCategory(category);
}
}

View File

@@ -0,0 +1,111 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.category;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.alfresco.rest.repo.resource.Categories.CATEGORY_NAME_PREFIX;
import static org.alfresco.rest.repo.resource.Categories.ROOT_CATEGORY;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.repo.resource.general.MultiCreator;
import org.alfresco.rest.repo.resource.general.MultipleResourcesCreator;
public class SerialCategoriesCreator
extends MultipleResourcesCreator<RestCategoryModel, MultiCreator.CategoriesCreator>
implements MultiCreator.CategoriesCreator
{
private final RestWrapper restClient;
protected RestCategoryModel parent = ROOT_CATEGORY;
private final Map<String, RestCategoryModel> categoriesCache;
public SerialCategoriesCreator(RestWrapper restClient, Map<String, RestCategoryModel> categoriesCache)
{
super();
this.restClient = restClient;
this.categoriesCache = categoriesCache;
}
@Override
protected CategoriesCreator self()
{
return this;
}
@Override
public CategoriesCreator underCategory(RestCategoryModel parent)
{
this.parent = parent;
return this;
}
@Override
public List<RestCategoryModel> create()
{
return createRawCategories(parent, names);
}
@Override
protected String generateRandomName()
{
return this.generateRandomNameWith(EMPTY);
}
@Override
protected String generateRandomNameWith(String prefix)
{
return super.generateRandomNameWith(CATEGORY_NAME_PREFIX + prefix + "_");
}
private List<RestCategoryModel> createRawCategories(RestCategoryModel parent, List<String> categoryNames)
{
List<RestCategoryModel> createdCategories = new ArrayList<>();
AtomicInteger i = new AtomicInteger();
categoryNames.forEach(categoryName -> {
RestCategoryModel createdCategory = createCategory(categoryName, getOrNull(aliases, i.getAndIncrement()), parent);
createdCategories.add(createdCategory);
});
return createdCategories;
}
protected RestCategoryModel createCategory(String name, String alias, RestCategoryModel parent)
{
return new RepoCategoryCreator(restClient, this.categoriesCache)
.withAlias(alias)
.withName(name)
.underCategory(parent)
.asUser(user)
.create();
}
}

View File

@@ -0,0 +1,111 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.content;
import java.util.Map;
import java.util.stream.Stream;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.model.RestTagModel;
import org.alfresco.rest.repo.resource.Files;
import org.alfresco.rest.repo.resource.general.MultiCreator;
import org.alfresco.rest.repo.resource.general.Specifier;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.model.ContentModel;
import org.alfresco.utility.model.FolderModel;
public class MultiContentCreator extends RepoFolderCreator implements Specifier.MultiContentSpecifier
{
private final RestWrapper restClient;
private final Files files;
protected MultiContentCreator(DataContent dataContent, RestWrapper restClient, Files files, Map<String, FolderModel> folders)
{
super(dataContent, folders);
this.files = files;
this.restClient = restClient;
}
@Override
public FileCreator file(String name)
{
return files.add().file(name).underFolder(parent).withinSite(site).asUser(user);
}
@Override
public FileCreator randomFile()
{
return files.add().randomFile().underFolder(parent).withinSite(site).asUser(user);
}
@Override
public FileCreator randomFile(String prefix)
{
return files.add().randomFile(prefix).underFolder(parent).withinSite(site).asUser(user);
}
@Override
public MultiCreator.FilesCreator files(String... names)
{
return files.add().files(names).underFolder(parent).withinSite(site).asUser(user);
}
@Override
public MultiCreator.FilesCreator randomFiles(String... prefixes)
{
return files.add().randomFiles(prefixes).underFolder(parent).withinSite(site).asUser(user);
}
@Override
public MultiCreator.FilesCreator randomFiles(int quantity)
{
return files.add().randomFiles(quantity).underFolder(parent).withinSite(site).asUser(user);
}
@Override
public void secondaryContent(ContentModel content)
{
buildNodeRestRequest(restClient, parent).addSecondaryChild(content);
}
@Override
public void secondaryContent(ContentModel... contents)
{
buildNodeRestRequest(restClient, parent).addSecondaryChildren(contents);
}
@Override
public void tag(RestTagModel tag)
{
buildNodeRestRequest(restClient, parent).addTag(tag.getTag());
}
@Override
public void tags(RestTagModel... tags)
{
buildNodeRestRequest(restClient, parent).addTags(Stream.of(tags).map(RestTagModel::getTag).toArray(String[]::new));
}
}

View File

@@ -0,0 +1,65 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.content;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.model.FolderModel;
public class NestedFoldersCreator extends SerialFoldersCreator
{
public NestedFoldersCreator(DataContent dataContent, Map<String, FolderModel> folders)
{
super(dataContent, folders);
}
@Override
public List<FolderModel> create()
{
verifyDataConsistency();
return createNestedFoldersUnder(parent, names, 0);
}
private List<FolderModel> createNestedFoldersUnder(FolderModel parent, List<String> folderNames, int index)
{
List<FolderModel> createdFolders = new ArrayList<>();
folderNames.stream().findFirst().ifPresent(folderName -> {
FolderModel createdFolder = createFolder(folderName, getOrNull(titles, index), getOrNull(descriptions, index), parent, getOrNull(aliases, index));
createdFolders.add(createdFolder);
List<String> remainingNames = folderNames.stream().skip(1).toList();
if (!remainingNames.isEmpty())
{
createdFolders.addAll(createNestedFoldersUnder(createdFolder, remainingNames, index + 1));
}
});
return createdFolders;
}
}

View File

@@ -0,0 +1,142 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.content;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.alfresco.rest.repo.resource.Files.FILE_NAME_PREFIX;
import java.util.Map;
import org.alfresco.rest.repo.resource.general.ContentCreator;
import org.alfresco.rest.repo.resource.general.Creator;
import org.alfresco.rest.repo.resource.general.MultiCreator;
import org.alfresco.rest.repo.resource.general.Specifier;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FileType;
public class PlainFileCreator
extends ContentCreator<FileModel, Creator.FileCreator>
implements Creator.FileCreator, Specifier.FileSpecifier
{
private final DataContent dataContent;
private final Map<String, FileModel> filesCache;
public PlainFileCreator(DataContent dataContent, Map<String, FileModel> filesCache)
{
super(new FileModel());
this.dataContent = dataContent;
this.filesCache = filesCache;
this.contentModel.setFileType(FileType.TEXT_PLAIN);
}
@Override
protected FileCreator self()
{
return this;
}
@Override
public FileCreator withRandomName(String prefix)
{
withAlias(prefix);
return super.withRandomName(prefix);
}
@Override
public FileCreator file(String name)
{
return this.withName(name);
}
@Override
public FileCreator randomFile()
{
return this.withRandomName();
}
@Override
public FileCreator randomFile(String prefix)
{
return this.withRandomName(prefix);
}
@Override
public MultiCreator.FilesCreator files(String... names)
{
return new SerialFilesCreator(dataContent, filesCache).withNames(names).withinSite(site).asUser(user);
}
@Override
public MultiCreator.FilesCreator randomFiles(String... prefixes)
{
return new SerialFilesCreator(dataContent, filesCache).withRandomNames(prefixes).withinSite(site).asUser(user);
}
@Override
public MultiCreator.FilesCreator randomFiles(int quantity)
{
return new SerialFilesCreator(dataContent, filesCache).withRandomNames(quantity).withinSite(site).asUser(user);
}
@Override
public FileCreator ofType(FileType fileType)
{
contentModel.setFileType(fileType);
return this;
}
@Override
public FileCreator withContent(String fileContent)
{
contentModel.setContent(fileContent);
return this;
}
@Override
public FileModel create()
{
contentModel.setName(contentModel.getName() + "." + contentModel.getFileType().extension);
FileModel createdFile = create(dataContent, dataContent::createContent);
filesCache.put(alias, createdFile);
return createdFile;
}
@Override
protected String generateRandomName()
{
return this.generateRandomNameWith(EMPTY);
}
@Override
protected String generateRandomNameWith(String prefix, String suffix)
{
return super.generateRandomNameWith(FILE_NAME_PREFIX + prefix + "_", suffix);
}
}

View File

@@ -0,0 +1,73 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.content;
import java.util.Map;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.repo.resource.general.ContentModifier;
import org.alfresco.rest.repo.resource.general.Modifier;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
public class PlainFileModifier
extends ContentModifier<FileModel, Modifier.FileModifier>
implements Modifier.FileModifier
{
private final Map<String, FileModel> filesCache;
public PlainFileModifier(DataContent dataContent, RestWrapper restClient, FileModel file, Map<String, FileModel> filesCache)
{
super(dataContent, restClient, file);
this.filesCache = filesCache;
}
@Override
protected FileModifier self()
{
return this;
}
@Override
public FileModel get(String id)
{
return super.get(id, FileModel::new);
}
@Override
public FileModel copyTo(FolderModel target)
{
return super.copyTo(target, FileModel::new);
}
@Override
public void delete()
{
filesCache.remove(contentModel.getNodeRef());
super.delete();
}
}

View File

@@ -0,0 +1,143 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.content;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.alfresco.rest.repo.resource.Folders.FOLDER_NAME_PREFIX;
import java.util.Map;
import org.alfresco.rest.repo.resource.general.ContentCreator;
import org.alfresco.rest.repo.resource.general.Creator;
import org.alfresco.rest.repo.resource.general.MultiCreator;
import org.alfresco.rest.repo.resource.general.Specifier;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.model.FolderModel;
public class RepoFolderCreator
extends ContentCreator<FolderModel, Creator.FolderCreator>
implements Creator.FolderCreator, Specifier.FolderSpecifier
{
private final DataContent dataContent;
private final Map<String, FolderModel> foldersCache;
public RepoFolderCreator(DataContent dataContent, Map<String, FolderModel> foldersCache)
{
super(new FolderModel());
this.dataContent = dataContent;
this.foldersCache = foldersCache;
}
@Override
protected RepoFolderCreator self()
{
return this;
}
@Override
public FolderCreator folder(String name)
{
return this.withName(name);
}
@Override
public FolderCreator randomFolder()
{
return this.withRandomName();
}
@Override
public FolderCreator randomFolder(String prefix)
{
return this.withRandomName(prefix);
}
@Override
public MultiCreator.FoldersCreator folders(String... names)
{
return new SerialFoldersCreator(dataContent, foldersCache).withNames(names).withinSite(site).asUser(user);
}
@Override
public MultiCreator.FoldersCreator randomFolders(String... prefixes)
{
return new SerialFoldersCreator(dataContent, foldersCache).withRandomNames(prefixes).withinSite(site).asUser(user);
}
@Override
public MultiCreator.FoldersCreator randomFolders(int quantity)
{
return new SerialFoldersCreator(dataContent, foldersCache).withRandomNames(quantity).withinSite(site).asUser(user);
}
@Override
public MultiCreator.FoldersCreator nestedFolders(String... names)
{
return new NestedFoldersCreator(dataContent, foldersCache).withNames(names).withinSite(site).asUser(user);
}
@Override
public MultiCreator.FoldersCreator nestedRandomFolders(String... prefixes)
{
return new NestedFoldersCreator(dataContent, foldersCache).withRandomNames(prefixes).withinSite(site).asUser(user);
}
@Override
public MultiCreator.FoldersCreator nestedRandomFolders(int depth)
{
return new NestedFoldersCreator(dataContent, foldersCache).withRandomNames(depth).withinSite(site).asUser(user);
}
@Override
public FolderCreator withRandomName(String prefix)
{
withAlias(prefix);
return super.withRandomName(prefix);
}
@Override
public FolderModel create()
{
FolderModel createdFolder = create(dataContent, dataContent::createFolder);
foldersCache.put(alias, createdFolder);
return createdFolder;
}
@Override
protected String generateRandomName()
{
return this.generateRandomNameWith(EMPTY);
}
@Override
protected String generateRandomNameWith(String prefix)
{
return super.generateRandomNameWith(FOLDER_NAME_PREFIX + prefix + "_");
}
}

View File

@@ -0,0 +1,108 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.content;
import java.util.Map;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.model.RestTagModel;
import org.alfresco.rest.repo.resource.Files;
import org.alfresco.rest.repo.resource.general.ContentModifier;
import org.alfresco.rest.repo.resource.general.Modifier;
import org.alfresco.rest.repo.resource.general.Specifier;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.model.ContentModel;
import org.alfresco.utility.model.FolderModel;
public class RepoFolderModifier
extends ContentModifier<FolderModel, Modifier.FolderModifier>
implements Modifier.FolderModifier
{
private final RestWrapper restClient;
private final DataContent dataContent;
private final Files files;
private final Map<String, FolderModel> foldersCache;
public RepoFolderModifier(DataContent dataContent, RestWrapper restClient, FolderModel folder, Files files, Map<String, FolderModel> foldersCache)
{
super(dataContent, restClient, folder);
this.dataContent = dataContent;
this.restClient = restClient;
this.files = files;
this.foldersCache = foldersCache;
}
@Override
protected FolderModifier self()
{
return this;
}
@Override
public Specifier.MultiContentSpecifier add()
{
return (Specifier.MultiContentSpecifier) new MultiContentCreator(dataContent, restClient, files, foldersCache)
.underFolder(contentModel).withinSite(site).asUser(user);
}
@Override
public Specifier.AssociationSpecifier remove()
{
return new Specifier.AssociationSpecifier() {
@Override
public void secondaryContent(ContentModel content)
{
buildNodeRestRequest(restClient, contentModel).removeSecondaryChild(content);
}
@Override
public void tag(RestTagModel tag)
{
buildNodeRestRequest(restClient, contentModel).deleteTag(tag);
}
};
}
@Override
public FolderModel get(String id)
{
return super.get(id, FolderModel::new);
}
@Override
public FolderModel copyTo(FolderModel target)
{
return super.copyTo(target, FolderModel::new);
}
@Override
public void delete()
{
foldersCache.remove(contentModel.getName());
super.delete();
}
}

View File

@@ -0,0 +1,156 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.content;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.alfresco.rest.repo.resource.Files.FILE_NAME_PREFIX;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.alfresco.rest.repo.resource.general.MultiCreator;
import org.alfresco.rest.repo.resource.general.MultipleContentsCreator;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FileType;
import org.alfresco.utility.model.FolderModel;
public class SerialFilesCreator
extends MultipleContentsCreator<FileModel, MultiCreator.FilesCreator>
implements MultiCreator.FilesCreator
{
private final DataContent dataContent;
private List<FileType> fileTypes;
private List<String> filesContents;
private final Map<String, FileModel> filesCache;
public SerialFilesCreator(DataContent dataContent, Map<String, FileModel> filesCache)
{
super();
this.dataContent = dataContent;
this.filesCache = filesCache;
}
@Override
protected FilesCreator self()
{
return this;
}
@Override
public FilesCreator ofTypes(FileType... fileTypes)
{
this.fileTypes = List.of(fileTypes);
return this;
}
@Override
public FilesCreator withContents(List<String> filesContents)
{
this.filesContents = filesContents;
return this;
}
@Override
public FilesCreator withRandomContents(int wordsCount, int wordsMaxLength)
{
return withContents(
IntStream.of(0, names.size())
.mapToObj(i -> IntStream.range(0, wordsCount)
.mapToObj(j -> RandomStringUtils.randomAlphanumeric(1, wordsMaxLength))
.collect(Collectors.joining(" ")))
.collect(Collectors.toList()));
}
@Override
public List<FileModel> create()
{
verifyDataConsistency();
return createRawFilesUnder(parent, names);
}
@Override
protected void verifyDataConsistency()
{
super.verifyDataConsistency();
if (CollectionUtils.isEmpty(fileTypes) || fileTypes.size() < names.size())
{
throw new IllegalArgumentException("Provided file types size is different from created files amount");
}
if (CollectionUtils.isEmpty(filesContents) || filesContents.size() < names.size())
{
throw new IllegalArgumentException("Provided file contents size is different from created files amount");
}
}
@Override
protected String generateRandomName()
{
return this.generateRandomNameWith(EMPTY);
}
@Override
protected String generateRandomNameWith(String prefix)
{
return super.generateRandomNameWith(FILE_NAME_PREFIX + prefix + "_");
}
protected FileModel createFile(String fileName, FileType fileType, String title, String description, String fileContent, FolderModel parent, String alias)
{
return new PlainFileCreator(dataContent, filesCache)
.withAlias(alias)
.withName(fileName)
.ofType(fileType)
.withTitle(title)
.withDescription(description)
.withContent(fileContent)
.underFolder(parent)
.withinSite(site)
.asUser(user)
.create();
}
private List<FileModel> createRawFilesUnder(FolderModel parent, List<String> fileNames)
{
List<FileModel> createdFiles = new ArrayList<>();
AtomicInteger i = new AtomicInteger(0);
fileNames.forEach(fileName -> {
createdFiles.add(createFile(fileName, getOrNull(fileTypes, i.get()), getOrNull(titles, i.get()), getOrNull(descriptions, i.get()),
getOrNull(filesContents, i.get()), parent, getOrNull(aliases, i.get())));
i.getAndIncrement();
});
return createdFiles;
}
}

View File

@@ -0,0 +1,107 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.content;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.alfresco.rest.repo.resource.Folders.FOLDER_NAME_PREFIX;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import org.alfresco.rest.repo.resource.general.MultiCreator;
import org.alfresco.rest.repo.resource.general.MultipleContentsCreator;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.model.FolderModel;
public class SerialFoldersCreator
extends MultipleContentsCreator<FolderModel, MultiCreator.FoldersCreator>
implements MultiCreator.FoldersCreator
{
private final DataContent dataContent;
private final Map<String, FolderModel> foldersCache;
public SerialFoldersCreator(DataContent dataContent, Map<String, FolderModel> foldersCache)
{
super();
this.dataContent = dataContent;
this.foldersCache = foldersCache;
}
@Override
protected SerialFoldersCreator self()
{
return this;
}
@Override
public List<FolderModel> create()
{
verifyDataConsistency();
return createRawFoldersUnder(parent, names);
}
@Override
protected String generateRandomName()
{
return this.generateRandomNameWith(EMPTY);
}
@Override
protected String generateRandomNameWith(String prefix)
{
return super.generateRandomNameWith(FOLDER_NAME_PREFIX + prefix + "_");
}
protected FolderModel createFolder(String folderName, String title, String description, FolderModel parent, String alias)
{
return new RepoFolderCreator(dataContent, foldersCache)
.withAlias(alias)
.withName(folderName)
.withTitle(title)
.withDescription(description)
.underFolder(parent)
.withinSite(site)
.asUser(user)
.create();
}
private List<FolderModel> createRawFoldersUnder(FolderModel parent, List<String> folderNames)
{
List<FolderModel> createdFolders = new ArrayList<>();
AtomicInteger i = new AtomicInteger();
folderNames.forEach(folderName -> {
FolderModel createdFolder = createFolder(folderName, getOrNull(titles, i.get()), getOrNull(descriptions, i.get()), parent, getOrNull(aliases, i.get()));
createdFolders.add(createdFolder);
i.getAndIncrement();
});
return createdFolders;
}
}

View File

@@ -0,0 +1,105 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.general;
import java.util.function.Function;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.model.ContentModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
public abstract class ContentCreator<CONTENT extends ContentModel, SELF extends Creator.ContentCreator<CONTENT, ?>>
extends ResourceCreator<CONTENT, SELF>
implements Creator.ContentCreator<CONTENT, SELF>
{
private static final FolderModel DOCUMENT_LIBRARY = null;
protected SiteModel site;
protected final CONTENT contentModel;
protected FolderModel parent = DOCUMENT_LIBRARY;
public ContentCreator(CONTENT contentModel)
{
super();
this.contentModel = contentModel;
}
protected abstract SELF self();
@Override
public SELF withName(String name)
{
contentModel.setName(name);
return self();
}
@Override
public SELF withTitle(String title)
{
contentModel.setTitle(title);
return self();
}
@Override
public SELF withDescription(String description)
{
contentModel.setDescription(description);
return self();
}
@Override
public <FOLDER extends FolderModel> SELF underFolder(FOLDER parent)
{
this.parent = parent;
return self();
}
@Override
public <SITE extends SiteModel> SELF withinSite(SITE site)
{
this.site = site;
return self();
}
protected CONTENT create(DataContent dataContent, Function<CONTENT, CONTENT> creator)
{
if (site != null)
{
dataContent.usingSite(site);
}
if (parent != null)
{
dataContent.usingResource(parent);
}
if (user != null)
{
dataContent.usingUser(user);
}
return creator.apply(contentModel);
}
}

View File

@@ -0,0 +1,177 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.general;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.model.RestCategoryLinkBodyModel;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.model.RestNodeBodyMoveCopyModel;
import org.alfresco.rest.model.RestNodeModel;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.model.ContentModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
public abstract class ContentModifier<CONTENT extends ContentModel, SELF extends Modifier.ContentModifier<CONTENT, ?>>
extends ResourceModifier<CONTENT, SELF>
implements Modifier.ContentModifier<CONTENT, SELF>
{
protected SiteModel site;
private final DataContent dataContent;
private final RestWrapper restClient;
protected final CONTENT contentModel;
protected ContentModifier(DataContent dataContent, RestWrapper restClient, CONTENT contentModel)
{
super();
this.dataContent = dataContent;
this.restClient = restClient;
this.contentModel = contentModel;
}
public <SITE extends SiteModel> SELF withinSite(SITE site)
{
this.site = site;
return self();
}
protected CONTENT get(String id, Supplier<CONTENT> contentSupplier)
{
ContentModel getNodeModel = new ContentModel();
getNodeModel.setNodeRef(id);
RestNodeModel node = buildNodeRestRequest(restClient, getNodeModel).getNode();
CONTENT content = contentSupplier.get();
content.setName(node.getName());
content.setNodeRef(node.getId());
content.setCmisLocation(getCmisLocation(node.getPath(), node.getName()));
return content;
}
@Override
public <FOLDER extends FolderModel> void moveTo(FOLDER target)
{
RestNodeBodyMoveCopyModel moveModel = new RestNodeBodyMoveCopyModel();
moveModel.setTargetParentId(target.getNodeRef());
moveModel.setName(contentModel.getName());
RestNodeModel movedNode = buildNodeRestRequest(restClient, contentModel).includePath().move(moveModel);
contentModel.setCmisLocation(getCmisLocation(movedNode.getPath(), movedNode.getName()));
}
protected CONTENT copyTo(FolderModel target, Function<CONTENT, CONTENT> contentSupplier)
{
RestNodeBodyMoveCopyModel copyModel = new RestNodeBodyMoveCopyModel();
copyModel.setTargetParentId(target.getNodeRef());
copyModel.setName(contentModel.getName());
RestNodeModel nodeCopy = buildNodeRestRequest(restClient, contentModel).includePath().copy(copyModel);
CONTENT contentCopy = contentSupplier.apply(contentModel);
contentCopy.setName(nodeCopy.getName());
contentCopy.setNodeRef(nodeCopy.getId());
contentCopy.setCmisLocation(getCmisLocation(nodeCopy.getPath(), nodeCopy.getName()));
return contentCopy;
}
@Override
public void delete()
{
dataContent.usingUser(user).usingResource(contentModel).deleteContent();
}
@Override
public <FOLDER extends FolderModel> void linkTo(FOLDER secondaryParent)
{
buildNodeRestRequest(restClient, secondaryParent).addSecondaryChild(contentModel);
}
@Override
@SafeVarargs
public final <FOLDER extends FolderModel> void linkTo(FOLDER... secondaryParents)
{
Stream.of(secondaryParents).forEach(secondaryParent -> buildNodeRestRequest(restClient, secondaryParent).addSecondaryChildren(contentModel));
}
@Override
public <FOLDER extends FolderModel> void unlinkFrom(FOLDER secondaryParent)
{
buildNodeRestRequest(restClient, secondaryParent).removeSecondaryChild(contentModel);
}
@Override
public <CATEGORY extends RestCategoryModel> void linkTo(CATEGORY category)
{
buildNodeRestRequest(restClient, contentModel).linkToCategory(
RestCategoryLinkBodyModel.builder().categoryId(category.getId()).create());
}
@Override
@SafeVarargs
public final <CATEGORY extends RestCategoryModel> void linkTo(CATEGORY... categories)
{
buildNodeRestRequest(restClient, contentModel).linkToCategories(
Stream.of(categories)
.map(category -> RestCategoryLinkBodyModel.builder().categoryId(category.getId()).create())
.collect(Collectors.toList()));
}
@Override
public <CATEGORY extends RestCategoryModel> void unlinkFrom(CATEGORY category)
{
buildNodeRestRequest(restClient, contentModel).unlinkFromCategory(category.getId());
}
private static String getCmisLocation(Object pathMap, String name)
{
return Stream.concat(
Stream.of(pathMap)
.filter(Objects::nonNull)
.filter(path -> path instanceof Map)
.map(Map.class::cast)
.map(path -> path.get("elements"))
.filter(Objects::nonNull)
.filter(elements -> elements instanceof List)
.map(List.class::cast)
.flatMap(elements -> (Stream<?>) elements.stream())
.skip(1)
.filter(element -> element instanceof Map)
.map(Map.class::cast)
.map(element -> element.get("name"))
.filter(Objects::nonNull)
.filter(elementName -> elementName instanceof String)
.map(String.class::cast),
Stream.of(name))
.collect(Collectors.joining("/", "/", "/"));
}
}

View File

@@ -0,0 +1,107 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.general;
import java.util.random.RandomGenerator;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.commons.lang3.RandomStringUtils;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.utility.model.ContentModel;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FileType;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestModel;
import org.alfresco.utility.model.UserModel;
/**
* Declares operations, which can be performed to create repository resource.
*
* @param <RESOURCE>
* repository resource, e.g. folder, category, etc.
* @param <SELF>
* return type - this interface extension or implementation
*/
public interface Creator<RESOURCE extends TestModel, SELF extends Creator<RESOURCE, ?>>
{
SELF withName(String name);
<USER extends UserModel> SELF asUser(USER user);
RESOURCE create();
interface ContentCreator<CONTENT extends ContentModel, SELF extends ContentCreator<CONTENT, ?>>
extends Creator<CONTENT, SELF>
{
SELF withTitle(String title);
default SELF withRandomTitle()
{
return withTitle(RandomStringUtils.randomAlphanumeric(10));
}
SELF withDescription(String description);
default SELF withRandomDescription()
{
return withDescription(RandomStringUtils.randomAlphanumeric(20));
}
<FOLDER extends FolderModel> SELF underFolder(FOLDER parent);
<SITE extends SiteModel> SELF withinSite(SITE site);
}
interface FolderCreator extends ContentCreator<FolderModel, FolderCreator>
{}
interface FileCreator extends ContentCreator<FileModel, FileCreator>
{
FileCreator ofType(FileType fileType);
FileCreator withContent(String fileContent);
default FileCreator withRandomContent()
{
return withRandomContent(RandomGenerator.getDefault().nextInt(30, 70), 10);
}
default FileCreator withRandomContent(int wordsNumber, int wordsMaxLength)
{
return withContent(IntStream.range(0, wordsNumber)
.mapToObj(i -> RandomStringUtils.randomAlphanumeric(1, wordsMaxLength))
.collect(Collectors.joining(" ")));
}
}
interface CategoryCreator extends Creator<RestCategoryModel, CategoryCreator>
{
<CATEGORY extends RestCategoryModel> CategoryCreator underCategory(CATEGORY parent);
}
}

View File

@@ -0,0 +1,84 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.general;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.utility.model.ContentModel;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestModel;
import org.alfresco.utility.model.UserModel;
/**
* Declares operations, which can be performed on repository resource.
*
* @param <RESOURCE>
* repository resource, e.g. folder, category, etc.
* @param <SELF>
* return type - this interface extension or implementation
*/
public interface Modifier<RESOURCE extends TestModel, SELF extends Modifier<RESOURCE, ?>>
{
RESOURCE get(String id);
<USER extends UserModel> SELF asUser(USER user);
void delete();
interface ContentModifier<CONTENT extends ContentModel, SELF extends Modifier<CONTENT, ?>>
extends Modifier<CONTENT, SELF>
{
<FOLDER extends FolderModel> void moveTo(FOLDER target);
<FOLDER extends FolderModel> CONTENT copyTo(FOLDER target);
<FOLDER extends FolderModel> void linkTo(FOLDER secondaryParent);
<FOLDER extends FolderModel> void linkTo(FOLDER... secondaryParents);
<FOLDER extends FolderModel> void unlinkFrom(FOLDER secondaryParent);
<CATEGORY extends RestCategoryModel> void linkTo(CATEGORY category);
<CATEGORY extends RestCategoryModel> void linkTo(CATEGORY... categories);
<CATEGORY extends RestCategoryModel> void unlinkFrom(CATEGORY category);
<SITE extends SiteModel> SELF withinSite(SITE site);
}
interface FolderModifier extends ContentModifier<FolderModel, FolderModifier>,
ResourceIntroducer<Specifier.MultiContentSpecifier>, ResourceRemover<Specifier.AssociationSpecifier>
{}
interface FileModifier extends ContentModifier<FileModel, FileModifier>
{}
interface CategoryModifier extends Modifier<RestCategoryModel, CategoryModifier>,
ResourceIntroducer<Specifier.CategoriesSpecifier>
{}
}

View File

@@ -0,0 +1,92 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.general;
import java.util.List;
import java.util.random.RandomGenerator;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.utility.model.ContentModel;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FileType;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestModel;
import org.alfresco.utility.model.UserModel;
/**
* Declares actions, which can be performed to create multiple repository resources.
*
* @param <RESOURCE>
* repository resource, e.g. folder, category, etc.
* @param <SELF>
* return type - this interface extension or implementation
*/
public interface MultiCreator<RESOURCE extends TestModel, SELF extends MultiCreator<RESOURCE, ?>>
{
SELF withNames(String... names);
<USER extends UserModel> SELF asUser(USER user);
List<RESOURCE> create();
interface ContentsCreator<MODEL extends ContentModel, SELF extends ContentsCreator<MODEL, ?>> extends MultiCreator<MODEL, SELF>
{
SELF withTitles(String... titles);
SELF withRandomTitles();
SELF withDescriptions(String... descriptions);
SELF withRandomDescriptions();
<FOLDER extends FolderModel> SELF underFolder(FOLDER parent);
<SITE extends SiteModel> SELF withinSite(SITE site);
}
interface FoldersCreator extends ContentsCreator<FolderModel, FoldersCreator>
{}
interface FilesCreator extends ContentsCreator<FileModel, FilesCreator>
{
FilesCreator ofTypes(FileType... fileTypes);
FilesCreator withContents(List<String> filesContents);
default FilesCreator withRandomContents()
{
return withRandomContents(RandomGenerator.getDefault().nextInt(30, 70), 10);
}
FilesCreator withRandomContents(int wordsCount, int wordsMaxLength);
}
interface CategoriesCreator extends MultiCreator<RestCategoryModel, CategoriesCreator>
{
<CATEGORY extends RestCategoryModel> CategoriesCreator underCategory(CATEGORY parent);
}
}

View File

@@ -0,0 +1,106 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.general;
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.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.alfresco.utility.model.ContentModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
public abstract class MultipleContentsCreator<CONTENT extends ContentModel, SELF extends MultiCreator.ContentsCreator<CONTENT, ?>>
extends MultipleResourcesCreator<CONTENT, SELF>
implements MultiCreator.ContentsCreator<CONTENT, SELF>
{
protected FolderModel parent;
protected SiteModel site;
protected UserModel user;
protected List<String> titles = new ArrayList<>();
protected List<String> descriptions = new ArrayList<>();
public SELF withTitles(String... titles)
{
this.titles = Stream.of(titles).collect(Collectors.toList());
return self();
}
public SELF withRandomTitles()
{
this.titles = IntStream.range(0, names.size()).mapToObj(i -> RandomStringUtils.randomAlphanumeric(10)).collect(Collectors.toList());
return self();
}
public SELF withDescriptions(String... descriptions)
{
this.descriptions = Stream.of(descriptions).collect(Collectors.toList());
return self();
}
public SELF withRandomDescriptions()
{
this.descriptions = IntStream.range(0, names.size()).mapToObj(i -> RandomStringUtils.randomAlphanumeric(20)).collect(Collectors.toList());
return self();
}
public <FOLDER extends FolderModel> SELF underFolder(FOLDER parent)
{
this.parent = parent;
return self();
}
public <SITE extends SiteModel> SELF withinSite(SITE site)
{
this.site = site;
return self();
}
protected void verifyDataConsistency()
{
if (CollectionUtils.isEmpty(names))
{
throw new IllegalArgumentException("Names of files/folders to create needs to be provided");
}
if (CollectionUtils.isNotEmpty(titles) && titles.size() < names.size())
{
throw new IllegalArgumentException("Provided titles size is different from created files/folders amount");
}
if (CollectionUtils.isNotEmpty(descriptions) && descriptions.size() < names.size())
{
throw new IllegalArgumentException("Provided descriptions size is different from created files/folders amount");
}
}
}

View File

@@ -0,0 +1,129 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.general;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.requests.Node;
import org.alfresco.utility.model.RepoTestModel;
import org.alfresco.utility.model.TestModel;
import org.alfresco.utility.model.UserModel;
public abstract class MultipleResourcesCreator<RESOURCE extends TestModel, SELF extends MultiCreator<RESOURCE, ?>>
implements MultiCreator<RESOURCE, SELF>
{
protected UserModel user;
protected List<String> names;
protected List<String> aliases;
protected abstract SELF self();
public SELF withNames(String... names)
{
this.names = Stream.of(names).collect(Collectors.toList());
return self();
}
public SELF withRandomNames(String... prefixes)
{
this.aliases = Stream.of(prefixes).toList();
return withNames(Stream.of(prefixes).map(this::generateRandomNameWith).toArray(String[]::new));
}
public SELF withRandomNames(List<String> prefixes, List<String> suffixes)
{
this.aliases = prefixes;
if (CollectionUtils.isEmpty(prefixes) || CollectionUtils.isEmpty(suffixes) || prefixes.size() != suffixes.size())
{
throw new IllegalArgumentException("Provided suffixes size is different from prefixes size");
}
AtomicInteger i = new AtomicInteger();
return withNames(prefixes.stream()
.map(this::generateRandomNameWith)
.map(name -> name + suffixes.get(i.getAndIncrement()))
.toArray(String[]::new));
}
public SELF withRandomNames(int namesCount)
{
return withNames(IntStream.range(0, namesCount).mapToObj(i -> generateRandomName()).toArray(String[]::new));
}
@Override
public <USER extends UserModel> SELF asUser(USER user)
{
this.user = user;
return self();
}
protected String generateRandomName()
{
return generateRandomNameWith(RandomStringUtils.randomAlphanumeric(5) + "_");
}
protected String generateRandomNameWith(String prefix)
{
return generateRandomNameWith(prefix, EMPTY);
}
protected String generateRandomNameWith(String prefix, String suffix)
{
return prefix + UUID.randomUUID() + suffix;
}
protected Node buildNodeRestRequest(RestWrapper restClient, RepoTestModel node)
{
return restClient.authenticateUser(user).withCoreAPI().usingNode(node);
}
protected <T> T getOrNull(List<T> list, int index)
{
if (CollectionUtils.isEmpty(list))
{
return null;
}
if (index < 0 || index >= list.size())
{
return null;
}
return list.get(index);
}
}

View File

@@ -0,0 +1,104 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.general;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import java.util.UUID;
import org.apache.commons.lang3.RandomStringUtils;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.requests.Node;
import org.alfresco.utility.model.RepoTestModel;
import org.alfresco.utility.model.TestModel;
import org.alfresco.utility.model.UserModel;
public abstract class ResourceCreator<RESOURCE extends TestModel, SELF extends Creator<RESOURCE, ?>>
implements Creator<RESOURCE, SELF>
{
protected UserModel user;
protected String name;
protected String alias;
protected abstract SELF self();
@Override
public SELF withName(String name)
{
this.name = name;
return self();
}
public SELF withAlias(String alias)
{
this.alias = alias;
return self();
}
public SELF withRandomName()
{
return withName(generateRandomName());
}
public SELF withRandomName(String prefix)
{
return withName(generateRandomNameWith(prefix));
}
public SELF withRandomName(String prefix, String suffix)
{
return withName(generateRandomNameWith(prefix, suffix));
}
@Override
public <USER extends UserModel> SELF asUser(USER user)
{
this.user = user;
return self();
}
protected String generateRandomName()
{
return generateRandomNameWith(RandomStringUtils.randomAlphanumeric(5) + "_");
}
protected String generateRandomNameWith(String prefix)
{
return generateRandomNameWith(prefix, EMPTY);
}
protected String generateRandomNameWith(String prefix, String suffix)
{
return prefix + UUID.randomUUID() + suffix;
}
protected Node buildNodeRestRequest(RestWrapper restClient, RepoTestModel node)
{
return restClient.authenticateUser(user).withCoreAPI().usingNode(node);
}
}

View File

@@ -0,0 +1,37 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.general;
/**
* Declares an action introducing new repository resource like: folder, file, category, association, etc.
*
* @param <SPECIFIER>
* repository resource specifier, see {@link Specifier}
*/
public interface ResourceIntroducer<SPECIFIER extends Specifier>
{
SPECIFIER add();
}

View File

@@ -0,0 +1,53 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.general;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.requests.Node;
import org.alfresco.utility.model.RepoTestModel;
import org.alfresco.utility.model.TestModel;
import org.alfresco.utility.model.UserModel;
public abstract class ResourceModifier<RESOURCE extends TestModel, SELF extends Modifier<RESOURCE, ?>>
implements Modifier<RESOURCE, SELF>
{
protected UserModel user;
protected abstract SELF self();
@Override
public SELF asUser(UserModel user)
{
this.user = user;
return self();
}
protected Node buildNodeRestRequest(RestWrapper restClient, RepoTestModel node)
{
return restClient.authenticateUser(user).withCoreAPI().usingNode(node);
}
}

View File

@@ -0,0 +1,37 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.general;
/**
* Declares an action, which removes repository resource like association.
*
* @param <SPECIFIER>
* repository resource specifier, see {@link Specifier}
*/
public interface ResourceRemover<SPECIFIER extends Specifier>
{
SPECIFIER remove();
}

View File

@@ -0,0 +1,106 @@
/*-
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.repo.resource.general;
import org.alfresco.rest.model.RestTagModel;
import org.alfresco.utility.model.ContentModel;
/**
* Specifies repository resource to perform an operation on, like: add, modify, remove.
*/
public interface Specifier
{
interface FolderSpecifier extends Specifier
{
Creator.FolderCreator folder(String name);
Creator.FolderCreator randomFolder();
Creator.FolderCreator randomFolder(String prefix);
MultiCreator.FoldersCreator folders(String... names);
MultiCreator.FoldersCreator randomFolders(String... prefixes);
MultiCreator.FoldersCreator randomFolders(int quantity);
MultiCreator.FoldersCreator nestedFolders(String... names);
MultiCreator.FoldersCreator nestedRandomFolders(String... prefixes);
MultiCreator.FoldersCreator nestedRandomFolders(int depth);
}
interface FileSpecifier extends Specifier
{
Creator.FileCreator file(String name);
Creator.FileCreator randomFile();
Creator.FileCreator randomFile(String prefix);
MultiCreator.FilesCreator files(String... names);
MultiCreator.FilesCreator randomFiles(String... prefixes);
MultiCreator.FilesCreator randomFiles(int quantity);
}
interface AssociationSpecifier extends Specifier
{
<CONTENT extends ContentModel> void secondaryContent(CONTENT content);
<TAG extends RestTagModel> void tag(TAG tag);
}
interface MultiContentSpecifier extends FolderSpecifier, FileSpecifier, AssociationSpecifier
{
<CONTENT extends ContentModel> void secondaryContent(CONTENT... contents);
<TAG extends RestTagModel> void tags(TAG... tags);
}
interface CategoriesSpecifier extends Specifier
{
Creator.CategoryCreator category(String name);
Creator.CategoryCreator randomCategory();
Creator.CategoryCreator randomCategory(String prefix);
MultiCreator.CategoriesCreator categories(String... names);
MultiCreator.CategoriesCreator randomCategories(String... prefixes);
MultiCreator.CategoriesCreator randomCategories(int quantity);
MultiCreator.CategoriesCreator nestedCategories(String... names);
MultiCreator.CategoriesCreator nestedRandomCategories(String... prefixes);
MultiCreator.CategoriesCreator nestedRandomCategories(int depth);
}
}

View File

@@ -2,6 +2,11 @@ package org.alfresco.rest.favorites;
import java.util.List; import java.util.List;
import org.hamcrest.Matchers;
import org.springframework.http.HttpStatus;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.alfresco.dataprep.CMISUtil.DocumentType; import org.alfresco.dataprep.CMISUtil.DocumentType;
import org.alfresco.rest.RestTest; import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestErrorModel; import org.alfresco.rest.model.RestErrorModel;
@@ -20,14 +25,11 @@ import org.alfresco.utility.model.TestGroup;
import org.alfresco.utility.model.UserModel; import org.alfresco.utility.model.UserModel;
import org.alfresco.utility.testrail.ExecutionType; import org.alfresco.utility.testrail.ExecutionType;
import org.alfresco.utility.testrail.annotation.TestRail; import org.alfresco.utility.testrail.annotation.TestRail;
import org.hamcrest.Matchers;
import org.springframework.http.HttpStatus;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class GetFavoritesTests extends RestTest public class GetFavoritesTests extends RestTest
{ {
private static final String ALLOWABLE_OPERATIONS = "allowableOperations"; private static final String ALLOWABLE_OPERATIONS = "allowableOperations";
private static final String ASPECT_NAMES = "aspectNames";
private UserModel adminUserModel, userModel; private UserModel adminUserModel, userModel;
private SiteModel firstSiteModel; private SiteModel firstSiteModel;
private SiteModel secondSiteModel; private SiteModel secondSiteModel;
@@ -56,7 +58,7 @@ public class GetFavoritesTests extends RestTest
firstSiteUsers = dataUser.addUsersWithRolesToSite(firstSiteModel, UserRole.SiteManager, UserRole.SiteCollaborator, UserRole.SiteConsumer, firstSiteUsers = dataUser.addUsersWithRolesToSite(firstSiteModel, UserRole.SiteManager, UserRole.SiteCollaborator, UserRole.SiteConsumer,
UserRole.SiteContributor); UserRole.SiteContributor);
secondSiteUsers = dataUser.addUsersWithRolesToSite(secondSiteModel, UserRole.SiteManager, UserRole.SiteCollaborator, UserRole.SiteConsumer, secondSiteUsers = dataUser.addUsersWithRolesToSite(secondSiteModel, UserRole.SiteManager, UserRole.SiteCollaborator, UserRole.SiteConsumer,
UserRole.SiteContributor); UserRole.SiteContributor);
restClient.authenticateUser(userModel); restClient.authenticateUser(userModel);
restClient.withCoreAPI().usingUser(userModel).addSiteToFavorites(firstSiteModel); restClient.withCoreAPI().usingUser(userModel).addSiteToFavorites(firstSiteModel);
@@ -64,9 +66,9 @@ public class GetFavoritesTests extends RestTest
restClient.withCoreAPI().usingUser(userModel).addSiteToFavorites(thirdSiteModel); restClient.withCoreAPI().usingUser(userModel).addSiteToFavorites(thirdSiteModel);
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.SANITY, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.SANITY,
description = "Verify Manager user gets favorites with Rest API and status code is 200") description = "Verify Manager user gets favorites with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.SANITY }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.SANITY})
public void managerIsAbleToRetrieveFavorites() public void managerIsAbleToRetrieveFavorites()
{ {
restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteManager)); restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteManager));
@@ -79,10 +81,10 @@ public class GetFavoritesTests extends RestTest
.assertThat().entriesListContains("targetGuid", secondSiteModel.getGuid()); .assertThat().entriesListContains("targetGuid", secondSiteModel.getGuid());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.SANITY, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.SANITY,
description = "Verify user gets status code 401 if authentication call fails") description = "Verify user gets status code 401 if authentication call fails")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.SANITY }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.SANITY})
// @Bug(id = "MNT-16904", description = "It fails only on environment with tenants") // @Bug(id = "MNT-16904", description = "It fails only on environment with tenants")
public void userIsNotAbleToRetrieveFavoritesIfAuthenticationFails() public void userIsNotAbleToRetrieveFavoritesIfAuthenticationFails()
{ {
UserModel siteManager = firstSiteUsers.getOneUserWithRole(UserRole.SiteManager); UserModel siteManager = firstSiteUsers.getOneUserWithRole(UserRole.SiteManager);
@@ -91,44 +93,44 @@ public class GetFavoritesTests extends RestTest
restClient.assertStatusCodeIs(HttpStatus.UNAUTHORIZED); restClient.assertStatusCodeIs(HttpStatus.UNAUTHORIZED);
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify Admin user gets favorites sites with Rest API and status code is 200") description = "Verify Admin user gets favorites sites with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void adminIsAbleToRetrieveFavoritesSites() public void adminIsAbleToRetrieveFavoritesSites()
{ {
restClient.authenticateUser(adminUserModel).withCoreAPI().usingUser(adminUserModel).addSiteToFavorites(firstSiteModel); restClient.authenticateUser(adminUserModel).withCoreAPI().usingUser(adminUserModel).addSiteToFavorites(firstSiteModel);
restClient.withCoreAPI().usingUser(adminUserModel).addSiteToFavorites(secondSiteModel); restClient.withCoreAPI().usingUser(adminUserModel).addSiteToFavorites(secondSiteModel);
userFavorites = restClient.withCoreAPI() userFavorites = restClient.withCoreAPI()
.usingAuthUser().where().targetSiteExist().getFavorites(); .usingAuthUser().where().targetSiteExist().getFavorites();
restClient.assertStatusCodeIs(HttpStatus.OK); restClient.assertStatusCodeIs(HttpStatus.OK);
userFavorites.assertThat().entriesListContains("targetGuid", firstSiteModel.getGuid()) userFavorites.assertThat().entriesListContains("targetGuid", firstSiteModel.getGuid())
.and().entriesListContains("targetGuid", secondSiteModel.getGuid()); .and().entriesListContains("targetGuid", secondSiteModel.getGuid());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify Admin user gets favorites folders with Rest API and status code is 200") description = "Verify Admin user gets favorites folders with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void adminIsAbleToRetrieveFavoritesFolders() public void adminIsAbleToRetrieveFavoritesFolders()
{ {
restClient.authenticateUser(adminUserModel).withCoreAPI().usingUser(adminUserModel).addFolderToFavorites(firstFolderModel); restClient.authenticateUser(adminUserModel).withCoreAPI().usingUser(adminUserModel).addFolderToFavorites(firstFolderModel);
restClient.withCoreAPI().usingUser(adminUserModel).addFolderToFavorites(secondFolderModel); restClient.withCoreAPI().usingUser(adminUserModel).addFolderToFavorites(secondFolderModel);
userFavorites = restClient.withCoreAPI() userFavorites = restClient.withCoreAPI()
.usingAuthUser().where().targetFolderExist().getFavorites(); .usingAuthUser().where().targetFolderExist().getFavorites();
restClient.assertStatusCodeIs(HttpStatus.OK); restClient.assertStatusCodeIs(HttpStatus.OK);
userFavorites.assertThat().entriesListContains("targetGuid", firstFolderModel.getNodeRef()) userFavorites.assertThat().entriesListContains("targetGuid", firstFolderModel.getNodeRef())
.and().entriesListContains("targetGuid", secondFolderModel.getNodeRef()); .and().entriesListContains("targetGuid", secondFolderModel.getNodeRef());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify Admin user gets favorites files with Rest API and status code is 200") description = "Verify Admin user gets favorites files with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void adminIsAbleToRetrieveFavoritesFiles() public void adminIsAbleToRetrieveFavoritesFiles()
{ {
restClient.authenticateUser(adminUserModel).withCoreAPI().usingUser(adminUserModel).addFileToFavorites(firstFileModel); restClient.authenticateUser(adminUserModel).withCoreAPI().usingUser(adminUserModel).addFileToFavorites(firstFileModel);
restClient.withCoreAPI().usingUser(adminUserModel).addFileToFavorites(secondFileModel); restClient.withCoreAPI().usingUser(adminUserModel).addFileToFavorites(secondFileModel);
userFavorites = restClient.withCoreAPI() userFavorites = restClient.withCoreAPI()
.usingAuthUser().where().targetFileExist().getFavorites(); .usingAuthUser().where().targetFileExist().getFavorites();
restClient.assertStatusCodeIs(HttpStatus.OK); restClient.assertStatusCodeIs(HttpStatus.OK);
@@ -136,87 +138,87 @@ public class GetFavoritesTests extends RestTest
.and().entriesListContains("targetGuid", secondFileModel.getNodeRefWithoutVersion()); .and().entriesListContains("targetGuid", secondFileModel.getNodeRefWithoutVersion());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify Collaborator user gets favorites with Rest API and status code is 200") description = "Verify Collaborator user gets favorites with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void collaboratorIsAbleToRetrieveFavorites() public void collaboratorIsAbleToRetrieveFavorites()
{ {
restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator)) restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator))
.withCoreAPI().usingAuthUser().addSiteToFavorites(firstSiteModel); .withCoreAPI().usingAuthUser().addSiteToFavorites(firstSiteModel);
restClient.withCoreAPI().usingAuthUser().addSiteToFavorites(secondSiteModel); restClient.withCoreAPI().usingAuthUser().addSiteToFavorites(secondSiteModel);
userFavorites = restClient.withCoreAPI().usingAuthUser().getFavorites(); userFavorites = restClient.withCoreAPI().usingAuthUser().getFavorites();
restClient.assertStatusCodeIs(HttpStatus.OK); restClient.assertStatusCodeIs(HttpStatus.OK);
userFavorites.assertThat().entriesListContains("targetGuid", firstSiteModel.getGuid()) userFavorites.assertThat().entriesListContains("targetGuid", firstSiteModel.getGuid())
.and().entriesListContains("targetGuid", secondSiteModel.getGuid()); .and().entriesListContains("targetGuid", secondSiteModel.getGuid());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify Contributor user gets favorites with Rest API and status code is 200") description = "Verify Contributor user gets favorites with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void contributorIsAbleToRetrieveFavorites() public void contributorIsAbleToRetrieveFavorites()
{ {
restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteContributor)) restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteContributor))
.withCoreAPI().usingAuthUser().addSiteToFavorites(firstSiteModel); .withCoreAPI().usingAuthUser().addSiteToFavorites(firstSiteModel);
restClient.withCoreAPI().usingAuthUser().addSiteToFavorites(secondSiteModel); restClient.withCoreAPI().usingAuthUser().addSiteToFavorites(secondSiteModel);
userFavorites = restClient.withCoreAPI().usingAuthUser().getFavorites(); userFavorites = restClient.withCoreAPI().usingAuthUser().getFavorites();
restClient.assertStatusCodeIs(HttpStatus.OK); restClient.assertStatusCodeIs(HttpStatus.OK);
userFavorites.assertThat().entriesListContains("targetGuid", firstSiteModel.getGuid()).and() userFavorites.assertThat().entriesListContains("targetGuid", firstSiteModel.getGuid()).and()
.entriesListContains("targetGuid", secondSiteModel.getGuid()); .entriesListContains("targetGuid", secondSiteModel.getGuid());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify Consumer user gets favorites with Rest API and status code is 200") description = "Verify Consumer user gets favorites with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void consumerIsAbleToRetrieveFavorites() public void consumerIsAbleToRetrieveFavorites()
{ {
restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer)) restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer))
.withCoreAPI().usingAuthUser().addSiteToFavorites(firstSiteModel); .withCoreAPI().usingAuthUser().addSiteToFavorites(firstSiteModel);
restClient.withCoreAPI().usingAuthUser().addSiteToFavorites(secondSiteModel); restClient.withCoreAPI().usingAuthUser().addSiteToFavorites(secondSiteModel);
userFavorites = restClient.withCoreAPI().usingAuthUser().getFavorites(); userFavorites = restClient.withCoreAPI().usingAuthUser().getFavorites();
restClient.assertStatusCodeIs(HttpStatus.OK); restClient.assertStatusCodeIs(HttpStatus.OK);
userFavorites.assertThat().entriesListContains("targetGuid", firstSiteModel.getGuid()) userFavorites.assertThat().entriesListContains("targetGuid", firstSiteModel.getGuid())
.assertThat().entriesListContains("targetGuid", secondSiteModel.getGuid()); .assertThat().entriesListContains("targetGuid", secondSiteModel.getGuid());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify user doesn't have permission to get favorites of another user with Rest API and status code is 404") description = "Verify user doesn't have permission to get favorites of another user with Rest API and status code is 404")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsNotAbleToRetrieveFavoritesOfAnotherUser() public void userIsNotAbleToRetrieveFavoritesOfAnotherUser()
{ {
restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer)) restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer))
.withCoreAPI().usingUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator)).getFavorites(); .withCoreAPI().usingUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator)).getFavorites();
restClient.assertStatusCodeIs(HttpStatus.NOT_FOUND) restClient.assertStatusCodeIs(HttpStatus.NOT_FOUND)
.assertLastError().containsSummary(String.format(RestErrorModel.ENTITY_NOT_FOUND, firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator).getUsername())); .assertLastError().containsSummary(String.format(RestErrorModel.ENTITY_NOT_FOUND, firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator).getUsername()));
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify user doesn't have permission to get favorites of admin user with Rest API and status code is 200") description = "Verify user doesn't have permission to get favorites of admin user with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsNotAbleToRetrieveFavoritesOfAdminUser() public void userIsNotAbleToRetrieveFavoritesOfAdminUser()
{ {
restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer)).withCoreAPI() restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer)).withCoreAPI()
.usingUser(adminUserModel).getFavorites(); .usingUser(adminUserModel).getFavorites();
restClient.assertStatusCodeIs(HttpStatus.NOT_FOUND) restClient.assertStatusCodeIs(HttpStatus.NOT_FOUND)
.assertLastError().containsSummary(String.format(RestErrorModel.ENTITY_NOT_FOUND, adminUserModel.getUsername())); .assertLastError().containsSummary(String.format(RestErrorModel.ENTITY_NOT_FOUND, adminUserModel.getUsername()));
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify admin user doesn't have permission to get favorites of another user with Rest API and status code is 200") description = "Verify admin user doesn't have permission to get favorites of another user with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void adminIsNotAbleToRetrieveFavoritesOfAnotherUser() public void adminIsNotAbleToRetrieveFavoritesOfAnotherUser()
{ {
restClient.authenticateUser(adminUserModel).withCoreAPI().usingUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator)) restClient.authenticateUser(adminUserModel).withCoreAPI().usingUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator))
.getFavorites(); .getFavorites();
restClient.assertStatusCodeIs(HttpStatus.NOT_FOUND) restClient.assertStatusCodeIs(HttpStatus.NOT_FOUND)
.assertLastError().containsSummary(String.format(RestErrorModel.ENTITY_NOT_FOUND, firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator).getUsername())); .assertLastError().containsSummary(String.format(RestErrorModel.ENTITY_NOT_FOUND, firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator).getUsername()));
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify User gets only favorites sites with Rest API and status code is 200") description = "Verify User gets only favorites sites with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToRetrieveOnlyFavoritesSites() public void userIsAbleToRetrieveOnlyFavoritesSites()
{ {
restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteManager)); restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteManager));
@@ -232,9 +234,9 @@ public class GetFavoritesTests extends RestTest
.and().entriesListDoesNotContain("targetGuid", firstFolderModel.getNodeRef()); .and().entriesListDoesNotContain("targetGuid", firstFolderModel.getNodeRef());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify User gets only favorites files with Rest API and status code is 200") description = "Verify User gets only favorites files with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToRetrieveOnlyFavoritesFiles() public void userIsAbleToRetrieveOnlyFavoritesFiles()
{ {
restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator)); restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator));
@@ -250,9 +252,9 @@ public class GetFavoritesTests extends RestTest
.and().entriesListDoesNotContain("targetGuid", firstFolderModel.getNodeRef()); .and().entriesListDoesNotContain("targetGuid", firstFolderModel.getNodeRef());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify User gets only favorites folders with Rest API and status code is 200") description = "Verify User gets only favorites folders with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToRetrieveOnlyFavoritesFolders() public void userIsAbleToRetrieveOnlyFavoritesFolders()
{ {
restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator)); restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator));
@@ -268,9 +270,9 @@ public class GetFavoritesTests extends RestTest
.and().entriesListDoesNotContain("targetGuid", firstFileModel.getNodeRefWithoutVersion()); .and().entriesListDoesNotContain("targetGuid", firstFileModel.getNodeRefWithoutVersion());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify User gets only favorites files or folders with Rest API and status code is 200") description = "Verify User gets only favorites files or folders with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToRetrieveFavoritesFilesOrFolders() public void userIsAbleToRetrieveFavoritesFilesOrFolders()
{ {
restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer)); restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer));
@@ -289,9 +291,9 @@ public class GetFavoritesTests extends RestTest
.and().entriesListDoesNotContain("targetGuid", firstSiteModel.getGuid()); .and().entriesListDoesNotContain("targetGuid", firstSiteModel.getGuid());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify User gets only favorites files or sites with Rest API and status code is 200") description = "Verify User gets only favorites files or sites with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToRetrieveFavoritesFilesOrSites() public void userIsAbleToRetrieveFavoritesFilesOrSites()
{ {
restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteManager)); restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteManager));
@@ -310,9 +312,9 @@ public class GetFavoritesTests extends RestTest
.and().entriesListDoesNotContain("targetGuid", firstFolderModel.getNodeRef()); .and().entriesListDoesNotContain("targetGuid", firstFolderModel.getNodeRef());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify User gets only favorites folders or sites with Rest API and status code is 200") description = "Verify User gets only favorites folders or sites with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToRetrieveFavoritesFoldersOrSites() public void userIsAbleToRetrieveFavoritesFoldersOrSites()
{ {
restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteManager)); restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteManager));
@@ -331,9 +333,9 @@ public class GetFavoritesTests extends RestTest
.and().entriesListDoesNotContain("targetGuid", firstFileModel.getNodeRefWithoutVersion()); .and().entriesListDoesNotContain("targetGuid", firstFileModel.getNodeRefWithoutVersion());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify User gets all favorites with Rest API and status code is 200") description = "Verify User gets all favorites with Rest API and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToRetrieveAllFavorites() public void userIsAbleToRetrieveAllFavorites()
{ {
restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator)); restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator));
@@ -362,9 +364,9 @@ public class GetFavoritesTests extends RestTest
.and().entriesListDoesNotContain("targetGuid", secondFileModel.getNodeRefWithoutVersion()); .and().entriesListDoesNotContain("targetGuid", secondFileModel.getNodeRefWithoutVersion());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify request for a user with no favorites returns status 200") description = "Verify request for a user with no favorites returns status 200")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userHasNoFavorites() public void userHasNoFavorites()
{ {
restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteContributor)); restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteContributor));
@@ -374,9 +376,9 @@ public class GetFavoritesTests extends RestTest
userFavorites.assertThat().entriesListIsEmpty().and().paginationField("totalItems").is("0"); userFavorites.assertThat().entriesListIsEmpty().and().paginationField("totalItems").is("0");
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify request using invalid where parameter returns status 400") description = "Verify request using invalid where parameter returns status 400")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void getFavoritesUsingInvalidWhereParameter() public void getFavoritesUsingInvalidWhereParameter()
{ {
restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer)); restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer));
@@ -390,9 +392,9 @@ public class GetFavoritesTests extends RestTest
.assertLastError().containsSummary(String.format(RestErrorModel.INVALID_ARGUMENT, "WHERE query")); .assertLastError().containsSummary(String.format(RestErrorModel.INVALID_ARGUMENT, "WHERE query"));
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify User gets correct favorites after deleting a favorite") description = "Verify User gets correct favorites after deleting a favorite")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void checkFavoriteFolderIsRemoved() public void checkFavoriteFolderIsRemoved()
{ {
restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteManager)); restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteManager));
@@ -408,9 +410,9 @@ public class GetFavoritesTests extends RestTest
.and().paginationField("totalItems").is("2"); .and().paginationField("totalItems").is("2");
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify get favorites specifying -me- string in place of <personid> for request") description = "Verify get favorites specifying -me- string in place of <personid> for request")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToGetFavoritesWhenUsingMeAsUsername() public void userIsAbleToGetFavoritesWhenUsingMeAsUsername()
{ {
userFavorites = restClient.authenticateUser(userModel).withCoreAPI().usingMe().getFavorites(); userFavorites = restClient.authenticateUser(userModel).withCoreAPI().usingMe().getFavorites();
@@ -418,9 +420,9 @@ public class GetFavoritesTests extends RestTest
userFavorites.assertThat().entriesListContains("targetGuid", firstSiteModel.getGuid()).and().entriesListContains("targetGuid", secondSiteModel.getGuid()); userFavorites.assertThat().entriesListContains("targetGuid", firstSiteModel.getGuid()).and().entriesListContains("targetGuid", secondSiteModel.getGuid());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify get favorites using empty for where parameter for request") description = "Verify get favorites using empty for where parameter for request")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToGetFavoritesWhenUsingEmptyWhereParameter() public void userIsAbleToGetFavoritesWhenUsingEmptyWhereParameter()
{ {
userFavorites = restClient.authenticateUser(adminUserModel).withCoreAPI().usingAuthUser().where().getFavorites(); userFavorites = restClient.authenticateUser(adminUserModel).withCoreAPI().usingAuthUser().where().getFavorites();
@@ -428,27 +430,27 @@ public class GetFavoritesTests extends RestTest
.assertLastError().containsSummary(String.format(RestErrorModel.INVALID_ARGUMENT, "WHERE query")); .assertLastError().containsSummary(String.format(RestErrorModel.INVALID_ARGUMENT, "WHERE query"));
} }
@TestRail(section = { TestGroup.REST_API,TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify that for invalid maxItems parameter status code returned is 400.") description = "Verify that for invalid maxItems parameter status code returned is 400.")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void checkInvalidMaxItemsStatusCode() public void checkInvalidMaxItemsStatusCode()
{ {
restClient.authenticateUser(adminUserModel).withParams("maxItems=AB").withCoreAPI().usingUser(adminUserModel).getFavorites(); restClient.authenticateUser(adminUserModel).withParams("maxItems=AB").withCoreAPI().usingUser(adminUserModel).getFavorites();
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError().containsSummary("Invalid paging parameter"); restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError().containsSummary("Invalid paging parameter");
} }
@TestRail(section = { TestGroup.REST_API,TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify that for invalid skipCount parameter status code returned is 400.") description = "Verify that for invalid skipCount parameter status code returned is 400.")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void checkInvalidSkipCountStatusCode() public void checkInvalidSkipCountStatusCode()
{ {
restClient.authenticateUser(adminUserModel).withParams("skipCount=AB").withCoreAPI().usingUser(adminUserModel).getFavorites(); restClient.authenticateUser(adminUserModel).withParams("skipCount=AB").withCoreAPI().usingUser(adminUserModel).getFavorites();
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError().containsSummary("Invalid paging parameter"); restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError().containsSummary("Invalid paging parameter");
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify get favorites when using invalid network id for non-tenant user") description = "Verify get favorites when using invalid network id for non-tenant user")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void getFavoritesWhenNetworkIdIsInvalid() public void getFavoritesWhenNetworkIdIsInvalid()
{ {
UserModel networkUserModel = dataUser.createRandomTestUser(); UserModel networkUserModel = dataUser.createRandomTestUser();
@@ -457,9 +459,9 @@ public class GetFavoritesTests extends RestTest
restClient.assertStatusCodeIs(HttpStatus.NOT_FOUND).assertLastError().containsSummary(String.format(RestErrorModel.ENTITY_NOT_FOUND, networkUserModel.getUsername())); restClient.assertStatusCodeIs(HttpStatus.NOT_FOUND).assertLastError().containsSummary(String.format(RestErrorModel.ENTITY_NOT_FOUND, networkUserModel.getUsername()));
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify get favorites using AND instead of OR in where parameter for request") description = "Verify get favorites using AND instead of OR in where parameter for request")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsNotAbleToGetFavoritesWhenUsingANDInWhereParameter() public void userIsNotAbleToGetFavoritesWhenUsingANDInWhereParameter()
{ {
userFavorites = restClient.withCoreAPI().usingAuthUser().where().targetFolderExist().invalidWhereParameter("AND").targetFileExist().getFavorites(); userFavorites = restClient.withCoreAPI().usingAuthUser().where().targetFolderExist().invalidWhereParameter("AND").targetFileExist().getFavorites();
@@ -467,9 +469,9 @@ public class GetFavoritesTests extends RestTest
.assertLastError().containsSummary(String.format(RestErrorModel.INVALID_ARGUMENT, "WHERE query")); .assertLastError().containsSummary(String.format(RestErrorModel.INVALID_ARGUMENT, "WHERE query"));
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify get favorites using wrong name instead of EXISTS in where parameter for request") description = "Verify get favorites using wrong name instead of EXISTS in where parameter for request")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsNotAbleToGetFavoritesWhenUsingWrongWhereParameter() public void userIsNotAbleToGetFavoritesWhenUsingWrongWhereParameter()
{ {
userFavorites = restClient.withCoreAPI().usingAuthUser().where().invalidWhereParameter("EXIST((target/site))").targetFileExist().getFavorites(); userFavorites = restClient.withCoreAPI().usingAuthUser().where().invalidWhereParameter("EXIST((target/site))").targetFileExist().getFavorites();
@@ -477,9 +479,9 @@ public class GetFavoritesTests extends RestTest
.assertLastError().containsSummary(String.format(RestErrorModel.INVALID_ARGUMENT, "WHERE query")); .assertLastError().containsSummary(String.format(RestErrorModel.INVALID_ARGUMENT, "WHERE query"));
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify get favorites except the first one for request") description = "Verify get favorites except the first one for request")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToGetFavoritesExceptTheFirstOne() public void userIsAbleToGetFavoritesExceptTheFirstOne()
{ {
userFavorites = restClient.authenticateUser(userModel).withParams("skipCount=1").withCoreAPI().usingUser(userModel).getFavorites(); userFavorites = restClient.authenticateUser(userModel).withParams("skipCount=1").withCoreAPI().usingUser(userModel).getFavorites();
@@ -490,9 +492,9 @@ public class GetFavoritesTests extends RestTest
.and().entriesListDoesNotContain("targetGuid", thirdSiteModel.getGuid()); .and().entriesListDoesNotContain("targetGuid", thirdSiteModel.getGuid());
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify get first two favorites sites") description = "Verify get first two favorites sites")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToGetFirstTwoFavorites() public void userIsAbleToGetFirstTwoFavorites()
{ {
userFavorites = restClient.authenticateUser(userModel).withParams("maxItems=2").withCoreAPI().usingUser(userModel).getFavorites(); userFavorites = restClient.authenticateUser(userModel).withParams("maxItems=2").withCoreAPI().usingUser(userModel).getFavorites();
@@ -506,9 +508,9 @@ public class GetFavoritesTests extends RestTest
.and().field("count").is("2"); .and().field("count").is("2");
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify get favorites sites when using empty values for skipCount and maxItems") description = "Verify get favorites sites when using empty values for skipCount and maxItems")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToGetFavoritesWhenSkipCountAndMaxItemsAreEmpty() public void userIsAbleToGetFavoritesWhenSkipCountAndMaxItemsAreEmpty()
{ {
restClient.authenticateUser(userModel).withParams("skipCount= ").withCoreAPI().usingUser(userModel).getFavorites(); restClient.authenticateUser(userModel).withParams("skipCount= ").withCoreAPI().usingUser(userModel).getFavorites();
@@ -518,9 +520,9 @@ public class GetFavoritesTests extends RestTest
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError().containsSummary(String.format(RestErrorModel.INVALID_MAXITEMS, " ")); restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError().containsSummary(String.format(RestErrorModel.INVALID_MAXITEMS, " "));
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify the get favorites request for a high value for skipCount parameter") description = "Verify the get favorites request for a high value for skipCount parameter")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToGetFavoritesWithHighSkipCount() public void userIsAbleToGetFavoritesWithHighSkipCount()
{ {
userFavorites = restClient.authenticateUser(userModel).withParams("skipCount=999999999").withCoreAPI().usingUser(userModel).getFavorites(); userFavorites = restClient.authenticateUser(userModel).withParams("skipCount=999999999").withCoreAPI().usingUser(userModel).getFavorites();
@@ -529,9 +531,9 @@ public class GetFavoritesTests extends RestTest
userFavorites.assertThat().entriesListIsEmpty().assertThat().paginationField("skipCount").is("999999999"); userFavorites.assertThat().entriesListIsEmpty().assertThat().paginationField("skipCount").is("999999999");
} }
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify the get favorites request with properties parameter applied") description = "Verify the get favorites request with properties parameter applied")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void userIsAbleToGetFavoritesWithPropertiesParamApplied() public void userIsAbleToGetFavoritesWithPropertiesParamApplied()
{ {
userFavorites = restClient.authenticateUser(userModel).withParams("properties=targetGuid").withCoreAPI().usingUser(userModel).getFavorites(); userFavorites = restClient.authenticateUser(userModel).withParams("properties=targetGuid").withCoreAPI().usingUser(userModel).getFavorites();
@@ -541,8 +543,8 @@ public class GetFavoritesTests extends RestTest
restPersonFavoritesModel.assertThat().field("targetGuid").is(thirdSiteModel.getGuid()).and().field("createdAt").isNull(); restPersonFavoritesModel.assertThat().field("targetGuid").is(thirdSiteModel.getGuid()).and().field("createdAt").isNull();
} }
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION, description = "Verify entry details for get favorites response with Rest API") @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION, description = "Verify entry details for get favorites response with Rest API")
public void checkResponseSchemaForGetFavorites() public void checkResponseSchemaForGetFavorites()
{ {
userFavorites = restClient.authenticateUser(userModel).withCoreAPI().usingAuthUser().getFavorites(); userFavorites = restClient.authenticateUser(userModel).withCoreAPI().usingAuthUser().getFavorites();
@@ -564,8 +566,7 @@ public class GetFavoritesTests extends RestTest
description = "Verify if get favorites response returns allowableOperations object when requested") description = "Verify if get favorites response returns allowableOperations object when requested")
public void checkResponsesForGetFavoritesWithAllowableOperations() public void checkResponsesForGetFavoritesWithAllowableOperations()
{ {
final RestPersonFavoritesModelsCollection adminFavorites = final RestPersonFavoritesModelsCollection adminFavorites = restClient.authenticateUser(adminUserModel).withCoreAPI().usingAuthUser().include(ALLOWABLE_OPERATIONS).getFavorites();
restClient.authenticateUser(adminUserModel).withCoreAPI().usingAuthUser().include(ALLOWABLE_OPERATIONS).getFavorites();
restClient.assertStatusCodeIs(HttpStatus.OK); restClient.assertStatusCodeIs(HttpStatus.OK);
adminFavorites.getEntries().stream() adminFavorites.getEntries().stream()
@@ -576,18 +577,30 @@ public class GetFavoritesTests extends RestTest
@TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION, @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify the get favorites request with properties parameter applied") description = "Verify the get favorites request with properties parameter applied")
@Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
public void checkSearchResponseContainsIsFavoriteWhenRequested() throws InterruptedException { public void checkSearchResponseContainsIsFavoriteWhenRequested() throws InterruptedException
{
final SearchRequest query = new SearchRequest(); final SearchRequest query = new SearchRequest();
final RestRequestQueryModel queryReq = new RestRequestQueryModel(); final RestRequestQueryModel queryReq = new RestRequestQueryModel();
queryReq.setQuery(firstFileModel.getName()); queryReq.setQuery(firstFileModel.getName());
query.setQuery(queryReq); query.setQuery(queryReq);
query.setInclude(List.of("isFavorite")); query.setInclude(List.of("isFavorite"));
Utility.sleep(500, 60000, () -> Utility.sleep(500, 60000, () -> {
{ restClient.authenticateUser(adminUserModel).withSearchAPI().search(query);
restClient.authenticateUser(adminUserModel).withSearchAPI().search(query); restClient.onResponse().assertThat().body("list.entries.entry[0].isFavorite", Matchers.notNullValue());
restClient.onResponse().assertThat().body("list.entries.entry[0].isFavorite", Matchers.notNullValue()); });
} }
);
@Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION})
@TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION,
description = "Verify if get favorites response returns aspectNames when requested")
public void checkResponsesForGetFavoritesWithAspectNames()
{
final RestPersonFavoritesModelsCollection adminFavorites = restClient.authenticateUser(adminUserModel).withCoreAPI().usingAuthUser().include(ASPECT_NAMES).getFavorites();
restClient.assertStatusCodeIs(HttpStatus.OK);
adminFavorites.getEntries().stream()
.map(RestPersonFavoritesModel::onModel)
.forEach(m -> m.assertThat().field(ASPECT_NAMES).isNotEmpty());
} }
} }

View File

@@ -9,7 +9,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId> <artifactId>alfresco-community-repo-tests</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<developers> <developers>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId> <artifactId>alfresco-community-repo-packaging</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<properties> <properties>
@@ -113,7 +113,7 @@
<dependency> <dependency>
<groupId>org.owasp.encoder</groupId> <groupId>org.owasp.encoder</groupId>
<artifactId>encoder</artifactId> <artifactId>encoder</artifactId>
<version>1.2.3</version> <version>1.3.1</version>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -140,7 +140,7 @@
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId> <artifactId>buildnumber-maven-plugin</artifactId>
<version>3.2.0</version> <version>3.2.1</version>
<executions> <executions>
<execution> <execution>
<phase>validate</phase> <phase>validate</phase>

95
pom.xml
View File

@@ -2,7 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>alfresco-community-repo</artifactId> <artifactId>alfresco-community-repo</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name> <name>Alfresco Community Repo Parent</name>
@@ -51,45 +51,45 @@
<dependency.alfresco-server-root.version>7.0.1</dependency.alfresco-server-root.version> <dependency.alfresco-server-root.version>7.0.1</dependency.alfresco-server-root.version>
<dependency.activiti-engine.version>5.23.0</dependency.activiti-engine.version> <dependency.activiti-engine.version>5.23.0</dependency.activiti-engine.version>
<dependency.activiti.version>5.23.0</dependency.activiti.version> <dependency.activiti.version>5.23.0</dependency.activiti.version>
<dependency.alfresco-transform-core.version>5.1.4</dependency.alfresco-transform-core.version> <dependency.alfresco-transform-core.version>5.1.5-A1</dependency.alfresco-transform-core.version>
<dependency.alfresco-transform-service.version>4.1.4</dependency.alfresco-transform-service.version> <dependency.alfresco-transform-service.version>4.1.5-A1</dependency.alfresco-transform-service.version>
<dependency.alfresco-greenmail.version>7.0</dependency.alfresco-greenmail.version> <dependency.alfresco-greenmail.version>7.0</dependency.alfresco-greenmail.version>
<dependency.acs-event-model.version>0.0.27</dependency.acs-event-model.version> <dependency.acs-event-model.version>0.0.33</dependency.acs-event-model.version>
<dependency.aspectj.version>1.9.22.1</dependency.aspectj.version> <dependency.aspectj.version>1.9.22.1</dependency.aspectj.version>
<dependency.spring.version>6.0.19</dependency.spring.version> <dependency.spring.version>6.1.13</dependency.spring.version>
<dependency.spring-security.version>6.3.1</dependency.spring-security.version> <dependency.spring-security.version>6.3.3</dependency.spring-security.version>
<dependency.antlr.version>3.5.3</dependency.antlr.version> <dependency.antlr.version>3.5.3</dependency.antlr.version>
<dependency.jackson.version>2.15.2</dependency.jackson.version> <dependency.jackson.version>2.17.2</dependency.jackson.version>
<dependency.cxf.version>4.0.5</dependency.cxf.version> <dependency.cxf.version>4.0.5</dependency.cxf.version>
<dependency.opencmis.version>1.0.0-jakarta-1</dependency.opencmis.version> <dependency.opencmis.version>1.0.0-jakarta-1</dependency.opencmis.version>
<dependency.webscripts.version>9.0</dependency.webscripts.version> <dependency.webscripts.version>9.4</dependency.webscripts.version>
<dependency.bouncycastle.version>1.78.1</dependency.bouncycastle.version> <dependency.bouncycastle.version>1.78.1</dependency.bouncycastle.version>
<dependency.mockito-core.version>5.12.0</dependency.mockito-core.version> <dependency.mockito-core.version>5.14.1</dependency.mockito-core.version>
<dependency.assertj.version>3.26.3</dependency.assertj.version> <dependency.assertj.version>3.26.3</dependency.assertj.version>
<dependency.org-json.version>20231013</dependency.org-json.version> <dependency.org-json.version>20240303</dependency.org-json.version>
<dependency.commons-dbcp.version>2.12.0</dependency.commons-dbcp.version> <dependency.commons-dbcp.version>2.12.0</dependency.commons-dbcp.version>
<dependency.commons-io.version>2.16.1</dependency.commons-io.version> <dependency.commons-io.version>2.16.1</dependency.commons-io.version>
<dependency.gson.version>2.11.0</dependency.gson.version> <dependency.gson.version>2.11.0</dependency.gson.version>
<dependency.guava.version>33.2.1-jre</dependency.guava.version> <dependency.guava.version>33.3.1-jre</dependency.guava.version>
<dependency.httpclient.version>4.5.14</dependency.httpclient.version> <dependency.httpclient.version>4.5.14</dependency.httpclient.version>
<dependency.httpcore.version>4.4.16</dependency.httpcore.version> <dependency.httpcore.version>4.4.16</dependency.httpcore.version>
<dependency.httpcomponents-httpclient5.version>5.2.1</dependency.httpcomponents-httpclient5.version> <dependency.httpcomponents-httpclient5.version>5.2.1</dependency.httpcomponents-httpclient5.version>
<dependency.httpcomponents-httpcore5.version>5.2.5</dependency.httpcomponents-httpcore5.version> <dependency.httpcomponents-httpcore5.version>5.3</dependency.httpcomponents-httpcore5.version>
<dependency.commons-httpclient.version>3.1-HTTPCLIENT-1265</dependency.commons-httpclient.version> <dependency.commons-httpclient.version>3.1-HTTPCLIENT-1265</dependency.commons-httpclient.version>
<dependency.xercesImpl.version>2.12.2</dependency.xercesImpl.version> <dependency.xercesImpl.version>2.12.2</dependency.xercesImpl.version>
<dependency.slf4j.version>2.0.13</dependency.slf4j.version> <dependency.slf4j.version>2.0.16</dependency.slf4j.version>
<dependency.log4j.version>2.23.1</dependency.log4j.version> <dependency.log4j.version>2.23.1</dependency.log4j.version>
<dependency.groovy.version>3.0.22</dependency.groovy.version> <dependency.groovy.version>3.0.22</dependency.groovy.version>
<dependency.tika.version>2.9.2</dependency.tika.version> <dependency.tika.version>2.9.2</dependency.tika.version>
<dependency.truezip.version>7.7.10</dependency.truezip.version> <dependency.truezip.version>7.7.10</dependency.truezip.version>
<dependency.poi.version>5.2.5</dependency.poi.version> <dependency.poi.version>5.3.0</dependency.poi.version>
<dependency.jboss.logging.version>3.5.0.Final</dependency.jboss.logging.version> <dependency.jboss.logging.version>3.5.0.Final</dependency.jboss.logging.version>
<dependency.camel.version>4.6.0</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies --> <dependency.camel.version>4.6.0</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies -->
<dependency.netty.version>4.1.110.Final</dependency.netty.version> <!-- must be in sync with camels transitive dependencies, e.g.: netty-common --> <dependency.netty.version>4.1.113.Final</dependency.netty.version> <!-- must be in sync with camels transitive dependencies, e.g.: netty-common -->
<dependency.activemq.version>5.18.3</dependency.activemq.version> <dependency.activemq.version>5.18.3</dependency.activemq.version>
<dependency.apache-compress.version>1.26.2</dependency.apache-compress.version> <dependency.apache-compress.version>1.27.1</dependency.apache-compress.version>
<dependency.awaitility.version>4.2.1</dependency.awaitility.version> <dependency.awaitility.version>4.2.2</dependency.awaitility.version>
<dependency.swagger-ui.version>4.1.3</dependency.swagger-ui.version> <dependency.swagger-ui.version>4.1.3</dependency.swagger-ui.version>
<dependency.swagger-parser.version>1.0.71</dependency.swagger-parser.version> <dependency.swagger-parser.version>1.0.71</dependency.swagger-parser.version>
<dependency.maven-filtering.version>3.1.1</dependency.maven-filtering.version> <dependency.maven-filtering.version>3.1.1</dependency.maven-filtering.version>
@@ -100,8 +100,8 @@
<dependency.jakarta-ee-jaxb-api.version>4.0.2</dependency.jakarta-ee-jaxb-api.version> <dependency.jakarta-ee-jaxb-api.version>4.0.2</dependency.jakarta-ee-jaxb-api.version>
<dependency.jakarta-ee-jaxb-impl.version>4.0.5</dependency.jakarta-ee-jaxb-impl.version> <dependency.jakarta-ee-jaxb-impl.version>4.0.5</dependency.jakarta-ee-jaxb-impl.version>
<dependency.jakarta-ws-api.version>3.0.1</dependency.jakarta-ws-api.version> <dependency.jakarta-ws-api.version>3.0.1</dependency.jakarta-ws-api.version>
<dependency.jakarta-soap-api.version>2.0.1</dependency.jakarta-soap-api.version> <dependency.jakarta-soap-api.version>3.0.2</dependency.jakarta-soap-api.version>
<dependency.jakarta-annotation-api.version>2.1.1</dependency.jakarta-annotation-api.version> <dependency.jakarta-annotation-api.version>3.0.0</dependency.jakarta-annotation-api.version>
<dependency.jakarta-transaction-api.version>2.0.1</dependency.jakarta-transaction-api.version> <dependency.jakarta-transaction-api.version>2.0.1</dependency.jakarta-transaction-api.version>
<dependency.jakarta-jws-api.version>3.0.0</dependency.jakarta-jws-api.version> <dependency.jakarta-jws-api.version>3.0.0</dependency.jakarta-jws-api.version>
<dependency.jakarta-ee-mail.version>2.0.1</dependency.jakarta-ee-mail.version> <dependency.jakarta-ee-mail.version>2.0.1</dependency.jakarta-ee-mail.version>
@@ -109,7 +109,7 @@
<dependency.jakarta-ee-jms.version>3.1.0</dependency.jakarta-ee-jms.version> <dependency.jakarta-ee-jms.version>3.1.0</dependency.jakarta-ee-jms.version>
<dependency.java-ee-activation.version>1.2.0</dependency.java-ee-activation.version> <dependency.java-ee-activation.version>1.2.0</dependency.java-ee-activation.version>
<dependency.jakarta-ee-json-api.version>2.1.3</dependency.jakarta-ee-json-api.version> <dependency.jakarta-ee-json-api.version>2.1.3</dependency.jakarta-ee-json-api.version>
<dependency.jakarta-ee-json-impl.version>1.1.6</dependency.jakarta-ee-json-impl.version> <dependency.jakarta-ee-json-impl.version>1.1.7</dependency.jakarta-ee-json-impl.version>
<dependency.jakarta-json-path.version>2.9.0</dependency.jakarta-json-path.version> <dependency.jakarta-json-path.version>2.9.0</dependency.jakarta-json-path.version>
<dependency.json-smart.version>2.5.1</dependency.json-smart.version> <dependency.json-smart.version>2.5.1</dependency.json-smart.version>
<alfresco.googledrive.version>4.1.0</alfresco.googledrive.version> <alfresco.googledrive.version>4.1.0</alfresco.googledrive.version>
@@ -117,13 +117,16 @@
<alfresco.api-explorer.version>23.3.0</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share --> <alfresco.api-explorer.version>23.3.0</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
<alfresco.maven-plugin.version>2.2.0</alfresco.maven-plugin.version> <alfresco.maven-plugin.version>2.2.0</alfresco.maven-plugin.version>
<license-maven-plugin.version>2.0.1</license-maven-plugin.version> <license-maven-plugin.version>2.4.0</license-maven-plugin.version>
<spotless-plugin.version>2.43.0</spotless-plugin.version>
<!-- Do not match any files by default, but this can be overridden from the command line. -->
<spotless-include-list>NO_AUTOMATED_FORMATTING</spotless-include-list>
<dependency.postgresql.version>42.7.3</dependency.postgresql.version> <dependency.postgresql.version>42.7.4</dependency.postgresql.version>
<dependency.mysql.version>8.0.30</dependency.mysql.version> <dependency.mysql.version>8.0.30</dependency.mysql.version>
<dependency.mysql-image.version>8</dependency.mysql-image.version> <dependency.mysql-image.version>8</dependency.mysql-image.version>
<dependency.mariadb.version>2.7.4</dependency.mariadb.version> <dependency.mariadb.version>2.7.4</dependency.mariadb.version>
<dependency.tas-utility.version>5.0.1</dependency.tas-utility.version> <dependency.tas-utility.version>5.0.2</dependency.tas-utility.version>
<dependency.rest-assured.version>5.5.0</dependency.rest-assured.version> <dependency.rest-assured.version>5.5.0</dependency.rest-assured.version>
<dependency.tas-email.version>2.0.0</dependency.tas-email.version> <dependency.tas-email.version>2.0.0</dependency.tas-email.version>
<dependency.tas-webdav.version>1.21</dependency.tas-webdav.version> <dependency.tas-webdav.version>1.21</dependency.tas-webdav.version>
@@ -411,7 +414,7 @@
<dependency> <dependency>
<groupId>commons-codec</groupId> <groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId> <artifactId>commons-codec</artifactId>
<version>1.17.0</version> <version>1.17.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-lang</groupId> <groupId>commons-lang</groupId>
@@ -573,7 +576,7 @@
<dependency> <dependency>
<groupId>org.yaml</groupId> <groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId> <artifactId>snakeyaml</artifactId>
<version>2.2</version> <version>2.3</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
@@ -689,7 +692,7 @@
<dependency> <dependency>
<groupId>com.drewnoakes</groupId> <groupId>com.drewnoakes</groupId>
<artifactId>metadata-extractor</artifactId> <artifactId>metadata-extractor</artifactId>
<version>2.18.0</version> <version>2.19.0</version>
</dependency> </dependency>
<!-- upgrade dependency from TIKA --> <!-- upgrade dependency from TIKA -->
<dependency> <dependency>
@@ -700,7 +703,7 @@
<dependency> <dependency>
<groupId>com.networknt</groupId> <groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId> <artifactId>json-schema-validator</artifactId>
<version>1.5.0</version> <version>1.5.1</version>
</dependency> </dependency>
<!-- upgrade dependency from TIKA --> <!-- upgrade dependency from TIKA -->
<dependency> <dependency>
@@ -790,14 +793,14 @@
<dependency> <dependency>
<groupId>joda-time</groupId> <groupId>joda-time</groupId>
<artifactId>joda-time</artifactId> <artifactId>joda-time</artifactId>
<version>2.12.5</version> <version>2.13.0</version>
</dependency> </dependency>
<!-- provided dependencies --> <!-- provided dependencies -->
<dependency> <dependency>
<groupId>jakarta.servlet</groupId> <groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId> <artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version> <version>6.1.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
@@ -1012,7 +1015,7 @@
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-failsafe-plugin</artifactId> <artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version> <version>3.5.0</version>
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
@@ -1020,12 +1023,12 @@
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-war-plugin</artifactId> <artifactId>maven-war-plugin</artifactId>
<version>3.3.2</version> <version>3.4.0</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>3.7.0</version> <version>3.10.1</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@@ -1035,7 +1038,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId> <artifactId>maven-dependency-plugin</artifactId>
<version>3.7.1</version> <version>3.8.0</version>
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-assembly-plugin</artifactId> <artifactId>maven-assembly-plugin</artifactId>
@@ -1090,7 +1093,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId> <artifactId>maven-enforcer-plugin</artifactId>
<version>3.3.0</version> <version>3.5.0</version>
<executions> <executions>
<execution> <execution>
<id>enforce-banned-dependencies</id> <id>enforce-banned-dependencies</id>
@@ -1146,6 +1149,26 @@
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
<version>${spotless-plugin.version}</version>
<configuration>
<java>
<includes>
${spotless-include-list}
</includes>
<eclipse>
<file>alfresco-formatter.xml</file>
</eclipse>
<importOrder>
<order>\#java|\#javax|\#jakarta,\#,\#org.alfresco,java|javax|jakarta,,org.alfresco</order>
</importOrder>
<removeUnusedImports />
<formatAnnotations />
</java>
</configuration>
</plugin>
</plugins> </plugins>
</pluginManagement> </pluginManagement>
<plugins> <plugins>
@@ -1157,6 +1180,10 @@
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId> <artifactId>maven-enforcer-plugin</artifactId>
</plugin> </plugin>
<plugin>
<groupId>com.diffplug.spotless</groupId>
<artifactId>spotless-maven-plugin</artifactId>
</plugin>
</plugins> </plugins>
</build> </build>
</project> </project>

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId> <artifactId>alfresco-community-repo</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<dependencies> <dependencies>
@@ -45,7 +45,7 @@
<dependency> <dependency>
<groupId>org.apache.santuario</groupId> <groupId>org.apache.santuario</groupId>
<artifactId>xmlsec</artifactId> <artifactId>xmlsec</artifactId>
<version>3.0.3</version> <version>4.0.2</version>
</dependency> </dependency>
<!-- newer version, see REPO-3133 --> <!-- newer version, see REPO-3133 -->
<dependency> <dependency>
@@ -137,7 +137,7 @@
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId> <artifactId>jetty-webapp</artifactId>
<version>11.0.22</version> <version>11.0.24</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@@ -25,15 +25,24 @@
*/ */
package org.alfresco.repo.web.scripts.content; package org.alfresco.repo.web.scripts.content;
import static java.util.Optional.ofNullable;
import static java.util.function.Predicate.not;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import jakarta.servlet.ServletContext; import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
import org.springframework.web.context.ServletContextAware;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.web.scripts.MimeTypeUtil; import org.alfresco.repo.web.scripts.MimeTypeUtil;
import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.dictionary.DictionaryService;
@@ -42,13 +51,6 @@ import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
import org.springframework.web.context.ServletContextAware;
/** /**
* Content Retrieval Service * Content Retrieval Service
@@ -62,7 +64,7 @@ public class ContentGet extends StreamContent implements ServletContextAware
// Logger // Logger
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final Log logger = LogFactory.getLog(ContentGet.class); private static final Log logger = LogFactory.getLog(ContentGet.class);
// Component dependencies // Component dependencies
private ServletContext servletContext; private ServletContext servletContext;
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
@@ -72,18 +74,19 @@ public class ContentGet extends StreamContent implements ServletContextAware
private List<String> nonAttachContentTypes = Collections.emptyList(); private List<String> nonAttachContentTypes = Collections.emptyList();
/** /**
* @param nonAttachContentTypes List<String> * @param nonAttachContentTypes
* List<String>
*/ */
public void setNonAttachContentTypes(List<String> nonAttachContentTypes) public void setNonAttachContentTypes(List<String> nonAttachContentTypes)
{ {
if (nonAttachContentTypes != null && !nonAttachContentTypes.isEmpty()) this.nonAttachContentTypes = ofNullable(nonAttachContentTypes)
{ .map(types -> types.stream().filter(not(String::isBlank)).toList())
this.nonAttachContentTypes = nonAttachContentTypes; .orElse(Collections.emptyList());
}
} }
/** /**
* @param servletContext ServletContext * @param servletContext
* ServletContext
*/ */
public void setServletContext(ServletContext servletContext) public void setServletContext(ServletContext servletContext)
{ {
@@ -91,23 +94,26 @@ public class ContentGet extends StreamContent implements ServletContextAware
} }
/** /**
* @param dictionaryService DictionaryService * @param dictionaryService
* DictionaryService
*/ */
public void setDictionaryService(DictionaryService dictionaryService) public void setDictionaryService(DictionaryService dictionaryService)
{ {
this.dictionaryService = dictionaryService; this.dictionaryService = dictionaryService;
} }
/** /**
* @param namespaceService NamespaceService * @param namespaceService
* NamespaceService
*/ */
public void setNamespaceService(NamespaceService namespaceService) public void setNamespaceService(NamespaceService namespaceService)
{ {
this.namespaceService = namespaceService; this.namespaceService = namespaceService;
} }
/** /**
* @param contentService ContentService * @param contentService
* ContentService
*/ */
public void setContentService(ContentService contentService) public void setContentService(ContentService contentService)
{ {
@@ -118,7 +124,7 @@ public class ContentGet extends StreamContent implements ServletContextAware
* @see org.springframework.extensions.webscripts.WebScript#execute(WebScriptRequest, WebScriptResponse) * @see org.springframework.extensions.webscripts.WebScript#execute(WebScriptRequest, WebScriptResponse)
*/ */
public void execute(WebScriptRequest req, WebScriptResponse res) public void execute(WebScriptRequest req, WebScriptResponse res)
throws IOException throws IOException
{ {
// create map of args // create map of args
String[] names = req.getParameterNames(); String[] names = req.getParameterNames();
@@ -127,10 +133,10 @@ public class ContentGet extends StreamContent implements ServletContextAware
{ {
args.put(name, req.getParameter(name)); args.put(name, req.getParameter(name));
} }
// create map of template vars // create map of template vars
Map<String, String> templateVars = req.getServiceMatch().getTemplateVars(); Map<String, String> templateVars = req.getServiceMatch().getTemplateVars();
// create object reference from url // create object reference from url
ObjectReference reference = createObjectReferenceFromUrl(args, templateVars); ObjectReference reference = createObjectReferenceFromUrl(args, templateVars);
NodeRef nodeRef = reference.getNodeRef(); NodeRef nodeRef = reference.getNodeRef();
@@ -139,7 +145,6 @@ public class ContentGet extends StreamContent implements ServletContextAware
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + reference.toString()); throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + reference.toString());
} }
// render content // render content
QName propertyQName = ContentModel.PROP_CONTENT; QName propertyQName = ContentModel.PROP_CONTENT;
String contentPart = templateVars.get("property"); String contentPart = templateVars.get("property");
@@ -186,7 +191,7 @@ public class ContentGet extends StreamContent implements ServletContextAware
if (attach && rfc5987Supported) if (attach && rfc5987Supported)
{ {
String name = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME); String name = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
// maintain the original name of the node during the download - do not modify it - see MNT-16510 // maintain the original name of the node during the download - do not modify it - see MNT-16510
streamContent(req, res, nodeRef, propertyQName, attach, name, model); streamContent(req, res, nodeRef, propertyQName, attach, name, model);
} }
@@ -195,4 +200,4 @@ public class ContentGet extends StreamContent implements ServletContextAware
streamContent(req, res, nodeRef, propertyQName, attach, null, model); streamContent(req, res, nodeRef, propertyQName, attach, null, model);
} }
} }
} }

View File

@@ -712,8 +712,7 @@ public class CustomModelsImpl implements CustomModels
boolean withForm = Boolean.valueOf(propName); boolean withForm = Boolean.valueOf(propName);
try try
{ {
NodeRef nodeRef = customModelService.createDownloadNode(modelName, withForm); NodeRef nodeRef = customModelService.createDownloadNode(modelName, withForm, modelName + DownloadsImpl.DEFAULT_ARCHIVE_EXTENSION);
nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, modelName + DownloadsImpl.DEFAULT_ARCHIVE_EXTENSION);
return new CustomModelDownload(nodeRef); return new CustomModelDownload(nodeRef);
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -1,460 +1,460 @@
/* /*
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2019 Alfresco Software Limited * Copyright (C) 2005 - 2019 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is * the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms: * provided under the following open source license terms:
* *
* Alfresco is free software: you can redistribute it and/or modify * Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Alfresco is distributed in the hope that it will be useful, * Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.rest.api.impl; package org.alfresco.rest.api.impl;
import static org.alfresco.rest.api.Nodes.PARAM_INCLUDE_ALLOWABLEOPERATIONS; import static org.alfresco.rest.api.Nodes.PARAM_INCLUDE_ALLOWABLEOPERATIONS;
import static org.alfresco.rest.api.Nodes.PARAM_INCLUDE_ASPECTNAMES;
import java.util.AbstractList;
import java.util.ArrayList; import java.util.AbstractList;
import java.util.Arrays; import java.util.ArrayList;
import java.util.Collections; import java.util.Arrays;
import java.util.HashMap; import java.util.Collections;
import java.util.HashSet; import java.util.HashMap;
import java.util.List; import java.util.HashSet;
import java.util.Map; import java.util.List;
import java.util.Set; import java.util.Map;
import java.util.stream.Collectors; import java.util.Set;
import java.util.stream.Collectors;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.apache.commons.collections.CollectionUtils;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.favourites.PersonFavourite; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.site.SiteDoesNotExistException; import org.alfresco.model.ContentModel;
import org.alfresco.repo.site.SiteModel; import org.alfresco.query.PagingResults;
import org.alfresco.rest.api.Favourites; import org.alfresco.repo.favourites.PersonFavourite;
import org.alfresco.rest.api.Nodes; import org.alfresco.repo.site.SiteDoesNotExistException;
import org.alfresco.rest.api.People; import org.alfresco.repo.site.SiteModel;
import org.alfresco.rest.api.Sites; import org.alfresco.rest.api.Favourites;
import org.alfresco.rest.api.model.Document; import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.DocumentTarget; import org.alfresco.rest.api.People;
import org.alfresco.rest.api.model.Favourite; import org.alfresco.rest.api.Sites;
import org.alfresco.rest.api.model.Folder; import org.alfresco.rest.api.model.Document;
import org.alfresco.rest.api.model.FolderTarget; import org.alfresco.rest.api.model.DocumentTarget;
import org.alfresco.rest.api.model.Node; import org.alfresco.rest.api.model.Favourite;
import org.alfresco.rest.api.model.PathInfo; import org.alfresco.rest.api.model.Folder;
import org.alfresco.rest.api.model.Site; import org.alfresco.rest.api.model.FolderTarget;
import org.alfresco.rest.api.model.SiteTarget; import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.Target; import org.alfresco.rest.api.model.PathInfo;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.api.model.Site;
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException; import org.alfresco.rest.api.model.SiteTarget;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.api.model.Target;
import org.alfresco.rest.framework.resource.parameters.Paging; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.parameters.Parameters; import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
import org.alfresco.rest.framework.resource.parameters.Params; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.SortColumn; import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper; import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper.WalkerCallbackAdapter; import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.service.cmr.favourites.FavouritesService; import org.alfresco.rest.framework.resource.parameters.SortColumn;
import org.alfresco.service.cmr.favourites.FavouritesService.SortFields; import org.alfresco.rest.framework.resource.parameters.where.QueryHelper;
import org.alfresco.service.cmr.favourites.FavouritesService.Type; import org.alfresco.rest.framework.resource.parameters.where.QueryHelper.WalkerCallbackAdapter;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.favourites.FavouritesService;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.favourites.FavouritesService.SortFields;
import org.alfresco.service.cmr.site.SiteInfo; import org.alfresco.service.cmr.favourites.FavouritesService.Type;
import org.alfresco.service.cmr.site.SiteService; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QName; import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.util.Pair; import org.alfresco.service.cmr.site.SiteService;
import org.apache.commons.collections.CollectionUtils; import org.alfresco.service.namespace.NamespaceService;
import org.apache.commons.logging.Log; import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.LogFactory; import org.alfresco.util.Pair;
/** /**
* Public REST API: Centralises access to favourites functionality and maps between representations repository and api representations. * Public REST API: Centralises access to favourites functionality and maps between representations repository and api representations.
* *
* @author steveglover * @author steveglover
* @since publicapi1.0 * @since publicapi1.0
*/ */
public class FavouritesImpl implements Favourites public class FavouritesImpl implements Favourites
{ {
private static final Log logger = LogFactory.getLog(FavouritesImpl.class); private static final List<String> ALLOWED_INCLUDES = List.of(PARAM_INCLUDE_PROPERTIES, PARAM_INCLUDE_ASPECTNAMES, PARAM_INCLUDE_ALLOWABLEOPERATIONS);
private static final List<String> ALLOWED_INCLUDES = List.of(PARAM_INCLUDE_PROPERTIES, PARAM_INCLUDE_ALLOWABLEOPERATIONS); private People people;
private Sites sites;
private People people; private Nodes nodes;
private Sites sites; private FavouritesService favouritesService;
private Nodes nodes; private SiteService siteService;
private FavouritesService favouritesService; private NamespaceService namespaceService;
private SiteService siteService;
private NamespaceService namespaceService; // additional exclude properties for favourites as these can be already top-level properties
private static final List<QName> EXCLUDED_PROPS = Arrays.asList(
// additional exclude properties for favourites as these can be already top-level properties ContentModel.PROP_TITLE,
private static final List<QName> EXCLUDED_PROPS = Arrays.asList( ContentModel.PROP_DESCRIPTION,
ContentModel.PROP_TITLE, SiteModel.PROP_SITE_VISIBILITY,
ContentModel.PROP_DESCRIPTION, SiteModel.PROP_SITE_PRESET);
SiteModel.PROP_SITE_VISIBILITY,
SiteModel.PROP_SITE_PRESET public void setPeople(People people)
); {
this.people = people;
public void setPeople(People people) }
{
this.people = people; public void setSites(Sites sites)
} {
this.sites = sites;
public void setSites(Sites sites) }
{
this.sites = sites; public void setNodes(Nodes nodes)
} {
this.nodes = nodes;
public void setNodes(Nodes nodes) }
{
this.nodes = nodes; public void setFavouritesService(FavouritesService favouritesService)
} {
this.favouritesService = favouritesService;
public void setFavouritesService(FavouritesService favouritesService) }
{
this.favouritesService = favouritesService; public void setSiteService(SiteService siteService)
} {
this.siteService = siteService;
public void setSiteService(SiteService siteService) }
{
this.siteService = siteService; public void setNamespaceService(NamespaceService namespaceService)
} {
this.namespaceService = namespaceService;
public void setNamespaceService(NamespaceService namespaceService) }
{
this.namespaceService = namespaceService; private Target getTarget(PersonFavourite personFavourite, Parameters parameters)
} {
Target target;
private Target getTarget(PersonFavourite personFavourite, Parameters parameters) NodeRef nodeRef = personFavourite.getNodeRef();
{ Type type = personFavourite.getType();
Target target = null; if (type.equals(Type.FILE))
NodeRef nodeRef = personFavourite.getNodeRef(); {
Type type = personFavourite.getType(); Document document = nodes.getDocument(nodeRef);
if(type.equals(Type.FILE)) setPathInfo(document, parameters.getInclude());
{ target = new DocumentTarget(document);
Document document = nodes.getDocument(nodeRef); }
setPathInfo(document, parameters.getInclude()); else if (type.equals(Type.FOLDER))
target = new DocumentTarget(document); {
} Folder folder = nodes.getFolder(nodeRef);
else if(type.equals(Type.FOLDER)) setPathInfo(folder, parameters.getInclude());
{ target = new FolderTarget(folder);
Folder folder = nodes.getFolder(nodeRef); }
setPathInfo(folder, parameters.getInclude()); else if (type.equals(Type.SITE))
target = new FolderTarget(folder); {
} SiteInfo siteInfo = siteService.getSite(nodeRef);
else if(type.equals(Type.SITE)) String role = sites.getSiteRole(siteInfo.getShortName());
{ Site site = new Site(siteInfo, role);
SiteInfo siteInfo = siteService.getSite(nodeRef); target = new SiteTarget(site);
String role = sites.getSiteRole(siteInfo.getShortName()); }
Site site = new Site(siteInfo, role); else
target = new SiteTarget(site); {
} throw new AlfrescoRuntimeException("Unexpected favourite target type: " + type);
else }
{
throw new AlfrescoRuntimeException("Unexpected favourite target type: " + type); return target;
} }
return target; private Favourite getFavourite(PersonFavourite personFavourite, Parameters parameters)
} {
Favourite fav = new Favourite();
private Favourite getFavourite(PersonFavourite personFavourite, Parameters parameters) fav.setTargetGuid(personFavourite.getNodeRef().getId());
{ fav.setCreatedAt(personFavourite.getCreatedAt());
Favourite fav = new Favourite(); Target target = getTarget(personFavourite, parameters);
fav.setTargetGuid(personFavourite.getNodeRef().getId()); fav.setTarget(target);
fav.setCreatedAt(personFavourite.getCreatedAt());
Target target = getTarget(personFavourite, parameters); // REPO-1147 allow retrieving additional properties
fav.setTarget(target); final List<String> paramsInclude = parameters.getInclude();
if (!Collections.disjoint(paramsInclude, ALLOWED_INCLUDES))
// REPO-1147 allow retrieving additional properties {
final List<String> paramsInclude = parameters.getInclude(); final List<String> includes = ALLOWED_INCLUDES.stream().filter(paramsInclude::contains).collect(Collectors.toList());
if (!Collections.disjoint(paramsInclude, ALLOWED_INCLUDES)) // get node representation with only properties included
{ Node node = nodes.getFolderOrDocument(personFavourite.getNodeRef(), null, null, includes, null);
final List<String> includes = ALLOWED_INCLUDES.stream().filter(a -> paramsInclude.contains(a)).collect(Collectors.toList()); // Create a map from node properties excluding properties already in this Favorite
// get node representation with only properties included Map<String, Object> filteredNodeProperties = filterProps(node.getProperties(), EXCLUDED_PROPS);
Node node = nodes.getFolderOrDocument(personFavourite.getNodeRef(), null, null, includes, null); if (!filteredNodeProperties.isEmpty() && paramsInclude.contains(PARAM_INCLUDE_PROPERTIES))
// Create a map from node properties excluding properties already in this Favorite {
Map<String, Object> filteredNodeProperties = filterProps(node.getProperties(), EXCLUDED_PROPS); fav.setProperties(filteredNodeProperties);
if(filteredNodeProperties.size() > 0 && paramsInclude.contains(PARAM_INCLUDE_PROPERTIES)) }
{ if (paramsInclude.contains(PARAM_INCLUDE_ASPECTNAMES))
fav.setProperties(filteredNodeProperties); {
} fav.setAspectNames(node.getAspectNames());
final List<String> allowableOperations = node.getAllowableOperations(); }
if (CollectionUtils.isNotEmpty(allowableOperations) && paramsInclude.contains(PARAM_INCLUDE_ALLOWABLEOPERATIONS)) final List<String> allowableOperations = node.getAllowableOperations();
{ if (CollectionUtils.isNotEmpty(allowableOperations) && paramsInclude.contains(PARAM_INCLUDE_ALLOWABLEOPERATIONS))
fav.setAllowableOperations(allowableOperations); {
} fav.setAllowableOperations(allowableOperations);
} }
}
return fav;
} return fav;
}
private Map<String, Object> filterProps(Map<String, Object> properties, List<QName> toRemove)
{ private Map<String, Object> filterProps(Map<String, Object> properties, List<QName> toRemove)
Map<String, Object> filteredProps = properties == null ? new HashMap<>() : new HashMap<>(properties); {
List<String> propsToRemove = toRemove.stream().map(e -> e.toPrefixString(namespaceService)).collect(Collectors.toList()); Map<String, Object> filteredProps = properties == null ? new HashMap<>() : new HashMap<>(properties);
filteredProps.keySet().removeAll(propsToRemove); List<String> propsToRemove = toRemove.stream().map(e -> e.toPrefixString(namespaceService)).collect(Collectors.toList());
return filteredProps; filteredProps.keySet().removeAll(propsToRemove);
} return filteredProps;
}
private CollectionWithPagingInfo<Favourite> wrap(Paging paging, PagingResults<PersonFavourite> personFavourites, Parameters parameters)
{ private CollectionWithPagingInfo<Favourite> wrap(Paging paging, PagingResults<PersonFavourite> personFavourites, Parameters parameters)
final List<PersonFavourite> page = personFavourites.getPage(); {
final List<Favourite> list = new AbstractList<Favourite>() final List<PersonFavourite> page = personFavourites.getPage();
{ final List<Favourite> list = new AbstractList<>() {
@Override @Override
public Favourite get(int index) public Favourite get(int index)
{ {
PersonFavourite personFavourite = page.get(index); PersonFavourite personFavourite = page.get(index);
Favourite fav = getFavourite(personFavourite, parameters); Favourite fav = getFavourite(personFavourite, parameters);
return fav; return fav;
} }
@Override @Override
public int size() public int size()
{ {
return page.size(); return page.size();
} }
}; };
Pair<Integer, Integer> pair = personFavourites.getTotalResultCount(); Pair<Integer, Integer> pair = personFavourites.getTotalResultCount();
Integer total = null; Integer total = null;
if(pair.getFirst().equals(pair.getSecond())) if (pair.getFirst().equals(pair.getSecond()))
{ {
total = pair.getFirst(); total = pair.getFirst();
} }
return CollectionWithPagingInfo.asPaged(paging, list, personFavourites.hasMoreItems(), total); return CollectionWithPagingInfo.asPaged(paging, list, personFavourites.hasMoreItems(), total);
} }
@Override @Override
public Favourite addFavourite(String personId, Favourite favourite) public Favourite addFavourite(String personId, Favourite favourite)
{ {
Parameters parameters = getDefaultParameters(personId, null); Parameters parameters = getDefaultParameters(personId, null);
return addFavourite(personId, favourite, parameters); return addFavourite(personId, favourite, parameters);
} }
@Override @Override
public Favourite addFavourite(String personId, Favourite favourite, Parameters parameters) public Favourite addFavourite(String personId, Favourite favourite, Parameters parameters)
{ {
Favourite ret = null; Favourite ret = null;
personId = people.validatePerson(personId, true); personId = people.validatePerson(personId, true);
Target target = favourite.getTarget(); Target target = favourite.getTarget();
if(target == null) if (target == null)
{ {
throw new InvalidArgumentException("target is missing"); throw new InvalidArgumentException("target is missing");
} }
else if(target instanceof SiteTarget) else if (target instanceof SiteTarget)
{ {
SiteTarget siteTarget = (SiteTarget)target; SiteTarget siteTarget = (SiteTarget) target;
String guid = siteTarget.getSite().getGuid(); String guid = siteTarget.getSite().getGuid();
SiteInfo siteInfo = sites.validateSite(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, guid)); SiteInfo siteInfo = sites.validateSite(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, guid));
NodeRef siteNodeRef = siteInfo.getNodeRef(); NodeRef siteNodeRef = siteInfo.getNodeRef();
String siteId = siteInfo.getShortName(); String siteId = siteInfo.getShortName();
try try
{ {
PersonFavourite personFavourite = favouritesService.addFavourite(personId, siteNodeRef); PersonFavourite personFavourite = favouritesService.addFavourite(personId, siteNodeRef);
ret = getFavourite(personFavourite, parameters); ret = getFavourite(personFavourite, parameters);
} }
catch(SiteDoesNotExistException e) catch (SiteDoesNotExistException e)
{ {
throw new RelationshipResourceNotFoundException(personId, siteId); throw new RelationshipResourceNotFoundException(personId, siteId);
} }
} }
else if(target instanceof DocumentTarget) else if (target instanceof DocumentTarget)
{ {
DocumentTarget documentTarget = (DocumentTarget)target; DocumentTarget documentTarget = (DocumentTarget) target;
NodeRef nodeRef = documentTarget.getFile().getGuid(); NodeRef nodeRef = documentTarget.getFile().getGuid();
if(!nodes.nodeMatches(nodeRef, Collections.singleton(ContentModel.TYPE_CONTENT), null)) if (!nodes.nodeMatches(nodeRef, Collections.singleton(ContentModel.TYPE_CONTENT), null))
{ {
throw new RelationshipResourceNotFoundException(personId, nodeRef.getId()); throw new RelationshipResourceNotFoundException(personId, nodeRef.getId());
} }
PersonFavourite personFavourite = favouritesService.addFavourite(personId, nodeRef); PersonFavourite personFavourite = favouritesService.addFavourite(personId, nodeRef);
ret = getFavourite(personFavourite, parameters); ret = getFavourite(personFavourite, parameters);
} }
else if(target instanceof FolderTarget) else if (target instanceof FolderTarget)
{ {
FolderTarget folderTarget = (FolderTarget)target; FolderTarget folderTarget = (FolderTarget) target;
NodeRef nodeRef = folderTarget.getFolder().getGuid(); NodeRef nodeRef = folderTarget.getFolder().getGuid();
if(!nodes.nodeMatches(nodeRef, Collections.singleton(ContentModel.TYPE_FOLDER), Collections.singleton(SiteModel.TYPE_SITE))) if (!nodes.nodeMatches(nodeRef, Collections.singleton(ContentModel.TYPE_FOLDER), Collections.singleton(SiteModel.TYPE_SITE)))
{ {
throw new RelationshipResourceNotFoundException(personId, nodeRef.getId()); throw new RelationshipResourceNotFoundException(personId, nodeRef.getId());
} }
PersonFavourite personFavourite = favouritesService.addFavourite(personId, nodeRef); PersonFavourite personFavourite = favouritesService.addFavourite(personId, nodeRef);
ret = getFavourite(personFavourite, parameters); ret = getFavourite(personFavourite, parameters);
} }
return ret; return ret;
} }
@Override @Override
public void removeFavourite(String personId, String id) public void removeFavourite(String personId, String id)
{ {
personId = people.validatePerson(personId, true); personId = people.validatePerson(personId, true);
NodeRef nodeRef = nodes.validateNode(id); NodeRef nodeRef = nodes.validateNode(id);
boolean exists = false; boolean exists = false;
Type type = favouritesService.getType(nodeRef); Type type = favouritesService.getType(nodeRef);
if(type.equals(Type.SITE)) if (type.equals(Type.SITE))
{ {
SiteInfo siteInfo = siteService.getSite(nodeRef); SiteInfo siteInfo = siteService.getSite(nodeRef);
if(siteInfo == null) if (siteInfo == null)
{ {
// shouldn't happen because the type implies it's a site // shouldn't happen because the type implies it's a site
throw new AlfrescoRuntimeException("Unable to find site with nodeRef " + nodeRef); throw new AlfrescoRuntimeException("Unable to find site with nodeRef " + nodeRef);
} }
exists = favouritesService.removeFavourite(personId, siteInfo.getNodeRef()); exists = favouritesService.removeFavourite(personId, siteInfo.getNodeRef());
} }
else if(type.equals(Type.FILE)) else if (type.equals(Type.FILE))
{ {
exists = favouritesService.removeFavourite(personId, nodeRef); exists = favouritesService.removeFavourite(personId, nodeRef);
} }
else if(type.equals(Type.FOLDER)) else if (type.equals(Type.FOLDER))
{ {
exists = favouritesService.removeFavourite(personId, nodeRef); exists = favouritesService.removeFavourite(personId, nodeRef);
} }
if(!exists) if (!exists)
{ {
throw new RelationshipResourceNotFoundException(personId, id); throw new RelationshipResourceNotFoundException(personId, id);
} }
} }
@Override @Override
public Favourite getFavourite(String personId, String favouriteId) public Favourite getFavourite(String personId, String favouriteId)
{ {
Parameters parameters = getDefaultParameters(personId, favouriteId); Parameters parameters = getDefaultParameters(personId, favouriteId);
return getFavourite(personId, favouriteId, parameters); return getFavourite(personId, favouriteId, parameters);
} }
@Override @Override
public Favourite getFavourite(String personId, String favouriteId, Parameters parameters) public Favourite getFavourite(String personId, String favouriteId, Parameters parameters)
{ {
NodeRef nodeRef = nodes.validateNode(favouriteId); NodeRef nodeRef = nodes.validateNode(favouriteId);
personId = people.validatePerson(personId, true); personId = people.validatePerson(personId, true);
PersonFavourite personFavourite = favouritesService.getFavourite(personId, nodeRef); PersonFavourite personFavourite = favouritesService.getFavourite(personId, nodeRef);
if(personFavourite != null) if (personFavourite != null)
{ {
Favourite favourite = getFavourite(personFavourite, parameters); Favourite favourite = getFavourite(personFavourite, parameters);
return favourite; return favourite;
} }
else else
{ {
throw new RelationshipResourceNotFoundException(personId, favouriteId); throw new RelationshipResourceNotFoundException(personId, favouriteId);
} }
} }
@Override @Override
public CollectionWithPagingInfo<Favourite> getFavourites(String personId, final Parameters parameters) public CollectionWithPagingInfo<Favourite> getFavourites(String personId, final Parameters parameters)
{ {
personId = people.validatePerson(personId, true); personId = people.validatePerson(personId, true);
Paging paging = parameters.getPaging(); Paging paging = parameters.getPaging();
List<Pair<FavouritesService.SortFields, Boolean>> sortProps = getSortProps(parameters); List<Pair<FavouritesService.SortFields, Boolean>> sortProps = getSortProps(parameters);
final Set<Type> filteredByClientQuery = new HashSet<Type>(); final Set<Type> filteredByClientQuery = new HashSet<>();
Set<Type> filterTypes = FavouritesService.Type.ALL_FILTER_TYPES; //Default all Set<Type> filterTypes = FavouritesService.Type.ALL_FILTER_TYPES; // Default all
// filterType is of the form 'target.<site|file|folder>' // filterType is of the form 'target.<site|file|folder>'
QueryHelper.walk(parameters.getQuery(), new WalkerCallbackAdapter() QueryHelper.walk(parameters.getQuery(), new WalkerCallbackAdapter() {
{ @Override
@Override public void or()
public void or() { {
//OR is supported but exists() will be called for each EXISTS so we don't // OR is supported but exists() will be called for each EXISTS so we don't
//need to do anything here. If we don't override it then it will be assumed // need to do anything here. If we don't override it then it will be assumed
//that OR in the grammar is not supported. // that OR in the grammar is not supported.
} }
@Override @Override
public void exists(String filteredByClient, boolean negated) { public void exists(String filteredByClient, boolean negated)
if(filteredByClient != null) {
{ if (filteredByClient != null)
int idx = filteredByClient.lastIndexOf("/"); {
if(idx == -1 || idx == filteredByClient.length()) int idx = filteredByClient.lastIndexOf('/');
{ if (idx == -1 || idx == filteredByClient.length())
throw new InvalidArgumentException(); {
} throw new InvalidArgumentException();
else }
{ else
String filtertype = filteredByClient.substring(idx + 1).toUpperCase(); {
filteredByClientQuery.add(Type.valueOf(filtertype)); String filtertype = filteredByClient.substring(idx + 1).toUpperCase();
} filteredByClientQuery.add(Type.valueOf(filtertype));
} }
}
}
}); }
});
if (filteredByClientQuery.size() > 0)
{ if (!filteredByClientQuery.isEmpty())
filterTypes = filteredByClientQuery; {
} filterTypes = filteredByClientQuery;
}
final PagingResults<PersonFavourite> favourites = favouritesService.getPagedFavourites(personId, filterTypes, sortProps, Util.getPagingRequest(paging));
final PagingResults<PersonFavourite> favourites = favouritesService.getPagedFavourites(personId, filterTypes, sortProps, Util.getPagingRequest(paging));
return wrap(paging, favourites, parameters);
} return wrap(paging, favourites, parameters);
}
private void setPathInfo(Node node, List<String> includeParam)
{ private void setPathInfo(Node node, List<String> includeParam)
if (includeParam.contains(PARAM_INCLUDE_PATH)) {
{ if (includeParam.contains(PARAM_INCLUDE_PATH))
PathInfo pathInfo = nodes.lookupPathInfo(node.getNodeRef(), null); {
node.setPath(pathInfo); PathInfo pathInfo = nodes.lookupPathInfo(node.getNodeRef(), null);
} node.setPath(pathInfo);
} }
}
/**
* Returns a {@code {@link Parameters} object where almost all of its values are null. /**
* the non-null value is the {@literal include} and whatever value is passed for {@code personId} and {@code favouriteId} * Returns a {@code {@link Parameters} object where almost all of its values are null. the non-null value is the {@literal include} and whatever value is passed for {@code personId} and {@code favouriteId}
*/ */
private Parameters getDefaultParameters(String personId, String favouriteId) private Parameters getDefaultParameters(String personId, String favouriteId)
{ {
Params.RecognizedParams recognizedParams = new Params.RecognizedParams(null, null, null, null, Collections.emptyList(), null, null, null, Params.RecognizedParams recognizedParams = new Params.RecognizedParams(null, null, null, null, Collections.emptyList(), null, null, null,
false); false);
Parameters parameters = Params.valueOf(recognizedParams, personId, favouriteId, null); Parameters parameters = Params.valueOf(recognizedParams, personId, favouriteId, null);
return parameters; return parameters;
} }
private List<Pair<FavouritesService.SortFields, Boolean>> getSortProps(Parameters parameters) private List<Pair<FavouritesService.SortFields, Boolean>> getSortProps(Parameters parameters)
{ {
List<Pair<FavouritesService.SortFields, Boolean>> sortProps = new ArrayList<>(); List<Pair<FavouritesService.SortFields, Boolean>> sortProps = new ArrayList<>();
List<SortColumn> sortCols = parameters.getSorting(); List<SortColumn> sortCols = parameters.getSorting();
if ((sortCols != null) && (sortCols.size() > 0)) if (sortCols != null && !sortCols.isEmpty())
{ {
for (SortColumn sortCol : sortCols) for (SortColumn sortCol : sortCols)
{ {
SortFields sortField; SortFields sortField;
try try
{ {
sortField = SortFields.valueOf(sortCol.column); sortField = SortFields.valueOf(sortCol.column);
} }
catch (Exception e) catch (Exception e)
{ {
throw new InvalidArgumentException("Invalid sort field: " + sortCol.column); throw new InvalidArgumentException("Invalid sort field: " + sortCol.column);
} }
sortProps.add(new Pair<>(sortField, (sortCol.asc ? Boolean.TRUE : Boolean.FALSE))); sortProps.add(new Pair<>(sortField, sortCol.asc ? Boolean.TRUE : Boolean.FALSE));
} }
} }
else else
{ {
// default sort order // default sort order
sortProps = FavouritesService.DEFAULT_SORT_PROPS; sortProps = FavouritesService.DEFAULT_SORT_PROPS;
} }
return sortProps; return sortProps;
} }
} }

View File

@@ -2401,6 +2401,8 @@ public class NodesImpl implements Nodes
NodePermissions nodePerms = nodeInfo.getPermissions(); NodePermissions nodePerms = nodeInfo.getPermissions();
if (nodePerms != null) if (nodePerms != null)
{ {
String siteManagerAuthority = getSiteManagerAuthority(nodeRef);
// Cannot set inherited permissions, only direct (locally set) permissions can be set // Cannot set inherited permissions, only direct (locally set) permissions can be set
if ((nodePerms.getInherited() != null) && (nodePerms.getInherited().size() > 0)) if ((nodePerms.getInherited() != null) && (nodePerms.getInherited().size() > 0))
{ {
@@ -2411,7 +2413,7 @@ public class NodesImpl implements Nodes
if (nodePerms.getIsInheritanceEnabled() != null) if (nodePerms.getIsInheritanceEnabled() != null)
{ {
// If inheritance flag is being disabled, the site manager needs to have permission // If inheritance flag is being disabled, the site manager needs to have permission
setSiteManagerPermission(nodeRef, nodePerms); setSiteManagerPermission(nodeRef, nodePerms, siteManagerAuthority);
if (nodePerms.getIsInheritanceEnabled() != permissionService.getInheritParentPermissions(nodeRef)) if (nodePerms.getIsInheritanceEnabled() != permissionService.getInheritParentPermissions(nodeRef))
{ {
@@ -2510,8 +2512,19 @@ public class NodesImpl implements Nodes
} }
// remove any remaining direct perms // remove any remaining direct perms
boolean isInheritanceEnabled = permissionService.getInheritParentPermissions(nodeRef);
for (AccessPermission accessPerm : directPerms) for (AccessPermission accessPerm : directPerms)
{ {
// prevents deletion of site manager permissions when inheritance is disabled
boolean isSiteManagerAuthority = siteManagerAuthority != null && siteManagerAuthority.equals(accessPerm.getAuthority());
if (!isInheritanceEnabled && isSiteManagerAuthority)
{
if (logger.isDebugEnabled())
{
logger.debug("Site manager permissions will be kept since inheritance flag is disabled: " + nodeRef.getId());
}
continue;
}
permissionService.deletePermission(nodeRef, accessPerm.getAuthority(), accessPerm.getPermission()); permissionService.deletePermission(nodeRef, accessPerm.getAuthority(), accessPerm.getPermission());
} }
} }
@@ -2776,25 +2789,29 @@ public class NodesImpl implements Nodes
return updateExistingFile(null, nodeRef, fileName, contentInfo, stream, parameters, versionMajor, versionComment); return updateExistingFile(null, nodeRef, fileName, contentInfo, stream, parameters, versionMajor, versionComment);
} }
private void setSiteManagerPermission(NodeRef nodeRef, NodePermissions nodePerms) private String getSiteManagerAuthority(NodeRef nodeRef) {
return AuthenticationUtil.runAsSystem(() -> {
SiteInfo containingSite = siteService.getSite(nodeRef);
if (containingSite != null)
{
String thisSiteGroupPrefix = siteService.getSiteGroup(containingSite.getShortName());
return thisSiteGroupPrefix + "_" + SiteModel.SITE_MANAGER;
}
return null;
});
}
private void setSiteManagerPermission(NodeRef nodeRef, NodePermissions nodePerms, String siteManagerAuthority)
{ {
if (nodeRef != null && nodePerms != null) if (nodeRef != null && nodePerms != null && nodePerms.getIsInheritanceEnabled() != null && siteManagerAuthority != null)
{ {
try try
{ {
if (nodePerms.getIsInheritanceEnabled() != null && !nodePerms.getIsInheritanceEnabled()) if (!nodePerms.getIsInheritanceEnabled())
{ {
SiteInfo containingSite = siteService.getSite(nodeRef); permissionService.setPermission(nodeRef, siteManagerAuthority, SiteModel.SITE_MANAGER, true);
if (containingSite != null)
{
String thisSiteGroupPrefix = siteService.getSiteGroup(containingSite.getShortName());
final String siteManagerAuthority = thisSiteGroupPrefix + "_" + SiteModel.SITE_MANAGER;
AuthenticationUtil.runAsSystem(() -> {
permissionService.setPermission(nodeRef, siteManagerAuthority, SiteModel.SITE_MANAGER, true);
return null;
});
}
} }
} }
catch (Exception e) catch (Exception e)

View File

@@ -23,43 +23,65 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.rest.api.model; package org.alfresco.rest.api.model;
/** import java.util.Objects;
* A document target favourite.
* /**
* @author steveglover * A document target favourite.
* *
*/ * @author steveglover
public class DocumentTarget extends Target *
{ */
private Document file; public class DocumentTarget extends Target
{
public DocumentTarget() private Document file;
{
super(); public DocumentTarget()
} {
super();
public DocumentTarget(Document file) }
{
super(); public DocumentTarget(Document file)
this.file = file; {
} super();
this.file = file;
public void setDocument(Document file) }
{
this.file = file; public void setDocument(Document file)
} {
this.file = file;
public Document getFile() }
{
return file; public Document getFile()
} {
return file;
@Override }
public String toString()
{ @Override
return "DocumentTarget [file=" + file + "]"; public String toString()
} {
return "DocumentTarget [file=" + file + "]";
} }
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
DocumentTarget that = (DocumentTarget) o;
return Objects.equals(file, that.file);
}
@Override
public int hashCode()
{
return Objects.hashCode(file);
}
}

View File

@@ -1,103 +1,144 @@
/* /*
* #%L * #%L
* Alfresco Remote API * Alfresco Remote API
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2016 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is * the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms: * provided under the following open source license terms:
* *
* Alfresco is free software: you can redistribute it and/or modify * Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Alfresco is distributed in the hope that it will be useful, * Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.rest.api.model; package org.alfresco.rest.api.model;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import org.alfresco.rest.framework.resource.UniqueId;
import org.alfresco.rest.framework.resource.UniqueId;
/**
* Representation of a favourite (document, folder, site, ...). /**
* * Representation of a favourite (document, folder, site, ...).
* @author steveglover *
* * @author steveglover
*/ *
public class Favourite */
{ public class Favourite
private String targetGuid; {
private Date createdAt; private String targetGuid;
private Target target; private Date createdAt;
private Map<String, Object> properties; private Target target;
private List<String> allowableOperations; private Map<String, Object> properties;
private List<String> aspectNames;
public Date getCreatedAt() private List<String> allowableOperations;
{
return createdAt; public Date getCreatedAt()
} {
return createdAt;
public void setCreatedAt(Date createdAt) }
{
this.createdAt = createdAt; public void setCreatedAt(Date createdAt)
} {
this.createdAt = createdAt;
@UniqueId(name="targetGuid") }
public String getTargetGuid()
{ @UniqueId(name = "targetGuid")
return targetGuid; public String getTargetGuid()
} {
return targetGuid;
public void setTargetGuid(String targetGuid) }
{
this.targetGuid = targetGuid; public void setTargetGuid(String targetGuid)
} {
this.targetGuid = targetGuid;
public Target getTarget() }
{
return target; public Target getTarget()
} {
return target;
public void setTarget(Target target) }
{
this.target = target; public void setTarget(Target target)
} {
this.target = target;
public Map<String, Object> getProperties() }
{
return properties; public Map<String, Object> getProperties()
} {
return properties;
public void setProperties(Map<String, Object> properties) }
{
this.properties = properties; public void setProperties(Map<String, Object> properties)
} {
this.properties = properties;
public List<String> getAllowableOperations() { }
return allowableOperations;
} public List<String> getAspectNames()
{
public void setAllowableOperations(List<String> allowableOperations) { return aspectNames;
this.allowableOperations = allowableOperations; }
}
public void setAspectNames(List<String> aspectNames)
@Override {
public String toString() this.aspectNames = aspectNames;
{ }
return "Favourite [targetGuid=" + targetGuid
+ ", createdAt=" + createdAt + ", target=" + target + ", properties=" + properties + "]"; public List<String> getAllowableOperations()
} {
} return allowableOperations;
}
public void setAllowableOperations(List<String> allowableOperations)
{
this.allowableOperations = allowableOperations;
}
@Override
public String toString()
{
return "Favourite{" +
"targetGuid='" + targetGuid + '\'' +
", createdAt=" + createdAt +
", target=" + target +
", properties=" + properties +
", aspectNames=" + aspectNames +
", allowableOperations=" + allowableOperations +
'}';
}
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
Favourite favourite = (Favourite) o;
return Objects.equals(targetGuid, favourite.targetGuid) && Objects.equals(createdAt, favourite.createdAt) && Objects.equals(target, favourite.target) && Objects.equals(properties, favourite.properties) && Objects.equals(aspectNames, favourite.aspectNames) && Objects.equals(allowableOperations, favourite.allowableOperations);
}
@Override
public int hashCode()
{
return Objects.hash(targetGuid, createdAt, target, properties, aspectNames, allowableOperations);
}
}

View File

@@ -110,22 +110,10 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
@Override @Override
public Object execute() throws Throwable public Object execute() throws Throwable
{ {
try // Reset the request so that it can be read again in case of retry
{ resetRequest(req);
final Params params = paramsExtractor.extractParams(resource.getMetaData(), req); final Params params = paramsExtractor.extractParams(resource.getMetaData(), req);
return AbstractResourceWebScript.this.execute(resource, params, res, isReadOnly); return AbstractResourceWebScript.this.execute(resource, params, res, isReadOnly);
}
catch (Exception e)
{
if (req instanceof BufferedRequest)
{
// Reset the request in case of a transaction retry
((BufferedRequest) req).reset();
}
// re-throw original exception for retry
throw e;
}
} }
}; };
@@ -238,6 +226,15 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements
} }
} }
protected void resetRequest(WebScriptRequest req)
{
if (req instanceof BufferedRequest)
{
BufferedRequest bufferedRequest = (BufferedRequest) req;
bufferedRequest.reset();
}
}
protected RetryingTransactionHelper getTransactionHelper(String api) protected RetryingTransactionHelper getTransactionHelper(String api)
{ {
RetryingTransactionHelper transHelper = transactionService.getRetryingTransactionHelper(); RetryingTransactionHelper transHelper = transactionService.getRetryingTransactionHelper();

View File

@@ -250,7 +250,7 @@
<property name="delegate" ref="webscript.content.streamer" /> <property name="delegate" ref="webscript.content.streamer" />
<property name="contentService" ref="contentService" /> <property name="contentService" ref="contentService" />
<property name="repository" ref="repositoryHelper" /> <property name="repository" ref="repositoryHelper" />
<property name="nonAttachContentTypes" value="#{T(java.util.Arrays).asList('${content.nonAttach.mimetypes}')}" /> <property name="nonAttachContentTypes" value="#{'${content.nonAttach.mimetypes}'.split(',')}" />
</bean> </bean>
<!-- Content Info --> <!-- Content Info -->

View File

@@ -25,60 +25,59 @@
*/ */
package org.alfresco; package org.alfresco;
import org.alfresco.repo.web.scripts.TestWebScriptRepoServer;
import org.alfresco.util.testing.category.DBTests;
import org.alfresco.util.testing.category.NonBuildTests;
import org.junit.experimental.categories.Categories; import org.junit.experimental.categories.Categories;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Suite; import org.junit.runners.Suite;
import org.alfresco.repo.web.scripts.TestWebScriptRepoServer;
import org.alfresco.util.testing.category.DBTests;
import org.alfresco.util.testing.category.NonBuildTests;
@RunWith(Categories.class) @RunWith(Categories.class)
@Categories.ExcludeCategory({DBTests.class, NonBuildTests.class}) @Categories.ExcludeCategory({DBTests.class, NonBuildTests.class})
@Suite.SuiteClasses({ @Suite.SuiteClasses({
// [classpath:alfresco/application-context.xml, classpath:alfresco/web-scripts-application-context-test.xml, org.alfresco.repo.web.scripts.quickshare.QuickShareRestApiTest.class,
// classpath:alfresco/web-scripts-application-context.xml] org.alfresco.repo.web.scripts.admin.AdminWebScriptTest.class,
org.alfresco.repo.web.scripts.quickshare.QuickShareRestApiTest.class, org.alfresco.repo.web.scripts.audit.AuditWebScriptTest.class,
org.alfresco.repo.web.scripts.admin.AdminWebScriptTest.class, org.alfresco.repo.web.scripts.blogs.BlogServiceTest.class,
org.alfresco.repo.web.scripts.audit.AuditWebScriptTest.class, org.alfresco.repo.web.scripts.dictionary.DictionaryRestApiTest.class,
org.alfresco.repo.web.scripts.blogs.BlogServiceTest.class, org.alfresco.repo.web.scripts.discussion.DiscussionRestApiTest.class,
org.alfresco.repo.web.scripts.dictionary.DictionaryRestApiTest.class, org.alfresco.repo.web.scripts.activities.feed.control.FeedControlTest.class,
org.alfresco.repo.web.scripts.discussion.DiscussionRestApiTest.class, org.alfresco.repo.web.scripts.forms.FormRestApiGet_Test.class,
org.alfresco.repo.web.scripts.activities.feed.control.FeedControlTest.class, org.alfresco.repo.web.scripts.forms.FormRestApiJsonPost_Test.class,
org.alfresco.repo.web.scripts.forms.FormRestApiGet_Test.class, org.alfresco.repo.web.scripts.groups.GroupsTest.class,
org.alfresco.repo.web.scripts.forms.FormRestApiJsonPost_Test.class, org.alfresco.repo.web.scripts.invitation.InvitationWebScriptTest.class,
org.alfresco.repo.web.scripts.groups.GroupsTest.class, org.alfresco.repo.web.scripts.invite.InviteServiceTest.class,
org.alfresco.repo.web.scripts.invitation.InvitationWebScriptTest.class, org.alfresco.repo.web.scripts.LoginTest.class,
org.alfresco.repo.web.scripts.invite.InviteServiceTest.class, org.alfresco.repo.web.scripts.search.PersonSearchTest.class,
org.alfresco.repo.web.scripts.LoginTest.class, org.alfresco.repo.web.scripts.person.PersonServiceTest.class,
org.alfresco.repo.web.scripts.search.PersonSearchTest.class, org.alfresco.repo.web.scripts.preference.PreferenceServiceTest.class,
org.alfresco.repo.web.scripts.person.PersonServiceTest.class, org.alfresco.repo.web.scripts.rating.RatingRestApiTest.class,
org.alfresco.repo.web.scripts.preference.PreferenceServiceTest.class, org.alfresco.repo.web.scripts.replication.ReplicationRestApiTest.class,
org.alfresco.repo.web.scripts.rating.RatingRestApiTest.class, org.alfresco.repo.web.scripts.RepositoryContainerTest.class,
org.alfresco.repo.web.scripts.replication.ReplicationRestApiTest.class, org.alfresco.repo.web.scripts.rule.RuleServiceTest.class,
org.alfresco.repo.web.scripts.RepositoryContainerTest.class, org.alfresco.repo.web.scripts.action.RunningActionRestApiTest.class,
org.alfresco.repo.web.scripts.rule.RuleServiceTest.class, org.alfresco.repo.web.scripts.site.SiteServiceTest.class,
org.alfresco.repo.web.scripts.action.RunningActionRestApiTest.class, org.alfresco.repo.web.scripts.tagging.TaggingServiceTest.class,
org.alfresco.repo.web.scripts.site.SiteServiceTest.class, org.alfresco.repo.web.scripts.thumbnail.ThumbnailServiceTest.class,
org.alfresco.repo.web.scripts.tagging.TaggingServiceTest.class, org.alfresco.repo.web.scripts.transfer.TransferWebScriptTest.class,
org.alfresco.repo.web.scripts.thumbnail.ThumbnailServiceTest.class, org.alfresco.repo.web.scripts.workflow.ActivitiWorkflowRestApiTest.class,
org.alfresco.repo.web.scripts.transfer.TransferWebScriptTest.class, org.alfresco.repo.web.scripts.solr.SOLRWebScriptTest.class,
org.alfresco.repo.web.scripts.workflow.ActivitiWorkflowRestApiTest.class, org.alfresco.repo.web.scripts.subscriptions.SubscriptionServiceRestApiTest.class,
org.alfresco.repo.web.scripts.solr.SOLRWebScriptTest.class, org.alfresco.repo.web.scripts.facet.FacetRestApiTest.class,
org.alfresco.repo.web.scripts.subscriptions.SubscriptionServiceRestApiTest.class, org.alfresco.repo.web.scripts.comment.CommentsApiTest.class,
org.alfresco.repo.web.scripts.facet.FacetRestApiTest.class, org.alfresco.repo.web.scripts.content.ContentGetTest.class,
org.alfresco.repo.web.scripts.comment.CommentsApiTest.class, org.alfresco.repo.web.scripts.XssVulnerabilityTest.class,
org.alfresco.repo.web.scripts.content.ContentGetTest.class, org.alfresco.repo.web.scripts.links.LinksRestApiTest.class,
org.alfresco.repo.web.scripts.XssVulnerabilityTest.class, org.alfresco.repo.model.filefolder.RemoteFileFolderLoaderTest.class,
org.alfresco.repo.web.scripts.links.LinksRestApiTest.class, org.alfresco.repo.web.scripts.ReadOnlyTransactionInGetRestApiTest.class,
org.alfresco.repo.model.filefolder.RemoteFileFolderLoaderTest.class, org.alfresco.repo.web.scripts.custommodel.CustomModelImportTest.class,
org.alfresco.repo.web.scripts.ReadOnlyTransactionInGetRestApiTest.class, org.alfresco.repo.web.scripts.site.SurfConfigTest.class,
org.alfresco.repo.web.scripts.custommodel.CustomModelImportTest.class, org.alfresco.repo.web.scripts.node.NodeWebScripTest.class,
org.alfresco.repo.web.scripts.site.SurfConfigTest.class, org.alfresco.rest.api.impl.CommentsImplUnitTest.class,
org.alfresco.repo.web.scripts.node.NodeWebScripTest.class, org.alfresco.rest.api.impl.DownloadsImplCheckArchiveStatusUnitTest.class,
org.alfresco.rest.api.impl.CommentsImplUnitTest.class, org.alfresco.rest.api.impl.FavouritesImplUnitTest.class,
org.alfresco.rest.api.impl.DownloadsImplCheckArchiveStatusUnitTest.class, org.alfresco.rest.api.impl.RestApiDirectUrlConfigUnitTest.class
org.alfresco.rest.api.impl.RestApiDirectUrlConfigUnitTest.class,
org.alfresco.rest.api.impl.SizeDetailsImplTest.class
}) })
public class AppContext04TestSuite public class AppContext04TestSuite
{ {

View File

@@ -0,0 +1,134 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2020 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.api.impl;
import static java.util.Collections.singleton;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.openMocks;
import static org.alfresco.model.ContentModel.TYPE_CONTENT;
import static org.alfresco.service.cmr.favourites.FavouritesService.Type.FILE;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.alfresco.repo.favourites.PersonFavourite;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.People;
import org.alfresco.rest.api.model.Document;
import org.alfresco.rest.api.model.DocumentTarget;
import org.alfresco.rest.api.model.Favourite;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.cmr.favourites.FavouritesService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
/**
* Unit tests for {@link FavouritesImpl} class.
*/
public class FavouritesImplUnitTest
{
static final String NODE_ID = "12345678";
static final NodeRef NODE_REF = new NodeRef("favourite://node/" + NODE_ID);
static final String PERSON_ID = "personId";
static final String ASPECT_NAME = "some:aspect";
@InjectMocks
FavouritesImpl favouritesImpl;
@Mock
People people;
@Mock
Nodes nodes;
@Mock
FavouritesService favouritesService;
@Mock
NamespaceService namespaceService;
@Mock
Favourite favourite;
@Mock
Document document;
@Mock
PersonFavourite personFavourite;
@Before
public void setUp()
{
openMocks(this);
when(nodes.getDocument(NODE_REF)).thenReturn(document);
when(nodes.nodeMatches(NODE_REF, singleton(TYPE_CONTENT), null)).thenReturn(true);
when(document.getGuid()).thenReturn(NODE_REF);
when(people.validatePerson(PERSON_ID, true)).thenReturn(PERSON_ID);
when(personFavourite.getNodeRef()).thenReturn(NODE_REF);
when(personFavourite.getType()).thenReturn(FILE);
when(favouritesService.addFavourite(PERSON_ID, NODE_REF)).thenReturn(personFavourite);
when(namespaceService.getPrefixes(anyString())).thenReturn(List.of("prefix"));
}
@Test
public void testAddFavourite()
{
DocumentTarget documentTarget = new DocumentTarget(document);
when(favourite.getTarget()).thenReturn(documentTarget);
Favourite response = favouritesImpl.addFavourite(PERSON_ID, favourite);
Favourite expected = new Favourite();
expected.setTarget(documentTarget);
expected.setTargetGuid(NODE_ID);
assertEquals(expected, response);
}
@Test
public void testAddFavouriteIncludeAspectNames()
{
List<String> includes = List.of("aspectNames");
DocumentTarget documentTarget = new DocumentTarget(document);
when(favourite.getTarget()).thenReturn(documentTarget);
when(nodes.getFolderOrDocument(NODE_REF, null, null, includes, null)).thenReturn(document);
when(document.getAspectNames()).thenReturn(List.of(ASPECT_NAME));
Parameters parameters = mock(Parameters.class);
when(parameters.getInclude()).thenReturn(includes);
Favourite response = favouritesImpl.addFavourite(PERSON_ID, favourite, parameters);
Favourite expected = new Favourite();
expected.setTarget(documentTarget);
expected.setTargetGuid(NODE_ID);
expected.setAspectNames(List.of(ASPECT_NAME));
assertEquals(expected, response);
}
}

View File

@@ -35,6 +35,7 @@ import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -62,6 +63,7 @@ import org.alfresco.rest.api.model.ClassDefinition;
import org.alfresco.rest.api.model.ConstraintDefinition; import org.alfresco.rest.api.model.ConstraintDefinition;
import org.alfresco.rest.api.model.LockInfo; import org.alfresco.rest.api.model.LockInfo;
import org.alfresco.rest.api.model.NodePermissions; import org.alfresco.rest.api.model.NodePermissions;
import org.alfresco.rest.api.model.NodePermissions.NodePermission;
import org.alfresco.rest.api.model.NodeTarget; import org.alfresco.rest.api.model.NodeTarget;
import org.alfresco.rest.api.model.PropertyDefinition; import org.alfresco.rest.api.model.PropertyDefinition;
import org.alfresco.rest.api.model.Site; import org.alfresco.rest.api.model.Site;
@@ -6368,7 +6370,7 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest
* Tests if site manager permissions are kept after inheritance flag is disabled * Tests if site manager permissions are kept after inheritance flag is disabled
*/ */
@Test @Test
public void testSiteManagerPermission() throws Exception public void testSiteManagerPermission_MNT23379() throws Exception
{ {
// Change to User1 context // Change to User1 context
setRequestContext(user1); setRequestContext(user1);
@@ -6394,6 +6396,10 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest
Node nodeUpdate = new Node(); Node nodeUpdate = new Node();
NodePermissions nodePerms = new NodePermissions(); NodePermissions nodePerms = new NodePermissions();
nodePerms.setIsInheritanceEnabled(false); nodePerms.setIsInheritanceEnabled(false);
NodePermission permission = new NodePermission("GROUP_site_" + site1Id + "_SiteConsumer", SiteRole.SiteConsumer.toString(), AccessStatus.ALLOWED.toString());
List<NodePermission> locallySet = new ArrayList<>();
locallySet.add(permission);
nodePerms.setLocallySet(locallySet);
nodeUpdate.setPermissions(nodePerms); nodeUpdate.setPermissions(nodePerms);
put(URL_NODES, content1_Id, toJsonAsStringNonNull(nodeUpdate), null, 200); put(URL_NODES, content1_Id, toJsonAsStringNonNull(nodeUpdate), null, 200);
@@ -6409,6 +6415,76 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest
deleteSite(site1Id, true, 204); deleteSite(site1Id, true, 204);
} }
/**
* Test if inheritance flag is correctly set on a node placed inside a site
*/
@Test
public void testSiteNodeInheritance_MNT24282() throws Exception
{
// Change to User1 context
setRequestContext(user1);
// user1 creates a site
String site1Title = "site-testSiteInheritanceFlag_DocLib-" + RUNID;
String site1Id = createSite(site1Title, SiteVisibility.PUBLIC).getId();
String site1DocLibNodeId = getSiteContainerNodeId(site1Id, "documentLibrary");
// user1 adds user2 as a site consumer to the created site
addSiteMember(site1Id, user2, SiteRole.SiteConsumer);
// user1 creates folder hierarchy: folderA/folderB/folderC
Folder folderA = createFolder(site1DocLibNodeId, "folderA");
Folder folderB = createFolder(folderA.getId(), "folderB");
Folder folderC = createFolder(folderB.getId(), "folderC");
// user1 disables inheritance flag on folder B
disableSiteNodeInheritanceAsShare(site1Id, folderB.getId());
// user1 disables inheritance flag on folder C
disableSiteNodeInheritanceAsShare(site1Id, folderC.getId());
// user1 gives SiteManager permissions to user2 in folderC
Node nodeC = new Node();
NodePermissions permsC = new NodePermissions();
List<NodePermission> locallySet = new ArrayList<>();
locallySet.add(new NodePermission(user2, SiteRole.SiteManager.toString(), AccessStatus.ALLOWED.toString()));
permsC.setLocallySet(locallySet);
nodeC.setPermissions(permsC);
put(URL_NODES, folderC.getId(), toJsonAsStringNonNull(nodeC), null, 200);
// Change to User2 context
setRequestContext(user2);
// user2 creates folderD inside folderC
Folder folderD = createFolder(folderC.getId(), "folderD");
// user2 disables inheritance flag on folder D
disableSiteNodeInheritanceAsShare(site1Id, folderD.getId());
// user2 enables inheritance flag on folder D
setSiteNodeInheritance(site1Id, folderD.getId(), true, false);
// user2 disables inheritance flag on folder D
disableSiteNodeInheritanceAsShare(site1Id, folderD.getId());
// user2 should be able to re-enable and disable the inheritance flag without causing a permission denied error
setSiteNodeInheritance(site1Id, folderD.getId(), true, false);
setSiteNodeInheritance(site1Id, folderD.getId(), false, false);
// user2 checks if has access to the folder
Map<String, String> params = new HashMap<>();
params.put("include", "permissions");
HttpResponse response = getSingle(NodesEntityResource.class, folderD.getId(), params, 200);
Document node = jacksonUtil.parseEntry(response.getJsonResponse(), Document.class);
assertNotNull(node);
assertEquals(node.getId(), folderD.getId());
assertFalse("Folder D inheritance flag should be false", node.getPermissions().getIsInheritanceEnabled());
// cleanup
setRequestContext(user1);
deleteSite(site1Id, true, 204);
}
@Test @Test
public void testRuleAspectAfterUpdate() throws Exception public void testRuleAspectAfterUpdate() throws Exception
{ {
@@ -6445,5 +6521,28 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest
// Cleanup // Cleanup
delete(URL_NODES, folderId, 204); delete(URL_NODES, folderId, 204);
} }
private void disableSiteNodeInheritanceAsShare(String siteId, String nodeId) throws IOException
{
setSiteNodeInheritance(siteId, nodeId, false, true);
}
private void setSiteNodeInheritance(String siteId, String nodeId, boolean inheritanceFlag, boolean addSiteManager) throws IOException
{
Node node = new Node();
NodePermissions perms = new NodePermissions();
perms.setIsInheritanceEnabled(inheritanceFlag);
if (!inheritanceFlag && addSiteManager) {
List<NodePermission> locallySet = new ArrayList<>();
locallySet.add(new NodePermission("GROUP_site_" + siteId + "_SiteManager", SiteRole.SiteManager.toString(), AccessStatus.ALLOWED.toString()));
perms.setLocallySet(locallySet);
}
node.setPermissions(perms);
try {
put(URL_NODES, nodeId, toJsonAsStringNonNull(node), null, 200);
} catch (Exception e) {
throw new IOException("Failed to update permissions: " + e.getMessage(), e);
}
}
} }

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId> <artifactId>alfresco-community-repo</artifactId>
<version>23.4.0.9-SNAPSHOT</version> <version>23.4.0.42-SNAPSHOT</version>
</parent> </parent>
<dependencies> <dependencies>
@@ -94,7 +94,7 @@
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>3.14.0</version> <version>3.17.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>commons-codec</groupId> <groupId>commons-codec</groupId>
@@ -358,7 +358,7 @@
<dependency> <dependency>
<groupId>com.fasterxml.woodstox</groupId> <groupId>com.fasterxml.woodstox</groupId>
<artifactId>woodstox-core</artifactId> <artifactId>woodstox-core</artifactId>
<version>6.5.1</version> <version>7.0.0</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -397,12 +397,12 @@
<dependency> <dependency>
<groupId>org.mybatis</groupId> <groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId> <artifactId>mybatis</artifactId>
<version>3.5.13</version> <version>3.5.16</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mybatis</groupId> <groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId> <artifactId>mybatis-spring</artifactId>
<version>3.0.3</version> <version>3.0.4</version>
</dependency> </dependency>
<!-- Activiti --> <!-- Activiti -->

View File

@@ -46,8 +46,6 @@ import org.alfresco.service.cmr.repository.ScriptLocation;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.PersonService; import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.util.UrlUtil; import org.alfresco.util.UrlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Action to execute a JavaScript. The script has access to the default model. * Action to execute a JavaScript. The script has access to the default model.
@@ -58,10 +56,8 @@ import org.slf4j.LoggerFactory;
*/ */
public class ScriptActionExecuter extends ActionExecuterAbstractBase public class ScriptActionExecuter extends ActionExecuterAbstractBase
{ {
private static final Logger LOGGER = LoggerFactory.getLogger(ScriptActionExecuter.class);
public static final String NAME = "script"; public static final String NAME = "script";
public static final String PARAM_SCRIPTREF = "script-ref"; public static final String PARAM_SCRIPTREF = "script-ref";
private static final String SYSTEM_USER = "System";
private ServiceRegistry serviceRegistry; private ServiceRegistry serviceRegistry;
private SysAdminParams sysAdminParams; private SysAdminParams sysAdminParams;
@@ -156,14 +152,11 @@ public class ScriptActionExecuter extends ActionExecuterAbstractBase
{ {
// get the references we need to build the default scripting data-model // get the references we need to build the default scripting data-model
String userName = this.serviceRegistry.getAuthenticationService().getCurrentUserName(); String userName = this.serviceRegistry.getAuthenticationService().getCurrentUserName();
if (SYSTEM_USER.equals(userName))
{ // When a script is executed as a system user, there will no person or home space for providing to the scripting framework.
LOGGER.info("Skipping Script Execution for the System user."); NodeRef personRef = this.personService.getPersonOrNull(userName);
return; NodeRef homeSpaceRef = personRef == null ? null : (NodeRef)nodeService.getProperty(personRef, ContentModel.PROP_HOMEFOLDER);
}
NodeRef personRef = this.personService.getPerson(userName);
NodeRef homeSpaceRef = (NodeRef)nodeService.getProperty(personRef, ContentModel.PROP_HOMEFOLDER);
// the default scripting model provides access to well known objects and searching // the default scripting model provides access to well known objects and searching
// facilities - it also provides basic create/update/delete/copy/move services // facilities - it also provides basic create/update/delete/copy/move services
Map<String, Object> model = this.serviceRegistry.getScriptService().buildDefaultModel( Map<String, Object> model = this.serviceRegistry.getScriptService().buildDefaultModel(
@@ -207,6 +200,7 @@ public class ScriptActionExecuter extends ActionExecuterAbstractBase
/** /**
* @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List) * @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List)
*/ */
@Override
protected void addParameterDefinitions(List<ParameterDefinition> paramList) protected void addParameterDefinitions(List<ParameterDefinition> paramList)
{ {
if (scriptLocation == null) if (scriptLocation == null)

View File

@@ -1077,6 +1077,12 @@ public class CustomModelServiceImpl implements CustomModelService
@Override @Override
public NodeRef createDownloadNode(final String modelFileName, boolean withAssociatedForm) public NodeRef createDownloadNode(final String modelFileName, boolean withAssociatedForm)
{
return createDownloadNode(modelFileName, withAssociatedForm, null);
}
@Override
public NodeRef createDownloadNode(final String modelFileName, boolean withAssociatedForm, String downloadNodeName)
{ {
List<NodeRef> nodesToBeDownloaded = new ArrayList<>(2); List<NodeRef> nodesToBeDownloaded = new ArrayList<>(2);
@@ -1137,7 +1143,7 @@ public class CustomModelServiceImpl implements CustomModelService
try try
{ {
NodeRef archiveNodeRef = downloadService.createDownload(nodesToBeDownloaded.toArray(new NodeRef[nodesToBeDownloaded.size()]), false); NodeRef archiveNodeRef = downloadService.createDownload(nodesToBeDownloaded.toArray(new NodeRef[0]), false, downloadNodeName);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {

View File

@@ -28,12 +28,14 @@ package org.alfresco.repo.download;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.download.cannedquery.DownloadEntity; import org.alfresco.repo.download.cannedquery.DownloadEntity;
import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.download.DownloadService; import org.alfresco.service.cmr.download.DownloadService;
import org.alfresco.service.cmr.download.DownloadStatus; import org.alfresco.service.cmr.download.DownloadStatus;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
/** /**
@@ -50,6 +52,7 @@ public class DownloadServiceImpl implements DownloadService {
private ActionServiceHelper actionServiceHelper; private ActionServiceHelper actionServiceHelper;
private DownloadStorage downloadStorage; private DownloadStorage downloadStorage;
private RetryingTransactionHelper transactionHelper; private RetryingTransactionHelper transactionHelper;
private NodeService nodeService;
// Dependency setters // Dependency setters
public void setActionServiceHelper(ActionServiceHelper actionServiceHelper) public void setActionServiceHelper(ActionServiceHelper actionServiceHelper)
@@ -66,9 +69,19 @@ public class DownloadServiceImpl implements DownloadService {
{ {
this.downloadStorage = downloadStorage; this.downloadStorage = downloadStorage;
} }
@Override public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
@Override
public NodeRef createDownload(final NodeRef[] requestedNodes, final boolean recursive) { public NodeRef createDownload(final NodeRef[] requestedNodes, final boolean recursive) {
return createDownload(requestedNodes, recursive, null);
}
@Override
public NodeRef createDownload(final NodeRef[] requestedNodes, final boolean recursive, String downloadNodeName) {
ParameterCheck.mandatory("nodeRefs", requestedNodes); ParameterCheck.mandatory("nodeRefs", requestedNodes);
if (requestedNodes.length < 1) if (requestedNodes.length < 1)
{ {
@@ -91,7 +104,12 @@ public class DownloadServiceImpl implements DownloadService {
{ {
downloadStorage.addNodeToDownload(downloadNode, node); downloadStorage.addNodeToDownload(downloadNode, node);
} }
if (downloadNodeName != null)
{
nodeService.setProperty(downloadNode, ContentModel.PROP_NAME, downloadNodeName);
}
return downloadNode; return downloadNode;
} }
}, false, true); }, false, true);

View File

@@ -38,6 +38,12 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
import org.alfresco.repo.domain.node.NodeDAO; import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.node.TransactionEntity; import org.alfresco.repo.domain.node.TransactionEntity;
import org.alfresco.repo.event.v1.model.DataAttributes; import org.alfresco.repo.event.v1.model.DataAttributes;
@@ -81,11 +87,6 @@ import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.PropertyCheck; import org.alfresco.util.PropertyCheck;
import org.alfresco.util.TriPredicate; import org.alfresco.util.TriPredicate;
import org.alfresco.util.transaction.TransactionListenerAdapter; import org.alfresco.util.transaction.TransactionListenerAdapter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
/** /**
* Generates events and sends them to an event topic. * Generates events and sends them to an event topic.
@@ -93,8 +94,8 @@ import org.springframework.extensions.surf.util.AbstractLifecycleBean;
* @author Jamal Kaabi-Mofrad * @author Jamal Kaabi-Mofrad
*/ */
public class EventGenerator extends AbstractLifecycleBean implements InitializingBean, EventSupportedPolicies, public class EventGenerator extends AbstractLifecycleBean implements InitializingBean, EventSupportedPolicies,
ChildAssociationEventSupportedPolicies, ChildAssociationEventSupportedPolicies,
PeerAssociationEventSupportedPolicies PeerAssociationEventSupportedPolicies
{ {
private static final Log LOGGER = LogFactory.getLog(EventGenerator.class); private static final Log LOGGER = LogFactory.getLog(EventGenerator.class);
@@ -354,7 +355,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
} }
protected ChildAssociationEventConsolidator createChildAssociationEventConsolidator( protected ChildAssociationEventConsolidator createChildAssociationEventConsolidator(
ChildAssociationRef childAssociationRef) ChildAssociationRef childAssociationRef)
{ {
return new ChildAssociationEventConsolidator(childAssociationRef, nodeResourceHelper); return new ChildAssociationEventConsolidator(childAssociationRef, nodeResourceHelper);
} }
@@ -417,8 +418,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
} }
/** /**
* @return the {@link NodeEventConsolidator} for the supplied {@code nodeRef} from * @return the {@link NodeEventConsolidator} for the supplied {@code nodeRef} from the current transaction context.
* the current transaction context.
*/ */
protected NodeEventConsolidator getEventConsolidator(NodeRef nodeRef) protected NodeEventConsolidator getEventConsolidator(NodeRef nodeRef)
{ {
@@ -438,7 +438,6 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
return eventConsolidator; return eventConsolidator;
} }
protected Consolidators getTxnConsolidators(Object resourceKey) protected Consolidators getTxnConsolidators(Object resourceKey)
{ {
Consolidators consolidators = AlfrescoTransactionSupport.getResource(resourceKey); Consolidators consolidators = AlfrescoTransactionSupport.getResource(resourceKey);
@@ -451,8 +450,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
} }
/** /**
* @return the {@link ChildAssociationEventConsolidator} for the supplied {@code childAssociationRef} from * @return the {@link ChildAssociationEventConsolidator} for the supplied {@code childAssociationRef} from the current transaction context.
* the current transaction context.
*/ */
private ChildAssociationEventConsolidator getEventConsolidator(ChildAssociationRef childAssociationRef) private ChildAssociationEventConsolidator getEventConsolidator(ChildAssociationRef childAssociationRef)
{ {
@@ -473,8 +471,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
} }
/** /**
* @return the {@link PeerAssociationEventConsolidator} for the supplied {@code peerAssociationRef} from * @return the {@link PeerAssociationEventConsolidator} for the supplied {@code peerAssociationRef} from the current transaction context.
* the current transaction context.
*/ */
private PeerAssociationEventConsolidator getEventConsolidator(AssociationRef peerAssociationRef) private PeerAssociationEventConsolidator getEventConsolidator(AssociationRef peerAssociationRef)
{ {
@@ -507,10 +504,10 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
protected EventInfo getEventInfo(String user) protected EventInfo getEventInfo(String user)
{ {
return new EventInfo().setTimestamp(getCurrentTransactionTimestamp()) return new EventInfo().setTimestamp(getCurrentTransactionTimestamp())
.setId(UUID.randomUUID().toString()) .setId(UUID.randomUUID().toString())
.setTxnId(AlfrescoTransactionSupport.getTransactionId()) .setTxnId(AlfrescoTransactionSupport.getTransactionId())
.setPrincipal(user) .setPrincipal(user)
.setSource(URI.create("/" + descriptorService.getCurrentRepositoryDescriptor().getId())); .setSource(URI.create("/" + descriptorService.getCurrentRepositoryDescriptor().getId()));
} }
private ZonedDateTime getCurrentTransactionTimestamp() private ZonedDateTime getCurrentTransactionTimestamp()
@@ -523,13 +520,12 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
private static ChildAssociationRef childAssociationWithoutParentOf(ChildAssociationRef childAssociationRef) private static ChildAssociationRef childAssociationWithoutParentOf(ChildAssociationRef childAssociationRef)
{ {
return new ChildAssociationRef( return new ChildAssociationRef(
null, null,
null, null,
childAssociationRef.getQName(), childAssociationRef.getQName(),
childAssociationRef.getChildRef(), childAssociationRef.getChildRef(),
childAssociationRef.isPrimary(), childAssociationRef.isPrimary(),
childAssociationRef.getNthSibling() childAssociationRef.getNthSibling());
);
} }
@Override @Override
@@ -546,7 +542,10 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
@Override @Override
protected void onShutdown(ApplicationEvent applicationEvent) protected void onShutdown(ApplicationEvent applicationEvent)
{ {
//NOOP if (eventSender != null)
{
eventSender.destroy();
}
} }
protected class EventTransactionListener extends TransactionListenerAdapter protected class EventTransactionListener extends TransactionListenerAdapter
@@ -586,8 +585,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
} }
/** /**
* @return true if a node transaction is not only active, but also committed with modifications. * @return true if a node transaction is not only active, but also committed with modifications. This means that a {@link TransactionEntity} object was created.
* This means that a {@link TransactionEntity} object was created.
*/ */
protected boolean isTransactionCommitted() protected boolean isTransactionCommitted()
{ {
@@ -601,7 +599,8 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
try try
{ {
sendEvents(); sendEvents();
} catch (Exception e) }
catch (Exception e)
{ {
// Must consume the exception to protect other TransactionListeners // Must consume the exception to protect other TransactionListeners
LOGGER.error("Unexpected error while sending repository events", e); LOGGER.error("Unexpected error while sending repository events", e);
@@ -650,14 +649,19 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
/** /**
* Handles all kinds of events and sends them within dedicated transaction. * Handles all kinds of events and sends them within dedicated transaction.
* *
* @param entityReference - reference to an entity (e.g. node, child association, peer association) * @param entityReference
* @param eventConsolidator - object encapsulating events occurred in a transaction * - reference to an entity (e.g. node, child association, peer association)
* @param entityToEventEligibilityVerifier - allows to verify if entity is eligible to generate an even. If null no verification is necessary * @param eventConsolidator
* @param <REF> - entity reference type (e.g. {@link NodeRef}, {@link AssociationRef}, {@link ChildAssociationRef}) * - object encapsulating events occurred in a transaction
* @param <CON> - event consolidator type - extension of {@link EventConsolidator} * @param entityToEventEligibilityVerifier
* - allows to verify if entity is eligible to generate an even. If null no verification is necessary
* @param <REF>
* - entity reference type (e.g. {@link NodeRef}, {@link AssociationRef}, {@link ChildAssociationRef})
* @param <CON>
* - event consolidator type - extension of {@link EventConsolidator}
*/ */
private <REF extends EntityRef, CON extends EventConsolidator<REF, ? extends Resource>> void sendEvent( private <REF extends EntityRef, CON extends EventConsolidator<REF, ? extends Resource>> void sendEvent(
final REF entityReference, final CON eventConsolidator, final TriPredicate<REF, CON, EventInfo> entityToEventEligibilityVerifier) final REF entityReference, final CON eventConsolidator, final TriPredicate<REF, CON, EventInfo> entityToEventEligibilityVerifier)
{ {
final EventInfo eventInfo = getEventInfo(AuthenticationUtil.getFullyAuthenticatedUser()); final EventInfo eventInfo = getEventInfo(AuthenticationUtil.getFullyAuthenticatedUser());
if (isSendingEventBeforeCommitRequired()) if (isSendingEventBeforeCommitRequired())
@@ -676,16 +680,22 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
/** /**
* Creates events from various kinds of entities. * Creates events from various kinds of entities.
* *
* @param entityReference - reference to an entity (e.g. node, child association, peer association) * @param entityReference
* @param eventConsolidator - object encapsulating events occurred in a transaction * - reference to an entity (e.g. node, child association, peer association)
* @param eventInfo - object holding the event information * @param eventConsolidator
* @param entityToEventEligibilityVerifier - allows to verify if entity is eligible to generate an even. If null no verification is necessary * - object encapsulating events occurred in a transaction
* @param <REF> - entity reference type (e.g. {@link NodeRef}, {@link AssociationRef}, {@link ChildAssociationRef}) * @param eventInfo
* @param <CON> - event consolidator type - extension of {@link EventConsolidator} * - object holding the event information
* @param entityToEventEligibilityVerifier
* - allows to verify if entity is eligible to generate an even. If null no verification is necessary
* @param <REF>
* - entity reference type (e.g. {@link NodeRef}, {@link AssociationRef}, {@link ChildAssociationRef})
* @param <CON>
* - event consolidator type - extension of {@link EventConsolidator}
*/ */
private <REF extends EntityRef, CON extends EventConsolidator<REF, ? extends Resource>> Optional<RepoEvent<?>> createEvent( private <REF extends EntityRef, CON extends EventConsolidator<REF, ? extends Resource>> Optional<RepoEvent<?>> createEvent(
final REF entityReference, final CON eventConsolidator, final EventInfo eventInfo, final REF entityReference, final CON eventConsolidator, final EventInfo eventInfo,
final TriPredicate<REF, CON, EventInfo> entityToEventEligibilityVerifier) final TriPredicate<REF, CON, EventInfo> entityToEventEligibilityVerifier)
{ {
if (eventConsolidator.isTemporaryEntity()) if (eventConsolidator.isTemporaryEntity())
{ {
@@ -719,8 +729,8 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
if (LOGGER.isTraceEnabled()) if (LOGGER.isTraceEnabled())
{ {
LOGGER.trace("EventFilter - Excluding node: '" + nodeReference + "' of type: '" LOGGER.trace("EventFilter - Excluding node: '" + nodeReference + "' of type: '"
+ ((nodeType == null) ? "Unknown' " : nodeType.toPrefixString()) + ((nodeType == null) ? "Unknown' " : nodeType.toPrefixString())
+ "' created by: " + user); + "' created by: " + user);
} }
return false; return false;
} }
@@ -747,8 +757,8 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
if (LOGGER.isTraceEnabled()) if (LOGGER.isTraceEnabled())
{ {
LOGGER.trace("EventFilter - Excluding child association: '" + childAssociationReference + "' of type: '" LOGGER.trace("EventFilter - Excluding child association: '" + childAssociationReference + "' of type: '"
+ ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString()) + ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString())
+ "' created by: " + user); + "' created by: " + user);
} }
return false; return false;
} }
@@ -757,8 +767,8 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
if (LOGGER.isTraceEnabled()) if (LOGGER.isTraceEnabled())
{ {
LOGGER.trace("EventFilter - Excluding primary child association: '" + childAssociationReference + "' of type: '" LOGGER.trace("EventFilter - Excluding primary child association: '" + childAssociationReference + "' of type: '"
+ ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString()) + ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString())
+ "' created by: " + user); + "' created by: " + user);
} }
return false; return false;
} }
@@ -804,7 +814,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
{ {
if (peerAssocs == null) if (peerAssocs == null)
{ {
peerAssocs = new LinkedHashMap<>(29); peerAssocs = new LinkedHashMap<>(29);
} }
return peerAssocs; return peerAssocs;
} }

View File

@@ -37,17 +37,26 @@ public interface EventSender
{ {
/** /**
* Accepts a callback function creating an event and sends this event to specified destination. * Accepts a callback function creating an event and sends this event to specified destination.
* @param eventProducer - callback function that creates an event *
* @param eventProducer
* - callback function that creates an event
*/ */
void accept(Callable<Optional<RepoEvent<?>>> eventProducer); void accept(Callable<Optional<RepoEvent<?>>> eventProducer);
/** /**
* It's called right after event sender instantiation (see {@link org.alfresco.repo.event2.EventSenderFactoryBean}). * It's called right after event sender instantiation (see {@link org.alfresco.repo.event2.EventSenderFactoryBean}). It might be used to initialize the sender implementation.
* It might be used to initialize the sender implementation.
*/ */
default void initialize() default void initialize()
{ {
//no initialization by default // no initialization by default
}
/**
* It's called when the application context is closing, allowing {@link org.alfresco.repo.event2.EventGenerator} to perform cleanup operations.
*/
default void destroy()
{
// no destruction by default
} }
default boolean shouldParticipateInTransaction() default boolean shouldParticipateInTransaction()

View File

@@ -997,7 +997,7 @@ public class LockServiceImpl implements LockService,
} }
// Never return a null LockState // Never return a null LockState
Assert.notNull(lockState); Assert.notNull(lockState, "The lockState should not be null");
return lockState; return lockState;
} }

View File

@@ -2,23 +2,23 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2023 Alfresco Software Limited * Copyright (C) 2005 - 2024 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is * the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms: * provided under the following open source license terms:
* *
* Alfresco is free software: you can redistribute it and/or modify * Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Alfresco is distributed in the hope that it will be useful, * Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
@@ -30,10 +30,8 @@ import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Reader; import java.io.Reader;
import java.util.List; import java.util.List;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.alfresco.repo.search.QueryParserException;
import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.HttpStatus;
@@ -47,13 +45,16 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.json.JSONTokener; import org.json.JSONTokener;
import org.alfresco.httpclient.HttpClientException;
import org.alfresco.repo.search.QueryParserException;
public abstract class AbstractSolrQueryHTTPClient public abstract class AbstractSolrQueryHTTPClient
{ {
/** Logger for the class. */ /** Logger for the class. */
private static final Log LOGGER = LogFactory.getLog(AbstractSolrQueryHTTPClient.class); private static final Log LOGGER = LogFactory.getLog(AbstractSolrQueryHTTPClient.class);
public static final int DEFAULT_SAVEPOST_BUFFER = 4096; public static final int DEFAULT_SAVEPOST_BUFFER = 4096;
// Constants copied from org.apache.solr.common.params.HighlightParams (solr-solrj:1.4.1) // Constants copied from org.apache.solr.common.params.HighlightParams (solr-solrj:1.4.1)
// These values have been moved to this Alfresco class to avoid using solr-solrj library as dependency // These values have been moved to this Alfresco class to avoid using solr-solrj library as dependency
public static final String HIGHLIGHT_PARAMS_HIGHLIGHT = "hl"; public static final String HIGHLIGHT_PARAMS_HIGHLIGHT = "hl";
@@ -85,7 +86,7 @@ public abstract class AbstractSolrQueryHTTPClient
/** List of SOLR Exceptions that should be returning HTTP 501 status code in Remote API. */ /** List of SOLR Exceptions that should be returning HTTP 501 status code in Remote API. */
private static final List<String> STATUS_CODE_501_EXCEPTIONS = List.of("java.lang.UnsupportedOperationException"); private static final List<String> STATUS_CODE_501_EXCEPTIONS = List.of("java.lang.UnsupportedOperationException");
protected JSONObject postQuery(HttpClient httpClient, String url, JSONObject body) throws IOException, JSONException protected JSONObject postQuery(HttpClient httpClient, String url, JSONObject body) throws IOException, JSONException
{ {
PostMethod post = createNewPostMethod(url); PostMethod post = createNewPostMethod(url);
@@ -98,7 +99,7 @@ public abstract class AbstractSolrQueryHTTPClient
try try
{ {
httpClient.executeMethod(post); httpClient.executeMethod(post);
if(post.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY || post.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY) if (post.getStatusCode() == HttpStatus.SC_MOVED_PERMANENTLY || post.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY)
{ {
Header locationHeader = post.getResponseHeader("location"); Header locationHeader = post.getResponseHeader("location");
if (locationHeader != null) if (locationHeader != null)
@@ -139,8 +140,11 @@ public abstract class AbstractSolrQueryHTTPClient
Reader reader = new BufferedReader(new InputStreamReader(post.getResponseBodyAsStream(), post.getResponseCharSet())); Reader reader = new BufferedReader(new InputStreamReader(post.getResponseBodyAsStream(), post.getResponseCharSet()));
// TODO - replace with streaming-based solution e.g. SimpleJSON ContentHandler // TODO - replace with streaming-based solution e.g. SimpleJSON ContentHandler
JSONObject json = new JSONObject(new JSONTokener(reader)); return new JSONObject(new JSONTokener(reader));
return json; }
catch (IOException e)
{
throw new HttpClientException("[%s] %s".formatted(this.getClass().getSimpleName(), e.getMessage()), e);
} }
finally finally
{ {

View File

@@ -2,7 +2,7 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2024 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
@@ -23,133 +23,127 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.repo.security.permissions; package org.alfresco.repo.security.permissions;
import java.util.Collection; import java.util.Collection;
import org.springframework.aop.IntroductionAdvisor; import org.springframework.aop.IntroductionAdvisor;
import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DefaultIntroductionAdvisor; import org.springframework.aop.support.DelegatingIntroductionInterceptor;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
/**
/** * Interface for collection-based results that describe permission filtering behaviour around cut-off limits.
* Interface for collection-based results that describe permission filtering *
* behaviour around cut-off limits. * @author Derek Hulley
* * @since 4.0
* @author Derek Hulley */
* @since 4.0 public interface PermissionCheckCollection<T>
*/ {
public interface PermissionCheckCollection<T> /**
{ * Get the desired number of results. Permission checks can stop once the number of return objects reaches this number.
/** *
* Get the desired number of results. Permission checks can stop once the number of * @return the number of results desired
* return objects reaches this number. */
* int getTargetResultCount();
* @return the number of results desired
*/ /**
int getTargetResultCount(); * Get the maximum time for permission checks to execute before cutting the results off. <br/>
* Zero: Ignore this value.
/** *
* Get the maximum time for permission checks to execute before cutting the results off. * @return the time allowed for permission checks before cutoff
* <br/>Zero: Ignore this value. */
* long getCutOffAfterTimeMs();
* @return the time allowed for permission checks before cutoff
*/ /**
long getCutOffAfterTimeMs(); * Get the maximum number of permission checks to perform before cutting the results off
*
/** * @return the maximum number of permission checks before cutoff
* Get the maximum number of permission checks to perform before cutting the results off */
* int getCutOffAfterCount();
* @return the maximum number of permission checks before cutoff
*/ /**
int getCutOffAfterCount(); * Helper 'introduction' to allow simple addition of the {@link PermissionCheckCollection} interface to existing collections.
*
/** * @param <T>
* Helper 'introduction' to allow simple addition of the {@link PermissionCheckCollection} interface to * the type of the <code>Collection</code> in use
* existing collections. *
* * @author Derek Hulley
* @param <T> the type of the <code>Collection</code> in use * @since 4.0
* */
* @author Derek Hulley @SuppressWarnings("serial")
* @since 4.0 class PermissionCheckCollectionMixin<T> extends DelegatingIntroductionInterceptor implements PermissionCheckCollection<T>
*/ {
@SuppressWarnings("serial") private final int targetResultCount;
public static class PermissionCheckCollectionMixin<T> extends DelegatingIntroductionInterceptor implements PermissionCheckCollection<T> private final long cutOffAfterTimeMs;
{ private final int cutOffAfterCount;
private final int targetResultCount;
private final long cutOffAfterTimeMs; private PermissionCheckCollectionMixin(int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount)
private final int cutOffAfterCount; {
super();
private PermissionCheckCollectionMixin(int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount) this.targetResultCount = targetResultCount;
{ this.cutOffAfterTimeMs = cutOffAfterTimeMs;
super(); this.cutOffAfterCount = cutOffAfterCount;
this.targetResultCount = targetResultCount; if (cutOffAfterTimeMs <= 0)
this.cutOffAfterTimeMs = cutOffAfterTimeMs; {
this.cutOffAfterCount = cutOffAfterCount; cutOffAfterTimeMs = 0;
if (cutOffAfterTimeMs <= 0) }
{ if (cutOffAfterCount <= 0)
cutOffAfterTimeMs = 0; {
} cutOffAfterCount = 0;
if (cutOffAfterCount <= 0) }
{ }
cutOffAfterCount = 0;
} @Override
} public int getTargetResultCount()
{
@Override return targetResultCount;
public int getTargetResultCount() }
{
return targetResultCount; @Override
} public long getCutOffAfterTimeMs()
{
@Override return cutOffAfterTimeMs;
public long getCutOffAfterTimeMs() }
{
return cutOffAfterTimeMs; @Override
} public int getCutOffAfterCount()
{
@Override return cutOffAfterCount;
public int getCutOffAfterCount() }
{
return cutOffAfterCount; /**
} * Helper method to create a {@link PermissionCheckCollection} from an existing <code>Collection</code>
*
/** * @param <TT>
* Helper method to create a {@link PermissionCheckCollection} from an existing <code>Collection</code> * the type of the <code>Collection</code>
* * @param collection
* @param <TT> the type of the <code>Collection</code> * the <code>Collection</code> to proxy
* @param collection the <code>Collection</code> to proxy * @param targetResultCount
* @param targetResultCount the desired number of results or default to the collection size * the desired number of results or default to the collection size
* @param cutOffAfterTimeMs the number of milliseconds to wait before cut-off or zero to use the system default * @param cutOffAfterTimeMs
* time-based cut-off. * the number of milliseconds to wait before cut-off or zero to use the system default time-based cut-off.
* @param cutOffAfterCount the number of permission checks to process before cut-off or zero to use the system default * @param cutOffAfterCount
* count-based cut-off. * the number of permission checks to process before cut-off or zero to use the system default count-based cut-off.
* @return a <code>Collection</code> of the same type but including the * @return a <code>Collection</code> of the same type but including the {@link PermissionCheckCollection} interface
* {@link PermissionCheckCollection} interface */
*/ @SuppressWarnings("unchecked")
@SuppressWarnings("unchecked") public static <TT> Collection<TT> create(
public static final <TT> Collection<TT> create( Collection<TT> collection,
Collection<TT> collection, int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount)
int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount) {
{ if (targetResultCount <= 0)
if (targetResultCount <= 0) {
{ targetResultCount = collection.size();
targetResultCount = collection.size(); }
} // Create the mixin
// Create the mixin DelegatingIntroductionInterceptor mixin = new PermissionCheckCollectionMixin<>(
DelegatingIntroductionInterceptor mixin = new PermissionCheckCollectionMixin<Integer>( targetResultCount,
targetResultCount, cutOffAfterTimeMs,
cutOffAfterTimeMs, cutOffAfterCount);
cutOffAfterCount); // Create the advisor
// Create the advisor IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckCollection.class);
IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckCollection.class); // Create Proxy
// Proxy return (Collection<TT>) ProxyFactoryUtils.createProxy(collection, advisor);
ProxyFactory pf = new ProxyFactory(collection); }
pf.addAdvisor(advisor); }
Object proxiedObject = pf.getProxy(); }
// Done
return (Collection<TT>) proxiedObject;
}
}
}

View File

@@ -2,161 +2,160 @@
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited * Copyright (C) 2005 - 2024 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is * the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms: * provided under the following open source license terms:
* *
* Alfresco is free software: you can redistribute it and/or modify * Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Alfresco is distributed in the hope that it will be useful, * Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.repo.security.permissions; package org.alfresco.repo.security.permissions;
import java.util.Collection; import java.util.Collection;
import org.springframework.aop.IntroductionAdvisor; import org.springframework.aop.IntroductionAdvisor;
import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DefaultIntroductionAdvisor; import org.springframework.aop.support.DelegatingIntroductionInterceptor;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
/**
/** * Interface for collection-based results that carry extra information about the state of permission cut-offs.
* Interface for collection-based results that carry extra information *
* about the state of permission cut-offs. * @author Derek Hulley
* * @since 4.0
* @author Derek Hulley */
* @since 4.0 public interface PermissionCheckedCollection<T>
*/ {
public interface PermissionCheckedCollection<T> /**
{ * Check if the results have been truncated by permission check limits.
/** *
* Check if the results have been truncated by permission check limits. * @return <tt>true</tt> - if the results (usually a collection) have been cut off by permission check limits
* */
* @return <tt>true</tt> - if the results (usually a collection) have been boolean isCutOff();
* cut off by permission check limits
*/ /**
boolean isCutOff(); * Get the number of objects in the original (unfiltered) collection that did <b>not</b> have any permission checks.
*
/** * @return number of entries from the original collection that were not checked
* Get the number of objects in the original (unfiltered) collection that did */
* <b>not</b> have any permission checks. int sizeUnchecked();
*
* @return number of entries from the original collection that were not checked /**
*/ * Get the number of objects in the original (unfiltered) collection.
int sizeUnchecked(); *
* @return number of entries in the original, pre-checked collection
/** */
* Get the number of objects in the original (unfiltered) collection. int sizeOriginal();
*
* @return number of entries in the original, pre-checked collection /**
*/ * Helper 'introduction' to allow simple addition of the {@link PermissionCheckedCollection} interface to existing collections.
int sizeOriginal(); *
* @param <T>
/** * the type of the <code>Collection</code> in use
* Helper 'introduction' to allow simple addition of the {@link PermissionCheckedCollection} interface to *
* existing collections. * @author Derek Hulley
* * @since 4.0
* @param <T> the type of the <code>Collection</code> in use */
* @SuppressWarnings("serial")
* @author Derek Hulley class PermissionCheckedCollectionMixin<T> extends DelegatingIntroductionInterceptor implements PermissionCheckedCollection<T>
* @since 4.0 {
*/ private final boolean isCutOff;
@SuppressWarnings("serial") private final int sizeUnchecked;
public static class PermissionCheckedCollectionMixin<T> extends DelegatingIntroductionInterceptor implements PermissionCheckedCollection<T> private final int sizeOriginal;
{
private final boolean isCutOff; private PermissionCheckedCollectionMixin(boolean isCutOff, int sizeUnchecked, int sizeOriginal)
private final int sizeUnchecked; {
private final int sizeOriginal; super();
private PermissionCheckedCollectionMixin(boolean isCutOff, int sizeUnchecked, int sizeOriginal) this.isCutOff = isCutOff;
{ this.sizeUnchecked = sizeUnchecked;
super(); this.sizeOriginal = sizeOriginal;
this.isCutOff = isCutOff; }
this.sizeUnchecked = sizeUnchecked;
this.sizeOriginal = sizeOriginal; @Override
} public boolean isCutOff()
@Override {
public boolean isCutOff() return isCutOff;
{ }
return isCutOff;
} @Override
@Override public int sizeUnchecked()
public int sizeUnchecked() {
{ return sizeUnchecked;
return sizeUnchecked; }
}
@Override @Override
public int sizeOriginal() public int sizeOriginal()
{ {
return sizeOriginal; return sizeOriginal;
} }
/**
* Helper method to create a {@link PermissionCheckedCollection} from an existing <code>Collection</code> /**
* by applying the same values as present on a potentially permission-checked source. If the * Helper method to create a {@link PermissionCheckedCollection} from an existing <code>Collection</code> by applying the same values as present on a potentially permission-checked source. If the existing checked source is <b>NOT</b> permission-checked, then the collection will not be decorated.
* existing checked source is <b>NOT</b> permission-checked, then the collection will not be *
* decorated. * @param <TT>
* * the type of the <code>Collection</code>
* @param <TT> the type of the <code>Collection</code> * @param collection
* @param collection the <code>Collection</code> to proxy * the <code>Collection</code> to proxy
* @param checkedSource a collection that might implement {@link PermissionCheckedCollection} * @param checkedSource
* @return a <code>Collection</code> of the same type but including the * a collection that might implement {@link PermissionCheckedCollection}
* {@link PermissionCheckedCollection} interface * @return a <code>Collection</code> of the same type but including the {@link PermissionCheckedCollection} interface
*/ */
public static final <TT> Collection<TT> create( public static <TT> Collection<TT> create(
Collection<TT> collection, Collection<?> checkedSource) Collection<TT> collection, Collection<?> checkedSource)
{ {
if (checkedSource instanceof PermissionCheckedCollection) if (checkedSource instanceof PermissionCheckedCollection)
{ {
PermissionCheckedCollection<?> source = (PermissionCheckedCollection<?>) checkedSource; PermissionCheckedCollection<?> source = (PermissionCheckedCollection<?>) checkedSource;
return create(collection, source.isCutOff(), source.sizeUnchecked(), source.sizeOriginal()); return create(collection, source.isCutOff(), source.sizeUnchecked(), source.sizeOriginal());
} }
else else
{ {
return collection; return collection;
} }
} }
/**
* Helper method to create a {@link PermissionCheckedCollection} from an existing <code>Collection</code> /**
* * Helper method to create a {@link PermissionCheckedCollection} from an existing <code>Collection</code>
* @param <TT> the type of the <code>Collection</code> *
* @param collection the <code>Collection</code> to proxy * @param <TT>
* @param isCutOff <tt>true</tt> if permission checking was cut off before completion * the type of the <code>Collection</code>
* @param sizeUnchecked number of entries from the original collection that were not checked * @param collection
* @param sizeOriginal number of entries in the original, pre-checked collection * the <code>Collection</code> to proxy
* @return a <code>Collection</code> of the same type but including the * @param isCutOff
* {@link PermissionCheckedCollection} interface * <tt>true</tt> if permission checking was cut off before completion
*/ * @param sizeUnchecked
@SuppressWarnings("unchecked") * number of entries from the original collection that were not checked
public static final <TT> Collection<TT> create( * @param sizeOriginal
Collection<TT> collection, * number of entries in the original, pre-checked collection
boolean isCutOff, int sizeUnchecked, int sizeOriginal) * @return a <code>Collection</code> of the same type but including the {@link PermissionCheckedCollection} interface
{ */
// Create the mixin @SuppressWarnings("unchecked")
DelegatingIntroductionInterceptor mixin = new PermissionCheckedCollectionMixin<Integer>( public static <TT> Collection<TT> create(
isCutOff, Collection<TT> collection,
sizeUnchecked, boolean isCutOff, int sizeUnchecked, int sizeOriginal)
sizeOriginal {
); // Create the mixin
// Create the advisor DelegatingIntroductionInterceptor mixin = new PermissionCheckedCollectionMixin<>(
IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckedCollection.class); isCutOff,
// Proxy sizeUnchecked,
ProxyFactory pf = new ProxyFactory(collection); sizeOriginal);
pf.addAdvisor(advisor); // Create the advisor
Object proxiedObject = pf.getProxy(); IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckedCollection.class);
// Create Proxy
// Done return (Collection<TT>) ProxyFactoryUtils.createProxy(collection, advisor);
return (Collection<TT>) proxiedObject; }
} }
} }
}

View File

@@ -0,0 +1,59 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2024 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.security.permissions;
import java.util.Collection;
import java.util.Deque;
import java.util.List;
import org.springframework.aop.IntroductionAdvisor;
import org.springframework.aop.framework.ProxyFactory;
class ProxyFactoryUtils
{
private ProxyFactoryUtils()
{}
/**
* Delegate creation of {@link ProxyFactory} and proxy to have control over it in one place.
*
* @param collection
* given collection for ProxyFactory.
* @param advisor
* given advisor for ProxyFactory.
* @return the proxy object.
*/
protected static Object createProxy(Collection<?> collection, IntroductionAdvisor advisor)
{
ProxyFactory pf = new ProxyFactory(collection);
pf.addAdvisor(advisor);
if (pf.isInterfaceProxied(List.class) && pf.isInterfaceProxied(Deque.class))
{
pf.removeInterface(Deque.class);
}
return pf.getProxy();
}
}

View File

@@ -40,7 +40,7 @@ import org.alfresco.service.cmr.repository.NodeRef;
public interface DownloadService public interface DownloadService
{ {
/** /**
* Start the creation of a downlaodable archive file containing the content * Start the creation of a downloadable archive file containing the content
* from the given nodeRefs. * from the given nodeRefs.
* *
* Implementations are expected to do this asynchronously, with clients * Implementations are expected to do this asynchronously, with clients
@@ -50,10 +50,27 @@ public interface DownloadService
* extended in the future, to support additional archive types. * extended in the future, to support additional archive types.
* *
* @param nodeRefs NodeRefs of content to be added to the archive file * @param nodeRefs NodeRefs of content to be added to the archive file
* @param recusirsive Recurse into container nodes * @param recursive Recurse into container nodes
* @return Reference to node which will eventually contain the archive file * @return Reference to node which will eventually contain the archive file
*/ */
public NodeRef createDownload(NodeRef[] nodeRefs, boolean recusirsive); NodeRef createDownload(NodeRef[] nodeRefs, boolean recursive);
/**
* Start the creation of a downloadable archive file containing the content
* from the given nodeRefs.
*
* Implementations are expected to do this asynchronously, with clients
* using the returned NodeRef to check on progress.
* Initially, only zip files will be supported, however this could be
* extended in the future, to support additional archive types.
*
* @param nodeRefs NodeRefs of content to be added to the archive file
* @param recursive Recurse into container nodes
* @param downloadNodeName Download node name
* @return Reference to node which will eventually contain the archive file
*/
NodeRef createDownload(NodeRef[] nodeRefs, boolean recursive, String downloadNodeName);
/** /**
* Get the status of the of the download identified by downloadNode. * Get the status of the of the download identified by downloadNode.

View File

@@ -115,6 +115,7 @@
<property name="actionServiceHelper" ref="downloadActionServiceHelper"/> <property name="actionServiceHelper" ref="downloadActionServiceHelper"/>
<property name="downloadStorage" ref="downloadStorage"/> <property name="downloadStorage" ref="downloadStorage"/>
<property name="transactionHelper" ref="retryingTransactionHelper"/> <property name="transactionHelper" ref="retryingTransactionHelper"/>
<property name="nodeService" ref="NodeService"/>
</bean> </bean>
<bean id="downloadCleanerSchedulerAccessor" class="org.springframework.scheduling.quartz.SchedulerAccessorBean"> <bean id="downloadCleanerSchedulerAccessor" class="org.springframework.scheduling.quartz.SchedulerAccessorBean">

View File

@@ -349,6 +349,29 @@ public class DownloadServiceIntegrationTest
validateEntries(entryNames, allEntries, true); validateEntries(entryNames, allEntries, true);
} }
@Test public void createDownloadWithName() throws IOException, InterruptedException
{
// Initiate the download
final NodeRef downloadNode = DOWNLOAD_SERVICE.createDownload(new NodeRef[] {rootFile}, false, "test.zip");
Assert.assertNotNull(downloadNode);
testNodes.addNodeRef(downloadNode);
// Validate that the download node has been persisted correctly.
TRANSACTION_HELPER.doInTransaction(new RetryingTransactionCallback<Object>()
{
@Override
public Object execute() throws Throwable
{
Map<QName, Serializable> properties = NODE_SERVICE.getProperties(downloadNode);
Assert.assertEquals(Boolean.FALSE, properties.get(DownloadModel.PROP_RECURSIVE));
Assert.assertEquals("test.zip",properties.get(ContentModel.PROP_NAME));
return null;
}
});
}
private void validateEntries(final Set<String> entryNames, final Set<String> expectedEntries, boolean onlyExpected) private void validateEntries(final Set<String> entryNames, final Set<String> expectedEntries, boolean onlyExpected)
{ {
Set<String> copy = new TreeSet<String>(entryNames); Set<String> copy = new TreeSet<String>(entryNames);

View File

@@ -1,155 +1,173 @@
/* /*
* #%L * #%L
* Alfresco Repository * Alfresco Repository
* %% * %%
* Copyright (C) 2005 - 2023 Alfresco Software Limited * Copyright (C) 2005 - 2024 Alfresco Software Limited
* %% * %%
* This file is part of the Alfresco software. * This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of * If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is * the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms: * provided under the following open source license terms:
* *
* Alfresco is free software: you can redistribute it and/or modify * Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Alfresco is distributed in the hope that it will be useful, * Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.repo.search.impl.solr; package org.alfresco.repo.search.impl.solr;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail; import static org.junit.Assert.assertThrows;
import static org.mockito.Mockito.doReturn; import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.spy; import static org.junit.Assert.fail;
import static org.mockito.Mockito.verify; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.doReturn;
import static org.mockito.MockitoAnnotations.openMocks; import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import jakarta.servlet.http.HttpServletResponse; import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream; import static org.mockito.MockitoAnnotations.openMocks;
import org.alfresco.repo.search.QueryParserException; import java.io.ByteArrayInputStream;
import org.apache.commons.httpclient.Header; import java.io.IOException;
import org.apache.commons.httpclient.HttpClient; import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.Header;
import org.json.JSONObject; import org.apache.commons.httpclient.HttpClient;
import org.junit.Before; import org.apache.commons.httpclient.URI;
import org.junit.Test; import org.apache.commons.httpclient.methods.PostMethod;
import org.mockito.Mock; import org.json.JSONObject;
import org.junit.Before;
/** Tests for the {@link AbstractSolrQueryHTTPClient}. */ import org.junit.Test;
public class AbstractSolrQueryHTTPClientTest import org.mockito.Mock;
{
/** A URL for use in the tests. */ import org.alfresco.httpclient.HttpClientException;
private static final String URL = "http://this/is/a/url"; import org.alfresco.repo.search.QueryParserException;
/** The abstract class under test. */ /** Tests for the {@link AbstractSolrQueryHTTPClient}. */
private AbstractSolrQueryHTTPClient abstractSolrQueryHTTPClient = spy(AbstractSolrQueryHTTPClient.class); public class AbstractSolrQueryHTTPClientTest
@Mock {
private HttpClient httpClient; /** A URL for use in the tests. */
@Mock private static final String URL = "http://this/is/a/url";
private JSONObject body;
@Mock /** The abstract class under test. */
private PostMethod postMethod; private final AbstractSolrQueryHTTPClient abstractSolrQueryHTTPClient = spy(AbstractSolrQueryHTTPClient.class);
@Mock @Mock
private Header header; private HttpClient httpClient;
@Mock
@Before private JSONObject body;
public void setUp() throws Exception @Mock
{ private PostMethod postMethod;
openMocks(this); @Mock
private Header header;
doReturn(postMethod).when(abstractSolrQueryHTTPClient).createNewPostMethod(URL);
when(postMethod.getResponseCharSet()).thenReturn("UTF-8"); @Before
} public void setUp() throws Exception
{
/** Check postQuery works as expected for the success case. */ openMocks(this);
@Test
public void testPostQuery_success() throws Exception doReturn(postMethod).when(abstractSolrQueryHTTPClient).createNewPostMethod(URL);
{ when(postMethod.getResponseCharSet()).thenReturn("UTF-8");
when(body.toString()).thenReturn("Example body"); }
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_OK);
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}")); /** Check postQuery works as expected for the success case. */
@Test
JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body); public void testPostQuery_success() throws Exception
{
assertEquals("Unexpected JSON response received.", "{}", response.toString()); when(body.toString()).thenReturn("Example body");
} when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_OK);
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}"));
/** Check that the status code is usually passed through from Solr. */
@Test JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
public void testPostQuery_failure() throws Exception
{ assertEquals("Unexpected JSON response received.", "{}", response.toString());
String failureMessage = "{\"error\": {\"trace\": \"ExceptionClass: Stacktrace\"}}"; }
when(body.toString()).thenReturn("Example body"); /** Check that the status code is usually passed through from Solr. */
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_NOT_FOUND); @Test
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage)); public void testPostQuery_failure() throws Exception
when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage); {
String failureMessage = "{\"error\": {\"trace\": \"ExceptionClass: Stacktrace\"}}";
try
{ when(body.toString()).thenReturn("Example body");
abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body); when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_NOT_FOUND);
fail("Expected a QueryParserException to be thrown."); when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage));
} when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage);
catch (QueryParserException e)
{ try
assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_FOUND); {
verify(postMethod).releaseConnection(); abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
} fail("Expected a QueryParserException to be thrown.");
} }
catch (QueryParserException e)
/** Check that the status code is replaced with "Not Implemented" for an unsupported query option. */ {
@Test assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_FOUND);
public void testPostQuery_unsupportedOperation() throws Exception verify(postMethod).releaseConnection();
{ }
String failureMessage = "{\"error\": {\"trace\": \"java.lang.UnsupportedOperationException: Stacktrace\"}}"; }
when(body.toString()).thenReturn("Example body"); /** Check that the status code is replaced with "Not Implemented" for an unsupported query option. */
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); @Test
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage)); public void testPostQuery_unsupportedOperation() throws Exception
when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage); {
String failureMessage = "{\"error\": {\"trace\": \"java.lang.UnsupportedOperationException: Stacktrace\"}}";
try
{ when(body.toString()).thenReturn("Example body");
abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body); when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
fail("Expected a QueryParserException to be thrown."); when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage));
} when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage);
catch (QueryParserException e)
{ try
assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_IMPLEMENTED); {
} abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
} fail("Expected a QueryParserException to be thrown.");
}
/** Check that a redirect can be followed if the endpoint reports that it's moved. */ catch (QueryParserException e)
@Test {
public void testPostQuery_moved() throws Exception assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_IMPLEMENTED);
{ }
when(body.toString()).thenReturn("Example body"); }
// Report "moved" for the first invocation and then OK for subsequent requests.
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_MOVED_PERMANENTLY).thenReturn(HttpServletResponse.SC_OK); /** Check that a redirect can be followed if the endpoint reports that it's moved. */
when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}")); @Test
when(postMethod.getResponseHeader("location")).thenReturn(header); public void testPostQuery_moved() throws Exception
when(header.getValue()).thenReturn("http://new/URL"); {
when(body.toString()).thenReturn("Example body");
JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body); // Report "moved" for the first invocation and then OK for subsequent requests.
when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_MOVED_PERMANENTLY).thenReturn(HttpServletResponse.SC_OK);
verify(postMethod).setURI(new URI("http://new/URL", true)); when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}"));
assertEquals("Unexpected JSON response received.", "{}", response.toString()); when(postMethod.getResponseHeader("location")).thenReturn(header);
} when(header.getValue()).thenReturn("http://new/URL");
/** Create an input stream containing the given string. */ JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body);
private ByteArrayInputStream convertStringToInputStream(String message)
{ verify(postMethod).setURI(new URI("http://new/URL", true));
return new ByteArrayInputStream(message.getBytes()); assertEquals("Unexpected JSON response received.", "{}", response.toString());
} }
}
@Test
public void testPostQuery_handlesIOException() throws Exception
{
String messageFromHttp = "Some IO Exception";
when(httpClient.executeMethod(any())).thenThrow(new IOException(messageFromHttp));
HttpClientException expectedException = assertThrows(HttpClientException.class, () -> abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body));
String exceptionMessage = expectedException.getMessage();
assertTrue(exceptionMessage.endsWith("[%s] %s".formatted(abstractSolrQueryHTTPClient.getClass().getSimpleName(), messageFromHttp)));
}
/** Create an input stream containing the given string. */
private ByteArrayInputStream convertStringToInputStream(String message)
{
return new ByteArrayInputStream(message.getBytes());
}
}

View File

@@ -68,4 +68,4 @@ services:
volumes: volumes:
- ../../../repository/src/test/resources/realms/alfresco-realm.json:/opt/keycloak/data/import/alfresco-realm.json - ../../../repository/src/test/resources/realms/alfresco-realm.json:/opt/keycloak/data/import/alfresco-realm.json
ports: ports:
- 8999:8080 - 8999:8080

View File

@@ -0,0 +1,40 @@
#!/usr/bin/env bash
set +x
if [[ -z ${GITHUB_MODIFIED_FILES} ]]
then
modified_files=$(git diff --cached --name-only --diff-filter=ACMR)
else
modified_files=${GITHUB_MODIFIED_FILES}
fi
include_list=""
for file in ${modified_files}
do
include_list="${include_list},${file}"
done
include_list=${include_list:1}
mvn spotless:apply validate -DlicenseUpdateHeaders=true -Pags,all-tas-tests -Dspotless-include-list="${include_list}" > /dev/null || true
all_nonconformant_files=$(git diff --name-only --diff-filter=ACMR)
for file in ${all_nonconformant_files}
do
revert=1
for modified_file in ${modified_files}
do
if [[ "${modified_file}" == "${file}" ]]
then
revert=0
break
fi
done
if [[ ${revert} == 1 ]]
then
git checkout -- "${file}"
fi
done
set -x