diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index adc6852d89..7a90a7f642 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -42,9 +42,16 @@ jobs: !contains(github.event.head_commit.message, '[force') steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 + with: + fetch-depth: 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" run: bash ./scripts/ci/init.sh - name: "Prepare maven cache and check compilation" @@ -62,12 +69,12 @@ jobs: !contains(github.event.head_commit.message, '[force') steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" 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 with: srcclr-api-token: ${{ secrets.SRCCLR_API_TOKEN }} @@ -85,10 +92,10 @@ jobs: !contains(github.event.head_commit.message, '[force') steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/github-download-file@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 + - uses: Alfresco/alfresco-build-tools/.github/actions/github-download-file@v7.1.0 with: token: ${{ secrets.BOT_GITHUB_TOKEN }} repository: "Alfresco/veracode-baseline-archive" @@ -135,10 +142,10 @@ jobs: !contains(github.event.head_commit.message, '[skip tests]') && !contains(github.event.head_commit.message, '[force]') steps: - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v7.0.0 - - uses: Alfresco/ya-pmd-scan@v4.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 + - uses: Alfresco/ya-pmd-scan@v4.1.0 with: classpath-build-command: "mvn test-compile -ntp -Pags -pl \"-:alfresco-community-repo-docker\"" @@ -168,14 +175,14 @@ jobs: testAttributes: "-Dtest=AllMmtUnitTestSuite" steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" run: bash ./scripts/ci/init.sh - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testModule }} @@ -206,7 +213,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: tests-outcome: ${{ steps.run-tests.outcome }} @@ -248,9 +255,9 @@ jobs: REQUIRES_INSTALLED_ARTIFACTS: true steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Build" timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} run: | @@ -259,10 +266,11 @@ jobs: - name: "Set transformers tag" run: echo "TRANSFORMERS_TAG=$(mvn help:evaluate -Dexpression=dependency.alfresco-transform-core.version -q -DforceStdout)" >> $GITHUB_ENV - 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 - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testSuite }} @@ -283,7 +291,7 @@ jobs: env: RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }} 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[@]}" continue-on-error: true - name: "Update GitHub Step Summary" @@ -293,7 +301,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: tests-outcome: ${{ steps.run-tests.outcome }} @@ -326,9 +334,9 @@ jobs: version: ['10.2.18', '10.4', '10.5'] steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" run: bash ./scripts/ci/init.sh - name: Run MariaDB ${{ matrix.version }} database @@ -337,7 +345,7 @@ jobs: MARIADB_VERSION: ${{ matrix.version }} - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.version }} @@ -368,7 +376,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: tests-outcome: ${{ steps.run-tests.outcome }} @@ -397,9 +405,9 @@ jobs: !contains(github.event.head_commit.message, '[force') steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" run: bash ./scripts/ci/init.sh - name: "Run MariaDB 10.6 database" @@ -408,7 +416,7 @@ jobs: MARIADB_VERSION: 10.6 - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} @@ -439,7 +447,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: tests-outcome: ${{ steps.run-tests.outcome }} @@ -468,9 +476,9 @@ jobs: !contains(github.event.head_commit.message, '[force') steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" run: bash ./scripts/ci/init.sh - name: "Run MySQL 8 database" @@ -479,7 +487,7 @@ jobs: MYSQL_VERSION: 8 - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} @@ -500,7 +508,7 @@ jobs: env: RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }} 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[@]}" continue-on-error: true - name: "Update GitHub Step Summary" @@ -510,7 +518,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: tests-outcome: ${{ steps.run-tests.outcome }} @@ -538,9 +546,9 @@ jobs: !contains(github.event.head_commit.message, '[force') steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" run: bash ./scripts/ci/init.sh - name: "Run PostgreSQL 13.12 database" @@ -549,7 +557,7 @@ jobs: POSTGRES_VERSION: 13.12 - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} @@ -570,7 +578,7 @@ jobs: env: RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }} 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[@]}" continue-on-error: true - name: "Update GitHub Step Summary" @@ -580,7 +588,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: tests-outcome: ${{ steps.run-tests.outcome }} @@ -608,9 +616,9 @@ jobs: !contains(github.event.head_commit.message, '[force') steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" run: bash ./scripts/ci/init.sh - name: "Run PostgreSQL 14.9 database" @@ -619,7 +627,7 @@ jobs: POSTGRES_VERSION: 14.9 - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} @@ -640,7 +648,7 @@ jobs: env: RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }} 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[@]}" continue-on-error: true - name: "Update GitHub Step Summary" @@ -650,7 +658,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: tests-outcome: ${{ steps.run-tests.outcome }} @@ -678,9 +686,9 @@ jobs: !contains(github.event.head_commit.message, '[force') steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" run: bash ./scripts/ci/init.sh - name: "Run PostgreSQL 15.4 database" @@ -689,7 +697,7 @@ jobs: POSTGRES_VERSION: 15.4 - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} @@ -710,7 +718,7 @@ jobs: env: RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }} 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[@]}" continue-on-error: true - name: "Update GitHub Step Summary" @@ -720,7 +728,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: tests-outcome: ${{ steps.run-tests.outcome }} @@ -746,16 +754,16 @@ jobs: !contains(github.event.head_commit.message, '[force') steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" run: bash ./scripts/ci/init.sh - name: "Run ActiveMQ" run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile activemq up -d - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} @@ -786,7 +794,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: 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' steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" run: bash ./scripts/ci/init.sh - name: "Set transformers tag" @@ -867,10 +875,11 @@ jobs: echo "HOSTNAME_VERIFICATION_DISABLED=false" >> "$GITHUB_ENV" fi - 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 - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testSuite }} ${{ matrix.idp }} @@ -901,7 +910,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: tests-outcome: ${{ steps.run-tests.outcome }} @@ -959,15 +968,16 @@ jobs: REQUIRES_LOCAL_IMAGES: true steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Build" timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} run: | bash ./scripts/ci/init.sh bash ./scripts/ci/build.sh - name: "Set up the environment" + timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} run: | ${{ 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" @@ -976,7 +986,7 @@ jobs: run: mvn install -pl :alfresco-community-repo-integration-test -am -DskipTests -Pall-tas-tests - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.test-name }} @@ -1014,7 +1024,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: tests-outcome: ${{ steps.tests.outcome }} @@ -1040,16 +1050,16 @@ jobs: !contains(github.event.head_commit.message, '[force') steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" run: bash ./scripts/ci/init.sh - name: "Run Postgres 15.4 database" run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile postgres up -d - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} @@ -1080,7 +1090,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: tests-outcome: ${{ steps.run-tests.outcome }} @@ -1114,9 +1124,9 @@ jobs: REQUIRES_INSTALLED_ARTIFACTS: true steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Build" timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} run: | @@ -1124,7 +1134,7 @@ jobs: bash ./scripts/ci/build.sh - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} 0${{ matrix.part }} - (PostgreSQL) ${{ matrix.test-name }} @@ -1160,9 +1170,9 @@ jobs: REQUIRES_INSTALLED_ARTIFACTS: true steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Build" timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} run: | @@ -1170,7 +1180,7 @@ jobs: bash ./scripts/ci/build.sh - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} 0${{ matrix.part }} - (MySQL) ${{ matrix.test-name }} @@ -1202,9 +1212,9 @@ jobs: REQUIRES_LOCAL_IMAGES: true steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Build" timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} run: | @@ -1218,7 +1228,7 @@ jobs: mvn -B install -pl :alfresco-governance-services-automation-community-rest-api -am -Pags -Pall-tas-tests -DskipTests - name: "Prepare Report Portal" 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 with: rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} @@ -1250,7 +1260,7 @@ jobs: continue-on-error: true - name: "Summarize Report Portal" 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 with: tests-outcome: ${{ steps.run-tests.outcome }} @@ -1292,9 +1302,9 @@ jobs: !contains(github.event.head_commit.message, '[force]') steps: - uses: actions/checkout@v4 - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Build" timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }} run: | diff --git a/.github/workflows/master_release.yml b/.github/workflows/master_release.yml index 5a7d49353d..c91e307eef 100644 --- a/.github/workflows/master_release.yml +++ b/.github/workflows/master_release.yml @@ -34,12 +34,12 @@ jobs: - uses: actions/checkout@v4 with: persist-credentials: false - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" 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: username: ${{ env.GIT_USERNAME }} email: ${{ env.GIT_EMAIL }} @@ -63,12 +63,12 @@ jobs: - uses: actions/checkout@v4 with: persist-credentials: false - - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v7.0.0 - - uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v7.0.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 - name: "Init" 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: username: ${{ env.GIT_USERNAME }} email: ${{ env.GIT_EMAIL }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..3f28bf9f45 --- /dev/null +++ b/.pre-commit-config.yaml @@ -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 diff --git a/.secrets.baseline b/.secrets.baseline new file mode 100644 index 0000000000..4f2c57dff6 --- /dev/null +++ b/.secrets.baseline @@ -0,0 +1,1892 @@ +{ + "version": "1.5.0", + "plugins_used": [ + { + "name": "ArtifactoryDetector" + }, + { + "name": "AWSKeyDetector" + }, + { + "name": "AzureStorageKeyDetector" + }, + { + "name": "Base64HighEntropyString", + "limit": 4.5 + }, + { + "name": "BasicAuthDetector" + }, + { + "name": "CloudantDetector" + }, + { + "name": "DiscordBotTokenDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "name": "GitLabTokenDetector" + }, + { + "name": "HexHighEntropyString", + "limit": 3.0 + }, + { + "name": "IbmCloudIamDetector" + }, + { + "name": "IbmCosHmacDetector" + }, + { + "name": "IPPublicDetector" + }, + { + "name": "JwtTokenDetector" + }, + { + "name": "KeywordDetector", + "keyword_exclude": "" + }, + { + "name": "MailchimpDetector" + }, + { + "name": "NpmDetector" + }, + { + "name": "OpenAIDetector" + }, + { + "name": "PrivateKeyDetector" + }, + { + "name": "PypiTokenDetector" + }, + { + "name": "SendGridDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "SoftlayerDetector" + }, + { + "name": "SquareOAuthDetector" + }, + { + "name": "StripeDetector" + }, + { + "name": "TelegramBotTokenDetector" + }, + { + "name": "TwilioKeyDetector" + } + ], + "filters_used": [ + { + "path": "detect_secrets.filters.allowlist.is_line_allowlisted" + }, + { + "path": "detect_secrets.filters.common.is_baseline_file", + "filename": ".secrets.baseline" + }, + { + "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", + "min_level": 2 + }, + { + "path": "detect_secrets.filters.heuristic.is_indirect_reference" + }, + { + "path": "detect_secrets.filters.heuristic.is_likely_id_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_lock_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_potential_uuid" + }, + { + "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign" + }, + { + "path": "detect_secrets.filters.heuristic.is_sequential_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_swagger_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_templated_secret" + } + ], + "results": { + ".github/workflows/ci.yml": [ + { + "type": "Secret Keyword", + "filename": ".github/workflows/ci.yml", + "hashed_secret": "b86dc2f033a63f2b7b9e7d270ab806d2910d7572", + "is_verified": false, + "line_number": 293 + }, + { + "type": "Secret Keyword", + "filename": ".github/workflows/ci.yml", + "hashed_secret": "1bfb0e20f886150ba59b853bcd49dea893e00966", + "is_verified": false, + "line_number": 368 + }, + { + "type": "Secret Keyword", + "filename": ".github/workflows/ci.yml", + "hashed_secret": "128f14373ccfaff49e3664045d3a11b50cbb7b39", + "is_verified": false, + "line_number": 902 + } + ], + ".github/workflows/master_release.yml": [ + { + "type": "Secret Keyword", + "filename": ".github/workflows/master_release.yml", + "hashed_secret": "3e26d6750975d678acb8fa35a0f69237881576b0", + "is_verified": false, + "line_number": 24, + "is_secret": false + } + ], + "amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/TestData.java": [ + { + "type": "Secret Keyword", + "filename": "amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/TestData.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 57, + "is_secret": false + } + ], + "amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/retentionschedule/RetentionScheduleStepTests.java": [ + { + "type": "Secret Keyword", + "filename": "amps/ags/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/retentionschedule/RetentionScheduleStepTests.java", + "hashed_secret": "e3557f3b0f2189660980d213f75d1a7828d56af1", + "is_verified": false, + "line_number": 83, + "is_secret": false + } + ], + "amps/ags/rm-automation/rm-automation-community-rest-api/src/test/resources/default.properties": [ + { + "type": "Secret Keyword", + "filename": "amps/ags/rm-automation/rm-automation-community-rest-api/src/test/resources/default.properties", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 21, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "amps/ags/rm-automation/rm-automation-community-rest-api/src/test/resources/default.properties", + "hashed_secret": "a4a747bd4ba5e3a5049cad116881867c71fb625b", + "is_verified": false, + "line_number": 87, + "is_secret": false + } + ], + "amps/ags/rm-community/rm-community-repo/docker-compose.yml": [ + { + "type": "Secret Keyword", + "filename": "amps/ags/rm-community/rm-community-repo/docker-compose.yml", + "hashed_secret": "953bf453cebf3913edbe172ec292c4ff81d27415", + "is_verified": false, + "line_number": 13 + }, + { + "type": "Secret Keyword", + "filename": "amps/ags/rm-community/rm-community-repo/docker-compose.yml", + "hashed_secret": "22b56e39272fd3bcd467c8e902c9dae5490b2277", + "is_verified": false, + "line_number": 22 + }, + { + "type": "Secret Keyword", + "filename": "amps/ags/rm-community/rm-community-repo/docker-compose.yml", + "hashed_secret": "d1ebbc78705ad98aa2c8fb357d2e30c8f001673a", + "is_verified": false, + "line_number": 76 + } + ], + "amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMPermissionModel.java": [ + { + "type": "Secret Keyword", + "filename": "amps/ags/rm-community/rm-community-repo/source/java/org/alfresco/module/org_alfresco_module_rm/capability/RMPermissionModel.java", + "hashed_secret": "b1f53ef1d62bcc8dc4701e495a7472b380c45afc", + "is_verified": false, + "line_number": 121, + "is_secret": false + } + ], + "amps/ags/rm-community/rm-community-repo/src/test/properties/local/alfresco-global.properties": [ + { + "type": "Secret Keyword", + "filename": "amps/ags/rm-community/rm-community-repo/src/test/properties/local/alfresco-global.properties", + "hashed_secret": "e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4", + "is_verified": false, + "line_number": 70, + "is_secret": false + } + ], + "core/src/main/java/org/alfresco/encryption/AlfrescoKeyStore.java": [ + { + "type": "Secret Keyword", + "filename": "core/src/main/java/org/alfresco/encryption/AlfrescoKeyStore.java", + "hashed_secret": "a718763bca0f328b0e7ce2a98d9e79fc271bf827", + "is_verified": false, + "line_number": 35, + "is_secret": false + } + ], + "core/src/main/java/org/alfresco/httpclient/HttpClientFactory.java": [ + { + "type": "Secret Keyword", + "filename": "core/src/main/java/org/alfresco/httpclient/HttpClientFactory.java", + "hashed_secret": "5d3c708390e5f51413e414393d4ad2a6d0e59a45", + "is_verified": false, + "line_number": 126, + "is_secret": false + } + ], + "core/src/test/resources/keystore-tests/empty-alias-metadata.properties": [ + { + "type": "Secret Keyword", + "filename": "core/src/test/resources/keystore-tests/empty-alias-metadata.properties", + "hashed_secret": "99a3024c77ef51c031038ab2c696f85e93ca9e62", + "is_verified": false, + "line_number": 2, + "is_secret": false + } + ], + "core/src/test/resources/keystore-tests/ks1-metadata.properties": [ + { + "type": "Secret Keyword", + "filename": "core/src/test/resources/keystore-tests/ks1-metadata.properties", + "hashed_secret": "99a3024c77ef51c031038ab2c696f85e93ca9e62", + "is_verified": false, + "line_number": 2, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "core/src/test/resources/keystore-tests/ks1-metadata.properties", + "hashed_secret": "41315a3765e4803f355d0582fed38a3a510d9692", + "is_verified": false, + "line_number": 3, + "is_secret": false + } + ], + "core/src/test/resources/keystore-tests/wrong-alias-metadata.properties": [ + { + "type": "Secret Keyword", + "filename": "core/src/test/resources/keystore-tests/wrong-alias-metadata.properties", + "hashed_secret": "99a3024c77ef51c031038ab2c696f85e93ca9e62", + "is_verified": false, + "line_number": 2, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "core/src/test/resources/keystore-tests/wrong-alias-metadata.properties", + "hashed_secret": "41315a3765e4803f355d0582fed38a3a510d9692", + "is_verified": false, + "line_number": 3, + "is_secret": false + } + ], + "core/src/test/resources/keystore-tests/wrong-key-password-metadata.properties": [ + { + "type": "Secret Keyword", + "filename": "core/src/test/resources/keystore-tests/wrong-key-password-metadata.properties", + "hashed_secret": "99a3024c77ef51c031038ab2c696f85e93ca9e62", + "is_verified": false, + "line_number": 2, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "core/src/test/resources/keystore-tests/wrong-key-password-metadata.properties", + "hashed_secret": "8d4170611a0278170def15c9a7c6b16706cd23ea", + "is_verified": false, + "line_number": 3, + "is_secret": false + } + ], + "core/src/test/resources/keystore-tests/wrong-keystore-password-metadata.properties": [ + { + "type": "Secret Keyword", + "filename": "core/src/test/resources/keystore-tests/wrong-keystore-password-metadata.properties", + "hashed_secret": "6809ffccad03b80fa1fbc32c17e7e054805ec30b", + "is_verified": false, + "line_number": 2, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "core/src/test/resources/keystore-tests/wrong-keystore-password-metadata.properties", + "hashed_secret": "41315a3765e4803f355d0582fed38a3a510d9692", + "is_verified": false, + "line_number": 3, + "is_secret": false + } + ], + "packaging/distribution/src/main/resources/keystore/metadata-keystore/keystore-passwords.properties": [ + { + "type": "Secret Keyword", + "filename": "packaging/distribution/src/main/resources/keystore/metadata-keystore/keystore-passwords.properties", + "hashed_secret": "f039ca7aa02b913940a6a97f01251f257178068f", + "is_verified": false, + "line_number": 6, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "packaging/distribution/src/main/resources/keystore/metadata-keystore/keystore-passwords.properties", + "hashed_secret": "22ccad749b70baa70011eaab411efa0c4128ee86", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "packaging/tests/environment/docker-compose-minimal+transforms.yml": [ + { + "type": "Secret Keyword", + "filename": "packaging/tests/environment/docker-compose-minimal+transforms.yml", + "hashed_secret": "9e3d103f7aa5f4f778cf752087dfceeba15d4fef", + "is_verified": false, + "line_number": 13 + }, + { + "type": "Secret Keyword", + "filename": "packaging/tests/environment/docker-compose-minimal+transforms.yml", + "hashed_secret": "92cda941553ea9ba9b39716c79a46b08a740613c", + "is_verified": false, + "line_number": 23 + }, + { + "type": "Secret Keyword", + "filename": "packaging/tests/environment/docker-compose-minimal+transforms.yml", + "hashed_secret": "d1ebbc78705ad98aa2c8fb357d2e30c8f001673a", + "is_verified": false, + "line_number": 76 + } + ], + "packaging/tests/environment/docker-compose-minimal.yml": [ + { + "type": "Secret Keyword", + "filename": "packaging/tests/environment/docker-compose-minimal.yml", + "hashed_secret": "9e3d103f7aa5f4f778cf752087dfceeba15d4fef", + "is_verified": false, + "line_number": 13 + }, + { + "type": "Secret Keyword", + "filename": "packaging/tests/environment/docker-compose-minimal.yml", + "hashed_secret": "92cda941553ea9ba9b39716c79a46b08a740613c", + "is_verified": false, + "line_number": 23 + }, + { + "type": "Secret Keyword", + "filename": "packaging/tests/environment/docker-compose-minimal.yml", + "hashed_secret": "d1ebbc78705ad98aa2c8fb357d2e30c8f001673a", + "is_verified": false, + "line_number": 79 + } + ], + "packaging/tests/scripts/wait-for-alfresco-start.sh": [ + { + "type": "Secret Keyword", + "filename": "packaging/tests/scripts/wait-for-alfresco-start.sh", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 15, + "is_secret": false + } + ], + "packaging/tests/tas-cmis/src/main/java/org/alfresco/cmis/AuthParameterProviderFactory.java": [ + { + "type": "JSON Web Token", + "filename": "packaging/tests/tas-cmis/src/main/java/org/alfresco/cmis/AuthParameterProviderFactory.java", + "hashed_secret": "a28cecdb5056cf30135809b921e38a84deb6c345", + "is_verified": false, + "line_number": 102, + "is_secret": false + }, + { + "type": "JSON Web Token", + "filename": "packaging/tests/tas-cmis/src/main/java/org/alfresco/cmis/AuthParameterProviderFactory.java", + "hashed_secret": "5e39d8e2991ef9705998de26b33f11be0f3cdcde", + "is_verified": false, + "line_number": 103, + "is_secret": false + } + ], + "packaging/tests/tas-cmis/src/main/resources/default.properties": [ + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-cmis/src/main/resources/default.properties", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 8, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-cmis/src/main/resources/default.properties", + "hashed_secret": "a4a747bd4ba5e3a5049cad116881867c71fb625b", + "is_verified": false, + "line_number": 76, + "is_secret": false + } + ], + "packaging/tests/tas-cmis/src/test/resources/default.properties": [ + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-cmis/src/test/resources/default.properties", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 8, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-cmis/src/test/resources/default.properties", + "hashed_secret": "a4a747bd4ba5e3a5049cad116881867c71fb625b", + "is_verified": false, + "line_number": 84, + "is_secret": false + } + ], + "packaging/tests/tas-email/src/test/resources/default.properties": [ + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-email/src/test/resources/default.properties", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 8, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-email/src/test/resources/default.properties", + "hashed_secret": "43b7ed74f99cf021109506832a48aa75435b817d", + "is_verified": false, + "line_number": 35, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-email/src/test/resources/default.properties", + "hashed_secret": "a4a747bd4ba5e3a5049cad116881867c71fb625b", + "is_verified": false, + "line_number": 97, + "is_secret": false + } + ], + "packaging/tests/tas-integration/src/test/resources/default.properties": [ + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-integration/src/test/resources/default.properties", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 8, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-integration/src/test/resources/default.properties", + "hashed_secret": "a4a747bd4ba5e3a5049cad116881867c71fb625b", + "is_verified": false, + "line_number": 118, + "is_secret": false + } + ], + "packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/core/RestAisAuthentication.java": [ + { + "type": "JSON Web Token", + "filename": "packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/core/RestAisAuthentication.java", + "hashed_secret": "a28cecdb5056cf30135809b921e38a84deb6c345", + "is_verified": false, + "line_number": 79, + "is_secret": false + }, + { + "type": "JSON Web Token", + "filename": "packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/core/RestAisAuthentication.java", + "hashed_secret": "5e39d8e2991ef9705998de26b33f11be0f3cdcde", + "is_verified": false, + "line_number": 80, + "is_secret": false + } + ], + "packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestSitePersonMembershipRequestModelsCollection.java": [ + { + "type": "Base64 High Entropy String", + "filename": "packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestSitePersonMembershipRequestModelsCollection.java", + "hashed_secret": "8b30a14989d7b8093ac29462fe29423d836625b4", + "is_verified": false, + "line_number": 39, + "is_secret": false + } + ], + "packaging/tests/tas-restapi/src/main/resources/default.properties": [ + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-restapi/src/main/resources/default.properties", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 21, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-restapi/src/main/resources/default.properties", + "hashed_secret": "a4a747bd4ba5e3a5049cad116881867c71fb625b", + "is_verified": false, + "line_number": 87, + "is_secret": false + } + ], + "packaging/tests/tas-restapi/src/test/resources/default.properties": [ + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-restapi/src/test/resources/default.properties", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 21, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-restapi/src/test/resources/default.properties", + "hashed_secret": "a4a747bd4ba5e3a5049cad116881867c71fb625b", + "is_verified": false, + "line_number": 87, + "is_secret": false + } + ], + "packaging/tests/tas-webdav/src/test/resources/default.properties": [ + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-webdav/src/test/resources/default.properties", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 8, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "packaging/tests/tas-webdav/src/test/resources/default.properties", + "hashed_secret": "a4a747bd4ba5e3a5049cad116881867c71fb625b", + "is_verified": false, + "line_number": 73, + "is_secret": false + } + ], + "packaging/war/src/main/webapp/META-INF/context.xml": [ + { + "type": "Secret Keyword", + "filename": "packaging/war/src/main/webapp/META-INF/context.xml", + "hashed_secret": "a4a747bd4ba5e3a5049cad116881867c71fb625b", + "is_verified": false, + "line_number": 4, + "is_secret": false + } + ], + "packaging/war/src/main/webapp/scripts/yui-3.3.0-dependencies.js": [ + { + "type": "Hex High Entropy String", + "filename": "packaging/war/src/main/webapp/scripts/yui-3.3.0-dependencies.js", + "hashed_secret": "c53c35a5b0f18b4e9061b386eeacc58e3dfcd24b", + "is_verified": false, + "line_number": 38, + "is_secret": false + } + ], + "remote-api/src/main/java/org/alfresco/repo/web/scripts/tenant/AbstractTenantAdminWebScript.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/main/java/org/alfresco/repo/web/scripts/tenant/AbstractTenantAdminWebScript.java", + "hashed_secret": "889d2688743fdce6115117a5ba7dbc5f33e0ce03", + "is_verified": false, + "line_number": 38, + "is_secret": false + } + ], + "remote-api/src/main/java/org/alfresco/web/app/servlet/AlfrescoX509ServletFilter.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/main/java/org/alfresco/web/app/servlet/AlfrescoX509ServletFilter.java", + "hashed_secret": "43d52295ed5cb7e2b772f2b8be9695ddde971c49", + "is_verified": false, + "line_number": 62, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "remote-api/src/main/java/org/alfresco/web/app/servlet/AlfrescoX509ServletFilter.java", + "hashed_secret": "1bd5147ff91b8b1220d2f1ffde850ebabbc5ec8c", + "is_verified": false, + "line_number": 63, + "is_secret": false + } + ], + "remote-api/src/main/resources/alfresco/subsystems/Authentication/kerberos/kerberos-filter.properties": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/main/resources/alfresco/subsystems/Authentication/kerberos/kerberos-filter.properties", + "hashed_secret": "e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4", + "is_verified": false, + "line_number": 2, + "is_secret": false + } + ], + "remote-api/src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/person/people.post.json.js": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/main/resources/alfresco/templates/webscripts/org/alfresco/repository/person/people.post.json.js", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 25, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/repo/remoteticket/RemoteAlfrescoTicketServiceTest.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/repo/remoteticket/RemoteAlfrescoTicketServiceTest.java", + "hashed_secret": "a926a50b320cea0d6c008a04322627400fe33f55", + "is_verified": false, + "line_number": 74, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/repo/web/scripts/node/NodeWebScripTest.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/repo/web/scripts/node/NodeWebScripTest.java", + "hashed_secret": "a926a50b320cea0d6c008a04322627400fe33f55", + "is_verified": false, + "line_number": 95, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/repo/web/scripts/servlet/RemoteAuthenticatorFactoryAdminConsoleAccessTest.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/repo/web/scripts/servlet/RemoteAuthenticatorFactoryAdminConsoleAccessTest.java", + "hashed_secret": "4ffa743f28fc949c19e65ab045d7906d0609a2c2", + "is_verified": false, + "line_number": 269, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/repo/web/scripts/solr/SOLRAuthenticationFilterTest.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/repo/web/scripts/solr/SOLRAuthenticationFilterTest.java", + "hashed_secret": "76ed0a056aa77060de25754586440cff390791d0", + "is_verified": false, + "line_number": 63, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/repo/webdav/LockMethodTest.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/repo/webdav/LockMethodTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 109, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/repo/webdav/UnlockMethodTest.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/repo/webdav/UnlockMethodTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 106, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/rest/api/tests/AbstractBaseApiTest.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/rest/api/tests/AbstractBaseApiTest.java", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 120, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/rest/api/tests/RepoService.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/rest/api/tests/RepoService.java", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 418, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/rest/api/tests/TestCMIS.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/rest/api/tests/TestCMIS.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 182, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/rest/api/tests/TestPeople.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/rest/api/tests/TestPeople.java", + "hashed_secret": "e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4", + "is_verified": false, + "line_number": 592, + "is_secret": false + }, + { + "type": "Hex High Entropy String", + "filename": "remote-api/src/test/java/org/alfresco/rest/api/tests/TestPeople.java", + "hashed_secret": "53dad674827218e94c8fe9c1984c8dd9db512a17", + "is_verified": false, + "line_number": 728, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/rest/api/tests/TestPeople.java", + "hashed_secret": "be66cf01c56d963de61462f37a43df2305367216", + "is_verified": false, + "line_number": 1429, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/rest/api/tests/TestPeople.java", + "hashed_secret": "283d47a9338ed1100b5fe2a5aff2d1f7c799bfd0", + "is_verified": false, + "line_number": 1430, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/rest/api/tests/TestPeople.java", + "hashed_secret": "425a715491af2bbec1eef2def6fa8d79c3050401", + "is_verified": false, + "line_number": 1452, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/rest/api/tests/TestRemovePermissions.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/rest/api/tests/TestRemovePermissions.java", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 57, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/rest/api/tests/client/AuthenticatedHttp.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/rest/api/tests/client/AuthenticatedHttp.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 54, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/rest/api/tests/client/UserData.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/rest/api/tests/client/UserData.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 42, + "is_secret": false + } + ], + "remote-api/src/test/java/org/alfresco/web/app/servlet/AlfrescoX509ServletFilterTest.java": [ + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/web/app/servlet/AlfrescoX509ServletFilterTest.java", + "hashed_secret": "43d52295ed5cb7e2b772f2b8be9695ddde971c49", + "is_verified": false, + "line_number": 50, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/web/app/servlet/AlfrescoX509ServletFilterTest.java", + "hashed_secret": "1bd5147ff91b8b1220d2f1ffde850ebabbc5ec8c", + "is_verified": false, + "line_number": 51, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/web/app/servlet/AlfrescoX509ServletFilterTest.java", + "hashed_secret": "5d3c708390e5f51413e414393d4ad2a6d0e59a45", + "is_verified": false, + "line_number": 52, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/web/app/servlet/AlfrescoX509ServletFilterTest.java", + "hashed_secret": "e5e9fa1ba31ecd1ae84f75caaa474f3a663f05f4", + "is_verified": false, + "line_number": 53, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/web/app/servlet/AlfrescoX509ServletFilterTest.java", + "hashed_secret": "3324f82c5b370b84973c54f8ab9a582328146694", + "is_verified": false, + "line_number": 56, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "remote-api/src/test/java/org/alfresco/web/app/servlet/AlfrescoX509ServletFilterTest.java", + "hashed_secret": "02bc8dee91680edf3de772b31247d23a45b3bf5a", + "is_verified": false, + "line_number": 57, + "is_secret": false + } + ], + "repository/src/main/java/org/alfresco/heartbeat/jobs/LockingJob.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/java/org/alfresco/heartbeat/jobs/LockingJob.java", + "hashed_secret": "b003370e1497c5003e21f1ec5da89e3d2d819506", + "is_verified": false, + "line_number": 60, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/main/java/org/alfresco/heartbeat/jobs/LockingJob.java", + "hashed_secret": "fc99e6a90240c45f46ed33a4d96a3dbecef41c60", + "is_verified": false, + "line_number": 61, + "is_secret": false + } + ], + "repository/src/main/java/org/alfresco/heartbeat/jobs/NonLockingJob.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/java/org/alfresco/heartbeat/jobs/NonLockingJob.java", + "hashed_secret": "b003370e1497c5003e21f1ec5da89e3d2d819506", + "is_verified": false, + "line_number": 52, + "is_secret": false + } + ], + "repository/src/main/java/org/alfresco/repo/admin/patch/impl/AdminUserPatch.java": [ + { + "type": "Hex High Entropy String", + "filename": "repository/src/main/java/org/alfresco/repo/admin/patch/impl/AdminUserPatch.java", + "hashed_secret": "87a754b00f7ee047d496808125d6259104e9382a", + "is_verified": false, + "line_number": 60, + "is_secret": false + } + ], + "repository/src/main/java/org/alfresco/repo/invitation/WorkflowModelNominatedInvitation.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/java/org/alfresco/repo/invitation/WorkflowModelNominatedInvitation.java", + "hashed_secret": "59ca42c026e181a60e4bf26c980a65b4ef457e16", + "is_verified": false, + "line_number": 90, + "is_secret": false + } + ], + "repository/src/main/java/org/alfresco/repo/remoteconnector/RemoteConnectorServiceImpl.java": [ + { + "type": "Hex High Entropy String", + "filename": "repository/src/main/java/org/alfresco/repo/remoteconnector/RemoteConnectorServiceImpl.java", + "hashed_secret": "a172ffc990129fe6f68b50f6037c54a1894ee3fd", + "is_verified": false, + "line_number": 204, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/main/java/org/alfresco/repo/remoteconnector/RemoteConnectorServiceImpl.java", + "hashed_secret": "a172ffc990129fe6f68b50f6037c54a1894ee3fd", + "is_verified": false, + "line_number": 204, + "is_secret": false + } + ], + "repository/src/main/java/org/alfresco/repo/security/authentication/ResetPasswordServiceImpl.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/java/org/alfresco/repo/security/authentication/ResetPasswordServiceImpl.java", + "hashed_secret": "e25df0eeed8d8eb4e198c3464c7bf747bc26eff8", + "is_verified": false, + "line_number": 92, + "is_secret": false + } + ], + "repository/src/main/java/org/alfresco/repo/security/authentication/SimpleAcceptOrRejectAllAuthenticationComponentImpl.java": [ + { + "type": "Hex High Entropy String", + "filename": "repository/src/main/java/org/alfresco/repo/security/authentication/SimpleAcceptOrRejectAllAuthenticationComponentImpl.java", + "hashed_secret": "304de25a3d73b68ad408ca3843356b5cf67f6f14", + "is_verified": false, + "line_number": 93, + "is_secret": false + } + ], + "repository/src/main/java/org/alfresco/repo/transfer/TransferServiceImpl2.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/java/org/alfresco/repo/transfer/TransferServiceImpl2.java", + "hashed_secret": "9ae9f2be7702b726809545808a8a9ba2e5a38410", + "is_verified": false, + "line_number": 130, + "is_secret": false + } + ], + "repository/src/main/java/org/alfresco/repo/workflow/WorkflowModelResetPassword.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/java/org/alfresco/repo/workflow/WorkflowModelResetPassword.java", + "hashed_secret": "65e636b62dec4469612f16d52ff6df67f9da39e5", + "is_verified": false, + "line_number": 47, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/main/java/org/alfresco/repo/workflow/WorkflowModelResetPassword.java", + "hashed_secret": "4562cd9b8a9ece1f797784a2256a0812778680e1", + "is_verified": false, + "line_number": 63, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/content-service.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/content-service.properties", + "hashed_secret": "4737a3ab81d198fe7e81e91ce484ace21e13fdf4", + "is_verified": false, + "line_number": 24, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/reset-password-messages.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/reset-password-messages.properties", + "hashed_secret": "5c4bc97ee5d0ac344829dbcef02d7302feb098a8", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/reset-password-messages_cs.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/reset-password-messages_cs.properties", + "hashed_secret": "3840ac3163c4ae3c44592e153e8aa9c005eb4976", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/reset-password-messages_da.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/reset-password-messages_da.properties", + "hashed_secret": "7795d909f846130a4b0ca2ceb11a45595a926dd7", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/reset-password-messages_de.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/reset-password-messages_de.properties", + "hashed_secret": "6ac2476e6b3264476c266b8b62e58463876eec93", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/reset-password-messages_es.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/reset-password-messages_es.properties", + "hashed_secret": "95c4a994da53f9d8c72f0090abd7dd4ee27e6a97", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/reset-password-messages_fi.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/reset-password-messages_fi.properties", + "hashed_secret": "92651e851d1a520088933d6b71c6706fc9b7fffe", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/reset-password-messages_fr.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/reset-password-messages_fr.properties", + "hashed_secret": "bb642b8d5071dbbf3779269cba14e721dc262bf7", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/reset-password-messages_it.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/reset-password-messages_it.properties", + "hashed_secret": "add35a788b003ae03ac5d8295f85ba295bc72ffd", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/reset-password-messages_nb.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/reset-password-messages_nb.properties", + "hashed_secret": "eb7fbdaf36ad281fde77f529f34af1d978f1bffe", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/reset-password-messages_nl.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/reset-password-messages_nl.properties", + "hashed_secret": "b64c2b68f7d1657c41a91ebf1fcf3fc31b05f6bd", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/reset-password-messages_pl.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/reset-password-messages_pl.properties", + "hashed_secret": "9d2c0d9b6442c31608b506bc56d6bd3fb7e6b7f6", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/reset-password-messages_pt_BR.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/reset-password-messages_pt_BR.properties", + "hashed_secret": "c46c3f680d905635a6921b359958008cb01a88ca", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service.properties", + "hashed_secret": "a945c7b85d492603ff45bc8b5ffebb3f93e801f8", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service_cs.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service_cs.properties", + "hashed_secret": "9f7107d692855f31ac45258147f51061f58912fd", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service_da.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service_da.properties", + "hashed_secret": "1908bd06e765ab2a7eccb65eb75e969b6b1cd7d0", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service_de.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service_de.properties", + "hashed_secret": "6532379d6c1e79379b9cf6525931289f989277b0", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service_es.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service_es.properties", + "hashed_secret": "af1daa244f81315fd558c04acef3abcc7d2a2f33", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service_fi.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service_fi.properties", + "hashed_secret": "a09629af4a7dc396527e2564da7ab83432c2442c", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service_fr.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service_fr.properties", + "hashed_secret": "5a540b7894111df6f7e4415f7f268cb3f1021d6f", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service_it.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service_it.properties", + "hashed_secret": "a337872fcdd32797bce4edfff734dc46cfc43ff9", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service_nb.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service_nb.properties", + "hashed_secret": "12a34c67bcf44c9ab1468b2f8ee7829a2df4568a", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service_nl.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service_nl.properties", + "hashed_secret": "e3bbf7fadd78a31531a446935bc03b73211c9fd0", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service_pl.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service_pl.properties", + "hashed_secret": "9618b3812f9d4b1adbdcd428b79bf2e8049f4cfd", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service_pt_BR.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service_pt_BR.properties", + "hashed_secret": "6eda6f1f1c71323a31fa2320efa8007d3265b0d4", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/messages/transfer-service_sv.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/messages/transfer-service_sv.properties", + "hashed_secret": "edcb85415622decdad5e58098a287f24478eb0db", + "is_verified": false, + "line_number": 48, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/repository.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/repository.properties", + "hashed_secret": "a4a747bd4ba5e3a5049cad116881867c71fb625b", + "is_verified": false, + "line_number": 245, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/repository.properties", + "hashed_secret": "1459a56410378e4d3ab470eff570e5eae1742762", + "is_verified": false, + "line_number": 312, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/repository.properties", + "hashed_secret": "84551ae5442affc9f1a2d3b4c86ae8b24860149d", + "is_verified": false, + "line_number": 770, + "is_secret": false + } + ], + "repository/src/main/resources/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/alfresco/subsystems/Authentication/ldap/ldap-authentication.properties", + "hashed_secret": "ca9d2dd42543cea510c0b9c2bce22272f4fb264a", + "is_verified": false, + "line_number": 187, + "is_secret": false + } + ], + "repository/src/main/resources/org/alfresco/encryption/keystore-parameters.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/main/resources/org/alfresco/encryption/keystore-parameters.properties", + "hashed_secret": "f039ca7aa02b913940a6a97f01251f257178068f", + "is_verified": false, + "line_number": 1, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/filesys/FTPServerTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/filesys/FTPServerTest.java", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 88, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/filesys/FTPServerTest.java", + "hashed_secret": "c464af817287343305cbd6493c593885695df531", + "is_verified": false, + "line_number": 92, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/filesys/FTPServerTest.java", + "hashed_secret": "8ad8572a0b3fc4cb3afc1baaebc97a2cae58eb8c", + "is_verified": false, + "line_number": 93, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/filesys/FTPServerTest.java", + "hashed_secret": "915692b4d7465b0084354173d552ac90145dc315", + "is_verified": false, + "line_number": 94, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java": [ + { + "type": "Base64 High Entropy String", + "filename": "repository/src/test/java/org/alfresco/filesys/repo/ContentDiskDriverTest.java", + "hashed_secret": "8c85434f6f339a24b808810bd95629d0f5856355", + "is_verified": false, + "line_number": 1280, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/opencmis/CMISTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/opencmis/CMISTest.java", + "hashed_secret": "9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684", + "is_verified": false, + "line_number": 4134, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/coci/CheckOutCheckInServiceImplTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/coci/CheckOutCheckInServiceImplTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 140, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/i18n/MessageServiceImplTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/i18n/MessageServiceImplTest.java", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 102, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/imap/ImapMessageTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/imap/ImapMessageTest.java", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 118, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/imap/ImapServiceImplCacheTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/imap/ImapServiceImplCacheTest.java", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 68, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/imap/ImapServiceImplTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/imap/ImapServiceImplTest.java", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 116, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/imap/LoadTester.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/imap/LoadTester.java", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 80, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/imap/RemoteLoadTester.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/imap/RemoteLoadTester.java", + "hashed_secret": "678721c0433c8cf5c9069a0e70784cf1839e866b", + "is_verified": false, + "line_number": 58, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/invitation/site/InviteSenderTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/invitation/site/InviteSenderTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 109, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/lock/LockBehaviourImplTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/lock/LockBehaviourImplTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 112, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/lock/LockServiceImplTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/lock/LockServiceImplTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 103, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/management/JmxDumpUtilTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/management/JmxDumpUtilTest.java", + "hashed_secret": "9f1bf21429a1074c37c6017bb76c3e3132bab061", + "is_verified": false, + "line_number": 65, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/management/JmxDumpUtilTest.java", + "hashed_secret": "209b9067f058a1c526cd5db7057f52ed1bbd6583", + "is_verified": false, + "line_number": 70, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/management/JmxDumpUtilTest.java", + "hashed_secret": "1af7165c744122c81be672d0deb9f04c02117c42", + "is_verified": false, + "line_number": 75, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/model/filefolder/FileFolderServiceImplTest.java", + "hashed_secret": "9e10e28cb9c3e381c13d13fa97dd97148982cdaa", + "is_verified": false, + "line_number": 595, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/notification/NotificationServiceImplSystemTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/notification/NotificationServiceImplSystemTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 74, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/oauth1/OAuth1CredentialsStoreServiceTest.java": [ + { + "type": "Hex High Entropy String", + "filename": "repository/src/test/java/org/alfresco/repo/oauth1/OAuth1CredentialsStoreServiceTest.java", + "hashed_secret": "c60646de4c4893cf860a12ecb7ba4f5317b1a1d0", + "is_verified": false, + "line_number": 61, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/oauth1/OAuth1CredentialsStoreServiceTest.java", + "hashed_secret": "c60646de4c4893cf860a12ecb7ba4f5317b1a1d0", + "is_verified": false, + "line_number": 61, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/oauth1/OAuth1CredentialsStoreServiceTest.java", + "hashed_secret": "ad8a621976e9a19cc78af501a84638a04fca9b83", + "is_verified": false, + "line_number": 65, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/oauth2/OAuth2CredentialsStoreServiceTest.java": [ + { + "type": "Hex High Entropy String", + "filename": "repository/src/test/java/org/alfresco/repo/oauth2/OAuth2CredentialsStoreServiceTest.java", + "hashed_secret": "c60646de4c4893cf860a12ecb7ba4f5317b1a1d0", + "is_verified": false, + "line_number": 70, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/rendition2/AbstractRenditionIntegrationTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/rendition2/AbstractRenditionIntegrationTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 127, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/replication/ReplicationServiceIntegrationTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/replication/ReplicationServiceIntegrationTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 1328, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/security/authentication/AuthenticationServiceImplTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/security/authentication/AuthenticationServiceImplTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 68, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/security/authentication/AuthenticationTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/security/authentication/AuthenticationTest.java", + "hashed_secret": "607e729c2f77c4e821e68e26b4c1f5a4398624e9", + "is_verified": false, + "line_number": 2129, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/security/authentication/AuthorizationTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/security/authentication/AuthorizationTest.java", + "hashed_secret": "9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684", + "is_verified": false, + "line_number": 37, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/security/authentication/CompositePasswordEncoderTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/security/authentication/CompositePasswordEncoderTest.java", + "hashed_secret": "4360136f24381dcec1d35d79fbf7dac4b54dfe97", + "is_verified": false, + "line_number": 301, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/security/authentication/identityservice/IdentityServiceFacadeFactoryBeanTest.java": [ + { + "type": "Base64 High Entropy String", + "filename": "repository/src/test/java/org/alfresco/repo/security/authentication/identityservice/IdentityServiceFacadeFactoryBeanTest.java", + "hashed_secret": "c4b66dbe168ad1d2b19119494a0da063801bc3bb", + "is_verified": false, + "line_number": 83, + "is_secret": false + }, + { + "type": "JSON Web Token", + "filename": "repository/src/test/java/org/alfresco/repo/security/authentication/identityservice/IdentityServiceFacadeFactoryBeanTest.java", + "hashed_secret": "c5aad1895e1dcff195992938f1bcc9954d575ac9", + "is_verified": false, + "line_number": 92, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/security/authentication/identityservice/LazyInstantiatingIdentityServiceFacadeUnitTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/security/authentication/identityservice/LazyInstantiatingIdentityServiceFacadeUnitTest.java", + "hashed_secret": "12e59296b0d17c1ceb345a7adca98574c835ba24", + "is_verified": false, + "line_number": 45, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/security/authentication/identityservice/SpringBasedIdentityServiceFacadeUnitTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/security/authentication/identityservice/SpringBasedIdentityServiceFacadeUnitTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 46, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/tenant/MultiTNodeServiceInterceptorTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/tenant/MultiTNodeServiceInterceptorTest.java", + "hashed_secret": "a63d4b132a9a1d3430f9ae507825f572449e0d17", + "is_verified": false, + "line_number": 51, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/transfer/HttpClientTransmitterImplTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/transfer/HttpClientTransmitterImplTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 75, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/transfer/TransferServiceCallbackTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/transfer/TransferServiceCallbackTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 664, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/transfer/TransferServiceImplTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/transfer/TransferServiceImplTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 203, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/transfer/TransferServiceImplTest.java", + "hashed_secret": "ad782ecdac770fc6eb9a62e44f90873fb97fb26b", + "is_verified": false, + "line_number": 513, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/transfer/TransferServiceImplTest.java", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 3687, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/transfer/TransferServiceToBeRefactoredTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/transfer/TransferServiceToBeRefactoredTest.java", + "hashed_secret": "8be3c943b1609fffbfc51aad666d0a04adf83c9d", + "is_verified": false, + "line_number": 2682, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/transfer/TransferServiceToBeRefactoredTest.java", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 3772, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/transfer/manifest/ManifestIntegrationTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/transfer/manifest/ManifestIntegrationTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 115, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/transfer/manifest/TransferManifestTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/transfer/manifest/TransferManifestTest.java", + "hashed_secret": "5395ebfd174b0a5617e6f409dfbb3e064e3fdf0a", + "is_verified": false, + "line_number": 127, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/version/BaseVersionStoreTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/version/BaseVersionStoreTest.java", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 149, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/version/NodeServiceImplTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/version/NodeServiceImplTest.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 86, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/repo/version/VersionServiceImplTest.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/repo/version/VersionServiceImplTest.java", + "hashed_secret": "dee17075a8c96d9c57c15d56b1f64e5abc1caf0b", + "is_verified": false, + "line_number": 122, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/util/test/junitrules/AlfrescoTenant.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/util/test/junitrules/AlfrescoTenant.java", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 67, + "is_secret": false + } + ], + "repository/src/test/java/org/alfresco/util/test/testusers/TestUserComponentImpl.java": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/java/org/alfresco/util/test/testusers/TestUserComponentImpl.java", + "hashed_secret": "f73e110427648014568f7144031a6d48060eab0a", + "is_verified": false, + "line_number": 55, + "is_secret": false + } + ], + "repository/src/test/resources/alfresco-global.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/resources/alfresco-global.properties", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 21, + "is_secret": false + } + ], + "repository/src/test/resources/alfresco/keystore-tests/encryption-test-context.xml": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/resources/alfresco/keystore-tests/encryption-test-context.xml", + "hashed_secret": "99a3024c77ef51c031038ab2c696f85e93ca9e62", + "is_verified": false, + "line_number": 12, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/test/resources/alfresco/keystore-tests/encryption-test-context.xml", + "hashed_secret": "316d20a7e5744b8542e2a4b14b0a38084150c8ae", + "is_verified": false, + "line_number": 13, + "is_secret": false + } + ], + "repository/src/test/resources/alfresco/keystore/keystore-passwords.properties": [ + { + "type": "Secret Keyword", + "filename": "repository/src/test/resources/alfresco/keystore/keystore-passwords.properties", + "hashed_secret": "f039ca7aa02b913940a6a97f01251f257178068f", + "is_verified": false, + "line_number": 6, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "repository/src/test/resources/alfresco/keystore/keystore-passwords.properties", + "hashed_secret": "22ccad749b70baa70011eaab411efa0c4128ee86", + "is_verified": false, + "line_number": 10, + "is_secret": false + } + ], + "repository/src/test/resources/bulkimport/folder1/folder1.1/quick.vdx": [ + { + "type": "Hex High Entropy String", + "filename": "repository/src/test/resources/bulkimport/folder1/folder1.1/quick.vdx", + "hashed_secret": "37c332070388a4797ccf1fa64f7029a193ce0371", + "is_verified": false, + "line_number": 2, + "is_secret": false + } + ], + "repository/src/test/resources/imap/test-tnef-message.eml": [ + { + "type": "AWS Access Key", + "filename": "repository/src/test/resources/imap/test-tnef-message.eml", + "hashed_secret": "b3a5ad926ea30683aa0628700e681923b79a0537", + "is_verified": false, + "line_number": 159, + "is_secret": false + } + ], + "repository/src/test/resources/quick/quick.vdx": [ + { + "type": "Hex High Entropy String", + "filename": "repository/src/test/resources/quick/quick.vdx", + "hashed_secret": "37c332070388a4797ccf1fa64f7029a193ce0371", + "is_verified": false, + "line_number": 2, + "is_secret": false + } + ], + "repository/src/test/resources/realms/alfresco-realm.json": [ + { + "type": "Base64 High Entropy String", + "filename": "repository/src/test/resources/realms/alfresco-realm.json", + "hashed_secret": "3fd30b50f0bc29e976e17546c5d52d39fac358ee", + "is_verified": false, + "line_number": 1792, + "is_secret": false + }, + { + "type": "Base64 High Entropy String", + "filename": "repository/src/test/resources/realms/alfresco-realm.json", + "hashed_secret": "8f45a0ff50a62e6f42d8b968dd5a59c4e8b973aa", + "is_verified": false, + "line_number": 1843, + "is_secret": false + } + ], + "scripts/ci/docker-compose/docker-compose.yaml": [ + { + "type": "Secret Keyword", + "filename": "scripts/ci/docker-compose/docker-compose.yaml", + "hashed_secret": "d033e22ae348aeb5660fc2140aec35850c4da997", + "is_verified": false, + "line_number": 39, + "is_secret": false + }, + { + "type": "Secret Keyword", + "filename": "scripts/ci/docker-compose/docker-compose.yaml", + "hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8", + "is_verified": false, + "line_number": 43, + "is_secret": false + } + ] + }, + "generated_at": "2024-10-02T10:18:47Z" +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 740a9afe34..0f34a26c43 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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 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. You can report an issue in the ALF project of the [Alfresco issue tracker](http://issues.alfresco.com). diff --git a/alfresco-formatter.xml b/alfresco-formatter.xml new file mode 100644 index 0000000000..9d6b8943ac --- /dev/null +++ b/alfresco-formatter.xml @@ -0,0 +1,401 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/amps/ags/pom.xml b/amps/ags/pom.xml index ac447d0d01..367dadea73 100644 --- a/amps/ags/pom.xml +++ b/amps/ags/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo-amps - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/amps/ags/rm-automation/pom.xml b/amps/ags/rm-automation/pom.xml index 2c76755c10..09bc77c278 100644 --- a/amps/ags/rm-automation/pom.xml +++ b/amps/ags/rm-automation/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-governance-services-community-parent - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/amps/ags/rm-automation/rm-automation-community-rest-api/pom.xml b/amps/ags/rm-automation/rm-automation-community-rest-api/pom.xml index f01887e7d4..ad877b07d2 100644 --- a/amps/ags/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/amps/ags/rm-automation/rm-automation-community-rest-api/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-governance-services-automation-community-repo - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT @@ -98,7 +98,7 @@ com.github.docker-java docker-java - 3.3.6 + 3.4.0 org.bouncycastle diff --git a/amps/ags/rm-community/pom.xml b/amps/ags/rm-community/pom.xml index 94ae73b734..85cd817a94 100644 --- a/amps/ags/rm-community/pom.xml +++ b/amps/ags/rm-community/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-governance-services-community-parent - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/amps/ags/rm-community/rm-community-repo/.env b/amps/ags/rm-community/rm-community-repo/.env index c528c95c4a..c937095503 100644 --- a/amps/ags/rm-community/rm-community-repo/.env +++ b/amps/ags/rm-community/rm-community-repo/.env @@ -1,3 +1,3 @@ -SOLR6_TAG=2.0.11 +SOLR6_TAG=2.0.12 POSTGRES_TAG=15.4 ACTIVEMQ_TAG=5.18.3-jre17-rockylinux8 diff --git a/amps/ags/rm-community/rm-community-repo/pom.xml b/amps/ags/rm-community/rm-community-repo/pom.xml index 6fa62a2ce8..321e69ab74 100644 --- a/amps/ags/rm-community/rm-community-repo/pom.xml +++ b/amps/ags/rm-community/rm-community-repo/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-governance-services-community-repo-parent - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/amps/ags/rm-community/rm-community-rest-api-explorer/pom.xml b/amps/ags/rm-community/rm-community-rest-api-explorer/pom.xml index 148033e867..b27166ed79 100644 --- a/amps/ags/rm-community/rm-community-rest-api-explorer/pom.xml +++ b/amps/ags/rm-community/rm-community-rest-api-explorer/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-governance-services-community-repo-parent - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/amps/pom.xml b/amps/pom.xml index b39dbf0d03..b9e0317980 100644 --- a/amps/pom.xml +++ b/amps/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/amps/share-services/pom.xml b/amps/share-services/pom.xml index d598f95196..0b16f63814 100644 --- a/amps/share-services/pom.xml +++ b/amps/share-services/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-community-repo-amps - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/core/pom.xml b/core/pom.xml index 8c09e7e63b..c7664fb86c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/core/src/main/java/org/alfresco/httpclient/HttpClientException.java b/core/src/main/java/org/alfresco/httpclient/HttpClientException.java index 9dc0f38784..3d9b0cffb5 100644 --- a/core/src/main/java/org/alfresco/httpclient/HttpClientException.java +++ b/core/src/main/java/org/alfresco/httpclient/HttpClientException.java @@ -27,4 +27,9 @@ public class HttpClientException extends AlfrescoRuntimeException { super(msgId); } + + public HttpClientException(String msgId, Throwable cause) + { + super(msgId, cause); + } } diff --git a/data-model/pom.xml b/data-model/pom.xml index d076b8e753..167e6e5cf3 100644 --- a/data-model/pom.xml +++ b/data-model/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT @@ -132,7 +132,7 @@ com.fasterxml.woodstox woodstox-core - 6.5.1 + 7.0.0 diff --git a/data-model/src/main/java/org/alfresco/service/cmr/dictionary/CustomModelService.java b/data-model/src/main/java/org/alfresco/service/cmr/dictionary/CustomModelService.java index c0a63df4f5..c5cd90d96e 100644 --- a/data-model/src/main/java/org/alfresco/service/cmr/dictionary/CustomModelService.java +++ b/data-model/src/main/java/org/alfresco/service/cmr/dictionary/CustomModelService.java @@ -238,6 +238,17 @@ public interface CustomModelService */ 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}. * diff --git a/mmt/pom.xml b/mmt/pom.xml index 2a8fa687ab..b3a582b893 100644 --- a/mmt/pom.xml +++ b/mmt/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/packaging/distribution/pom.xml b/packaging/distribution/pom.xml index 281036569c..f2e8f6c594 100644 --- a/packaging/distribution/pom.xml +++ b/packaging/distribution/pom.xml @@ -9,6 +9,6 @@ org.alfresco alfresco-community-repo-packaging - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/packaging/docker-alfresco/pom.xml b/packaging/docker-alfresco/pom.xml index 0e9e9b2a39..313a96357f 100644 --- a/packaging/docker-alfresco/pom.xml +++ b/packaging/docker-alfresco/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo-packaging - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/packaging/pom.xml b/packaging/pom.xml index 2ef99abd44..84a0056771 100644 --- a/packaging/pom.xml +++ b/packaging/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/packaging/tests/environment/.env b/packaging/tests/environment/.env index c528c95c4a..c937095503 100644 --- a/packaging/tests/environment/.env +++ b/packaging/tests/environment/.env @@ -1,3 +1,3 @@ -SOLR6_TAG=2.0.11 +SOLR6_TAG=2.0.12 POSTGRES_TAG=15.4 ACTIVEMQ_TAG=5.18.3-jre17-rockylinux8 diff --git a/packaging/tests/pom.xml b/packaging/tests/pom.xml index 24a51a3d3a..07715e448f 100644 --- a/packaging/tests/pom.xml +++ b/packaging/tests/pom.xml @@ -6,7 +6,7 @@ org.alfresco alfresco-community-repo-packaging - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/packaging/tests/tas-cmis/pom.xml b/packaging/tests/tas-cmis/pom.xml index 92ac9099ff..d28ada2444 100644 --- a/packaging/tests/tas-cmis/pom.xml +++ b/packaging/tests/tas-cmis/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo-tests - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/packaging/tests/tas-email/pom.xml b/packaging/tests/tas-email/pom.xml index 9cb636a24b..8e1c689d69 100644 --- a/packaging/tests/tas-email/pom.xml +++ b/packaging/tests/tas-email/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-community-repo-tests - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/packaging/tests/tas-integration/pom.xml b/packaging/tests/tas-integration/pom.xml index 762cc05fd9..b111f5a870 100644 --- a/packaging/tests/tas-integration/pom.xml +++ b/packaging/tests/tas-integration/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-community-repo-tests - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/packaging/tests/tas-restapi/pom.xml b/packaging/tests/tas-restapi/pom.xml index bfaf5bf989..77e1869706 100644 --- a/packaging/tests/tas-restapi/pom.xml +++ b/packaging/tests/tas-restapi/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-community-repo-tests - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT @@ -17,7 +17,7 @@ UTF-8 master 4.5.6 - 3.14.0 + 3.17.0 8.3.3 17 diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestPersonFavoritesModel.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestPersonFavoritesModel.java index 7643872eec..9969f9aadb 100644 --- a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestPersonFavoritesModel.java +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestPersonFavoritesModel.java @@ -36,22 +36,22 @@ public class RestPersonFavoritesModel extends TestModel implements IRestModel aspectNames; private List allowableOperations; - + private RestTargetModel target; public RestPersonFavoritesModel() - { - } + {} public RestPersonFavoritesModel(String targetGuid, String createdAt) { @@ -69,7 +69,7 @@ public class RestPersonFavoritesModel extends TestModel implements IRestModel getAllowableOperations() { + public List getAspectNames() + { + return aspectNames; + } + + public void setAspectNames(List aspectNames) + { + this.aspectNames = aspectNames; + } + + public List getAllowableOperations() + { return allowableOperations; } - public void setAllowableOperations(List allowableOperations) { + public void setAllowableOperations(List allowableOperations) + { this.allowableOperations = allowableOperations; } } diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/Categories.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/Categories.java new file mode 100644 index 0000000000..6e8550721f --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/Categories.java @@ -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 . + * #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 +{ + 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 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(); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/Files.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/Files.java new file mode 100644 index 0000000000..3a31d47721 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/Files.java @@ -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 . + * #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 +{ + 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 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(); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/Folders.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/Folders.java new file mode 100644 index 0000000000..7216b08311 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/Folders.java @@ -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 . + * #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 +{ + 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 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(); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/ResourceManager.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/ResourceManager.java new file mode 100644 index 0000000000..d0dd4b462e --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/ResourceManager.java @@ -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 . + * #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 > + * repository resource, e.g. folder, file, category, etc. + * @param + * repository resource specifier, see {@link Specifier} + * @param > + * repository resource modifier, see {@link Modifier} + */ +public interface ResourceManager> + extends ResourceIntroducer +{ + 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)); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/cache/MultiKeyResourceMap.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/cache/MultiKeyResourceMap.java new file mode 100644 index 0000000000..5cac493c6f --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/cache/MultiKeyResourceMap.java @@ -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 . + * #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 + * repository resource, e.g. folder, category, etc. + */ +public class MultiKeyResourceMap extends HashMap +{ + 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 keys = new HashMap<>(); + private final Function idSupplier; + private final Function nameSupplier; + + public MultiKeyResourceMap(Function idSupplier, Function 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 findKeysFor(Object id) + { + return keys.entrySet() + .stream() + .filter(entry -> id.equals(entry.getValue())) + .map(Entry::getKey) + .collect(Collectors.toSet()); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/category/NestedCategoriesCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/category/NestedCategoriesCreator.java new file mode 100644 index 0000000000..f40a90e9f8 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/category/NestedCategoriesCreator.java @@ -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 . + * #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 categories) + { + super(restClient, categories); + } + + @Override + public List create() + { + return createNestedCategories(parent, names, 0); + } + + private List createNestedCategories(RestCategoryModel parent, List categoryNames, int index) + { + List createdCategories = new ArrayList<>(); + categoryNames.stream().findFirst().ifPresent(categoryName -> { + RestCategoryModel createdCategory = createCategory(categoryName, getOrNull(aliases, index), parent); + createdCategories.add(createdCategory); + List remainingNames = categoryNames.stream().skip(1).toList(); + if (!remainingNames.isEmpty()) + { + createdCategories.addAll(createNestedCategories(createdCategory, remainingNames, index + 1)); + } + }); + + return createdCategories; + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/category/RepoCategoryCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/category/RepoCategoryCreator.java new file mode 100644 index 0000000000..57b2f8e777 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/category/RepoCategoryCreator.java @@ -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 . + * #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 + implements Creator.CategoryCreator, Specifier.CategoriesSpecifier +{ + + private final RestWrapper restClient; + private RestCategoryModel parent = ROOT_CATEGORY; + private final Map categoriesCache; + + public RepoCategoryCreator(RestWrapper restClient, Map 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 + "_"); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/category/RepoCategoryModifier.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/category/RepoCategoryModifier.java new file mode 100644 index 0000000000..4740d6cb95 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/category/RepoCategoryModifier.java @@ -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 . + * #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 + implements Modifier.CategoryModifier +{ + + private final RestWrapper restClient; + private final RestCategoryModel category; + private final Map categoriesCache; + + public RepoCategoryModifier(RestWrapper restClient, RestCategoryModel category, Map 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); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/category/SerialCategoriesCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/category/SerialCategoriesCreator.java new file mode 100644 index 0000000000..427dffd056 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/category/SerialCategoriesCreator.java @@ -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 . + * #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 + implements MultiCreator.CategoriesCreator +{ + + private final RestWrapper restClient; + protected RestCategoryModel parent = ROOT_CATEGORY; + private final Map categoriesCache; + + public SerialCategoriesCreator(RestWrapper restClient, Map 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 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 createRawCategories(RestCategoryModel parent, List categoryNames) + { + List 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(); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/MultiContentCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/MultiContentCreator.java new file mode 100644 index 0000000000..5bbb31bd52 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/MultiContentCreator.java @@ -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 . + * #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 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)); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/NestedFoldersCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/NestedFoldersCreator.java new file mode 100644 index 0000000000..c041f72ffe --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/NestedFoldersCreator.java @@ -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 . + * #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 folders) + { + super(dataContent, folders); + } + + @Override + public List create() + { + verifyDataConsistency(); + return createNestedFoldersUnder(parent, names, 0); + } + + private List createNestedFoldersUnder(FolderModel parent, List folderNames, int index) + { + List 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 remainingNames = folderNames.stream().skip(1).toList(); + if (!remainingNames.isEmpty()) + { + createdFolders.addAll(createNestedFoldersUnder(createdFolder, remainingNames, index + 1)); + } + }); + + return createdFolders; + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/PlainFileCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/PlainFileCreator.java new file mode 100644 index 0000000000..fed7f4c626 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/PlainFileCreator.java @@ -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 . + * #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 + implements Creator.FileCreator, Specifier.FileSpecifier +{ + + private final DataContent dataContent; + private final Map filesCache; + + public PlainFileCreator(DataContent dataContent, Map 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); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/PlainFileModifier.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/PlainFileModifier.java new file mode 100644 index 0000000000..6bed9eb5d8 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/PlainFileModifier.java @@ -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 . + * #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 + implements Modifier.FileModifier +{ + private final Map filesCache; + + public PlainFileModifier(DataContent dataContent, RestWrapper restClient, FileModel file, Map 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(); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/RepoFolderCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/RepoFolderCreator.java new file mode 100644 index 0000000000..4bc1a3985f --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/RepoFolderCreator.java @@ -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 . + * #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 + implements Creator.FolderCreator, Specifier.FolderSpecifier +{ + + private final DataContent dataContent; + private final Map foldersCache; + + public RepoFolderCreator(DataContent dataContent, Map 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 + "_"); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/RepoFolderModifier.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/RepoFolderModifier.java new file mode 100644 index 0000000000..7e95f7b412 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/RepoFolderModifier.java @@ -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 . + * #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 + implements Modifier.FolderModifier +{ + + private final RestWrapper restClient; + private final DataContent dataContent; + private final Files files; + private final Map foldersCache; + + public RepoFolderModifier(DataContent dataContent, RestWrapper restClient, FolderModel folder, Files files, Map 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(); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/SerialFilesCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/SerialFilesCreator.java new file mode 100644 index 0000000000..015fb842ea --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/SerialFilesCreator.java @@ -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 . + * #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 + implements MultiCreator.FilesCreator +{ + private final DataContent dataContent; + private List fileTypes; + private List filesContents; + private final Map filesCache; + + public SerialFilesCreator(DataContent dataContent, Map 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 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 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 createRawFilesUnder(FolderModel parent, List fileNames) + { + List 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; + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/SerialFoldersCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/SerialFoldersCreator.java new file mode 100644 index 0000000000..5dba8bb5cf --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/content/SerialFoldersCreator.java @@ -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 . + * #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 + implements MultiCreator.FoldersCreator +{ + + private final DataContent dataContent; + private final Map foldersCache; + + public SerialFoldersCreator(DataContent dataContent, Map foldersCache) + { + super(); + this.dataContent = dataContent; + this.foldersCache = foldersCache; + } + + @Override + protected SerialFoldersCreator self() + { + return this; + } + + @Override + public List 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 createRawFoldersUnder(FolderModel parent, List folderNames) + { + List 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; + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ContentCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ContentCreator.java new file mode 100644 index 0000000000..7bb0ca4759 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ContentCreator.java @@ -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 . + * #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> + extends ResourceCreator + implements Creator.ContentCreator +{ + 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 SELF underFolder(FOLDER parent) + { + this.parent = parent; + return self(); + } + + @Override + public SELF withinSite(SITE site) + { + this.site = site; + return self(); + } + + protected CONTENT create(DataContent dataContent, Function creator) + { + if (site != null) + { + dataContent.usingSite(site); + } + if (parent != null) + { + dataContent.usingResource(parent); + } + if (user != null) + { + dataContent.usingUser(user); + } + + return creator.apply(contentModel); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ContentModifier.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ContentModifier.java new file mode 100644 index 0000000000..6f6daf0a25 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ContentModifier.java @@ -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 . + * #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> + extends ResourceModifier + implements Modifier.ContentModifier +{ + 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 SELF withinSite(SITE site) + { + this.site = site; + return self(); + } + + protected CONTENT get(String id, Supplier 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 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 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 void linkTo(FOLDER secondaryParent) + { + buildNodeRestRequest(restClient, secondaryParent).addSecondaryChild(contentModel); + } + + @Override + @SafeVarargs + public final void linkTo(FOLDER... secondaryParents) + { + Stream.of(secondaryParents).forEach(secondaryParent -> buildNodeRestRequest(restClient, secondaryParent).addSecondaryChildren(contentModel)); + } + + @Override + public void unlinkFrom(FOLDER secondaryParent) + { + buildNodeRestRequest(restClient, secondaryParent).removeSecondaryChild(contentModel); + } + + @Override + public void linkTo(CATEGORY category) + { + buildNodeRestRequest(restClient, contentModel).linkToCategory( + RestCategoryLinkBodyModel.builder().categoryId(category.getId()).create()); + } + + @Override + @SafeVarargs + public final void linkTo(CATEGORY... categories) + { + buildNodeRestRequest(restClient, contentModel).linkToCategories( + Stream.of(categories) + .map(category -> RestCategoryLinkBodyModel.builder().categoryId(category.getId()).create()) + .collect(Collectors.toList())); + } + + @Override + public 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("/", "/", "/")); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/Creator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/Creator.java new file mode 100644 index 0000000000..80502dfc6b --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/Creator.java @@ -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 . + * #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 + * repository resource, e.g. folder, category, etc. + * @param + * return type - this interface extension or implementation + */ +public interface Creator> +{ + SELF withName(String name); + + SELF asUser(USER user); + + RESOURCE create(); + + interface ContentCreator> + extends Creator + { + SELF withTitle(String title); + + default SELF withRandomTitle() + { + return withTitle(RandomStringUtils.randomAlphanumeric(10)); + } + + SELF withDescription(String description); + + default SELF withRandomDescription() + { + return withDescription(RandomStringUtils.randomAlphanumeric(20)); + } + + SELF underFolder(FOLDER parent); + + SELF withinSite(SITE site); + } + + interface FolderCreator extends ContentCreator + {} + + interface FileCreator extends ContentCreator + { + 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 + { + CategoryCreator underCategory(CATEGORY parent); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/Modifier.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/Modifier.java new file mode 100644 index 0000000000..23ae379709 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/Modifier.java @@ -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 . + * #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 + * repository resource, e.g. folder, category, etc. + * @param + * return type - this interface extension or implementation + */ +public interface Modifier> +{ + RESOURCE get(String id); + + SELF asUser(USER user); + + void delete(); + + interface ContentModifier> + extends Modifier + { + void moveTo(FOLDER target); + + CONTENT copyTo(FOLDER target); + + void linkTo(FOLDER secondaryParent); + + void linkTo(FOLDER... secondaryParents); + + void unlinkFrom(FOLDER secondaryParent); + + void linkTo(CATEGORY category); + + void linkTo(CATEGORY... categories); + + void unlinkFrom(CATEGORY category); + + SELF withinSite(SITE site); + } + + interface FolderModifier extends ContentModifier, + ResourceIntroducer, ResourceRemover + {} + + interface FileModifier extends ContentModifier + {} + + interface CategoryModifier extends Modifier, + ResourceIntroducer + {} +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/MultiCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/MultiCreator.java new file mode 100644 index 0000000000..8b859b9cf0 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/MultiCreator.java @@ -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 . + * #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 + * repository resource, e.g. folder, category, etc. + * @param + * return type - this interface extension or implementation + */ +public interface MultiCreator> +{ + SELF withNames(String... names); + + SELF asUser(USER user); + + List create(); + + interface ContentsCreator> extends MultiCreator + { + SELF withTitles(String... titles); + + SELF withRandomTitles(); + + SELF withDescriptions(String... descriptions); + + SELF withRandomDescriptions(); + + SELF underFolder(FOLDER parent); + + SELF withinSite(SITE site); + } + + interface FoldersCreator extends ContentsCreator + {} + + interface FilesCreator extends ContentsCreator + { + FilesCreator ofTypes(FileType... fileTypes); + + FilesCreator withContents(List filesContents); + + default FilesCreator withRandomContents() + { + return withRandomContents(RandomGenerator.getDefault().nextInt(30, 70), 10); + } + + FilesCreator withRandomContents(int wordsCount, int wordsMaxLength); + } + + interface CategoriesCreator extends MultiCreator + { + CategoriesCreator underCategory(CATEGORY parent); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/MultipleContentsCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/MultipleContentsCreator.java new file mode 100644 index 0000000000..470a5e14db --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/MultipleContentsCreator.java @@ -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 . + * #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> + extends MultipleResourcesCreator + implements MultiCreator.ContentsCreator +{ + + protected FolderModel parent; + protected SiteModel site; + protected UserModel user; + protected List titles = new ArrayList<>(); + protected List 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 SELF underFolder(FOLDER parent) + { + this.parent = parent; + return self(); + } + + public 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"); + } + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/MultipleResourcesCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/MultipleResourcesCreator.java new file mode 100644 index 0000000000..1f4a3f4cde --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/MultipleResourcesCreator.java @@ -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 . + * #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> + implements MultiCreator +{ + + protected UserModel user; + protected List names; + protected List 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 prefixes, List 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 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 getOrNull(List list, int index) + { + if (CollectionUtils.isEmpty(list)) + { + return null; + } + + if (index < 0 || index >= list.size()) + { + return null; + } + + return list.get(index); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ResourceCreator.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ResourceCreator.java new file mode 100644 index 0000000000..949b1d52fb --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ResourceCreator.java @@ -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 . + * #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> + implements Creator +{ + + 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 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); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ResourceIntroducer.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ResourceIntroducer.java new file mode 100644 index 0000000000..399cdef206 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ResourceIntroducer.java @@ -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 . + * #L% + */ +package org.alfresco.rest.repo.resource.general; + +/** + * Declares an action introducing new repository resource like: folder, file, category, association, etc. + * + * @param + * repository resource specifier, see {@link Specifier} + */ +public interface ResourceIntroducer +{ + SPECIFIER add(); +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ResourceModifier.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ResourceModifier.java new file mode 100644 index 0000000000..6389bf9ee7 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ResourceModifier.java @@ -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 . + * #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> + implements Modifier +{ + + 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); + } +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ResourceRemover.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ResourceRemover.java new file mode 100644 index 0000000000..40038346b6 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/ResourceRemover.java @@ -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 . + * #L% + */ +package org.alfresco.rest.repo.resource.general; + +/** + * Declares an action, which removes repository resource like association. + * + * @param + * repository resource specifier, see {@link Specifier} + */ +public interface ResourceRemover +{ + SPECIFIER remove(); +} diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/Specifier.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/Specifier.java new file mode 100644 index 0000000000..81894c43c1 --- /dev/null +++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/repo/resource/general/Specifier.java @@ -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 . + * #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 + { + void secondaryContent(CONTENT content); + + void tag(TAG tag); + } + + interface MultiContentSpecifier extends FolderSpecifier, FileSpecifier, AssociationSpecifier + { + void secondaryContent(CONTENT... contents); + + 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); + } +} diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/favorites/GetFavoritesTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/favorites/GetFavoritesTests.java index 93727c7f9a..3897d4cbcf 100644 --- a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/favorites/GetFavoritesTests.java +++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/favorites/GetFavoritesTests.java @@ -2,6 +2,11 @@ package org.alfresco.rest.favorites; 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.rest.RestTest; 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.testrail.ExecutionType; 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 { private static final String ALLOWABLE_OPERATIONS = "allowableOperations"; + private static final String ASPECT_NAMES = "aspectNames"; private UserModel adminUserModel, userModel; private SiteModel firstSiteModel; private SiteModel secondSiteModel; @@ -56,7 +58,7 @@ public class GetFavoritesTests extends RestTest firstSiteUsers = dataUser.addUsersWithRolesToSite(firstSiteModel, UserRole.SiteManager, UserRole.SiteCollaborator, UserRole.SiteConsumer, UserRole.SiteContributor); secondSiteUsers = dataUser.addUsersWithRolesToSite(secondSiteModel, UserRole.SiteManager, UserRole.SiteCollaborator, UserRole.SiteConsumer, - UserRole.SiteContributor); + UserRole.SiteContributor); restClient.authenticateUser(userModel); restClient.withCoreAPI().usingUser(userModel).addSiteToFavorites(firstSiteModel); @@ -64,9 +66,9 @@ public class GetFavoritesTests extends RestTest 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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.SANITY }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.SANITY}) public void managerIsAbleToRetrieveFavorites() { restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteManager)); @@ -79,10 +81,10 @@ public class GetFavoritesTests extends RestTest .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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.SANITY }) -// @Bug(id = "MNT-16904", description = "It fails only on environment with tenants") + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.SANITY}) + // @Bug(id = "MNT-16904", description = "It fails only on environment with tenants") public void userIsNotAbleToRetrieveFavoritesIfAuthenticationFails() { UserModel siteManager = firstSiteUsers.getOneUserWithRole(UserRole.SiteManager); @@ -91,44 +93,44 @@ public class GetFavoritesTests extends RestTest 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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void adminIsAbleToRetrieveFavoritesSites() { restClient.authenticateUser(adminUserModel).withCoreAPI().usingUser(adminUserModel).addSiteToFavorites(firstSiteModel); restClient.withCoreAPI().usingUser(adminUserModel).addSiteToFavorites(secondSiteModel); - + userFavorites = restClient.withCoreAPI() .usingAuthUser().where().targetSiteExist().getFavorites(); restClient.assertStatusCodeIs(HttpStatus.OK); 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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void adminIsAbleToRetrieveFavoritesFolders() { restClient.authenticateUser(adminUserModel).withCoreAPI().usingUser(adminUserModel).addFolderToFavorites(firstFolderModel); restClient.withCoreAPI().usingUser(adminUserModel).addFolderToFavorites(secondFolderModel); - + userFavorites = restClient.withCoreAPI() .usingAuthUser().where().targetFolderExist().getFavorites(); restClient.assertStatusCodeIs(HttpStatus.OK); 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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void adminIsAbleToRetrieveFavoritesFiles() { restClient.authenticateUser(adminUserModel).withCoreAPI().usingUser(adminUserModel).addFileToFavorites(firstFileModel); restClient.withCoreAPI().usingUser(adminUserModel).addFileToFavorites(secondFileModel); - + userFavorites = restClient.withCoreAPI() .usingAuthUser().where().targetFileExist().getFavorites(); restClient.assertStatusCodeIs(HttpStatus.OK); @@ -136,87 +138,87 @@ public class GetFavoritesTests extends RestTest .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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void collaboratorIsAbleToRetrieveFavorites() { restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator)) - .withCoreAPI().usingAuthUser().addSiteToFavorites(firstSiteModel); + .withCoreAPI().usingAuthUser().addSiteToFavorites(firstSiteModel); restClient.withCoreAPI().usingAuthUser().addSiteToFavorites(secondSiteModel); - + userFavorites = restClient.withCoreAPI().usingAuthUser().getFavorites(); restClient.assertStatusCodeIs(HttpStatus.OK); 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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void contributorIsAbleToRetrieveFavorites() { restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteContributor)) - .withCoreAPI().usingAuthUser().addSiteToFavorites(firstSiteModel); + .withCoreAPI().usingAuthUser().addSiteToFavorites(firstSiteModel); restClient.withCoreAPI().usingAuthUser().addSiteToFavorites(secondSiteModel); - + userFavorites = restClient.withCoreAPI().usingAuthUser().getFavorites(); restClient.assertStatusCodeIs(HttpStatus.OK); 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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void consumerIsAbleToRetrieveFavorites() { restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer)) - .withCoreAPI().usingAuthUser().addSiteToFavorites(firstSiteModel); + .withCoreAPI().usingAuthUser().addSiteToFavorites(firstSiteModel); restClient.withCoreAPI().usingAuthUser().addSiteToFavorites(secondSiteModel); - + userFavorites = restClient.withCoreAPI().usingAuthUser().getFavorites(); restClient.assertStatusCodeIs(HttpStatus.OK); 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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsNotAbleToRetrieveFavoritesOfAnotherUser() { 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) .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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsNotAbleToRetrieveFavoritesOfAdminUser() { restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer)).withCoreAPI() - .usingUser(adminUserModel).getFavorites(); + .usingUser(adminUserModel).getFavorites(); 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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void adminIsNotAbleToRetrieveFavoritesOfAnotherUser() { restClient.authenticateUser(adminUserModel).withCoreAPI().usingUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator)) - .getFavorites(); + .getFavorites(); 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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToRetrieveOnlyFavoritesSites() { restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteManager)); @@ -232,9 +234,9 @@ public class GetFavoritesTests extends RestTest .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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToRetrieveOnlyFavoritesFiles() { restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator)); @@ -250,9 +252,9 @@ public class GetFavoritesTests extends RestTest .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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToRetrieveOnlyFavoritesFolders() { restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator)); @@ -268,9 +270,9 @@ public class GetFavoritesTests extends RestTest .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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToRetrieveFavoritesFilesOrFolders() { restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer)); @@ -289,9 +291,9 @@ public class GetFavoritesTests extends RestTest .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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToRetrieveFavoritesFilesOrSites() { restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteManager)); @@ -310,9 +312,9 @@ public class GetFavoritesTests extends RestTest .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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToRetrieveFavoritesFoldersOrSites() { restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteManager)); @@ -331,9 +333,9 @@ public class GetFavoritesTests extends RestTest .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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToRetrieveAllFavorites() { restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteCollaborator)); @@ -362,9 +364,9 @@ public class GetFavoritesTests extends RestTest .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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userHasNoFavorites() { restClient.authenticateUser(secondSiteUsers.getOneUserWithRole(UserRole.SiteContributor)); @@ -374,9 +376,9 @@ public class GetFavoritesTests extends RestTest 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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void getFavoritesUsingInvalidWhereParameter() { restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteConsumer)); @@ -390,9 +392,9 @@ public class GetFavoritesTests extends RestTest .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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void checkFavoriteFolderIsRemoved() { restClient.authenticateUser(firstSiteUsers.getOneUserWithRole(UserRole.SiteManager)); @@ -408,9 +410,9 @@ public class GetFavoritesTests extends RestTest .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 for request") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToGetFavoritesWhenUsingMeAsUsername() { 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()); } - @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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToGetFavoritesWhenUsingEmptyWhereParameter() { 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")); } - @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.") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void checkInvalidMaxItemsStatusCode() { restClient.authenticateUser(adminUserModel).withParams("maxItems=AB").withCoreAPI().usingUser(adminUserModel).getFavorites(); 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.") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void checkInvalidSkipCountStatusCode() { restClient.authenticateUser(adminUserModel).withParams("skipCount=AB").withCoreAPI().usingUser(adminUserModel).getFavorites(); 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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void getFavoritesWhenNetworkIdIsInvalid() { 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())); } - @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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsNotAbleToGetFavoritesWhenUsingANDInWhereParameter() { 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")); } - @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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsNotAbleToGetFavoritesWhenUsingWrongWhereParameter() { 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")); } - @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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToGetFavoritesExceptTheFirstOne() { 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()); } - @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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToGetFirstTwoFavorites() { 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"); } - @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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToGetFavoritesWhenSkipCountAndMaxItemsAreEmpty() { 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, " ")); } - @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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToGetFavoritesWithHighSkipCount() { 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"); } - @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") - @Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION }) + @Test(groups = {TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION}) public void userIsAbleToGetFavoritesWithPropertiesParamApplied() { 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(); } - @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") + @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") public void checkResponseSchemaForGetFavorites() { 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") public void checkResponsesForGetFavoritesWithAllowableOperations() { - final RestPersonFavoritesModelsCollection adminFavorites = - restClient.authenticateUser(adminUserModel).withCoreAPI().usingAuthUser().include(ALLOWABLE_OPERATIONS).getFavorites(); + final RestPersonFavoritesModelsCollection adminFavorites = restClient.authenticateUser(adminUserModel).withCoreAPI().usingAuthUser().include(ALLOWABLE_OPERATIONS).getFavorites(); restClient.assertStatusCodeIs(HttpStatus.OK); adminFavorites.getEntries().stream() @@ -576,18 +577,30 @@ public class GetFavoritesTests extends RestTest @TestRail(section = {TestGroup.REST_API, TestGroup.FAVORITES}, executionType = ExecutionType.REGRESSION, description = "Verify the get favorites request with properties parameter applied") @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 RestRequestQueryModel queryReq = new RestRequestQueryModel(); queryReq.setQuery(firstFileModel.getName()); query.setQuery(queryReq); query.setInclude(List.of("isFavorite")); - Utility.sleep(500, 60000, () -> - { - restClient.authenticateUser(adminUserModel).withSearchAPI().search(query); - restClient.onResponse().assertThat().body("list.entries.entry[0].isFavorite", Matchers.notNullValue()); - } - ); + Utility.sleep(500, 60000, () -> { + restClient.authenticateUser(adminUserModel).withSearchAPI().search(query); + 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()); } } diff --git a/packaging/tests/tas-webdav/pom.xml b/packaging/tests/tas-webdav/pom.xml index 7d289d5e26..d8866540b6 100644 --- a/packaging/tests/tas-webdav/pom.xml +++ b/packaging/tests/tas-webdav/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-community-repo-tests - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT diff --git a/packaging/war/pom.xml b/packaging/war/pom.xml index 0c4694c4c8..6299dfc036 100644 --- a/packaging/war/pom.xml +++ b/packaging/war/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo-packaging - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT @@ -113,7 +113,7 @@ org.owasp.encoder encoder - 1.2.3 + 1.3.1 @@ -140,7 +140,7 @@ org.codehaus.mojo buildnumber-maven-plugin - 3.2.0 + 3.2.1 validate diff --git a/pom.xml b/pom.xml index 4efd75b6ac..01dcb9fb9c 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 alfresco-community-repo - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT pom Alfresco Community Repo Parent @@ -51,45 +51,45 @@ 7.0.1 5.23.0 5.23.0 - 5.1.4 - 4.1.4 + 5.1.5-A1 + 4.1.5-A1 7.0 - 0.0.27 + 0.0.33 1.9.22.1 - 6.0.19 - 6.3.1 + 6.1.13 + 6.3.3 3.5.3 - 2.15.2 + 2.17.2 4.0.5 1.0.0-jakarta-1 - 9.0 + 9.4 1.78.1 - 5.12.0 + 5.14.1 3.26.3 - 20231013 + 20240303 2.12.0 2.16.1 2.11.0 - 33.2.1-jre + 33.3.1-jre 4.5.14 4.4.16 5.2.1 - 5.2.5 + 5.3 3.1-HTTPCLIENT-1265 2.12.2 - 2.0.13 + 2.0.16 2.23.1 3.0.22 2.9.2 7.7.10 - 5.2.5 + 5.3.0 3.5.0.Final 4.6.0 - 4.1.110.Final + 4.1.113.Final 5.18.3 - 1.26.2 - 4.2.1 + 1.27.1 + 4.2.2 4.1.3 1.0.71 3.1.1 @@ -100,8 +100,8 @@ 4.0.2 4.0.5 3.0.1 - 2.0.1 - 2.1.1 + 3.0.2 + 3.0.0 2.0.1 3.0.0 2.0.1 @@ -109,7 +109,7 @@ 3.1.0 1.2.0 2.1.3 - 1.1.6 + 1.1.7 2.9.0 2.5.1 4.1.0 @@ -117,13 +117,16 @@ 23.3.0 2.2.0 - 2.0.1 + 2.4.0 + 2.43.0 + + NO_AUTOMATED_FORMATTING - 42.7.3 + 42.7.4 8.0.30 8 2.7.4 - 5.0.1 + 5.0.2 5.5.0 2.0.0 1.21 @@ -411,7 +414,7 @@ commons-codec commons-codec - 1.17.0 + 1.17.1 commons-lang @@ -573,7 +576,7 @@ org.yaml snakeyaml - 2.2 + 2.3 com.fasterxml.jackson.core @@ -689,7 +692,7 @@ com.drewnoakes metadata-extractor - 2.18.0 + 2.19.0 @@ -700,7 +703,7 @@ com.networknt json-schema-validator - 1.5.0 + 1.5.1 @@ -790,14 +793,14 @@ joda-time joda-time - 2.12.5 + 2.13.0 jakarta.servlet jakarta.servlet-api - 6.0.0 + 6.1.0 provided @@ -1012,7 +1015,7 @@ maven-failsafe-plugin - 2.22.2 + 3.5.0 maven-jar-plugin @@ -1020,12 +1023,12 @@ maven-war-plugin - 3.3.2 + 3.4.0 org.apache.maven.plugins maven-javadoc-plugin - 3.7.0 + 3.10.1 org.apache.maven.plugins @@ -1035,7 +1038,7 @@ org.apache.maven.plugins maven-dependency-plugin - 3.7.1 + 3.8.0 maven-assembly-plugin @@ -1090,7 +1093,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.3.0 + 3.5.0 enforce-banned-dependencies @@ -1146,6 +1149,26 @@ + + com.diffplug.spotless + spotless-maven-plugin + ${spotless-plugin.version} + + + + ${spotless-include-list} + + + alfresco-formatter.xml + + + \#java|\#javax|\#jakarta,\#,\#org.alfresco,java|javax|jakarta,,org.alfresco + + + + + + @@ -1157,6 +1180,10 @@ org.apache.maven.plugins maven-enforcer-plugin + + com.diffplug.spotless + spotless-maven-plugin + diff --git a/remote-api/pom.xml b/remote-api/pom.xml index 1d53f771c6..e61a918e1b 100644 --- a/remote-api/pom.xml +++ b/remote-api/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT @@ -45,7 +45,7 @@ org.apache.santuario xmlsec - 3.0.3 + 4.0.2 @@ -137,7 +137,7 @@ org.eclipse.jetty jetty-webapp - 11.0.22 + 11.0.24 test diff --git a/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentGet.java b/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentGet.java index b929343ac3..3c704cc308 100644 --- a/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentGet.java +++ b/remote-api/src/main/java/org/alfresco/repo/web/scripts/content/ContentGet.java @@ -25,15 +25,24 @@ */ 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.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; - import jakarta.servlet.ServletContext; 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.repo.web.scripts.MimeTypeUtil; 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.namespace.NamespaceService; 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 @@ -62,7 +64,7 @@ public class ContentGet extends StreamContent implements ServletContextAware // Logger @SuppressWarnings("unused") private static final Log logger = LogFactory.getLog(ContentGet.class); - + // Component dependencies private ServletContext servletContext; private DictionaryService dictionaryService; @@ -72,18 +74,19 @@ public class ContentGet extends StreamContent implements ServletContextAware private List nonAttachContentTypes = Collections.emptyList(); /** - * @param nonAttachContentTypes List + * @param nonAttachContentTypes + * List */ public void setNonAttachContentTypes(List nonAttachContentTypes) { - if (nonAttachContentTypes != null && !nonAttachContentTypes.isEmpty()) - { - this.nonAttachContentTypes = nonAttachContentTypes; - } + this.nonAttachContentTypes = ofNullable(nonAttachContentTypes) + .map(types -> types.stream().filter(not(String::isBlank)).toList()) + .orElse(Collections.emptyList()); } /** - * @param servletContext ServletContext + * @param 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) { - this.dictionaryService = dictionaryService; + this.dictionaryService = dictionaryService; } /** - * @param namespaceService NamespaceService + * @param namespaceService + * NamespaceService */ public void setNamespaceService(NamespaceService namespaceService) { - this.namespaceService = namespaceService; + this.namespaceService = namespaceService; } - + /** - * @param contentService ContentService + * @param 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) */ public void execute(WebScriptRequest req, WebScriptResponse res) - throws IOException + throws IOException { // create map of args String[] names = req.getParameterNames(); @@ -127,10 +133,10 @@ public class ContentGet extends StreamContent implements ServletContextAware { args.put(name, req.getParameter(name)); } - + // create map of template vars Map templateVars = req.getServiceMatch().getTemplateVars(); - + // create object reference from url ObjectReference reference = createObjectReferenceFromUrl(args, templateVars); 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()); } - // render content QName propertyQName = ContentModel.PROP_CONTENT; String contentPart = templateVars.get("property"); @@ -186,7 +191,7 @@ public class ContentGet extends StreamContent implements ServletContextAware if (attach && rfc5987Supported) { 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 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); } } -} \ No newline at end of file +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/CustomModelsImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/CustomModelsImpl.java index 5231eac589..8368eb68b1 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/CustomModelsImpl.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/CustomModelsImpl.java @@ -712,8 +712,7 @@ public class CustomModelsImpl implements CustomModels boolean withForm = Boolean.valueOf(propName); try { - NodeRef nodeRef = customModelService.createDownloadNode(modelName, withForm); - nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, modelName + DownloadsImpl.DEFAULT_ARCHIVE_EXTENSION); + NodeRef nodeRef = customModelService.createDownloadNode(modelName, withForm, modelName + DownloadsImpl.DEFAULT_ARCHIVE_EXTENSION); return new CustomModelDownload(nodeRef); } catch (Exception ex) diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/FavouritesImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/FavouritesImpl.java index 5dd75b1591..6f2898e4a3 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/FavouritesImpl.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/FavouritesImpl.java @@ -1,460 +1,460 @@ -/* - * #%L - * Alfresco Remote API - * %% - * Copyright (C) 2005 - 2019 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 . - * #L% - */ -package org.alfresco.rest.api.impl; - -import static org.alfresco.rest.api.Nodes.PARAM_INCLUDE_ALLOWABLEOPERATIONS; - -import java.util.AbstractList; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -import org.alfresco.error.AlfrescoRuntimeException; -import org.alfresco.model.ContentModel; -import org.alfresco.query.PagingResults; -import org.alfresco.repo.favourites.PersonFavourite; -import org.alfresco.repo.site.SiteDoesNotExistException; -import org.alfresco.repo.site.SiteModel; -import org.alfresco.rest.api.Favourites; -import org.alfresco.rest.api.Nodes; -import org.alfresco.rest.api.People; -import org.alfresco.rest.api.Sites; -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.api.model.Folder; -import org.alfresco.rest.api.model.FolderTarget; -import org.alfresco.rest.api.model.Node; -import org.alfresco.rest.api.model.PathInfo; -import org.alfresco.rest.api.model.Site; -import org.alfresco.rest.api.model.SiteTarget; -import org.alfresco.rest.api.model.Target; -import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; -import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException; -import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; -import org.alfresco.rest.framework.resource.parameters.Paging; -import org.alfresco.rest.framework.resource.parameters.Parameters; -import org.alfresco.rest.framework.resource.parameters.Params; -import org.alfresco.rest.framework.resource.parameters.SortColumn; -import org.alfresco.rest.framework.resource.parameters.where.QueryHelper; -import org.alfresco.rest.framework.resource.parameters.where.QueryHelper.WalkerCallbackAdapter; -import org.alfresco.service.cmr.favourites.FavouritesService; -import org.alfresco.service.cmr.favourites.FavouritesService.SortFields; -import org.alfresco.service.cmr.favourites.FavouritesService.Type; -import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.StoreRef; -import org.alfresco.service.cmr.site.SiteInfo; -import org.alfresco.service.cmr.site.SiteService; -import org.alfresco.service.namespace.NamespaceService; -import org.alfresco.service.namespace.QName; -import org.alfresco.util.Pair; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Public REST API: Centralises access to favourites functionality and maps between representations repository and api representations. - * - * @author steveglover - * @since publicapi1.0 - */ -public class FavouritesImpl implements Favourites -{ - private static final Log logger = LogFactory.getLog(FavouritesImpl.class); - - private static final List ALLOWED_INCLUDES = List.of(PARAM_INCLUDE_PROPERTIES, PARAM_INCLUDE_ALLOWABLEOPERATIONS); - - private People people; - private Sites sites; - private Nodes nodes; - private FavouritesService favouritesService; - private SiteService siteService; - private NamespaceService namespaceService; - - // additional exclude properties for favourites as these can be already top-level properties - private static final List EXCLUDED_PROPS = Arrays.asList( - ContentModel.PROP_TITLE, - ContentModel.PROP_DESCRIPTION, - SiteModel.PROP_SITE_VISIBILITY, - SiteModel.PROP_SITE_PRESET - ); - - public void setPeople(People people) - { - this.people = people; - } - - public void setSites(Sites sites) - { - this.sites = sites; - } - - public void setNodes(Nodes nodes) - { - this.nodes = nodes; - } - - public void setFavouritesService(FavouritesService favouritesService) - { - this.favouritesService = favouritesService; - } - - public void setSiteService(SiteService siteService) - { - this.siteService = siteService; - } - - public void setNamespaceService(NamespaceService namespaceService) - { - this.namespaceService = namespaceService; - } - - private Target getTarget(PersonFavourite personFavourite, Parameters parameters) - { - Target target = null; - NodeRef nodeRef = personFavourite.getNodeRef(); - Type type = personFavourite.getType(); - if(type.equals(Type.FILE)) - { - Document document = nodes.getDocument(nodeRef); - setPathInfo(document, parameters.getInclude()); - target = new DocumentTarget(document); - } - else if(type.equals(Type.FOLDER)) - { - Folder folder = nodes.getFolder(nodeRef); - setPathInfo(folder, parameters.getInclude()); - target = new FolderTarget(folder); - } - else if(type.equals(Type.SITE)) - { - SiteInfo siteInfo = siteService.getSite(nodeRef); - String role = sites.getSiteRole(siteInfo.getShortName()); - Site site = new Site(siteInfo, role); - target = new SiteTarget(site); - } - else - { - throw new AlfrescoRuntimeException("Unexpected favourite target type: " + type); - } - - return target; - } - - private Favourite getFavourite(PersonFavourite personFavourite, Parameters parameters) - { - Favourite fav = new Favourite(); - fav.setTargetGuid(personFavourite.getNodeRef().getId()); - fav.setCreatedAt(personFavourite.getCreatedAt()); - Target target = getTarget(personFavourite, parameters); - fav.setTarget(target); - - // REPO-1147 allow retrieving additional properties - final List paramsInclude = parameters.getInclude(); - if (!Collections.disjoint(paramsInclude, ALLOWED_INCLUDES)) - { - final List includes = ALLOWED_INCLUDES.stream().filter(a -> paramsInclude.contains(a)).collect(Collectors.toList()); - // get node representation with only properties included - Node node = nodes.getFolderOrDocument(personFavourite.getNodeRef(), null, null, includes, null); - // Create a map from node properties excluding properties already in this Favorite - Map filteredNodeProperties = filterProps(node.getProperties(), EXCLUDED_PROPS); - if(filteredNodeProperties.size() > 0 && paramsInclude.contains(PARAM_INCLUDE_PROPERTIES)) - { - fav.setProperties(filteredNodeProperties); - } - final List allowableOperations = node.getAllowableOperations(); - if (CollectionUtils.isNotEmpty(allowableOperations) && paramsInclude.contains(PARAM_INCLUDE_ALLOWABLEOPERATIONS)) - { - fav.setAllowableOperations(allowableOperations); - } - } - - return fav; - } - - private Map filterProps(Map properties, List toRemove) - { - Map filteredProps = properties == null ? new HashMap<>() : new HashMap<>(properties); - List propsToRemove = toRemove.stream().map(e -> e.toPrefixString(namespaceService)).collect(Collectors.toList()); - filteredProps.keySet().removeAll(propsToRemove); - return filteredProps; - } - - private CollectionWithPagingInfo wrap(Paging paging, PagingResults personFavourites, Parameters parameters) - { - final List page = personFavourites.getPage(); - final List list = new AbstractList() - { - @Override - public Favourite get(int index) - { - PersonFavourite personFavourite = page.get(index); - Favourite fav = getFavourite(personFavourite, parameters); - return fav; - } - - @Override - public int size() - { - return page.size(); - } - }; - Pair pair = personFavourites.getTotalResultCount(); - Integer total = null; - if(pair.getFirst().equals(pair.getSecond())) - { - total = pair.getFirst(); - } - return CollectionWithPagingInfo.asPaged(paging, list, personFavourites.hasMoreItems(), total); - } - - @Override - public Favourite addFavourite(String personId, Favourite favourite) - { - Parameters parameters = getDefaultParameters(personId, null); - return addFavourite(personId, favourite, parameters); - } - - @Override - public Favourite addFavourite(String personId, Favourite favourite, Parameters parameters) - { - Favourite ret = null; - - personId = people.validatePerson(personId, true); - Target target = favourite.getTarget(); - if(target == null) - { - throw new InvalidArgumentException("target is missing"); - } - else if(target instanceof SiteTarget) - { - SiteTarget siteTarget = (SiteTarget)target; - String guid = siteTarget.getSite().getGuid(); - SiteInfo siteInfo = sites.validateSite(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, guid)); - NodeRef siteNodeRef = siteInfo.getNodeRef(); - String siteId = siteInfo.getShortName(); - - try - { - PersonFavourite personFavourite = favouritesService.addFavourite(personId, siteNodeRef); - ret = getFavourite(personFavourite, parameters); - } - catch(SiteDoesNotExistException e) - { - throw new RelationshipResourceNotFoundException(personId, siteId); - } - } - else if(target instanceof DocumentTarget) - { - DocumentTarget documentTarget = (DocumentTarget)target; - NodeRef nodeRef = documentTarget.getFile().getGuid(); - if(!nodes.nodeMatches(nodeRef, Collections.singleton(ContentModel.TYPE_CONTENT), null)) - { - throw new RelationshipResourceNotFoundException(personId, nodeRef.getId()); - } - - PersonFavourite personFavourite = favouritesService.addFavourite(personId, nodeRef); - ret = getFavourite(personFavourite, parameters); - } - else if(target instanceof FolderTarget) - { - FolderTarget folderTarget = (FolderTarget)target; - NodeRef nodeRef = folderTarget.getFolder().getGuid(); - if(!nodes.nodeMatches(nodeRef, Collections.singleton(ContentModel.TYPE_FOLDER), Collections.singleton(SiteModel.TYPE_SITE))) - { - throw new RelationshipResourceNotFoundException(personId, nodeRef.getId()); - } - - PersonFavourite personFavourite = favouritesService.addFavourite(personId, nodeRef); - ret = getFavourite(personFavourite, parameters); - } - - return ret; - } - - @Override - public void removeFavourite(String personId, String id) - { - personId = people.validatePerson(personId, true); - NodeRef nodeRef = nodes.validateNode(id); - boolean exists = false; - - Type type = favouritesService.getType(nodeRef); - if(type.equals(Type.SITE)) - { - SiteInfo siteInfo = siteService.getSite(nodeRef); - if(siteInfo == null) - { - // shouldn't happen because the type implies it's a site - throw new AlfrescoRuntimeException("Unable to find site with nodeRef " + nodeRef); - } - exists = favouritesService.removeFavourite(personId, siteInfo.getNodeRef()); - } - else if(type.equals(Type.FILE)) - { - exists = favouritesService.removeFavourite(personId, nodeRef); - } - else if(type.equals(Type.FOLDER)) - { - exists = favouritesService.removeFavourite(personId, nodeRef); - } - if(!exists) - { - throw new RelationshipResourceNotFoundException(personId, id); - } - } - - @Override - public Favourite getFavourite(String personId, String favouriteId) - { - Parameters parameters = getDefaultParameters(personId, favouriteId); - return getFavourite(personId, favouriteId, parameters); - } - - @Override - public Favourite getFavourite(String personId, String favouriteId, Parameters parameters) - { - NodeRef nodeRef = nodes.validateNode(favouriteId); - personId = people.validatePerson(personId, true); - - PersonFavourite personFavourite = favouritesService.getFavourite(personId, nodeRef); - if(personFavourite != null) - { - Favourite favourite = getFavourite(personFavourite, parameters); - return favourite; - } - else - { - throw new RelationshipResourceNotFoundException(personId, favouriteId); - } - } - - @Override - public CollectionWithPagingInfo getFavourites(String personId, final Parameters parameters) - { - personId = people.validatePerson(personId, true); - - Paging paging = parameters.getPaging(); - - List> sortProps = getSortProps(parameters); - - final Set filteredByClientQuery = new HashSet(); - Set filterTypes = FavouritesService.Type.ALL_FILTER_TYPES; //Default all - - // filterType is of the form 'target.' - QueryHelper.walk(parameters.getQuery(), new WalkerCallbackAdapter() - { - @Override - public void or() { - //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 - //that OR in the grammar is not supported. - } - - @Override - public void exists(String filteredByClient, boolean negated) { - if(filteredByClient != null) - { - int idx = filteredByClient.lastIndexOf("/"); - if(idx == -1 || idx == filteredByClient.length()) - { - throw new InvalidArgumentException(); - } - else - { - String filtertype = filteredByClient.substring(idx + 1).toUpperCase(); - filteredByClientQuery.add(Type.valueOf(filtertype)); - } - } - - } - }); - - if (filteredByClientQuery.size() > 0) - { - filterTypes = filteredByClientQuery; - } - - final PagingResults favourites = favouritesService.getPagedFavourites(personId, filterTypes, sortProps, Util.getPagingRequest(paging)); - - return wrap(paging, favourites, parameters); - } - - private void setPathInfo(Node node, List includeParam) - { - if (includeParam.contains(PARAM_INCLUDE_PATH)) - { - 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} - */ - private Parameters getDefaultParameters(String personId, String favouriteId) - { - Params.RecognizedParams recognizedParams = new Params.RecognizedParams(null, null, null, null, Collections.emptyList(), null, null, null, - false); - Parameters parameters = Params.valueOf(recognizedParams, personId, favouriteId, null); - return parameters; - } - - private List> getSortProps(Parameters parameters) - { - List> sortProps = new ArrayList<>(); - List sortCols = parameters.getSorting(); - if ((sortCols != null) && (sortCols.size() > 0)) - { - for (SortColumn sortCol : sortCols) - { - SortFields sortField; - try - { - sortField = SortFields.valueOf(sortCol.column); - } - catch (Exception e) - { - throw new InvalidArgumentException("Invalid sort field: " + sortCol.column); - } - sortProps.add(new Pair<>(sortField, (sortCol.asc ? Boolean.TRUE : Boolean.FALSE))); - } - } - else - { - // default sort order - sortProps = FavouritesService.DEFAULT_SORT_PROPS; - } - return sortProps; - } -} +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2019 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 . + * #L% + */ +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_ASPECTNAMES; + +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.commons.collections.CollectionUtils; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.query.PagingResults; +import org.alfresco.repo.favourites.PersonFavourite; +import org.alfresco.repo.site.SiteDoesNotExistException; +import org.alfresco.repo.site.SiteModel; +import org.alfresco.rest.api.Favourites; +import org.alfresco.rest.api.Nodes; +import org.alfresco.rest.api.People; +import org.alfresco.rest.api.Sites; +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.api.model.Folder; +import org.alfresco.rest.api.model.FolderTarget; +import org.alfresco.rest.api.model.Node; +import org.alfresco.rest.api.model.PathInfo; +import org.alfresco.rest.api.model.Site; +import org.alfresco.rest.api.model.SiteTarget; +import org.alfresco.rest.api.model.Target; +import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; +import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException; +import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; +import org.alfresco.rest.framework.resource.parameters.Paging; +import org.alfresco.rest.framework.resource.parameters.Parameters; +import org.alfresco.rest.framework.resource.parameters.Params; +import org.alfresco.rest.framework.resource.parameters.SortColumn; +import org.alfresco.rest.framework.resource.parameters.where.QueryHelper; +import org.alfresco.rest.framework.resource.parameters.where.QueryHelper.WalkerCallbackAdapter; +import org.alfresco.service.cmr.favourites.FavouritesService; +import org.alfresco.service.cmr.favourites.FavouritesService.SortFields; +import org.alfresco.service.cmr.favourites.FavouritesService.Type; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.cmr.site.SiteInfo; +import org.alfresco.service.cmr.site.SiteService; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.Pair; + +/** + * Public REST API: Centralises access to favourites functionality and maps between representations repository and api representations. + * + * @author steveglover + * @since publicapi1.0 + */ +public class FavouritesImpl implements Favourites +{ + private static final List ALLOWED_INCLUDES = List.of(PARAM_INCLUDE_PROPERTIES, PARAM_INCLUDE_ASPECTNAMES, PARAM_INCLUDE_ALLOWABLEOPERATIONS); + + private People people; + private Sites sites; + private Nodes nodes; + private FavouritesService favouritesService; + private SiteService siteService; + private NamespaceService namespaceService; + + // additional exclude properties for favourites as these can be already top-level properties + private static final List EXCLUDED_PROPS = Arrays.asList( + ContentModel.PROP_TITLE, + ContentModel.PROP_DESCRIPTION, + SiteModel.PROP_SITE_VISIBILITY, + SiteModel.PROP_SITE_PRESET); + + public void setPeople(People people) + { + this.people = people; + } + + public void setSites(Sites sites) + { + this.sites = sites; + } + + public void setNodes(Nodes nodes) + { + this.nodes = nodes; + } + + public void setFavouritesService(FavouritesService favouritesService) + { + this.favouritesService = favouritesService; + } + + public void setSiteService(SiteService siteService) + { + this.siteService = siteService; + } + + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } + + private Target getTarget(PersonFavourite personFavourite, Parameters parameters) + { + Target target; + NodeRef nodeRef = personFavourite.getNodeRef(); + Type type = personFavourite.getType(); + if (type.equals(Type.FILE)) + { + Document document = nodes.getDocument(nodeRef); + setPathInfo(document, parameters.getInclude()); + target = new DocumentTarget(document); + } + else if (type.equals(Type.FOLDER)) + { + Folder folder = nodes.getFolder(nodeRef); + setPathInfo(folder, parameters.getInclude()); + target = new FolderTarget(folder); + } + else if (type.equals(Type.SITE)) + { + SiteInfo siteInfo = siteService.getSite(nodeRef); + String role = sites.getSiteRole(siteInfo.getShortName()); + Site site = new Site(siteInfo, role); + target = new SiteTarget(site); + } + else + { + throw new AlfrescoRuntimeException("Unexpected favourite target type: " + type); + } + + return target; + } + + private Favourite getFavourite(PersonFavourite personFavourite, Parameters parameters) + { + Favourite fav = new Favourite(); + fav.setTargetGuid(personFavourite.getNodeRef().getId()); + fav.setCreatedAt(personFavourite.getCreatedAt()); + Target target = getTarget(personFavourite, parameters); + fav.setTarget(target); + + // REPO-1147 allow retrieving additional properties + final List paramsInclude = parameters.getInclude(); + if (!Collections.disjoint(paramsInclude, ALLOWED_INCLUDES)) + { + final List includes = ALLOWED_INCLUDES.stream().filter(paramsInclude::contains).collect(Collectors.toList()); + // get node representation with only properties included + Node node = nodes.getFolderOrDocument(personFavourite.getNodeRef(), null, null, includes, null); + // Create a map from node properties excluding properties already in this Favorite + Map filteredNodeProperties = filterProps(node.getProperties(), EXCLUDED_PROPS); + if (!filteredNodeProperties.isEmpty() && paramsInclude.contains(PARAM_INCLUDE_PROPERTIES)) + { + fav.setProperties(filteredNodeProperties); + } + if (paramsInclude.contains(PARAM_INCLUDE_ASPECTNAMES)) + { + fav.setAspectNames(node.getAspectNames()); + } + final List allowableOperations = node.getAllowableOperations(); + if (CollectionUtils.isNotEmpty(allowableOperations) && paramsInclude.contains(PARAM_INCLUDE_ALLOWABLEOPERATIONS)) + { + fav.setAllowableOperations(allowableOperations); + } + } + + return fav; + } + + private Map filterProps(Map properties, List toRemove) + { + Map filteredProps = properties == null ? new HashMap<>() : new HashMap<>(properties); + List propsToRemove = toRemove.stream().map(e -> e.toPrefixString(namespaceService)).collect(Collectors.toList()); + filteredProps.keySet().removeAll(propsToRemove); + return filteredProps; + } + + private CollectionWithPagingInfo wrap(Paging paging, PagingResults personFavourites, Parameters parameters) + { + final List page = personFavourites.getPage(); + final List list = new AbstractList<>() { + @Override + public Favourite get(int index) + { + PersonFavourite personFavourite = page.get(index); + Favourite fav = getFavourite(personFavourite, parameters); + return fav; + } + + @Override + public int size() + { + return page.size(); + } + }; + Pair pair = personFavourites.getTotalResultCount(); + Integer total = null; + if (pair.getFirst().equals(pair.getSecond())) + { + total = pair.getFirst(); + } + return CollectionWithPagingInfo.asPaged(paging, list, personFavourites.hasMoreItems(), total); + } + + @Override + public Favourite addFavourite(String personId, Favourite favourite) + { + Parameters parameters = getDefaultParameters(personId, null); + return addFavourite(personId, favourite, parameters); + } + + @Override + public Favourite addFavourite(String personId, Favourite favourite, Parameters parameters) + { + Favourite ret = null; + + personId = people.validatePerson(personId, true); + Target target = favourite.getTarget(); + if (target == null) + { + throw new InvalidArgumentException("target is missing"); + } + else if (target instanceof SiteTarget) + { + SiteTarget siteTarget = (SiteTarget) target; + String guid = siteTarget.getSite().getGuid(); + SiteInfo siteInfo = sites.validateSite(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, guid)); + NodeRef siteNodeRef = siteInfo.getNodeRef(); + String siteId = siteInfo.getShortName(); + + try + { + PersonFavourite personFavourite = favouritesService.addFavourite(personId, siteNodeRef); + ret = getFavourite(personFavourite, parameters); + } + catch (SiteDoesNotExistException e) + { + throw new RelationshipResourceNotFoundException(personId, siteId); + } + } + else if (target instanceof DocumentTarget) + { + DocumentTarget documentTarget = (DocumentTarget) target; + NodeRef nodeRef = documentTarget.getFile().getGuid(); + if (!nodes.nodeMatches(nodeRef, Collections.singleton(ContentModel.TYPE_CONTENT), null)) + { + throw new RelationshipResourceNotFoundException(personId, nodeRef.getId()); + } + + PersonFavourite personFavourite = favouritesService.addFavourite(personId, nodeRef); + ret = getFavourite(personFavourite, parameters); + } + else if (target instanceof FolderTarget) + { + FolderTarget folderTarget = (FolderTarget) target; + NodeRef nodeRef = folderTarget.getFolder().getGuid(); + if (!nodes.nodeMatches(nodeRef, Collections.singleton(ContentModel.TYPE_FOLDER), Collections.singleton(SiteModel.TYPE_SITE))) + { + throw new RelationshipResourceNotFoundException(personId, nodeRef.getId()); + } + + PersonFavourite personFavourite = favouritesService.addFavourite(personId, nodeRef); + ret = getFavourite(personFavourite, parameters); + } + + return ret; + } + + @Override + public void removeFavourite(String personId, String id) + { + personId = people.validatePerson(personId, true); + NodeRef nodeRef = nodes.validateNode(id); + boolean exists = false; + + Type type = favouritesService.getType(nodeRef); + if (type.equals(Type.SITE)) + { + SiteInfo siteInfo = siteService.getSite(nodeRef); + if (siteInfo == null) + { + // shouldn't happen because the type implies it's a site + throw new AlfrescoRuntimeException("Unable to find site with nodeRef " + nodeRef); + } + exists = favouritesService.removeFavourite(personId, siteInfo.getNodeRef()); + } + else if (type.equals(Type.FILE)) + { + exists = favouritesService.removeFavourite(personId, nodeRef); + } + else if (type.equals(Type.FOLDER)) + { + exists = favouritesService.removeFavourite(personId, nodeRef); + } + if (!exists) + { + throw new RelationshipResourceNotFoundException(personId, id); + } + } + + @Override + public Favourite getFavourite(String personId, String favouriteId) + { + Parameters parameters = getDefaultParameters(personId, favouriteId); + return getFavourite(personId, favouriteId, parameters); + } + + @Override + public Favourite getFavourite(String personId, String favouriteId, Parameters parameters) + { + NodeRef nodeRef = nodes.validateNode(favouriteId); + personId = people.validatePerson(personId, true); + + PersonFavourite personFavourite = favouritesService.getFavourite(personId, nodeRef); + if (personFavourite != null) + { + Favourite favourite = getFavourite(personFavourite, parameters); + return favourite; + } + else + { + throw new RelationshipResourceNotFoundException(personId, favouriteId); + } + } + + @Override + public CollectionWithPagingInfo getFavourites(String personId, final Parameters parameters) + { + personId = people.validatePerson(personId, true); + + Paging paging = parameters.getPaging(); + + List> sortProps = getSortProps(parameters); + + final Set filteredByClientQuery = new HashSet<>(); + Set filterTypes = FavouritesService.Type.ALL_FILTER_TYPES; // Default all + + // filterType is of the form 'target.' + QueryHelper.walk(parameters.getQuery(), new WalkerCallbackAdapter() { + @Override + public void or() + { + // 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 + // that OR in the grammar is not supported. + } + + @Override + public void exists(String filteredByClient, boolean negated) + { + if (filteredByClient != null) + { + int idx = filteredByClient.lastIndexOf('/'); + if (idx == -1 || idx == filteredByClient.length()) + { + throw new InvalidArgumentException(); + } + else + { + String filtertype = filteredByClient.substring(idx + 1).toUpperCase(); + filteredByClientQuery.add(Type.valueOf(filtertype)); + } + } + + } + }); + + if (!filteredByClientQuery.isEmpty()) + { + filterTypes = filteredByClientQuery; + } + + final PagingResults favourites = favouritesService.getPagedFavourites(personId, filterTypes, sortProps, Util.getPagingRequest(paging)); + + return wrap(paging, favourites, parameters); + } + + private void setPathInfo(Node node, List includeParam) + { + if (includeParam.contains(PARAM_INCLUDE_PATH)) + { + 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} + */ + private Parameters getDefaultParameters(String personId, String favouriteId) + { + Params.RecognizedParams recognizedParams = new Params.RecognizedParams(null, null, null, null, Collections.emptyList(), null, null, null, + false); + Parameters parameters = Params.valueOf(recognizedParams, personId, favouriteId, null); + return parameters; + } + + private List> getSortProps(Parameters parameters) + { + List> sortProps = new ArrayList<>(); + List sortCols = parameters.getSorting(); + if (sortCols != null && !sortCols.isEmpty()) + { + for (SortColumn sortCol : sortCols) + { + SortFields sortField; + try + { + sortField = SortFields.valueOf(sortCol.column); + } + catch (Exception e) + { + throw new InvalidArgumentException("Invalid sort field: " + sortCol.column); + } + sortProps.add(new Pair<>(sortField, sortCol.asc ? Boolean.TRUE : Boolean.FALSE)); + } + } + else + { + // default sort order + sortProps = FavouritesService.DEFAULT_SORT_PROPS; + } + return sortProps; + } +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/NodesImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/NodesImpl.java index e7fd991eea..db1d3c6670 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/NodesImpl.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/NodesImpl.java @@ -2401,6 +2401,8 @@ public class NodesImpl implements Nodes NodePermissions nodePerms = nodeInfo.getPermissions(); if (nodePerms != null) { + String siteManagerAuthority = getSiteManagerAuthority(nodeRef); + // Cannot set inherited permissions, only direct (locally set) permissions can be set if ((nodePerms.getInherited() != null) && (nodePerms.getInherited().size() > 0)) { @@ -2411,7 +2413,7 @@ public class NodesImpl implements Nodes if (nodePerms.getIsInheritanceEnabled() != null) { // 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)) { @@ -2510,8 +2512,19 @@ public class NodesImpl implements Nodes } // remove any remaining direct perms + boolean isInheritanceEnabled = permissionService.getInheritParentPermissions(nodeRef); 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()); } } @@ -2776,25 +2789,29 @@ public class NodesImpl implements Nodes 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 { - if (nodePerms.getIsInheritanceEnabled() != null && !nodePerms.getIsInheritanceEnabled()) + if (!nodePerms.getIsInheritanceEnabled()) { - SiteInfo containingSite = siteService.getSite(nodeRef); - - 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; - }); - } + permissionService.setPermission(nodeRef, siteManagerAuthority, SiteModel.SITE_MANAGER, true); } } catch (Exception e) diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/DocumentTarget.java b/remote-api/src/main/java/org/alfresco/rest/api/model/DocumentTarget.java index 261c5b8e41..6f9a3a42a2 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/model/DocumentTarget.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/DocumentTarget.java @@ -23,43 +23,65 @@ * along with Alfresco. If not, see . * #L% */ -package org.alfresco.rest.api.model; - -/** - * A document target favourite. - * - * @author steveglover - * - */ -public class DocumentTarget extends Target -{ - private Document file; - - public DocumentTarget() - { - super(); - } - - public DocumentTarget(Document file) - { - super(); - this.file = file; - } - - public void setDocument(Document file) - { - this.file = file; - } - - public Document getFile() - { - return file; - } - - @Override - public String toString() - { - return "DocumentTarget [file=" + file + "]"; - } - -} +package org.alfresco.rest.api.model; + +import java.util.Objects; + +/** + * A document target favourite. + * + * @author steveglover + * + */ +public class DocumentTarget extends Target +{ + private Document file; + + public DocumentTarget() + { + super(); + } + + public DocumentTarget(Document file) + { + super(); + this.file = file; + } + + public void setDocument(Document file) + { + this.file = file; + } + + public Document getFile() + { + return file; + } + + @Override + 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); + } +} diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/Favourite.java b/remote-api/src/main/java/org/alfresco/rest/api/model/Favourite.java index 79429a40ab..a499a19410 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/model/Favourite.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/Favourite.java @@ -1,103 +1,144 @@ -/* - * #%L - * Alfresco Remote API - * %% - * Copyright (C) 2005 - 2016 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 . - * #L% - */ -package org.alfresco.rest.api.model; - -import java.util.Date; -import java.util.List; -import java.util.Map; - -import org.alfresco.rest.framework.resource.UniqueId; - -/** - * Representation of a favourite (document, folder, site, ...). - * - * @author steveglover - * - */ -public class Favourite -{ - private String targetGuid; - private Date createdAt; - private Target target; - private Map properties; - private List allowableOperations; - - public Date getCreatedAt() - { - return createdAt; - } - - public void setCreatedAt(Date createdAt) - { - this.createdAt = createdAt; - } - - @UniqueId(name="targetGuid") - public String getTargetGuid() - { - return targetGuid; - } - - public void setTargetGuid(String targetGuid) - { - this.targetGuid = targetGuid; - } - - public Target getTarget() - { - return target; - } - - public void setTarget(Target target) - { - this.target = target; - } - - public Map getProperties() - { - return properties; - } - - public void setProperties(Map properties) - { - this.properties = properties; - } - - public List getAllowableOperations() { - return allowableOperations; - } - - public void setAllowableOperations(List allowableOperations) { - this.allowableOperations = allowableOperations; - } - - @Override - public String toString() - { - return "Favourite [targetGuid=" + targetGuid - + ", createdAt=" + createdAt + ", target=" + target + ", properties=" + properties + "]"; - } -} +/* + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2016 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 . + * #L% + */ +package org.alfresco.rest.api.model; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.alfresco.rest.framework.resource.UniqueId; + +/** + * Representation of a favourite (document, folder, site, ...). + * + * @author steveglover + * + */ +public class Favourite +{ + private String targetGuid; + private Date createdAt; + private Target target; + private Map properties; + private List aspectNames; + private List allowableOperations; + + public Date getCreatedAt() + { + return createdAt; + } + + public void setCreatedAt(Date createdAt) + { + this.createdAt = createdAt; + } + + @UniqueId(name = "targetGuid") + public String getTargetGuid() + { + return targetGuid; + } + + public void setTargetGuid(String targetGuid) + { + this.targetGuid = targetGuid; + } + + public Target getTarget() + { + return target; + } + + public void setTarget(Target target) + { + this.target = target; + } + + public Map getProperties() + { + return properties; + } + + public void setProperties(Map properties) + { + this.properties = properties; + } + + public List getAspectNames() + { + return aspectNames; + } + + public void setAspectNames(List aspectNames) + { + this.aspectNames = aspectNames; + } + + public List getAllowableOperations() + { + return allowableOperations; + } + + public void setAllowableOperations(List 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); + } +} diff --git a/remote-api/src/main/java/org/alfresco/rest/framework/webscripts/AbstractResourceWebScript.java b/remote-api/src/main/java/org/alfresco/rest/framework/webscripts/AbstractResourceWebScript.java index 32c0180c9c..360ca7b9fa 100644 --- a/remote-api/src/main/java/org/alfresco/rest/framework/webscripts/AbstractResourceWebScript.java +++ b/remote-api/src/main/java/org/alfresco/rest/framework/webscripts/AbstractResourceWebScript.java @@ -110,22 +110,10 @@ public abstract class AbstractResourceWebScript extends ApiWebScript implements @Override public Object execute() throws Throwable { - try - { - final Params params = paramsExtractor.extractParams(resource.getMetaData(), req); - 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; - } + // Reset the request so that it can be read again in case of retry + resetRequest(req); + final Params params = paramsExtractor.extractParams(resource.getMetaData(), req); + return AbstractResourceWebScript.this.execute(resource, params, res, isReadOnly); } }; @@ -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) { RetryingTransactionHelper transHelper = transactionService.getRetryingTransactionHelper(); diff --git a/remote-api/src/main/resources/alfresco/web-scripts-application-context.xml b/remote-api/src/main/resources/alfresco/web-scripts-application-context.xml index f255f96162..b1630853ec 100644 --- a/remote-api/src/main/resources/alfresco/web-scripts-application-context.xml +++ b/remote-api/src/main/resources/alfresco/web-scripts-application-context.xml @@ -250,7 +250,7 @@ - + diff --git a/remote-api/src/test/java/org/alfresco/AppContext04TestSuite.java b/remote-api/src/test/java/org/alfresco/AppContext04TestSuite.java index c56273db18..2ffec4fc7b 100644 --- a/remote-api/src/test/java/org/alfresco/AppContext04TestSuite.java +++ b/remote-api/src/test/java/org/alfresco/AppContext04TestSuite.java @@ -25,60 +25,59 @@ */ 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.runner.RunWith; 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) @Categories.ExcludeCategory({DBTests.class, NonBuildTests.class}) @Suite.SuiteClasses({ - // [classpath:alfresco/application-context.xml, classpath:alfresco/web-scripts-application-context-test.xml, - // classpath:alfresco/web-scripts-application-context.xml] - org.alfresco.repo.web.scripts.quickshare.QuickShareRestApiTest.class, - org.alfresco.repo.web.scripts.admin.AdminWebScriptTest.class, - org.alfresco.repo.web.scripts.audit.AuditWebScriptTest.class, - org.alfresco.repo.web.scripts.blogs.BlogServiceTest.class, - org.alfresco.repo.web.scripts.dictionary.DictionaryRestApiTest.class, - org.alfresco.repo.web.scripts.discussion.DiscussionRestApiTest.class, - org.alfresco.repo.web.scripts.activities.feed.control.FeedControlTest.class, - org.alfresco.repo.web.scripts.forms.FormRestApiGet_Test.class, - org.alfresco.repo.web.scripts.forms.FormRestApiJsonPost_Test.class, - org.alfresco.repo.web.scripts.groups.GroupsTest.class, - org.alfresco.repo.web.scripts.invitation.InvitationWebScriptTest.class, - org.alfresco.repo.web.scripts.invite.InviteServiceTest.class, - org.alfresco.repo.web.scripts.LoginTest.class, - org.alfresco.repo.web.scripts.search.PersonSearchTest.class, - org.alfresco.repo.web.scripts.person.PersonServiceTest.class, - org.alfresco.repo.web.scripts.preference.PreferenceServiceTest.class, - org.alfresco.repo.web.scripts.rating.RatingRestApiTest.class, - org.alfresco.repo.web.scripts.replication.ReplicationRestApiTest.class, - org.alfresco.repo.web.scripts.RepositoryContainerTest.class, - org.alfresco.repo.web.scripts.rule.RuleServiceTest.class, - org.alfresco.repo.web.scripts.action.RunningActionRestApiTest.class, - org.alfresco.repo.web.scripts.site.SiteServiceTest.class, - org.alfresco.repo.web.scripts.tagging.TaggingServiceTest.class, - org.alfresco.repo.web.scripts.thumbnail.ThumbnailServiceTest.class, - org.alfresco.repo.web.scripts.transfer.TransferWebScriptTest.class, - org.alfresco.repo.web.scripts.workflow.ActivitiWorkflowRestApiTest.class, - org.alfresco.repo.web.scripts.solr.SOLRWebScriptTest.class, - org.alfresco.repo.web.scripts.subscriptions.SubscriptionServiceRestApiTest.class, - org.alfresco.repo.web.scripts.facet.FacetRestApiTest.class, - org.alfresco.repo.web.scripts.comment.CommentsApiTest.class, - org.alfresco.repo.web.scripts.content.ContentGetTest.class, - org.alfresco.repo.web.scripts.XssVulnerabilityTest.class, - org.alfresco.repo.web.scripts.links.LinksRestApiTest.class, - org.alfresco.repo.model.filefolder.RemoteFileFolderLoaderTest.class, - org.alfresco.repo.web.scripts.ReadOnlyTransactionInGetRestApiTest.class, - org.alfresco.repo.web.scripts.custommodel.CustomModelImportTest.class, - org.alfresco.repo.web.scripts.site.SurfConfigTest.class, - org.alfresco.repo.web.scripts.node.NodeWebScripTest.class, - org.alfresco.rest.api.impl.CommentsImplUnitTest.class, - org.alfresco.rest.api.impl.DownloadsImplCheckArchiveStatusUnitTest.class, - org.alfresco.rest.api.impl.RestApiDirectUrlConfigUnitTest.class, - org.alfresco.rest.api.impl.SizeDetailsImplTest.class + org.alfresco.repo.web.scripts.quickshare.QuickShareRestApiTest.class, + org.alfresco.repo.web.scripts.admin.AdminWebScriptTest.class, + org.alfresco.repo.web.scripts.audit.AuditWebScriptTest.class, + org.alfresco.repo.web.scripts.blogs.BlogServiceTest.class, + org.alfresco.repo.web.scripts.dictionary.DictionaryRestApiTest.class, + org.alfresco.repo.web.scripts.discussion.DiscussionRestApiTest.class, + org.alfresco.repo.web.scripts.activities.feed.control.FeedControlTest.class, + org.alfresco.repo.web.scripts.forms.FormRestApiGet_Test.class, + org.alfresco.repo.web.scripts.forms.FormRestApiJsonPost_Test.class, + org.alfresco.repo.web.scripts.groups.GroupsTest.class, + org.alfresco.repo.web.scripts.invitation.InvitationWebScriptTest.class, + org.alfresco.repo.web.scripts.invite.InviteServiceTest.class, + org.alfresco.repo.web.scripts.LoginTest.class, + org.alfresco.repo.web.scripts.search.PersonSearchTest.class, + org.alfresco.repo.web.scripts.person.PersonServiceTest.class, + org.alfresco.repo.web.scripts.preference.PreferenceServiceTest.class, + org.alfresco.repo.web.scripts.rating.RatingRestApiTest.class, + org.alfresco.repo.web.scripts.replication.ReplicationRestApiTest.class, + org.alfresco.repo.web.scripts.RepositoryContainerTest.class, + org.alfresco.repo.web.scripts.rule.RuleServiceTest.class, + org.alfresco.repo.web.scripts.action.RunningActionRestApiTest.class, + org.alfresco.repo.web.scripts.site.SiteServiceTest.class, + org.alfresco.repo.web.scripts.tagging.TaggingServiceTest.class, + org.alfresco.repo.web.scripts.thumbnail.ThumbnailServiceTest.class, + org.alfresco.repo.web.scripts.transfer.TransferWebScriptTest.class, + org.alfresco.repo.web.scripts.workflow.ActivitiWorkflowRestApiTest.class, + org.alfresco.repo.web.scripts.solr.SOLRWebScriptTest.class, + org.alfresco.repo.web.scripts.subscriptions.SubscriptionServiceRestApiTest.class, + org.alfresco.repo.web.scripts.facet.FacetRestApiTest.class, + org.alfresco.repo.web.scripts.comment.CommentsApiTest.class, + org.alfresco.repo.web.scripts.content.ContentGetTest.class, + org.alfresco.repo.web.scripts.XssVulnerabilityTest.class, + org.alfresco.repo.web.scripts.links.LinksRestApiTest.class, + org.alfresco.repo.model.filefolder.RemoteFileFolderLoaderTest.class, + org.alfresco.repo.web.scripts.ReadOnlyTransactionInGetRestApiTest.class, + org.alfresco.repo.web.scripts.custommodel.CustomModelImportTest.class, + org.alfresco.repo.web.scripts.site.SurfConfigTest.class, + org.alfresco.repo.web.scripts.node.NodeWebScripTest.class, + org.alfresco.rest.api.impl.CommentsImplUnitTest.class, + org.alfresco.rest.api.impl.DownloadsImplCheckArchiveStatusUnitTest.class, + org.alfresco.rest.api.impl.FavouritesImplUnitTest.class, + org.alfresco.rest.api.impl.RestApiDirectUrlConfigUnitTest.class }) public class AppContext04TestSuite { diff --git a/remote-api/src/test/java/org/alfresco/rest/api/impl/FavouritesImplUnitTest.java b/remote-api/src/test/java/org/alfresco/rest/api/impl/FavouritesImplUnitTest.java new file mode 100644 index 0000000000..da38348a9e --- /dev/null +++ b/remote-api/src/test/java/org/alfresco/rest/api/impl/FavouritesImplUnitTest.java @@ -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 . + * #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 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); + } +} diff --git a/remote-api/src/test/java/org/alfresco/rest/api/tests/NodeApiTest.java b/remote-api/src/test/java/org/alfresco/rest/api/tests/NodeApiTest.java index 3b08d5c062..4a2d9359c4 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/tests/NodeApiTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/tests/NodeApiTest.java @@ -35,6 +35,7 @@ import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.File; +import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; 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.LockInfo; 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.PropertyDefinition; 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 */ @Test - public void testSiteManagerPermission() throws Exception + public void testSiteManagerPermission_MNT23379() throws Exception { // Change to User1 context setRequestContext(user1); @@ -6394,6 +6396,10 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest Node nodeUpdate = new Node(); NodePermissions nodePerms = new NodePermissions(); nodePerms.setIsInheritanceEnabled(false); + NodePermission permission = new NodePermission("GROUP_site_" + site1Id + "_SiteConsumer", SiteRole.SiteConsumer.toString(), AccessStatus.ALLOWED.toString()); + List locallySet = new ArrayList<>(); + locallySet.add(permission); + nodePerms.setLocallySet(locallySet); nodeUpdate.setPermissions(nodePerms); put(URL_NODES, content1_Id, toJsonAsStringNonNull(nodeUpdate), null, 200); @@ -6409,6 +6415,76 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest 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 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 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 public void testRuleAspectAfterUpdate() throws Exception { @@ -6445,5 +6521,28 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest // Cleanup 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 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); + } + } } diff --git a/repository/pom.xml b/repository/pom.xml index e727208b41..26df93ce4a 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 23.4.0.9-SNAPSHOT + 23.4.0.42-SNAPSHOT @@ -94,7 +94,7 @@ org.apache.commons commons-lang3 - 3.14.0 + 3.17.0 commons-codec @@ -358,7 +358,7 @@ com.fasterxml.woodstox woodstox-core - 6.5.1 + 7.0.0 @@ -397,12 +397,12 @@ org.mybatis mybatis - 3.5.13 + 3.5.16 org.mybatis mybatis-spring - 3.0.3 + 3.0.4 diff --git a/repository/src/main/java/org/alfresco/repo/action/executer/ScriptActionExecuter.java b/repository/src/main/java/org/alfresco/repo/action/executer/ScriptActionExecuter.java index 1a231d61de..1ffc18f0fa 100644 --- a/repository/src/main/java/org/alfresco/repo/action/executer/ScriptActionExecuter.java +++ b/repository/src/main/java/org/alfresco/repo/action/executer/ScriptActionExecuter.java @@ -46,8 +46,6 @@ import org.alfresco.service.cmr.repository.ScriptLocation; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.security.PersonService; 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. @@ -58,10 +56,8 @@ import org.slf4j.LoggerFactory; */ public class ScriptActionExecuter extends ActionExecuterAbstractBase { - private static final Logger LOGGER = LoggerFactory.getLogger(ScriptActionExecuter.class); public static final String NAME = "script"; public static final String PARAM_SCRIPTREF = "script-ref"; - private static final String SYSTEM_USER = "System"; private ServiceRegistry serviceRegistry; private SysAdminParams sysAdminParams; @@ -156,14 +152,11 @@ public class ScriptActionExecuter extends ActionExecuterAbstractBase { // get the references we need to build the default scripting data-model String userName = this.serviceRegistry.getAuthenticationService().getCurrentUserName(); - if (SYSTEM_USER.equals(userName)) - { - LOGGER.info("Skipping Script Execution for the System user."); - return; - } - NodeRef personRef = this.personService.getPerson(userName); - NodeRef homeSpaceRef = (NodeRef)nodeService.getProperty(personRef, ContentModel.PROP_HOMEFOLDER); - + + // When a script is executed as a system user, there will no person or home space for providing to the scripting framework. + NodeRef personRef = this.personService.getPersonOrNull(userName); + NodeRef homeSpaceRef = personRef == null ? null : (NodeRef)nodeService.getProperty(personRef, ContentModel.PROP_HOMEFOLDER); + // the default scripting model provides access to well known objects and searching // facilities - it also provides basic create/update/delete/copy/move services Map model = this.serviceRegistry.getScriptService().buildDefaultModel( @@ -207,6 +200,7 @@ public class ScriptActionExecuter extends ActionExecuterAbstractBase /** * @see org.alfresco.repo.action.ParameterizedItemAbstractBase#addParameterDefinitions(java.util.List) */ + @Override protected void addParameterDefinitions(List paramList) { if (scriptLocation == null) diff --git a/repository/src/main/java/org/alfresco/repo/dictionary/CustomModelServiceImpl.java b/repository/src/main/java/org/alfresco/repo/dictionary/CustomModelServiceImpl.java index 58bd7d6b39..f5f5c70194 100644 --- a/repository/src/main/java/org/alfresco/repo/dictionary/CustomModelServiceImpl.java +++ b/repository/src/main/java/org/alfresco/repo/dictionary/CustomModelServiceImpl.java @@ -1077,6 +1077,12 @@ public class CustomModelServiceImpl implements CustomModelService @Override 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 nodesToBeDownloaded = new ArrayList<>(2); @@ -1137,7 +1143,7 @@ public class CustomModelServiceImpl implements CustomModelService 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()) { diff --git a/repository/src/main/java/org/alfresco/repo/download/DownloadServiceImpl.java b/repository/src/main/java/org/alfresco/repo/download/DownloadServiceImpl.java index f14d702585..fc2d1b7b82 100644 --- a/repository/src/main/java/org/alfresco/repo/download/DownloadServiceImpl.java +++ b/repository/src/main/java/org/alfresco/repo/download/DownloadServiceImpl.java @@ -28,12 +28,14 @@ package org.alfresco.repo.download; import java.util.Date; import java.util.List; +import org.alfresco.model.ContentModel; import org.alfresco.repo.download.cannedquery.DownloadEntity; import org.alfresco.repo.transaction.RetryingTransactionHelper; import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; import org.alfresco.service.cmr.download.DownloadService; import org.alfresco.service.cmr.download.DownloadStatus; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.util.ParameterCheck; /** @@ -50,6 +52,7 @@ public class DownloadServiceImpl implements DownloadService { private ActionServiceHelper actionServiceHelper; private DownloadStorage downloadStorage; private RetryingTransactionHelper transactionHelper; + private NodeService nodeService; // Dependency setters public void setActionServiceHelper(ActionServiceHelper actionServiceHelper) @@ -66,9 +69,19 @@ public class DownloadServiceImpl implements DownloadService { { this.downloadStorage = downloadStorage; } - - @Override + + public void setNodeService(NodeService nodeService) + { + this.nodeService = nodeService; + } + + @Override 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); if (requestedNodes.length < 1) { @@ -91,7 +104,12 @@ public class DownloadServiceImpl implements DownloadService { { downloadStorage.addNodeToDownload(downloadNode, node); } - + + if (downloadNodeName != null) + { + nodeService.setProperty(downloadNode, ContentModel.PROP_NAME, downloadNodeName); + } + return downloadNode; } }, false, true); diff --git a/repository/src/main/java/org/alfresco/repo/event2/EventGenerator.java b/repository/src/main/java/org/alfresco/repo/event2/EventGenerator.java index f6a62ddac6..3142b42ebc 100644 --- a/repository/src/main/java/org/alfresco/repo/event2/EventGenerator.java +++ b/repository/src/main/java/org/alfresco/repo/event2/EventGenerator.java @@ -38,6 +38,12 @@ import java.util.Optional; import java.util.Set; 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.TransactionEntity; 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.TriPredicate; 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. @@ -93,8 +94,8 @@ import org.springframework.extensions.surf.util.AbstractLifecycleBean; * @author Jamal Kaabi-Mofrad */ public class EventGenerator extends AbstractLifecycleBean implements InitializingBean, EventSupportedPolicies, - ChildAssociationEventSupportedPolicies, - PeerAssociationEventSupportedPolicies + ChildAssociationEventSupportedPolicies, + PeerAssociationEventSupportedPolicies { private static final Log LOGGER = LogFactory.getLog(EventGenerator.class); @@ -354,7 +355,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin } protected ChildAssociationEventConsolidator createChildAssociationEventConsolidator( - ChildAssociationRef childAssociationRef) + ChildAssociationRef childAssociationRef) { 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 - * the current transaction context. + * @return the {@link NodeEventConsolidator} for the supplied {@code nodeRef} from the current transaction context. */ protected NodeEventConsolidator getEventConsolidator(NodeRef nodeRef) { @@ -438,7 +438,6 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin return eventConsolidator; } - protected Consolidators getTxnConsolidators(Object 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 - * the current transaction context. + * @return the {@link ChildAssociationEventConsolidator} for the supplied {@code childAssociationRef} from the current transaction context. */ 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 - * the current transaction context. + * @return the {@link PeerAssociationEventConsolidator} for the supplied {@code peerAssociationRef} from the current transaction context. */ private PeerAssociationEventConsolidator getEventConsolidator(AssociationRef peerAssociationRef) { @@ -507,10 +504,10 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin protected EventInfo getEventInfo(String user) { return new EventInfo().setTimestamp(getCurrentTransactionTimestamp()) - .setId(UUID.randomUUID().toString()) - .setTxnId(AlfrescoTransactionSupport.getTransactionId()) - .setPrincipal(user) - .setSource(URI.create("/" + descriptorService.getCurrentRepositoryDescriptor().getId())); + .setId(UUID.randomUUID().toString()) + .setTxnId(AlfrescoTransactionSupport.getTransactionId()) + .setPrincipal(user) + .setSource(URI.create("/" + descriptorService.getCurrentRepositoryDescriptor().getId())); } private ZonedDateTime getCurrentTransactionTimestamp() @@ -523,13 +520,12 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin private static ChildAssociationRef childAssociationWithoutParentOf(ChildAssociationRef childAssociationRef) { return new ChildAssociationRef( - null, - null, - childAssociationRef.getQName(), - childAssociationRef.getChildRef(), - childAssociationRef.isPrimary(), - childAssociationRef.getNthSibling() - ); + null, + null, + childAssociationRef.getQName(), + childAssociationRef.getChildRef(), + childAssociationRef.isPrimary(), + childAssociationRef.getNthSibling()); } @Override @@ -546,7 +542,10 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin @Override protected void onShutdown(ApplicationEvent applicationEvent) { - //NOOP + if (eventSender != null) + { + eventSender.destroy(); + } } 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. - * This means that a {@link TransactionEntity} object was created. + * @return true if a node transaction is not only active, but also committed with modifications. This means that a {@link TransactionEntity} object was created. */ protected boolean isTransactionCommitted() { @@ -601,7 +599,8 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin try { sendEvents(); - } catch (Exception e) + } + catch (Exception e) { // Must consume the exception to protect other TransactionListeners 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. * - * @param entityReference - reference to an entity (e.g. node, child association, peer association) - * @param eventConsolidator - object encapsulating events occurred in a transaction - * @param entityToEventEligibilityVerifier - allows to verify if entity is eligible to generate an even. If null no verification is necessary - * @param - entity reference type (e.g. {@link NodeRef}, {@link AssociationRef}, {@link ChildAssociationRef}) - * @param - event consolidator type - extension of {@link EventConsolidator} + * @param entityReference + * - reference to an entity (e.g. node, child association, peer association) + * @param eventConsolidator + * - object encapsulating events occurred in a transaction + * @param entityToEventEligibilityVerifier + * - allows to verify if entity is eligible to generate an even. If null no verification is necessary + * @param + * - entity reference type (e.g. {@link NodeRef}, {@link AssociationRef}, {@link ChildAssociationRef}) + * @param + * - event consolidator type - extension of {@link EventConsolidator} */ - private > void sendEvent( - final REF entityReference, final CON eventConsolidator, final TriPredicate entityToEventEligibilityVerifier) + private > void sendEvent( + final REF entityReference, final CON eventConsolidator, final TriPredicate entityToEventEligibilityVerifier) { final EventInfo eventInfo = getEventInfo(AuthenticationUtil.getFullyAuthenticatedUser()); if (isSendingEventBeforeCommitRequired()) @@ -676,16 +680,22 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin /** * Creates events from various kinds of entities. * - * @param entityReference - reference to an entity (e.g. node, child association, peer association) - * @param eventConsolidator - object encapsulating events occurred in a transaction - * @param eventInfo - 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 - entity reference type (e.g. {@link NodeRef}, {@link AssociationRef}, {@link ChildAssociationRef}) - * @param - event consolidator type - extension of {@link EventConsolidator} + * @param entityReference + * - reference to an entity (e.g. node, child association, peer association) + * @param eventConsolidator + * - object encapsulating events occurred in a transaction + * @param eventInfo + * - 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 + * - entity reference type (e.g. {@link NodeRef}, {@link AssociationRef}, {@link ChildAssociationRef}) + * @param + * - event consolidator type - extension of {@link EventConsolidator} */ private > Optional> createEvent( - final REF entityReference, final CON eventConsolidator, final EventInfo eventInfo, - final TriPredicate entityToEventEligibilityVerifier) + final REF entityReference, final CON eventConsolidator, final EventInfo eventInfo, + final TriPredicate entityToEventEligibilityVerifier) { if (eventConsolidator.isTemporaryEntity()) { @@ -719,8 +729,8 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin if (LOGGER.isTraceEnabled()) { LOGGER.trace("EventFilter - Excluding node: '" + nodeReference + "' of type: '" - + ((nodeType == null) ? "Unknown' " : nodeType.toPrefixString()) - + "' created by: " + user); + + ((nodeType == null) ? "Unknown' " : nodeType.toPrefixString()) + + "' created by: " + user); } return false; } @@ -747,8 +757,8 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin if (LOGGER.isTraceEnabled()) { LOGGER.trace("EventFilter - Excluding child association: '" + childAssociationReference + "' of type: '" - + ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString()) - + "' created by: " + user); + + ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString()) + + "' created by: " + user); } return false; } @@ -757,8 +767,8 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin if (LOGGER.isTraceEnabled()) { LOGGER.trace("EventFilter - Excluding primary child association: '" + childAssociationReference + "' of type: '" - + ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString()) - + "' created by: " + user); + + ((childAssocType == null) ? "Unknown' " : childAssocType.toPrefixString()) + + "' created by: " + user); } return false; } @@ -804,7 +814,7 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin { if (peerAssocs == null) { - peerAssocs = new LinkedHashMap<>(29); + peerAssocs = new LinkedHashMap<>(29); } return peerAssocs; } diff --git a/repository/src/main/java/org/alfresco/repo/event2/EventSender.java b/repository/src/main/java/org/alfresco/repo/event2/EventSender.java index 8ff7c47a2a..b97ee111a7 100644 --- a/repository/src/main/java/org/alfresco/repo/event2/EventSender.java +++ b/repository/src/main/java/org/alfresco/repo/event2/EventSender.java @@ -37,17 +37,26 @@ public interface EventSender { /** * 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>> eventProducer); /** - * 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's called right after event sender instantiation (see {@link org.alfresco.repo.event2.EventSenderFactoryBean}). It might be used to initialize the sender implementation. */ 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() diff --git a/repository/src/main/java/org/alfresco/repo/lock/LockServiceImpl.java b/repository/src/main/java/org/alfresco/repo/lock/LockServiceImpl.java index df0d2ea0b9..41b670c545 100644 --- a/repository/src/main/java/org/alfresco/repo/lock/LockServiceImpl.java +++ b/repository/src/main/java/org/alfresco/repo/lock/LockServiceImpl.java @@ -997,7 +997,7 @@ public class LockServiceImpl implements LockService, } // Never return a null LockState - Assert.notNull(lockState); + Assert.notNull(lockState, "The lockState should not be null"); return lockState; } diff --git a/repository/src/main/java/org/alfresco/repo/search/impl/solr/AbstractSolrQueryHTTPClient.java b/repository/src/main/java/org/alfresco/repo/search/impl/solr/AbstractSolrQueryHTTPClient.java index ffeb90d543..25b5d632e0 100644 --- a/repository/src/main/java/org/alfresco/repo/search/impl/solr/AbstractSolrQueryHTTPClient.java +++ b/repository/src/main/java/org/alfresco/repo/search/impl/solr/AbstractSolrQueryHTTPClient.java @@ -2,23 +2,23 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2023 Alfresco Software Limited + * 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 + * 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 . * #L% @@ -30,10 +30,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.util.List; - import jakarta.servlet.http.HttpServletResponse; -import org.alfresco.repo.search.QueryParserException; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpStatus; @@ -47,13 +45,16 @@ import org.json.JSONException; import org.json.JSONObject; import org.json.JSONTokener; +import org.alfresco.httpclient.HttpClientException; +import org.alfresco.repo.search.QueryParserException; + public abstract class AbstractSolrQueryHTTPClient { /** Logger for the class. */ private static final Log LOGGER = LogFactory.getLog(AbstractSolrQueryHTTPClient.class); public static final int DEFAULT_SAVEPOST_BUFFER = 4096; - + // 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 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. */ private static final List STATUS_CODE_501_EXCEPTIONS = List.of("java.lang.UnsupportedOperationException"); - + protected JSONObject postQuery(HttpClient httpClient, String url, JSONObject body) throws IOException, JSONException { PostMethod post = createNewPostMethod(url); @@ -98,7 +99,7 @@ public abstract class AbstractSolrQueryHTTPClient try { 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"); if (locationHeader != null) @@ -139,8 +140,11 @@ public abstract class AbstractSolrQueryHTTPClient Reader reader = new BufferedReader(new InputStreamReader(post.getResponseBodyAsStream(), post.getResponseCharSet())); // TODO - replace with streaming-based solution e.g. SimpleJSON ContentHandler - JSONObject json = new JSONObject(new JSONTokener(reader)); - return json; + return new JSONObject(new JSONTokener(reader)); + } + catch (IOException e) + { + throw new HttpClientException("[%s] %s".formatted(this.getClass().getSimpleName(), e.getMessage()), e); } finally { diff --git a/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckCollection.java b/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckCollection.java index 24b300b8e2..49f2fd840f 100644 --- a/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckCollection.java +++ b/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckCollection.java @@ -2,7 +2,7 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited + * 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 @@ -23,133 +23,127 @@ * along with Alfresco. If not, see . * #L% */ -package org.alfresco.repo.security.permissions; - -import java.util.Collection; - -import org.springframework.aop.IntroductionAdvisor; -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.support.DefaultIntroductionAdvisor; -import org.springframework.aop.support.DelegatingIntroductionInterceptor; - -/** - * Interface for collection-based results that describe permission filtering - * behaviour around cut-off limits. - * - * @author Derek Hulley - * @since 4.0 - */ -public interface PermissionCheckCollection -{ - /** - * Get the desired number of results. Permission checks can stop once the number of - * return objects reaches this number. - * - * @return the number of results desired - */ - int getTargetResultCount(); - - /** - * Get the maximum time for permission checks to execute before cutting the results off. - *
Zero: Ignore this value. - * - * @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 - */ - int getCutOffAfterCount(); - - /** - * Helper 'introduction' to allow simple addition of the {@link PermissionCheckCollection} interface to - * existing collections. - * - * @param the type of the Collection in use - * - * @author Derek Hulley - * @since 4.0 - */ - @SuppressWarnings("serial") - public static class PermissionCheckCollectionMixin extends DelegatingIntroductionInterceptor implements PermissionCheckCollection - { - private final int targetResultCount; - private final long cutOffAfterTimeMs; - private final int cutOffAfterCount; - - private PermissionCheckCollectionMixin(int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount) - { - super(); - this.targetResultCount = targetResultCount; - this.cutOffAfterTimeMs = cutOffAfterTimeMs; - this.cutOffAfterCount = cutOffAfterCount; - if (cutOffAfterTimeMs <= 0) - { - cutOffAfterTimeMs = 0; - } - if (cutOffAfterCount <= 0) - { - cutOffAfterCount = 0; - } - } - - @Override - public int getTargetResultCount() - { - return targetResultCount; - } - - @Override - public long getCutOffAfterTimeMs() - { - return cutOffAfterTimeMs; - } - - @Override - public int getCutOffAfterCount() - { - return cutOffAfterCount; - } - - /** - * Helper method to create a {@link PermissionCheckCollection} from an existing Collection - * - * @param the type of the Collection - * @param collection the Collection to proxy - * @param targetResultCount 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 - * time-based cut-off. - * @param cutOffAfterCount the number of permission checks to process before cut-off or zero to use the system default - * count-based cut-off. - * @return a Collection of the same type but including the - * {@link PermissionCheckCollection} interface - */ - @SuppressWarnings("unchecked") - public static final Collection create( - Collection collection, - int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount) - { - if (targetResultCount <= 0) - { - targetResultCount = collection.size(); - } - // Create the mixin - DelegatingIntroductionInterceptor mixin = new PermissionCheckCollectionMixin( - targetResultCount, - cutOffAfterTimeMs, - cutOffAfterCount); - // Create the advisor - IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckCollection.class); - // Proxy - ProxyFactory pf = new ProxyFactory(collection); - pf.addAdvisor(advisor); - Object proxiedObject = pf.getProxy(); - - // Done - return (Collection) proxiedObject; - } - } -} +package org.alfresco.repo.security.permissions; + +import java.util.Collection; + +import org.springframework.aop.IntroductionAdvisor; +import org.springframework.aop.support.DefaultIntroductionAdvisor; +import org.springframework.aop.support.DelegatingIntroductionInterceptor; + +/** + * Interface for collection-based results that describe permission filtering behaviour around cut-off limits. + * + * @author Derek Hulley + * @since 4.0 + */ +public interface PermissionCheckCollection +{ + /** + * Get the desired number of results. Permission checks can stop once the number of return objects reaches this number. + * + * @return the number of results desired + */ + int getTargetResultCount(); + + /** + * Get the maximum time for permission checks to execute before cutting the results off.
+ * Zero: Ignore this value. + * + * @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 + */ + int getCutOffAfterCount(); + + /** + * Helper 'introduction' to allow simple addition of the {@link PermissionCheckCollection} interface to existing collections. + * + * @param + * the type of the Collection in use + * + * @author Derek Hulley + * @since 4.0 + */ + @SuppressWarnings("serial") + class PermissionCheckCollectionMixin extends DelegatingIntroductionInterceptor implements PermissionCheckCollection + { + private final int targetResultCount; + private final long cutOffAfterTimeMs; + private final int cutOffAfterCount; + + private PermissionCheckCollectionMixin(int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount) + { + super(); + this.targetResultCount = targetResultCount; + this.cutOffAfterTimeMs = cutOffAfterTimeMs; + this.cutOffAfterCount = cutOffAfterCount; + if (cutOffAfterTimeMs <= 0) + { + cutOffAfterTimeMs = 0; + } + if (cutOffAfterCount <= 0) + { + cutOffAfterCount = 0; + } + } + + @Override + public int getTargetResultCount() + { + return targetResultCount; + } + + @Override + public long getCutOffAfterTimeMs() + { + return cutOffAfterTimeMs; + } + + @Override + public int getCutOffAfterCount() + { + return cutOffAfterCount; + } + + /** + * Helper method to create a {@link PermissionCheckCollection} from an existing Collection + * + * @param + * the type of the Collection + * @param collection + * the Collection to proxy + * @param targetResultCount + * 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 time-based cut-off. + * @param cutOffAfterCount + * the number of permission checks to process before cut-off or zero to use the system default count-based cut-off. + * @return a Collection of the same type but including the {@link PermissionCheckCollection} interface + */ + @SuppressWarnings("unchecked") + public static Collection create( + Collection collection, + int targetResultCount, long cutOffAfterTimeMs, int cutOffAfterCount) + { + if (targetResultCount <= 0) + { + targetResultCount = collection.size(); + } + // Create the mixin + DelegatingIntroductionInterceptor mixin = new PermissionCheckCollectionMixin<>( + targetResultCount, + cutOffAfterTimeMs, + cutOffAfterCount); + // Create the advisor + IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckCollection.class); + // Create Proxy + return (Collection) ProxyFactoryUtils.createProxy(collection, advisor); + } + } +} diff --git a/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckedCollection.java b/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckedCollection.java index 305cb9cd05..b855219951 100644 --- a/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckedCollection.java +++ b/repository/src/main/java/org/alfresco/repo/security/permissions/PermissionCheckedCollection.java @@ -2,161 +2,160 @@ * #%L * Alfresco Repository * %% - * Copyright (C) 2005 - 2016 Alfresco Software Limited + * 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 + * 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 . * #L% */ -package org.alfresco.repo.security.permissions; - -import java.util.Collection; - -import org.springframework.aop.IntroductionAdvisor; -import org.springframework.aop.framework.ProxyFactory; -import org.springframework.aop.support.DefaultIntroductionAdvisor; -import org.springframework.aop.support.DelegatingIntroductionInterceptor; - -/** - * Interface for collection-based results that carry extra information - * about the state of permission cut-offs. - * - * @author Derek Hulley - * @since 4.0 - */ -public interface PermissionCheckedCollection -{ - /** - * Check if the results have been truncated by permission check limits. - * - * @return true - if the results (usually a collection) have been - * cut off by permission check limits - */ - boolean isCutOff(); - - /** - * Get the number of objects in the original (unfiltered) collection that did - * not have any permission checks. - * - * @return number of entries from the original collection that were not checked - */ - int sizeUnchecked(); - - /** - * Get the number of objects in the original (unfiltered) collection. - * - * @return number of entries in the original, pre-checked collection - */ - int sizeOriginal(); - - /** - * Helper 'introduction' to allow simple addition of the {@link PermissionCheckedCollection} interface to - * existing collections. - * - * @param the type of the Collection in use - * - * @author Derek Hulley - * @since 4.0 - */ - @SuppressWarnings("serial") - public static class PermissionCheckedCollectionMixin extends DelegatingIntroductionInterceptor implements PermissionCheckedCollection - { - private final boolean isCutOff; - private final int sizeUnchecked; - private final int sizeOriginal; - private PermissionCheckedCollectionMixin(boolean isCutOff, int sizeUnchecked, int sizeOriginal) - { - super(); - this.isCutOff = isCutOff; - this.sizeUnchecked = sizeUnchecked; - this.sizeOriginal = sizeOriginal; - } - @Override - public boolean isCutOff() - { - return isCutOff; - } - @Override - public int sizeUnchecked() - { - return sizeUnchecked; - } - @Override - public int sizeOriginal() - { - return sizeOriginal; - } - /** - * Helper method to create a {@link PermissionCheckedCollection} from an existing Collection - * by applying the same values as present on a potentially permission-checked source. If the - * existing checked source is NOT permission-checked, then the collection will not be - * decorated. - * - * @param the type of the Collection - * @param collection the Collection to proxy - * @param checkedSource a collection that might implement {@link PermissionCheckedCollection} - * @return a Collection of the same type but including the - * {@link PermissionCheckedCollection} interface - */ - public static final Collection create( - Collection collection, Collection checkedSource) - { - if (checkedSource instanceof PermissionCheckedCollection) - { - PermissionCheckedCollection source = (PermissionCheckedCollection) checkedSource; - return create(collection, source.isCutOff(), source.sizeUnchecked(), source.sizeOriginal()); - } - else - { - return collection; - } - } - /** - * Helper method to create a {@link PermissionCheckedCollection} from an existing Collection - * - * @param the type of the Collection - * @param collection the Collection to proxy - * @param isCutOff true if permission checking was cut off before completion - * @param sizeUnchecked number of entries from the original collection that were not checked - * @param sizeOriginal number of entries in the original, pre-checked collection - * @return a Collection of the same type but including the - * {@link PermissionCheckedCollection} interface - */ - @SuppressWarnings("unchecked") - public static final Collection create( - Collection collection, - boolean isCutOff, int sizeUnchecked, int sizeOriginal) - { - // Create the mixin - DelegatingIntroductionInterceptor mixin = new PermissionCheckedCollectionMixin( - isCutOff, - sizeUnchecked, - sizeOriginal - ); - // Create the advisor - IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckedCollection.class); - // Proxy - ProxyFactory pf = new ProxyFactory(collection); - pf.addAdvisor(advisor); - Object proxiedObject = pf.getProxy(); - - // Done - return (Collection) proxiedObject; - } - } -} +package org.alfresco.repo.security.permissions; + +import java.util.Collection; + +import org.springframework.aop.IntroductionAdvisor; +import org.springframework.aop.support.DefaultIntroductionAdvisor; +import org.springframework.aop.support.DelegatingIntroductionInterceptor; + +/** + * Interface for collection-based results that carry extra information about the state of permission cut-offs. + * + * @author Derek Hulley + * @since 4.0 + */ +public interface PermissionCheckedCollection +{ + /** + * Check if the results have been truncated by permission check limits. + * + * @return true - if the results (usually a collection) have been cut off by permission check limits + */ + boolean isCutOff(); + + /** + * Get the number of objects in the original (unfiltered) collection that did not have any permission checks. + * + * @return number of entries from the original collection that were not checked + */ + int sizeUnchecked(); + + /** + * Get the number of objects in the original (unfiltered) collection. + * + * @return number of entries in the original, pre-checked collection + */ + int sizeOriginal(); + + /** + * Helper 'introduction' to allow simple addition of the {@link PermissionCheckedCollection} interface to existing collections. + * + * @param + * the type of the Collection in use + * + * @author Derek Hulley + * @since 4.0 + */ + @SuppressWarnings("serial") + class PermissionCheckedCollectionMixin extends DelegatingIntroductionInterceptor implements PermissionCheckedCollection + { + private final boolean isCutOff; + private final int sizeUnchecked; + private final int sizeOriginal; + + private PermissionCheckedCollectionMixin(boolean isCutOff, int sizeUnchecked, int sizeOriginal) + { + super(); + this.isCutOff = isCutOff; + this.sizeUnchecked = sizeUnchecked; + this.sizeOriginal = sizeOriginal; + } + + @Override + public boolean isCutOff() + { + return isCutOff; + } + + @Override + public int sizeUnchecked() + { + return sizeUnchecked; + } + + @Override + public int sizeOriginal() + { + return sizeOriginal; + } + + /** + * Helper method to create a {@link PermissionCheckedCollection} from an existing Collection by applying the same values as present on a potentially permission-checked source. If the existing checked source is NOT permission-checked, then the collection will not be decorated. + * + * @param + * the type of the Collection + * @param collection + * the Collection to proxy + * @param checkedSource + * a collection that might implement {@link PermissionCheckedCollection} + * @return a Collection of the same type but including the {@link PermissionCheckedCollection} interface + */ + public static Collection create( + Collection collection, Collection checkedSource) + { + if (checkedSource instanceof PermissionCheckedCollection) + { + PermissionCheckedCollection source = (PermissionCheckedCollection) checkedSource; + return create(collection, source.isCutOff(), source.sizeUnchecked(), source.sizeOriginal()); + } + else + { + return collection; + } + } + + /** + * Helper method to create a {@link PermissionCheckedCollection} from an existing Collection + * + * @param + * the type of the Collection + * @param collection + * the Collection to proxy + * @param isCutOff + * true if permission checking was cut off before completion + * @param sizeUnchecked + * number of entries from the original collection that were not checked + * @param sizeOriginal + * number of entries in the original, pre-checked collection + * @return a Collection of the same type but including the {@link PermissionCheckedCollection} interface + */ + @SuppressWarnings("unchecked") + public static Collection create( + Collection collection, + boolean isCutOff, int sizeUnchecked, int sizeOriginal) + { + // Create the mixin + DelegatingIntroductionInterceptor mixin = new PermissionCheckedCollectionMixin<>( + isCutOff, + sizeUnchecked, + sizeOriginal); + // Create the advisor + IntroductionAdvisor advisor = new DefaultIntroductionAdvisor(mixin, PermissionCheckedCollection.class); + // Create Proxy + return (Collection) ProxyFactoryUtils.createProxy(collection, advisor); + } + } +} diff --git a/repository/src/main/java/org/alfresco/repo/security/permissions/ProxyFactoryUtils.java b/repository/src/main/java/org/alfresco/repo/security/permissions/ProxyFactoryUtils.java new file mode 100644 index 0000000000..88333e79b4 --- /dev/null +++ b/repository/src/main/java/org/alfresco/repo/security/permissions/ProxyFactoryUtils.java @@ -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 . + * #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(); + } +} diff --git a/repository/src/main/java/org/alfresco/service/cmr/download/DownloadService.java b/repository/src/main/java/org/alfresco/service/cmr/download/DownloadService.java index 04f1a1ffae..8e637d3a61 100644 --- a/repository/src/main/java/org/alfresco/service/cmr/download/DownloadService.java +++ b/repository/src/main/java/org/alfresco/service/cmr/download/DownloadService.java @@ -40,7 +40,7 @@ import org.alfresco.service.cmr.repository.NodeRef; 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. * * 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. * * @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 */ - 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. diff --git a/repository/src/main/resources/alfresco/download-services-context.xml b/repository/src/main/resources/alfresco/download-services-context.xml index 451db5b4a0..f39e7d12dd 100644 --- a/repository/src/main/resources/alfresco/download-services-context.xml +++ b/repository/src/main/resources/alfresco/download-services-context.xml @@ -115,6 +115,7 @@ + diff --git a/repository/src/test/java/org/alfresco/repo/download/DownloadServiceIntegrationTest.java b/repository/src/test/java/org/alfresco/repo/download/DownloadServiceIntegrationTest.java index ecd70f275a..b3e49a095e 100644 --- a/repository/src/test/java/org/alfresco/repo/download/DownloadServiceIntegrationTest.java +++ b/repository/src/test/java/org/alfresco/repo/download/DownloadServiceIntegrationTest.java @@ -349,6 +349,29 @@ public class DownloadServiceIntegrationTest 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() + { + + @Override + public Object execute() throws Throwable + { + Map 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 entryNames, final Set expectedEntries, boolean onlyExpected) { Set copy = new TreeSet(entryNames); diff --git a/repository/src/test/java/org/alfresco/repo/search/impl/solr/AbstractSolrQueryHTTPClientTest.java b/repository/src/test/java/org/alfresco/repo/search/impl/solr/AbstractSolrQueryHTTPClientTest.java index 8fe0ba05f4..8be37a4db3 100644 --- a/repository/src/test/java/org/alfresco/repo/search/impl/solr/AbstractSolrQueryHTTPClientTest.java +++ b/repository/src/test/java/org/alfresco/repo/search/impl/solr/AbstractSolrQueryHTTPClientTest.java @@ -1,155 +1,173 @@ -/* - * #%L - * Alfresco Repository - * %% - * Copyright (C) 2005 - 2023 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 . - * #L% - */ -package org.alfresco.repo.search.impl.solr; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.mockito.MockitoAnnotations.openMocks; - -import jakarta.servlet.http.HttpServletResponse; -import java.io.ByteArrayInputStream; - -import org.alfresco.repo.search.QueryParserException; -import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.URI; -import org.apache.commons.httpclient.methods.PostMethod; -import org.json.JSONObject; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; - -/** Tests for the {@link AbstractSolrQueryHTTPClient}. */ -public class AbstractSolrQueryHTTPClientTest -{ - /** A URL for use in the tests. */ - private static final String URL = "http://this/is/a/url"; - - /** The abstract class under test. */ - private AbstractSolrQueryHTTPClient abstractSolrQueryHTTPClient = spy(AbstractSolrQueryHTTPClient.class); - @Mock - private HttpClient httpClient; - @Mock - private JSONObject body; - @Mock - private PostMethod postMethod; - @Mock - private Header header; - - @Before - public void setUp() throws Exception - { - openMocks(this); - - doReturn(postMethod).when(abstractSolrQueryHTTPClient).createNewPostMethod(URL); - when(postMethod.getResponseCharSet()).thenReturn("UTF-8"); - } - - /** Check postQuery works as expected for the success case. */ - @Test - public void testPostQuery_success() throws Exception - { - when(body.toString()).thenReturn("Example body"); - when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_OK); - when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}")); - - JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body); - - assertEquals("Unexpected JSON response received.", "{}", response.toString()); - } - - /** Check that the status code is usually passed through from Solr. */ - @Test - public void testPostQuery_failure() throws Exception - { - String failureMessage = "{\"error\": {\"trace\": \"ExceptionClass: Stacktrace\"}}"; - - when(body.toString()).thenReturn("Example body"); - when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_NOT_FOUND); - when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage)); - when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage); - - try - { - abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body); - fail("Expected a QueryParserException to be thrown."); - } - catch (QueryParserException e) - { - assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_FOUND); - verify(postMethod).releaseConnection(); - } - } - - /** Check that the status code is replaced with "Not Implemented" for an unsupported query option. */ - @Test - public void testPostQuery_unsupportedOperation() throws Exception - { - String failureMessage = "{\"error\": {\"trace\": \"java.lang.UnsupportedOperationException: Stacktrace\"}}"; - - when(body.toString()).thenReturn("Example body"); - when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage)); - when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage); - - try - { - abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body); - fail("Expected a QueryParserException to be thrown."); - } - catch (QueryParserException e) - { - assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_IMPLEMENTED); - } - } - - /** Check that a redirect can be followed if the endpoint reports that it's moved. */ - @Test - public void testPostQuery_moved() throws Exception - { - 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); - when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}")); - when(postMethod.getResponseHeader("location")).thenReturn(header); - when(header.getValue()).thenReturn("http://new/URL"); - - JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body); - - verify(postMethod).setURI(new URI("http://new/URL", true)); - assertEquals("Unexpected JSON response received.", "{}", response.toString()); - } - - /** Create an input stream containing the given string. */ - private ByteArrayInputStream convertStringToInputStream(String message) - { - return new ByteArrayInputStream(message.getBytes()); - } -} +/* + * #%L + * Alfresco Repository + * %% + * 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 . + * #L% + */ +package org.alfresco.repo.search.impl.solr; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.openMocks; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import jakarta.servlet.http.HttpServletResponse; + +import org.apache.commons.httpclient.Header; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.URI; +import org.apache.commons.httpclient.methods.PostMethod; +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; + +import org.alfresco.httpclient.HttpClientException; +import org.alfresco.repo.search.QueryParserException; + +/** Tests for the {@link AbstractSolrQueryHTTPClient}. */ +public class AbstractSolrQueryHTTPClientTest +{ + /** A URL for use in the tests. */ + private static final String URL = "http://this/is/a/url"; + + /** The abstract class under test. */ + private final AbstractSolrQueryHTTPClient abstractSolrQueryHTTPClient = spy(AbstractSolrQueryHTTPClient.class); + @Mock + private HttpClient httpClient; + @Mock + private JSONObject body; + @Mock + private PostMethod postMethod; + @Mock + private Header header; + + @Before + public void setUp() throws Exception + { + openMocks(this); + + doReturn(postMethod).when(abstractSolrQueryHTTPClient).createNewPostMethod(URL); + when(postMethod.getResponseCharSet()).thenReturn("UTF-8"); + } + + /** Check postQuery works as expected for the success case. */ + @Test + public void testPostQuery_success() throws Exception + { + when(body.toString()).thenReturn("Example body"); + when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_OK); + when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}")); + + JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body); + + assertEquals("Unexpected JSON response received.", "{}", response.toString()); + } + + /** Check that the status code is usually passed through from Solr. */ + @Test + public void testPostQuery_failure() throws Exception + { + String failureMessage = "{\"error\": {\"trace\": \"ExceptionClass: Stacktrace\"}}"; + + when(body.toString()).thenReturn("Example body"); + when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_NOT_FOUND); + when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage)); + when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage); + + try + { + abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body); + fail("Expected a QueryParserException to be thrown."); + } + catch (QueryParserException e) + { + assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_FOUND); + verify(postMethod).releaseConnection(); + } + } + + /** Check that the status code is replaced with "Not Implemented" for an unsupported query option. */ + @Test + public void testPostQuery_unsupportedOperation() throws Exception + { + String failureMessage = "{\"error\": {\"trace\": \"java.lang.UnsupportedOperationException: Stacktrace\"}}"; + + when(body.toString()).thenReturn("Example body"); + when(postMethod.getStatusCode()).thenReturn(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream(failureMessage)); + when(postMethod.getResponseBodyAsString()).thenReturn(failureMessage); + + try + { + abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body); + fail("Expected a QueryParserException to be thrown."); + } + catch (QueryParserException e) + { + assertEquals("Unexpected status code in exception.", e.getHttpStatusCode(), HttpServletResponse.SC_NOT_IMPLEMENTED); + } + } + + /** Check that a redirect can be followed if the endpoint reports that it's moved. */ + @Test + public void testPostQuery_moved() throws Exception + { + 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); + when(postMethod.getResponseBodyAsStream()).thenReturn(convertStringToInputStream("{}")); + when(postMethod.getResponseHeader("location")).thenReturn(header); + when(header.getValue()).thenReturn("http://new/URL"); + + JSONObject response = abstractSolrQueryHTTPClient.postQuery(httpClient, URL, body); + + verify(postMethod).setURI(new URI("http://new/URL", true)); + 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()); + } +} diff --git a/scripts/ci/docker-compose/docker-compose.yaml b/scripts/ci/docker-compose/docker-compose.yaml index bf96f0d391..29604ba4bc 100644 --- a/scripts/ci/docker-compose/docker-compose.yaml +++ b/scripts/ci/docker-compose/docker-compose.yaml @@ -68,4 +68,4 @@ services: volumes: - ../../../repository/src/test/resources/realms/alfresco-realm.json:/opt/keycloak/data/import/alfresco-realm.json ports: - - 8999:8080 \ No newline at end of file + - 8999:8080 diff --git a/scripts/hooks/check-format-and-headers.sh b/scripts/hooks/check-format-and-headers.sh new file mode 100755 index 0000000000..26286305d8 --- /dev/null +++ b/scripts/hooks/check-format-and-headers.sh @@ -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