mirror of
				https://github.com/Alfresco/alfresco-community-repo.git
				synced 2025-10-29 15:21:53 +00:00 
			
		
		
		
	Compare commits
	
		
			59 Commits
		
	
	
		
			23.3.0.8
			...
			feature/Up
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					1390b30302 | ||
| 
						 | 
					38b763c635 | ||
| 
						 | 
					762b6ce607 | ||
| 
						 | 
					0d89010ae6 | ||
| 
						 | 
					b744f267c1 | ||
| 
						 | 
					e840726a7d | ||
| 
						 | 
					c53683df85 | ||
| 
						 | 
					d9e58483ff | ||
| 
						 | 
					9e81472d06 | ||
| 
						 | 
					3e9cdc6b77 | ||
| 
						 | 
					e8ac8c2602 | ||
| 
						 | 
					eea58f4ba3 | ||
| 
						 | 
					a95fa4a83d | ||
| 
						 | 
					0b74d283e2 | ||
| 
						 | 
					052e21e62d | ||
| 
						 | 
					26f49e80e9 | ||
| 
						 | 
					c31158a113 | ||
| 
						 | 
					2b4fc52203 | ||
| 
						 | 
					6222e1dfde | ||
| 
						 | 
					077c48dea9 | ||
| 
						 | 
					1a0b8d8dee | ||
| 
						 | 
					66d007e703 | ||
| 
						 | 
					81a4c5bac0 | ||
| 
						 | 
					018157c808 | ||
| 
						 | 
					8db97184f2 | ||
| 
						 | 
					84948e051a | ||
| 
						 | 
					8c20a3271e | ||
| 
						 | 
					48c7abcfbe | ||
| 
						 | 
					53d77f8d71 | ||
| 
						 | 
					e8e747347a | ||
| 
						 | 
					fee244cb08 | ||
| 
						 | 
					2bec2bd1c4 | ||
| 
						 | 
					1cd8098f52 | ||
| 
						 | 
					30afcaa033 | ||
| 
						 | 
					bdf1a57630 | ||
| 
						 | 
					2723817832 | ||
| 
						 | 
					22acb2abe7 | ||
| 
						 | 
					3c616152a1 | ||
| 
						 | 
					8cfdc613cb | ||
| 
						 | 
					f1919934b2 | ||
| 
						 | 
					e9da60dac3 | ||
| 
						 | 
					0597b0997f | ||
| 
						 | 
					6dbe30e8f7 | ||
| 
						 | 
					d978b1cd68 | ||
| 
						 | 
					dce356fe74 | ||
| 
						 | 
					f965165894 | ||
| 
						 | 
					2ac44c24a8 | ||
| 
						 | 
					a0dc5a0d70 | ||
| 
						 | 
					af94063bbb | ||
| 
						 | 
					87b91b6cae | ||
| 
						 | 
					6bdcaa9b10 | ||
| 
						 | 
					86070d881c | ||
| 
						 | 
					a82199967c | ||
| 
						 | 
					f09266c081 | ||
| 
						 | 
					563f65825f | ||
| 
						 | 
					8bedeedfd5 | ||
| 
						 | 
					a73cf6a71d | ||
| 
						 | 
					1bdd6c022c | ||
| 
						 | 
					1b553dbcaf | 
							
								
								
									
										562
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										562
									
								
								.github/workflows/ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -29,6 +29,9 @@ env:
 | 
			
		||||
  AUTH0_CLIENT_ID: ${{ secrets.AUTH0_OIDC_ADMIN_CLIENT_ID }}
 | 
			
		||||
  AUTH0_CLIENT_SECRET: ${{ secrets.AUTH0_OIDC_CLIENT_SECRET }}
 | 
			
		||||
  AUTH0_ADMIN_PASSWORD: ${{ secrets.AUTH0_OIDC_ADMIN_PASSWORD }}
 | 
			
		||||
  # Report Portal settings
 | 
			
		||||
  RP_LAUNCH_PREFIX: "${{ github.workflow }} - ${{ github.job }}"
 | 
			
		||||
  RP_PROJECT: alfresco-backend
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  prepare:
 | 
			
		||||
@@ -142,13 +145,29 @@ jobs:
 | 
			
		||||
          classpath-build-command: "mvn test-compile -ntp -Pags -pl \"-:alfresco-community-repo-docker\""
 | 
			
		||||
 | 
			
		||||
  all_unit_tests_suite:
 | 
			
		||||
    name: "Core, Data-Model, Repository - AllUnitTestsSuite - Build and test"
 | 
			
		||||
    name: ${{ matrix.testName }} - AllUnitTestsSuite - Build and test
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    needs: [prepare]
 | 
			
		||||
    if: >
 | 
			
		||||
      !contains(github.event.head_commit.message, '[skip repo]') &&
 | 
			
		||||
      !contains(github.event.head_commit.message, '[skip tests]') &&
 | 
			
		||||
      !contains(github.event.head_commit.message, '[force')
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        include:
 | 
			
		||||
          - testName: Core
 | 
			
		||||
            testModule: core
 | 
			
		||||
            testAttributes: "-Dtest=AllCoreUnitTestSuite"
 | 
			
		||||
          - testName: Data-Model
 | 
			
		||||
            testModule: data-model
 | 
			
		||||
            testAttributes: "-Dtest=AllDataModelUnitTestSuite"
 | 
			
		||||
          - testName: Repository
 | 
			
		||||
            testModule: repository
 | 
			
		||||
            testAttributes: "-Dtest=AllUnitTestsSuite"
 | 
			
		||||
          - testName: Mmt
 | 
			
		||||
            testModule: mmt
 | 
			
		||||
            testAttributes: "-Dtest=AllMmtUnitTestSuite"
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v3
 | 
			
		||||
      - uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
 | 
			
		||||
@@ -156,10 +175,44 @@ jobs:
 | 
			
		||||
      - uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
 | 
			
		||||
      - name: "Init"
 | 
			
		||||
        run: bash ./scripts/ci/init.sh
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testModule }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Run tests"
 | 
			
		||||
        id: run-tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          mvn -B test -pl core,data-model -am -DfailIfNoTests=false
 | 
			
		||||
          mvn -B test -pl "repository,mmt" -am "-Dtest=AllUnitTestsSuite,AllMmtUnitTestSuite" -DfailIfNoTests=false
 | 
			
		||||
          eval "args=($RP_OPTS)"
 | 
			
		||||
          mvn -B test -pl ${{ matrix.testModule }} -am ${{ matrix.testAttributes }} -DfailIfNoTests=false "${args[@]}"
 | 
			
		||||
        continue-on-error: true
 | 
			
		||||
      - name: "Update GitHub Step Summary"
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.run-tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.run-tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=run-tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -200,9 +253,45 @@ 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"
 | 
			
		||||
        run: docker-compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile ${{ matrix.compose-profile }} up -d
 | 
			
		||||
        run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile ${{ matrix.compose-profile }} up -d
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testSuite }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Run tests"
 | 
			
		||||
        run: 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
 | 
			
		||||
        id: run-tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          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"
 | 
			
		||||
        run: |
 | 
			
		||||
            echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.run-tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.run-tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=run-tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -229,11 +318,47 @@ jobs:
 | 
			
		||||
      - name: "Init"
 | 
			
		||||
        run: bash ./scripts/ci/init.sh
 | 
			
		||||
      - name: Run MariaDB ${{ matrix.version }} database
 | 
			
		||||
        run: docker-compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile mariadb up -d
 | 
			
		||||
        run: docker compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile mariadb up -d
 | 
			
		||||
        env:
 | 
			
		||||
          MARIADB_VERSION: ${{ matrix.version }}
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.version }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Run tests"
 | 
			
		||||
        run: mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.name=alfresco -Ddb.url=jdbc:mariadb://localhost:3307/alfresco?useUnicode=yes\&characterEncoding=UTF-8 -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.driver=org.mariadb.jdbc.Driver
 | 
			
		||||
        id: run-tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          eval "args=($RP_OPTS)"
 | 
			
		||||
          mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.name=alfresco -Ddb.url=jdbc:mariadb://localhost:3307/alfresco?useUnicode=yes\&characterEncoding=UTF-8 -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.driver=org.mariadb.jdbc.Driver "${args[@]}"
 | 
			
		||||
        continue-on-error: true
 | 
			
		||||
      - name: "Update GitHub Step Summary"
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.run-tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.run-tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=run-tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -256,11 +381,47 @@ jobs:
 | 
			
		||||
      - name: "Init"
 | 
			
		||||
        run: bash ./scripts/ci/init.sh
 | 
			
		||||
      - name: "Run MariaDB 10.6 database"
 | 
			
		||||
        run: docker-compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile mariadb up -d
 | 
			
		||||
        run: docker compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile mariadb up -d
 | 
			
		||||
        env:
 | 
			
		||||
          MARIADB_VERSION: 10.6
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Run tests"
 | 
			
		||||
        run: mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.name=alfresco -Ddb.url=jdbc:mariadb://localhost:3307/alfresco?useUnicode=yes\&characterEncoding=UTF-8 -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.driver=org.mariadb.jdbc.Driver
 | 
			
		||||
        id: run-tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          eval "args=($RP_OPTS)"
 | 
			
		||||
          mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.name=alfresco -Ddb.url=jdbc:mariadb://localhost:3307/alfresco?useUnicode=yes\&characterEncoding=UTF-8 -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.driver=org.mariadb.jdbc.Driver "${args[@]}"
 | 
			
		||||
        continue-on-error: true
 | 
			
		||||
      - name: "Update GitHub Step Summary"
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.run-tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.run-tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=run-tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -283,11 +444,47 @@ jobs:
 | 
			
		||||
      - name: "Init"
 | 
			
		||||
        run: bash ./scripts/ci/init.sh
 | 
			
		||||
      - name: "Run MySQL 8 database"
 | 
			
		||||
        run: docker-compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile mysql up -d
 | 
			
		||||
        run: docker compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile mysql up -d
 | 
			
		||||
        env:
 | 
			
		||||
          MYSQL_VERSION: 8
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Run tests"
 | 
			
		||||
        run: 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
 | 
			
		||||
        id: run-tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          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"
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.run-tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.run-tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=run-tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -309,11 +506,47 @@ jobs:
 | 
			
		||||
      - name: "Init"
 | 
			
		||||
        run: bash ./scripts/ci/init.sh
 | 
			
		||||
      - name: "Run PostgreSQL 13.12 database"
 | 
			
		||||
        run: docker-compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile postgres up -d
 | 
			
		||||
        run: docker compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile postgres up -d
 | 
			
		||||
        env:
 | 
			
		||||
          POSTGRES_VERSION: 13.12
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Run tests"
 | 
			
		||||
        run: 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
 | 
			
		||||
        id: run-tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          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"
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.run-tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.run-tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=run-tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -335,11 +568,47 @@ jobs:
 | 
			
		||||
      - name: "Init"
 | 
			
		||||
        run: bash ./scripts/ci/init.sh
 | 
			
		||||
      - name: "Run PostgreSQL 14.9 database"
 | 
			
		||||
        run: docker-compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile postgres up -d
 | 
			
		||||
        run: docker compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile postgres up -d
 | 
			
		||||
        env:
 | 
			
		||||
          POSTGRES_VERSION: 14.9
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Run tests"
 | 
			
		||||
        run: 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
 | 
			
		||||
        id: run-tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          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"
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.run-tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.run-tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=run-tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -361,11 +630,47 @@ jobs:
 | 
			
		||||
      - name: "Init"
 | 
			
		||||
        run: bash ./scripts/ci/init.sh
 | 
			
		||||
      - name: "Run PostgreSQL 15.4 database"
 | 
			
		||||
        run: docker-compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile postgres up -d
 | 
			
		||||
        run: docker compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile postgres up -d
 | 
			
		||||
        env:
 | 
			
		||||
          POSTGRES_VERSION: 15.4
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Run tests"
 | 
			
		||||
        run: 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
 | 
			
		||||
        id: run-tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          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"
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.run-tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.run-tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=run-tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -385,9 +690,45 @@ jobs:
 | 
			
		||||
      - 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
 | 
			
		||||
        run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile activemq up -d
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.13.1
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Run tests"
 | 
			
		||||
        run: mvn -B test -pl repository -am -Dtest=CamelRoutesTest,CamelComponentsTest -DfailIfNoTests=false
 | 
			
		||||
        id: run-tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          eval "args=($RP_OPTS)"
 | 
			
		||||
          mvn -B test -pl repository -am -Dtest=MessagingUnitTestSuite -DfailIfNoTests=false "${args[@]}"
 | 
			
		||||
        continue-on-error: true
 | 
			
		||||
      - name: "Update GitHub Step Summary"
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.13.1
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.run-tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.run-tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=run-tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -456,9 +797,45 @@ jobs:
 | 
			
		||||
            echo "HOSTNAME_VERIFICATION_DISABLED=false" >> "$GITHUB_ENV"
 | 
			
		||||
          fi
 | 
			
		||||
      - name: "Set up the environment"
 | 
			
		||||
        run: docker-compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile ${{ matrix.compose-profile }} up -d
 | 
			
		||||
        run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile ${{ matrix.compose-profile }} up -d
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testSuite }} ${{ matrix.idp }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Run tests"
 | 
			
		||||
        run: mvn -B test -pl repository -am -Dtest=${{ matrix.testSuite }} -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco ${{ matrix.mvn-options }}
 | 
			
		||||
        id: run-tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          eval "args=($RP_OPTS)"
 | 
			
		||||
          mvn -B test -pl repository -am -Dtest=${{ matrix.testSuite }} -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco ${{ matrix.mvn-options }} "${args[@]}"
 | 
			
		||||
        continue-on-error: true
 | 
			
		||||
      - name: "Update GitHub Step Summary"
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.run-tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.run-tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=run-tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -519,16 +896,51 @@ jobs:
 | 
			
		||||
      - name: "Build TAS integration tests"
 | 
			
		||||
        if: ${{ matrix.test-name }} == 'Integration TAS tests'
 | 
			
		||||
        run: mvn install -pl :alfresco-community-repo-integration-test -am -DskipTests -Pall-tas-tests
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.test-name }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Run tests"
 | 
			
		||||
        id: tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
 | 
			
		||||
        run: mvn -B verify -f packaging/tests/${{ matrix.pom-dir }}/pom.xml -Pall-tas-tests,${{ matrix.test-profile }} -Denvironment=default -DrunBugs=false
 | 
			
		||||
        run: |
 | 
			
		||||
          eval "args=($RP_OPTS)"
 | 
			
		||||
          mvn -B verify -f packaging/tests/${{ matrix.pom-dir }}/pom.xml -Pall-tas-tests,${{ matrix.test-profile }} -Denvironment=default -DrunBugs=false "${args[@]}"
 | 
			
		||||
        continue-on-error: true
 | 
			
		||||
      - name: "Print output after success"
 | 
			
		||||
        if: ${{ always() && steps.tests.outcome == 'success' }}
 | 
			
		||||
        run: ${TAS_SCRIPTS}/output_tests_run.sh "packaging/tests/${{ matrix.pom-dir }}"
 | 
			
		||||
      - name: "Print output after failure"
 | 
			
		||||
        if: ${{ always() && steps.tests.outcome == 'failure' }}
 | 
			
		||||
        run: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/${{ matrix.pom-dir }}"
 | 
			
		||||
      - name: "Update GitHub Step Summary"
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -548,9 +960,45 @@ jobs:
 | 
			
		||||
      - 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
 | 
			
		||||
        run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile postgres up -d
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Run tests"
 | 
			
		||||
        run: mvn -B test -pl :alfresco-share-services -am -Dtest=ShareServicesTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
        id: run-tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          eval "args=($RP_OPTS)"
 | 
			
		||||
          mvn -B test -pl :alfresco-share-services -am -Dtest=ShareServicesTestSuite -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"
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.run-tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.run-tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=run-tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -580,9 +1028,21 @@ jobs:
 | 
			
		||||
        run: |
 | 
			
		||||
          bash ./scripts/ci/init.sh
 | 
			
		||||
          bash ./scripts/ci/build.sh
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} 0${{ matrix.part }} - (PostgreSQL) ${{ matrix.test-name }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Verify"
 | 
			
		||||
        timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
 | 
			
		||||
        run: mvn --file amps/ags/pom.xml -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-postgres -PagsAllTestSuitePt${{ matrix.part }} ${{ env.LOG_WARN }}
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          eval "args=($RP_OPTS)"
 | 
			
		||||
          mvn --file amps/ags/pom.xml -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-mysql -PagsAllTestSuitePt${{ matrix.part }} ${{ env.LOG_WARN }} "${args[@]}"
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -612,9 +1072,21 @@ jobs:
 | 
			
		||||
        run: |
 | 
			
		||||
          bash ./scripts/ci/init.sh
 | 
			
		||||
          bash ./scripts/ci/build.sh
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} 0${{ matrix.part }} - (MySQL) ${{ matrix.test-name }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Verify"
 | 
			
		||||
        timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
 | 
			
		||||
        run: mvn --file amps/ags/pom.xml -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-mysql -PagsAllTestSuitePt${{ matrix.part }} ${{ env.LOG_WARN }}
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          eval "args=($RP_OPTS)"
 | 
			
		||||
          mvn --file amps/ags/pom.xml -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-mysql -PagsAllTestSuitePt${{ matrix.part }} ${{ env.LOG_WARN }} "${args[@]}"
 | 
			
		||||
      - name: "Clean Maven cache"
 | 
			
		||||
        run: bash ./scripts/ci/cleanup_cache.sh
 | 
			
		||||
 | 
			
		||||
@@ -646,9 +1118,45 @@ jobs:
 | 
			
		||||
          ${{ env.TAS_SCRIPTS }}/start-compose.sh ./amps/ags/rm-community/rm-community-repo/docker-compose.yml
 | 
			
		||||
          ${{ env.TAS_SCRIPTS }}/wait-for-alfresco-start.sh "http://localhost:8080/alfresco"
 | 
			
		||||
          mvn -B install -pl :alfresco-governance-services-automation-community-rest-api -am -Pags -Pall-tas-tests -DskipTests
 | 
			
		||||
      - name: "Prepare Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
 | 
			
		||||
        id: rp-prepare
 | 
			
		||||
        with:
 | 
			
		||||
          rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-use-static-launch-name: true
 | 
			
		||||
      - name: "Add GitHub Step Summary"
 | 
			
		||||
        env:
 | 
			
		||||
          RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
 | 
			
		||||
          RP_KEY: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          RP_URL: ${{ steps.rp-prepare.outputs.url }}
 | 
			
		||||
        run: bash scripts/ci/add_step_summary.sh
 | 
			
		||||
      - name: "Test"
 | 
			
		||||
        id: run-tests
 | 
			
		||||
        timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
 | 
			
		||||
        run: mvn -B test -pl :alfresco-governance-services-automation-community-rest-api -Dskip.automationtests=false -Pags -Pall-tas-tests
 | 
			
		||||
        env:
 | 
			
		||||
          RP_OPTS: ${{ steps.rp-prepare.outputs.mvn-opts }}
 | 
			
		||||
        run: |
 | 
			
		||||
          eval "args=($RP_OPTS)"
 | 
			
		||||
          mvn -B test -pl :alfresco-governance-services-automation-community-rest-api -Dskip.automationtests=false -Pags -Pall-tas-tests "${args[@]}"
 | 
			
		||||
        continue-on-error: true
 | 
			
		||||
      - name: "Update GitHub Step Summary"
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
 | 
			
		||||
      - name: "Summarize Report Portal"
 | 
			
		||||
        uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
 | 
			
		||||
        id: rp-summarize
 | 
			
		||||
        with:
 | 
			
		||||
          tests-outcome: ${{ steps.run-tests.outcome }}
 | 
			
		||||
          rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
 | 
			
		||||
          rp-project: ${{ env.RP_PROJECT }}
 | 
			
		||||
          rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
 | 
			
		||||
      - name: "Exit on failure"
 | 
			
		||||
        if: steps.run-tests.outcome != 'success'
 | 
			
		||||
        run: |
 | 
			
		||||
          echo "::error title=run-tests::Tests failed: re-throwing on error."
 | 
			
		||||
          exit 1
 | 
			
		||||
      - name: "Configure AWS credentials"
 | 
			
		||||
        if: ${{ always() }}
 | 
			
		||||
        uses: aws-actions/configure-aws-credentials@v1
 | 
			
		||||
 
 | 
			
		||||
@@ -71,7 +71,7 @@ the _alfresco-internal_ repository:
 | 
			
		||||
   </snapshots>
 | 
			
		||||
</repository>
 | 
			
		||||
```
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
For additional instructions you can check the official Maven documentation:
 | 
			
		||||
* [setting up repositories](https://maven.apache.org/guides/mini/guide-multiple-repositories.html)
 | 
			
		||||
@@ -227,7 +227,7 @@ If only the Community or Enterprise images need to be built than the same comman
 | 
			
		||||
 | 
			
		||||
The Docker images of the Repo can be started independently from Share running the following command in the rm-repo-enterprise or rm-repo-community folder which contains the Docker-compose.yml file:
 | 
			
		||||
```
 | 
			
		||||
docker-compose up
 | 
			
		||||
docker compose up
 | 
			
		||||
```
 | 
			
		||||
> Be aware of the fact that the Share images can not be started independently from Repo
 | 
			
		||||
 | 
			
		||||
@@ -237,5 +237,5 @@ e.g. In order to start an instance of rm-enterprise-repo and rm-enterprise-share
 | 
			
		||||
 | 
			
		||||
If you have a license for jRebel then this can be used from the rm-community-share or rm-enterprise-share directories with:
 | 
			
		||||
```
 | 
			
		||||
docker-compose -f docker-compose.yml -f jrebel-docker-compose.yml --project-name agsdev up --build --force-recreate
 | 
			
		||||
docker compose -f docker-compose.yml -f jrebel-docker-compose.yml --project-name agsdev up --build --force-recreate
 | 
			
		||||
```
 | 
			
		||||
 
 | 
			
		||||
@@ -4,9 +4,9 @@ set -x
 | 
			
		||||
# Display running containers
 | 
			
		||||
docker ps
 | 
			
		||||
 | 
			
		||||
alfrescoContainerId=$(docker ps -a | grep '_alfresco_' | awk '{print $1}')
 | 
			
		||||
shareContainerId=$(docker ps -a | grep '_share_' | awk '{print $1}')
 | 
			
		||||
solrContainerId=$(docker ps -a | grep '_search_' | awk '{print $1}')
 | 
			
		||||
alfrescoContainerId=$(docker ps -a | grep '\-alfresco\-' | awk '{print $1}')
 | 
			
		||||
shareContainerId=$(docker ps -a | grep '\-share\-' | awk '{print $1}')
 | 
			
		||||
solrContainerId=$(docker ps -a | grep '\-search\-' | awk '{print $1}')
 | 
			
		||||
 | 
			
		||||
docker logs $alfrescoContainerId > alfresco.log
 | 
			
		||||
if [ -n "$shareContainerId" ]; then
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
   <parent>
 | 
			
		||||
      <groupId>org.alfresco</groupId>
 | 
			
		||||
      <artifactId>alfresco-community-repo-amps</artifactId>
 | 
			
		||||
      <version>23.3.0.8</version>
 | 
			
		||||
      <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
   </parent>
 | 
			
		||||
 | 
			
		||||
   <modules>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
   <parent>
 | 
			
		||||
      <groupId>org.alfresco</groupId>
 | 
			
		||||
      <artifactId>alfresco-governance-services-community-parent</artifactId>
 | 
			
		||||
      <version>23.3.0.8</version>
 | 
			
		||||
      <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
   </parent>
 | 
			
		||||
 | 
			
		||||
   <modules>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
   <parent>
 | 
			
		||||
      <groupId>org.alfresco</groupId>
 | 
			
		||||
      <artifactId>alfresco-governance-services-automation-community-repo</artifactId>
 | 
			
		||||
      <version>23.3.0.8</version>
 | 
			
		||||
      <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
   </parent>
 | 
			
		||||
 | 
			
		||||
   <build>
 | 
			
		||||
@@ -74,6 +74,16 @@
 | 
			
		||||
         <artifactId>alfresco-testng</artifactId>
 | 
			
		||||
         <version>1.1</version>
 | 
			
		||||
      </dependency>
 | 
			
		||||
      <dependency>
 | 
			
		||||
         <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
         <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
         <scope>test</scope>
 | 
			
		||||
      </dependency>
 | 
			
		||||
      <dependency>
 | 
			
		||||
         <groupId>com.squareup.okhttp3</groupId>
 | 
			
		||||
         <artifactId>okhttp</artifactId>
 | 
			
		||||
         <scope>test</scope>
 | 
			
		||||
      </dependency>
 | 
			
		||||
      <dependency>
 | 
			
		||||
         <groupId>org.apache.commons</groupId>
 | 
			
		||||
         <artifactId>commons-collections4</artifactId>
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ import org.alfresco.rest.rm.community.requests.gscore.GSCoreAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.ActionsExecutionAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.FilesAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.HoldsAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.RMUserAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.RecordCategoryAPI;
 | 
			
		||||
@@ -243,4 +244,14 @@ public class RestAPIFactory
 | 
			
		||||
    {
 | 
			
		||||
        return getGSCoreAPI(null).usingActionsExecutionsAPI();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public HoldsAPI getHoldsAPI()
 | 
			
		||||
    {
 | 
			
		||||
        return getGSCoreAPI(null).usingHoldsAPI();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public HoldsAPI getHoldsAPI(UserModel userModel)
 | 
			
		||||
    {
 | 
			
		||||
        return getGSCoreAPI(userModel).usingHoldsAPI();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -61,7 +61,6 @@ public class FilePlanComponentFields
 | 
			
		||||
    public static final String PROPERTIES_RECORD_SEARCH_DISPOSITION_EVENTS = "rma:recordSearchDispositionEvents";
 | 
			
		||||
    public static final String PROPERTIES_DECLASSIFICATION_REVIEW_COMPLETED_BY = "rma:declassificationReviewCompletedBy";
 | 
			
		||||
    public static final String PROPERTIES_DECLASSIFICATION_REVIEW_COMPLETED_AT = "rma:declassificationReviewCompletedAt";
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    /** File plan properties */
 | 
			
		||||
    public static final String PROPERTIES_COMPONENT_ID = "st:componentId";
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,83 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.model.hold;
 | 
			
		||||
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import org.alfresco.utility.model.TestModel;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * POJO for hold
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
@Builder
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class Hold extends TestModel
 | 
			
		||||
{
 | 
			
		||||
    @JsonProperty(required = true)
 | 
			
		||||
    private String id;
 | 
			
		||||
 | 
			
		||||
    @JsonProperty(required = true)
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
    @JsonProperty(required = true)
 | 
			
		||||
    private String description;
 | 
			
		||||
 | 
			
		||||
    @JsonProperty(required = true)
 | 
			
		||||
    private String reason;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object o)
 | 
			
		||||
    {
 | 
			
		||||
        if (this == o)
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (o == null || getClass() != o.getClass())
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        Hold hold = (Hold) o;
 | 
			
		||||
        return Objects.equals(id, hold.id) && Objects.equals(name, hold.name)
 | 
			
		||||
            && Objects.equals(description, hold.description) && Objects.equals(reason, hold.reason);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode()
 | 
			
		||||
    {
 | 
			
		||||
        return Objects.hash(id, name, description, reason);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.model.hold;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import org.alfresco.utility.model.TestModel;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * POJO for hold child
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
@Builder
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class HoldChild extends TestModel
 | 
			
		||||
{
 | 
			
		||||
    @JsonProperty(required = true)
 | 
			
		||||
    private String id;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.model.hold;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.core.RestModels;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle collection of {@link HoldChildEntry}
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
public class HoldChildCollection extends RestModels<HoldChildEntry, HoldChildCollection>
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.model.hold;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import org.alfresco.rest.core.RestModels;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * POJO for hold child entry
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
@Builder
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class HoldChildEntry extends RestModels<Hold, HoldChildEntry>
 | 
			
		||||
{
 | 
			
		||||
    @JsonProperty
 | 
			
		||||
    private HoldChildEntry entry;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.model.hold;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.core.RestModels;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle collection of {@link HoldEntry}
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
public class HoldCollection extends RestModels<HoldEntry, HoldCollection>
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.model.hold;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import org.alfresco.utility.model.TestModel;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * POJO for hold deletion reason
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
@Builder
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class HoldDeletionReason extends TestModel
 | 
			
		||||
{
 | 
			
		||||
    @JsonProperty
 | 
			
		||||
    private String reason;
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,52 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.model.hold;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import org.alfresco.rest.core.RestModels;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * POJO for hold child entry
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
@Builder
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class HoldDeletionReasonEntry extends RestModels<HoldDeletionReason, HoldDeletionReasonEntry>
 | 
			
		||||
{
 | 
			
		||||
    @JsonProperty
 | 
			
		||||
    private HoldDeletionReason entry;
 | 
			
		||||
}
 | 
			
		||||
@@ -26,31 +26,27 @@
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.model.hold;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.EqualsAndHashCode;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import org.alfresco.utility.model.TestModel;
 | 
			
		||||
import org.alfresco.rest.core.RestModels;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * POJO for hold entry
 | 
			
		||||
 *
 | 
			
		||||
 * @author Rodica Sutu
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
@Builder
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
@JsonIgnoreProperties (ignoreUnknown = true)
 | 
			
		||||
public class HoldEntry extends TestModel
 | 
			
		||||
public class HoldEntry extends RestModels<Hold, HoldEntry>
 | 
			
		||||
{
 | 
			
		||||
    @JsonProperty (required = true)
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
    @JsonProperty (required = true)
 | 
			
		||||
    private String nodeRef;
 | 
			
		||||
    @JsonProperty
 | 
			
		||||
    private Hold entry;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,56 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.model.hold.v0;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Builder;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import org.alfresco.utility.model.TestModel;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * POJO for hold entry
 | 
			
		||||
 *
 | 
			
		||||
 * @author Rodica Sutu
 | 
			
		||||
 * @since 3.2
 | 
			
		||||
 */
 | 
			
		||||
@Builder
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
@JsonIgnoreProperties (ignoreUnknown = true)
 | 
			
		||||
public class HoldEntry extends TestModel
 | 
			
		||||
{
 | 
			
		||||
    @JsonProperty (required = true)
 | 
			
		||||
    private String name;
 | 
			
		||||
 | 
			
		||||
    @JsonProperty (required = true)
 | 
			
		||||
    private String nodeRef;
 | 
			
		||||
}
 | 
			
		||||
@@ -37,6 +37,7 @@ import org.alfresco.rest.rm.community.requests.gscore.api.ActionsExecutionAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.RMModelRequest;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.FilesAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.HoldsAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.RMUserAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.RecordCategoryAPI;
 | 
			
		||||
@@ -190,4 +191,6 @@ public class GSCoreAPI extends RMModelRequest
 | 
			
		||||
    {
 | 
			
		||||
        return new ActionsExecutionAPI(getRmRestWrapper());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public HoldsAPI usingHoldsAPI() { return new HoldsAPI(getRmRestWrapper()); }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -38,6 +38,8 @@ import static org.springframework.http.HttpMethod.PUT;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.core.RMRestWrapper;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.fileplan.FilePlan;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.Hold;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldCollection;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryCollection;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.RMModelRequest;
 | 
			
		||||
@@ -213,4 +215,74 @@ public class FilePlanAPI extends RMModelRequest
 | 
			
		||||
                parameters));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a hold.
 | 
			
		||||
     *
 | 
			
		||||
     * @param holdModel The hold model
 | 
			
		||||
     * @param filePlanId The identifier of a file plan
 | 
			
		||||
     * @param parameters The URL parameters to add
 | 
			
		||||
     * @return The created {@link Hold}
 | 
			
		||||
     * @throws RuntimeException for the following cases:
 | 
			
		||||
     * <ul>
 | 
			
		||||
     *  <li>{@code filePlanId} is not a valid format or {@code filePlanId} is invalid</li>
 | 
			
		||||
     *  <li>authentication fails</li>
 | 
			
		||||
     *  <li>current user does not have permission to add children to {@code filePlanId}</li>
 | 
			
		||||
     *  <li>{@code filePlanIds} does not exist</li>
 | 
			
		||||
     *  <li>new name clashes with an existing node in the current parent container</li>
 | 
			
		||||
     * </ul>
 | 
			
		||||
     */
 | 
			
		||||
    public Hold createHold(Hold holdModel, String filePlanId, String parameters)
 | 
			
		||||
    {
 | 
			
		||||
        mandatoryString("filePlanId", filePlanId);
 | 
			
		||||
        mandatoryObject("holdModel", holdModel);
 | 
			
		||||
 | 
			
		||||
        return getRmRestWrapper().processModel(Hold.class, requestWithBody(
 | 
			
		||||
            POST,
 | 
			
		||||
            toJson(holdModel),
 | 
			
		||||
            "file-plans/{filePlanId}/holds",
 | 
			
		||||
            filePlanId,
 | 
			
		||||
            parameters
 | 
			
		||||
                                                                          ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * See {@link #createHold(Hold, String, String)}
 | 
			
		||||
     */
 | 
			
		||||
    public Hold createHold(Hold holdModel, String filePlanId)
 | 
			
		||||
    {
 | 
			
		||||
        return createHold(holdModel, filePlanId, EMPTY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the holds of a file plan.
 | 
			
		||||
     *
 | 
			
		||||
     * @param filePlanId The identifier of a file plan
 | 
			
		||||
     * @param parameters The URL parameters to add
 | 
			
		||||
     * @return The {@link HoldCollection} for the given {@code filePlanId}
 | 
			
		||||
     * @throws RuntimeException for the following cases:
 | 
			
		||||
     * <ul>
 | 
			
		||||
     *  <li>authentication fails</li>
 | 
			
		||||
     *  <li>current user does not have permission to read {@code filePlanId}</li>
 | 
			
		||||
     *  <li>{@code filePlanId} does not exist</li>
 | 
			
		||||
     *</ul>
 | 
			
		||||
     */
 | 
			
		||||
    public HoldCollection getHolds(String filePlanId, String parameters)
 | 
			
		||||
    {
 | 
			
		||||
        mandatoryString("filePlanId", filePlanId);
 | 
			
		||||
 | 
			
		||||
        return getRmRestWrapper().processModels(HoldCollection.class, simpleRequest(
 | 
			
		||||
            GET,
 | 
			
		||||
            "file-plans/{filePlanId}/holds?{parameters}",
 | 
			
		||||
            filePlanId,
 | 
			
		||||
            parameters
 | 
			
		||||
                                                                                   ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * See {@link #getHolds(String, String)}
 | 
			
		||||
     */
 | 
			
		||||
    public HoldCollection getHolds(String filePlanId)
 | 
			
		||||
    {
 | 
			
		||||
        return getHolds(filePlanId, EMPTY);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,290 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.requests.gscore.api;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.core.RestRequest.requestWithBody;
 | 
			
		||||
import static org.alfresco.rest.core.RestRequest.simpleRequest;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.ParameterCheck.mandatoryObject;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.ParameterCheck.mandatoryString;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.PojoUtility.toJson;
 | 
			
		||||
import static org.apache.commons.lang3.StringUtils.EMPTY;
 | 
			
		||||
import static org.springframework.http.HttpMethod.DELETE;
 | 
			
		||||
import static org.springframework.http.HttpMethod.GET;
 | 
			
		||||
import static org.springframework.http.HttpMethod.POST;
 | 
			
		||||
import static org.springframework.http.HttpMethod.PUT;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.core.RMRestWrapper;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.Hold;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldChildCollection;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldDeletionReason;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.RMModelRequest;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Holds REST API Wrapper
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
public class HoldsAPI extends RMModelRequest
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param rmRestWrapper
 | 
			
		||||
     */
 | 
			
		||||
    public HoldsAPI(RMRestWrapper rmRestWrapper)
 | 
			
		||||
    {
 | 
			
		||||
        super(rmRestWrapper);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets a hold.
 | 
			
		||||
     *
 | 
			
		||||
     * @param holdId The identifier of a hold
 | 
			
		||||
     * @param parameters The URL parameters to add
 | 
			
		||||
     * @return The {@link Hold} for the given {@code holdId}
 | 
			
		||||
     * @throws RuntimeException for the following cases:
 | 
			
		||||
     * <ul>
 | 
			
		||||
     *  <li>{@code holdId} is not a valid format</li>
 | 
			
		||||
     *  <li>authentication fails</li>
 | 
			
		||||
     *  <li>current user does not have permission to read {@code holdId}</li>
 | 
			
		||||
     *  <li>{@code holdId} does not exist</li>
 | 
			
		||||
     * </ul>
 | 
			
		||||
     */
 | 
			
		||||
    public Hold getHold(String holdId, String parameters)
 | 
			
		||||
    {
 | 
			
		||||
        mandatoryString("holdId", holdId);
 | 
			
		||||
 | 
			
		||||
        return getRmRestWrapper().processModel(Hold.class, simpleRequest(
 | 
			
		||||
            GET,
 | 
			
		||||
            "holds/{holdId}?{parameters}",
 | 
			
		||||
            holdId,
 | 
			
		||||
            parameters
 | 
			
		||||
                                                                        ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * See {@link #getHold(String, String)}
 | 
			
		||||
     */
 | 
			
		||||
    public Hold getHold(String holdId)
 | 
			
		||||
    {
 | 
			
		||||
        mandatoryString("holdId", holdId);
 | 
			
		||||
 | 
			
		||||
        return getHold(holdId, EMPTY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates a hold.
 | 
			
		||||
     *
 | 
			
		||||
     * @param holdModel     The hold model which holds the information
 | 
			
		||||
     * @param holdId        The identifier of the hold
 | 
			
		||||
     * @param parameters          The URL parameters to add
 | 
			
		||||
     * @throws RuntimeException for the following cases:
 | 
			
		||||
     * <ul>
 | 
			
		||||
     *  <li>the update request is invalid or {@code holdId} is not a valid format or {@code holdModel} is invalid</li>
 | 
			
		||||
     *  <li>authentication fails</li>
 | 
			
		||||
     *  <li>current user does not have permission to update {@code holdId}</li>
 | 
			
		||||
     *  <li>{@code holdId} does not exist</li>
 | 
			
		||||
     * </ul>
 | 
			
		||||
     */
 | 
			
		||||
    public Hold updateHold(Hold holdModel, String holdId, String parameters)
 | 
			
		||||
    {
 | 
			
		||||
        mandatoryObject("holdModel", holdModel);
 | 
			
		||||
        mandatoryString("holdId", holdId);
 | 
			
		||||
 | 
			
		||||
        return getRmRestWrapper().processModel(Hold.class, requestWithBody(
 | 
			
		||||
            PUT,
 | 
			
		||||
            toJson(holdModel),
 | 
			
		||||
            "holds/{holdId}?{parameters}",
 | 
			
		||||
            holdId,
 | 
			
		||||
            parameters
 | 
			
		||||
                                                                            ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * See {@link #updateHold(Hold, String, String)}
 | 
			
		||||
     */
 | 
			
		||||
    public Hold updateHold(Hold holdModel, String holdId)
 | 
			
		||||
    {
 | 
			
		||||
        mandatoryObject("holdModel", holdModel);
 | 
			
		||||
        mandatoryString("holdId", holdId);
 | 
			
		||||
 | 
			
		||||
        return updateHold(holdModel, holdId, EMPTY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deletes a hold.
 | 
			
		||||
     *
 | 
			
		||||
     * @param holdId The identifier of a hold
 | 
			
		||||
     * @throws RuntimeException for the following cases:
 | 
			
		||||
     * <ul>
 | 
			
		||||
     *  <li>{@code holdId} is not a valid format</li>
 | 
			
		||||
     *  <li>authentication fails</li>
 | 
			
		||||
     *  <li>current user does not have permission to delete {@code holdId}</li>
 | 
			
		||||
     *  <li>{@code holdId} does not exist</li>
 | 
			
		||||
     * </ul>
 | 
			
		||||
     */
 | 
			
		||||
    public void deleteHold(String holdId)
 | 
			
		||||
    {
 | 
			
		||||
        mandatoryString("holdId", holdId);
 | 
			
		||||
 | 
			
		||||
        getRmRestWrapper().processEmptyModel(simpleRequest(
 | 
			
		||||
            DELETE,
 | 
			
		||||
            "holds/{holdId}",
 | 
			
		||||
            holdId
 | 
			
		||||
                                                          ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deletes a hold and stores a reason for deletion in the audit log.
 | 
			
		||||
     *
 | 
			
		||||
     * @param reason        The reason for hold deletion
 | 
			
		||||
     * @param holdId        The identifier of a hold
 | 
			
		||||
     * @throws RuntimeException for the following cases:
 | 
			
		||||
     * <ul>
 | 
			
		||||
     *  <li>{@code holdId} is not a valid format or {@code reason} is invalid</li>
 | 
			
		||||
     *  <li>authentication fails</li>
 | 
			
		||||
     *  <li>current user does not have permission to delete {@code holdId}</li>
 | 
			
		||||
     *  <li>{@code holdId} does not exist</li>
 | 
			
		||||
     * </ul>
 | 
			
		||||
     */
 | 
			
		||||
    public HoldDeletionReason deleteHoldWithReason(HoldDeletionReason reason, String holdId)
 | 
			
		||||
    {
 | 
			
		||||
        mandatoryObject("reason", reason);
 | 
			
		||||
        mandatoryString("holdId", holdId);
 | 
			
		||||
 | 
			
		||||
        return getRmRestWrapper().processModel(HoldDeletionReason.class, requestWithBody(
 | 
			
		||||
            POST,
 | 
			
		||||
            toJson(reason),
 | 
			
		||||
            "holds/{holdId}/delete",
 | 
			
		||||
            holdId
 | 
			
		||||
                                                          ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Adds the relationship between a child and a parent hold.
 | 
			
		||||
     *
 | 
			
		||||
     * @param holdChild The hold child model
 | 
			
		||||
     * @param holdId The identifier of a hold
 | 
			
		||||
     * @param parameters The URL parameters to add
 | 
			
		||||
     * @return The created {@link Hold}
 | 
			
		||||
     * @throws RuntimeException for the following cases:
 | 
			
		||||
     * <ul>
 | 
			
		||||
     *  <li>{@code holdId} is not a valid format or {@code holdId} is invalid</li>
 | 
			
		||||
     *  <li>authentication fails</li>
 | 
			
		||||
     *  <li>current user does not have permission to add children to {@code holdId}</li>
 | 
			
		||||
     *  <li>{@code holdId} does not exist</li>
 | 
			
		||||
     * </ul>
 | 
			
		||||
     */
 | 
			
		||||
    public HoldChild addChildToHold(HoldChild holdChild, String holdId, String parameters)
 | 
			
		||||
    {
 | 
			
		||||
        mandatoryObject("holdId", holdId);
 | 
			
		||||
 | 
			
		||||
        return getRmRestWrapper().processModel(HoldChild.class, requestWithBody(
 | 
			
		||||
            POST,
 | 
			
		||||
            toJson(holdChild),
 | 
			
		||||
            "holds/{holdId}/children",
 | 
			
		||||
            holdId,
 | 
			
		||||
            parameters));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * See {@link #addChildToHold(HoldChild, String, String)}
 | 
			
		||||
     */
 | 
			
		||||
    public HoldChild addChildToHold(HoldChild holdChild, String holdId)
 | 
			
		||||
    {
 | 
			
		||||
        return addChildToHold(holdChild, holdId, EMPTY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Gets the children of a hold.
 | 
			
		||||
     *
 | 
			
		||||
     * @param holdId The identifier of a hold
 | 
			
		||||
     * @param parameters The URL parameters to add
 | 
			
		||||
     * @return The {@link HoldChildCollection} for the given {@code holdId}
 | 
			
		||||
     * @throws RuntimeException for the following cases:
 | 
			
		||||
     * <ul>
 | 
			
		||||
     *  <li>authentication fails</li>
 | 
			
		||||
     *  <li>current user does not have permission to read {@code holdId}</li>
 | 
			
		||||
     *  <li>{@code holdId} does not exist</li>
 | 
			
		||||
     *</ul>
 | 
			
		||||
     */
 | 
			
		||||
    public HoldChildCollection getChildren(String holdId, String parameters)
 | 
			
		||||
    {
 | 
			
		||||
        mandatoryString("holdId", holdId);
 | 
			
		||||
 | 
			
		||||
        return getRmRestWrapper().processModels(HoldChildCollection.class, simpleRequest(
 | 
			
		||||
            GET,
 | 
			
		||||
            "holds/{holdId}/children",
 | 
			
		||||
            holdId,
 | 
			
		||||
            parameters
 | 
			
		||||
                                                                                   ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * See {@link #getChildren(String, String)}
 | 
			
		||||
     */
 | 
			
		||||
    public HoldChildCollection getChildren(String holdId)
 | 
			
		||||
    {
 | 
			
		||||
        return getChildren(holdId, EMPTY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deletes the relationship between a child and a parent hold.
 | 
			
		||||
     *
 | 
			
		||||
     * @param holdChildId The identifier of hold child
 | 
			
		||||
     * @param holdId The identifier of a hold
 | 
			
		||||
     * @param parameters The URL parameters to add
 | 
			
		||||
     * @throws RuntimeException for the following cases:
 | 
			
		||||
     * <ul>
 | 
			
		||||
     *  <li>{@code holdId} or {@code holdChildId} is invalid</li>
 | 
			
		||||
     *  <li>authentication fails</li>
 | 
			
		||||
     *  <li>current user does not have permission to delete children from {@code holdId}</li>
 | 
			
		||||
     *  <li>{@code holdId} does not exist</li>
 | 
			
		||||
     * </ul>
 | 
			
		||||
     */
 | 
			
		||||
    public void deleteHoldChild(String holdId, String holdChildId, String parameters)
 | 
			
		||||
    {
 | 
			
		||||
        mandatoryString("holdId", holdId);
 | 
			
		||||
        mandatoryString("holdChildId", holdChildId);
 | 
			
		||||
 | 
			
		||||
        getRmRestWrapper().processEmptyModel(simpleRequest(
 | 
			
		||||
            DELETE,
 | 
			
		||||
            "holds/{holdId}/children/{holdChildId}",
 | 
			
		||||
            holdId,
 | 
			
		||||
            holdChildId,
 | 
			
		||||
            parameters
 | 
			
		||||
                                                          ));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * See {@link #deleteHoldChild(String, String, String)}
 | 
			
		||||
     */
 | 
			
		||||
    public void deleteHoldChild(String holdId, String holdChildId)
 | 
			
		||||
    {
 | 
			
		||||
        deleteHoldChild(holdId, holdChildId, EMPTY);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -36,7 +36,7 @@ import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.core.v0.APIUtils;
 | 
			
		||||
import org.alfresco.rest.core.v0.BaseAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldEntry;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.v0.HoldEntry;
 | 
			
		||||
import org.alfresco.rest.rm.community.util.PojoUtility;
 | 
			
		||||
import org.alfresco.utility.model.UserModel;
 | 
			
		||||
import org.apache.http.HttpResponse;
 | 
			
		||||
 
 | 
			
		||||
@@ -31,18 +31,18 @@ import static java.util.Arrays.asList;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.ADD_TO_HOLD;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.RMSiteUtil.FILE_PLAN_PATH;
 | 
			
		||||
import static org.alfresco.utility.Utility.buildPath;
 | 
			
		||||
import static org.alfresco.utility.Utility.removeLastSlash;
 | 
			
		||||
import static org.alfresco.utility.data.RandomData.getRandomName;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.apache.commons.httpclient.HttpStatus.SC_INTERNAL_SERVER_ERROR;
 | 
			
		||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
 | 
			
		||||
import static org.testng.AssertJUnit.assertEquals;
 | 
			
		||||
import static org.testng.AssertJUnit.assertTrue;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableMap;
 | 
			
		||||
@@ -50,12 +50,13 @@ import com.google.common.collect.ImmutableMap;
 | 
			
		||||
import org.alfresco.dataprep.CMISUtil;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.Hold;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.record.Record;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.user.UserPermissions;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.user.UserRoles;
 | 
			
		||||
import org.alfresco.rest.v0.HoldsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.RMAuditService;
 | 
			
		||||
import org.alfresco.rest.v0.service.RoleService;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
@@ -85,8 +86,6 @@ public class AuditAddToHoldTests extends BaseRMRestTest
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMAuditService rmAuditService;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private HoldsAPI holdsAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RoleService roleService;
 | 
			
		||||
 | 
			
		||||
    private UserModel rmAdmin, rmManagerNoReadOnHold, rmManagerNoReadOnNode;
 | 
			
		||||
@@ -94,17 +93,22 @@ public class AuditAddToHoldTests extends BaseRMRestTest
 | 
			
		||||
    private RecordCategory recordCategory;
 | 
			
		||||
    private RecordCategoryChild recordFolder;
 | 
			
		||||
    private List<AuditEntry> auditEntries;
 | 
			
		||||
    private final List<String> holdsList = asList(HOLD1, HOLD2);
 | 
			
		||||
    private List<String> holdsListRef = new ArrayList<>();
 | 
			
		||||
    private String hold1NodeRef;
 | 
			
		||||
    private String hold2NodeRef;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass (alwaysRun = true)
 | 
			
		||||
    public void preconditionForAuditAddToHoldTests()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create 2 holds.");
 | 
			
		||||
        hold1NodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(),
 | 
			
		||||
                getAdminUser().getPassword(), HOLD1, HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        String hold2NodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        hold1NodeRef = getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(HOLD1).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
 | 
			
		||||
            .getId();
 | 
			
		||||
        hold2NodeRef = getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(HOLD2).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
 | 
			
		||||
            .getId();
 | 
			
		||||
        holdsListRef = asList(hold1NodeRef, hold2NodeRef);
 | 
			
		||||
 | 
			
		||||
        STEP("Create a new record category with a record folder.");
 | 
			
		||||
@@ -169,7 +173,8 @@ public class AuditAddToHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Add node to hold.");
 | 
			
		||||
        holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), nodeId, HOLD1);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(nodeId).build(), hold1NodeRef);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        STEP("Check the audit log contains the entry for the add to hold event.");
 | 
			
		||||
        rmAuditService.checkAuditLogForEvent(getAdminUser(), ADD_TO_HOLD, rmAdmin, nodeName, nodePath,
 | 
			
		||||
@@ -191,9 +196,8 @@ public class AuditAddToHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Try to add the record to a hold by an user with no rights.");
 | 
			
		||||
        holdsAPI.addItemsToHolds(rmManagerNoReadOnHold.getUsername(), rmManagerNoReadOnHold.getPassword(),
 | 
			
		||||
                SC_INTERNAL_SERVER_ERROR, Collections.singletonList(recordToBeAdded.getId()),
 | 
			
		||||
                Collections.singletonList(hold1NodeRef));
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmManagerNoReadOnHold).addChildToHold(HoldChild.builder().id(recordToBeAdded.getId()).build(), hold1NodeRef);
 | 
			
		||||
        assertStatusCode(FORBIDDEN);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the audit log doesn't contain the entry for the unsuccessful add to hold.");
 | 
			
		||||
        assertTrue("The list of events should not contain Add to Hold entry ",
 | 
			
		||||
@@ -215,7 +219,7 @@ public class AuditAddToHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Add record folder to hold.");
 | 
			
		||||
        holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), notEmptyRecFolder.getId(), HOLD1);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(notEmptyRecFolder.getId()).build(), hold1NodeRef);
 | 
			
		||||
 | 
			
		||||
        auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getAdminUser(), ADD_TO_HOLD);
 | 
			
		||||
 | 
			
		||||
@@ -239,8 +243,9 @@ public class AuditAddToHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Add record to multiple holds.");
 | 
			
		||||
        holdsAPI.addItemsToHolds(rmAdmin.getUsername(), rmAdmin.getPassword(),
 | 
			
		||||
                Collections.singletonList(recordToBeAdded.getId()), holdsList);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(recordToBeAdded.getId()).build(), hold1NodeRef);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(recordToBeAdded.getId()).build(), hold2NodeRef);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getAdminUser(), ADD_TO_HOLD);
 | 
			
		||||
 | 
			
		||||
@@ -268,7 +273,7 @@ public class AuditAddToHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Add file to hold.");
 | 
			
		||||
        holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), contentToBeAdded.getNodeRefWithoutVersion(), HOLD1);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(contentToBeAdded.getNodeRefWithoutVersion()).build(), hold1NodeRef);
 | 
			
		||||
 | 
			
		||||
        STEP("Check that an user with no Read permissions can't see the entry for the add to hold event.");
 | 
			
		||||
        assertTrue("The list of events should not contain Add to Hold entry ",
 | 
			
		||||
@@ -289,7 +294,7 @@ public class AuditAddToHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Add file to hold.");
 | 
			
		||||
        holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), contentToBeAdded.getNodeRefWithoutVersion(), HOLD1);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(contentToBeAdded.getNodeRefWithoutVersion()).build(), hold1NodeRef);
 | 
			
		||||
 | 
			
		||||
        auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(rmManagerNoReadOnHold, ADD_TO_HOLD);
 | 
			
		||||
 | 
			
		||||
@@ -304,7 +309,8 @@ public class AuditAddToHoldTests extends BaseRMRestTest
 | 
			
		||||
    @AfterClass (alwaysRun = true)
 | 
			
		||||
    public void cleanUpAuditAddToHoldTests()
 | 
			
		||||
    {
 | 
			
		||||
        holdsListRef.forEach(holdRef -> holdsAPI.deleteHold(getAdminUser(), holdRef));
 | 
			
		||||
        holdsListRef.forEach(holdRef -> getRestAPIFactory().getHoldsAPI(getAdminUser()).deleteHold(holdRef));
 | 
			
		||||
 | 
			
		||||
        dataSite.usingAdmin().deleteSite(privateSite);
 | 
			
		||||
        asList(rmAdmin, rmManagerNoReadOnHold, rmManagerNoReadOnNode).forEach(user -> getDataUser().usingAdmin().deleteUser(user));
 | 
			
		||||
        deleteRecordCategory(recordCategory.getId());
 | 
			
		||||
 
 | 
			
		||||
@@ -31,9 +31,10 @@ import static java.util.Arrays.asList;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.CREATE_HOLD;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.apache.commons.httpclient.HttpStatus.SC_INTERNAL_SERVER_ERROR;
 | 
			
		||||
import static org.springframework.http.HttpStatus.CONFLICT;
 | 
			
		||||
import static org.testng.AssertJUnit.assertEquals;
 | 
			
		||||
import static org.testng.AssertJUnit.assertTrue;
 | 
			
		||||
 | 
			
		||||
@@ -44,8 +45,8 @@ import com.google.common.collect.ImmutableMap;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.Hold;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.user.UserRoles;
 | 
			
		||||
import org.alfresco.rest.v0.HoldsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.RMAuditService;
 | 
			
		||||
import org.alfresco.rest.v0.service.RoleService;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
@@ -73,8 +74,6 @@ public class AuditCreateHoldTests extends BaseRMRestTest
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMAuditService rmAuditService;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private HoldsAPI holdsAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RoleService roleService;
 | 
			
		||||
 | 
			
		||||
    private UserModel rmAdmin, rmManager;
 | 
			
		||||
@@ -102,8 +101,10 @@ public class AuditCreateHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a new hold.");
 | 
			
		||||
        String hold1NodeRef = holdsAPI.createHoldAndGetNodeRef(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD1,
 | 
			
		||||
                HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        String hold1NodeRef = getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(HOLD1).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
 | 
			
		||||
            .getId();
 | 
			
		||||
        holdsListRef.add(hold1NodeRef);
 | 
			
		||||
        STEP("Check the audit log contains the entry for the created hold with the hold details.");
 | 
			
		||||
        rmAuditService.checkAuditLogForEvent(getAdminUser(), CREATE_HOLD, rmAdmin, HOLD1,
 | 
			
		||||
@@ -120,13 +121,18 @@ public class AuditCreateHoldTests extends BaseRMRestTest
 | 
			
		||||
    public void createHoldEventIsNotAuditedForExistingHold()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a new hold.");
 | 
			
		||||
        String hold2NodeRef = holdsAPI.createHoldAndGetNodeRef(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        String hold2NodeRef = getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(HOLD2).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
 | 
			
		||||
            .getId();
 | 
			
		||||
        holdsListRef.add(hold2NodeRef);
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Try to create again the same hold and expect action to fail.");
 | 
			
		||||
        holdsAPI.createHold(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION,
 | 
			
		||||
                SC_INTERNAL_SERVER_ERROR);
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(HOLD2).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
 | 
			
		||||
        assertStatusCode(CONFLICT);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the audit log doesn't contain the entry for the second create hold event.");
 | 
			
		||||
        assertTrue("The list of events should not contain Create Hold entry ",
 | 
			
		||||
@@ -145,13 +151,17 @@ public class AuditCreateHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a new hold.");
 | 
			
		||||
        holdsAPI.createHold(rmAdmin.getUsername(), rmAdmin.getPassword(), holdName, HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        String nodeRef = getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(holdName).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS).getId();
 | 
			
		||||
 | 
			
		||||
        STEP("Get the list of audit entries for the create hold event.");
 | 
			
		||||
        List<AuditEntry> auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getAdminUser(), CREATE_HOLD);
 | 
			
		||||
 | 
			
		||||
        STEP("Delete the created hold.");
 | 
			
		||||
        holdsAPI.deleteHold(rmAdmin.getUsername(), rmAdmin.getPassword(), holdName);
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getHoldsAPI(rmAdmin)
 | 
			
		||||
            .deleteHold(nodeRef);
 | 
			
		||||
 | 
			
		||||
        STEP("Get again the list of audit entries for the create hold event.");
 | 
			
		||||
        List<AuditEntry> auditEntriesAfterDelete = rmAuditService.getAuditEntriesFilteredByEvent(getAdminUser(), CREATE_HOLD);
 | 
			
		||||
@@ -171,8 +181,10 @@ public class AuditCreateHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a new hold.");
 | 
			
		||||
        String hold3NodeRef = holdsAPI.createHoldAndGetNodeRef(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD3,
 | 
			
		||||
                HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        String hold3NodeRef = getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(HOLD3).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS).getId();
 | 
			
		||||
 | 
			
		||||
        holdsListRef.add(hold3NodeRef);
 | 
			
		||||
 | 
			
		||||
        STEP("Check that an user with no Read permissions over the hold can't see the entry for the create hold event");
 | 
			
		||||
@@ -183,7 +195,7 @@ public class AuditCreateHoldTests extends BaseRMRestTest
 | 
			
		||||
    @AfterClass (alwaysRun = true)
 | 
			
		||||
    public void cleanUpAuditCreateHoldTests()
 | 
			
		||||
    {
 | 
			
		||||
        holdsListRef.forEach(holdRef -> holdsAPI.deleteHold(getAdminUser(), holdRef));
 | 
			
		||||
        holdsListRef.forEach(holdRef -> getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHold(holdRef));
 | 
			
		||||
        asList(rmAdmin, rmManager).forEach(user -> getDataUser().usingAdmin().deleteUser(user));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -31,18 +31,20 @@ import static java.util.Arrays.asList;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.DELETE_HOLD;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.apache.commons.httpclient.HttpStatus.SC_INTERNAL_SERVER_ERROR;
 | 
			
		||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
 | 
			
		||||
import static org.testng.AssertJUnit.assertTrue;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableMap;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.Hold;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldDeletionReason;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.user.UserRoles;
 | 
			
		||||
import org.alfresco.rest.v0.HoldsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.RMAuditService;
 | 
			
		||||
import org.alfresco.rest.v0.service.RoleService;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
@@ -62,14 +64,13 @@ import org.testng.annotations.Test;
 | 
			
		||||
public class AuditDeleteHoldTests extends BaseRMRestTest
 | 
			
		||||
{
 | 
			
		||||
    private final String PREFIX = generateTestPrefix(AuditDeleteHoldTests.class);
 | 
			
		||||
    private final String HOLD = PREFIX + "holdToBeDeleted";
 | 
			
		||||
    private final String HOLD2 = PREFIX + "deleteHold";
 | 
			
		||||
    private final String hold = PREFIX + "holdToBeDeleted";
 | 
			
		||||
    private final String hold2 = PREFIX + "deleteHold";
 | 
			
		||||
    private final String hold3 = PREFIX + "deleteHoldWithReason";
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMAuditService rmAuditService;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private HoldsAPI holdsAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RoleService roleService;
 | 
			
		||||
 | 
			
		||||
    private UserModel rmAdmin, rmManager;
 | 
			
		||||
@@ -79,8 +80,10 @@ public class AuditDeleteHoldTests extends BaseRMRestTest
 | 
			
		||||
    public void preconditionForAuditDeleteHoldTests()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a new hold.");
 | 
			
		||||
        holdNodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD,
 | 
			
		||||
                HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        holdNodeRef = getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(hold).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
 | 
			
		||||
            .getId();
 | 
			
		||||
 | 
			
		||||
        STEP("Create 2 users with different permissions for the created hold.");
 | 
			
		||||
        rmAdmin = roleService.createUserWithRMRole(UserRoles.ROLE_RM_ADMIN.roleId);
 | 
			
		||||
@@ -99,17 +102,51 @@ public class AuditDeleteHoldTests extends BaseRMRestTest
 | 
			
		||||
    public void deleteHoldEventIsAudited()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a new hold.");
 | 
			
		||||
        String holdRef = holdsAPI.createHoldAndGetNodeRef(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD2,
 | 
			
		||||
                HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        String holdRef = getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(hold2).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
 | 
			
		||||
            .getId();
 | 
			
		||||
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Delete the created hold.");
 | 
			
		||||
        holdsAPI.deleteHold(rmAdmin, holdRef);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHold(holdRef);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the audit log contains the entry for the deleted hold with the hold details.");
 | 
			
		||||
        rmAuditService.checkAuditLogForEvent(getAdminUser(), DELETE_HOLD, rmAdmin, HOLD2,
 | 
			
		||||
                Collections.singletonList(ImmutableMap.of("new", "", "previous", HOLD2, "name", "Hold Name")));
 | 
			
		||||
        rmAuditService.checkAuditLogForEvent(getAdminUser(), DELETE_HOLD, rmAdmin, hold2,
 | 
			
		||||
                List.of(ImmutableMap.of("new", "", "previous", hold2, "name", "Hold Name"),
 | 
			
		||||
                    ImmutableMap.of("new", "", "previous", "", "name", "Hold deletion reason")));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given a hold is deleted with a reason
 | 
			
		||||
     * When I view the audit log
 | 
			
		||||
     * Then an entry has been created in the audit log which contains the following:
 | 
			
		||||
     *      name of the hold
 | 
			
		||||
     *      hold deletion reason
 | 
			
		||||
     *      user who deleted the hold
 | 
			
		||||
     *      date the delete occurred
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void deleteHoldWithReasonEventIsAudited()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a new hold.");
 | 
			
		||||
        String holdRef = getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(hold3).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
 | 
			
		||||
            .getId();
 | 
			
		||||
 | 
			
		||||
        String deletionReason = "Test reason";
 | 
			
		||||
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Delete the created hold with a reason.");
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldWithReason(HoldDeletionReason.builder().reason(deletionReason).build(), holdRef);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the audit log contains the entry for the deleted hold with the hold details.");
 | 
			
		||||
        rmAuditService.checkAuditLogForEvent(getAdminUser(), DELETE_HOLD, rmAdmin, hold3,
 | 
			
		||||
            List.of(ImmutableMap.of("new", "", "previous", hold3, "name", "Hold Name"),
 | 
			
		||||
                ImmutableMap.of("new", "", "previous", deletionReason, "name", "Hold deletion reason")));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -123,7 +160,8 @@ public class AuditDeleteHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Try to delete a hold by an user with no Read permissions over the hold.");
 | 
			
		||||
        holdsAPI.deleteHold(rmManager.getUsername(), rmManager.getPassword(), holdNodeRef, SC_INTERNAL_SERVER_ERROR);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmManager).deleteHold(holdNodeRef);
 | 
			
		||||
        assertStatusCode(FORBIDDEN);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the audit log doesn't contain the entry for the unsuccessful delete hold.");
 | 
			
		||||
        assertTrue("The list of events should not contain Delete Hold entry ",
 | 
			
		||||
@@ -133,7 +171,7 @@ public class AuditDeleteHoldTests extends BaseRMRestTest
 | 
			
		||||
    @AfterClass (alwaysRun = true)
 | 
			
		||||
    public void cleanUpAuditDeleteHoldTests()
 | 
			
		||||
    {
 | 
			
		||||
        holdsAPI.deleteHold(getAdminUser(), holdNodeRef);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmManager).deleteHold(holdNodeRef);
 | 
			
		||||
        asList(rmAdmin, rmManager).forEach(user -> getDataUser().usingAdmin().deleteUser(user));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,10 +25,14 @@
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.audit;
 | 
			
		||||
 | 
			
		||||
import static java.util.Arrays.asList;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.*;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.ADD_TO_HOLD;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.REMOVE_FROM_HOLD;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.utility.data.RandomData.getRandomName;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
@@ -37,20 +41,22 @@ import static org.hamcrest.MatcherAssert.assertThat;
 | 
			
		||||
import static org.hamcrest.Matchers.empty;
 | 
			
		||||
import static org.hamcrest.core.IsNot.not;
 | 
			
		||||
import static org.springframework.http.HttpStatus.CREATED;
 | 
			
		||||
import static org.testng.AssertJUnit.*;
 | 
			
		||||
import static org.testng.AssertJUnit.assertFalse;
 | 
			
		||||
import static org.testng.AssertJUnit.assertTrue;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.dataprep.CMISUtil;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.audit.AuditEvents;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.Hold;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.record.Record;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolder;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.user.UserRoles;
 | 
			
		||||
import org.alfresco.rest.v0.HoldsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.RMAuditService;
 | 
			
		||||
import org.alfresco.rest.v0.service.RoleService;
 | 
			
		||||
import org.alfresco.utility.model.FileModel;
 | 
			
		||||
@@ -69,8 +75,6 @@ public class AuditHoldsTest extends BaseRMRestTest {
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMAuditService rmAuditService;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private HoldsAPI holdsAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RoleService roleService;
 | 
			
		||||
    private UserModel rmAdmin;
 | 
			
		||||
    private RecordCategory recordCategory;
 | 
			
		||||
@@ -85,8 +89,11 @@ public class AuditHoldsTest extends BaseRMRestTest {
 | 
			
		||||
        rmAdmin = roleService.createUserWithRMRole(UserRoles.ROLE_RM_ADMIN.roleId);
 | 
			
		||||
 | 
			
		||||
        STEP("Create a hold");
 | 
			
		||||
        hold1NodeRef = holdsAPI.createHoldAndGetNodeRef(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD1, HOLD_REASON,
 | 
			
		||||
            HOLD_DESCRIPTION);
 | 
			
		||||
 | 
			
		||||
        hold1NodeRef = getRestAPIFactory()
 | 
			
		||||
                .getFilePlansAPI(rmAdmin)
 | 
			
		||||
                .createHold(Hold.builder().name(HOLD1).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
 | 
			
		||||
                .getId();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a collaboration site with a test file.");
 | 
			
		||||
        publicSite = dataSite.usingAdmin().createPublicRandomSite();
 | 
			
		||||
@@ -101,9 +108,11 @@ public class AuditHoldsTest extends BaseRMRestTest {
 | 
			
		||||
 | 
			
		||||
        STEP("Add some items to the hold, then remove them from the hold");
 | 
			
		||||
        final List<String> itemsList = asList(testFile.getNodeRefWithoutVersion(), recordToBeAdded.getId(), recordFolder2.getId());
 | 
			
		||||
        final List<String> holdsList = Collections.singletonList(HOLD1);
 | 
			
		||||
        holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), recordToBeAdded.getId(), HOLD1);
 | 
			
		||||
        holdsAPI.removeItemsFromHolds(rmAdmin.getUsername(), rmAdmin.getPassword(), itemsList, holdsList);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(recordToBeAdded.getId()).build(), hold1NodeRef);
 | 
			
		||||
        for(String childId : itemsList)
 | 
			
		||||
        {
 | 
			
		||||
            getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold1NodeRef, childId);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        STEP("Delete the record folder that was held");
 | 
			
		||||
        getRestAPIFactory().getRecordFolderAPI().deleteRecordFolder(recordFolder2.getId());
 | 
			
		||||
 
 | 
			
		||||
@@ -31,18 +31,18 @@ import static java.util.Arrays.asList;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.REMOVE_FROM_HOLD;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.RMSiteUtil.FILE_PLAN_PATH;
 | 
			
		||||
import static org.alfresco.utility.Utility.buildPath;
 | 
			
		||||
import static org.alfresco.utility.Utility.removeLastSlash;
 | 
			
		||||
import static org.alfresco.utility.data.RandomData.getRandomName;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.apache.commons.httpclient.HttpStatus.SC_INTERNAL_SERVER_ERROR;
 | 
			
		||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
 | 
			
		||||
import static org.testng.AssertJUnit.assertEquals;
 | 
			
		||||
import static org.testng.AssertJUnit.assertTrue;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import com.google.common.collect.ImmutableMap;
 | 
			
		||||
@@ -50,12 +50,13 @@ import com.google.common.collect.ImmutableMap;
 | 
			
		||||
import org.alfresco.dataprep.CMISUtil;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.Hold;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.record.Record;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.user.UserPermissions;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.user.UserRoles;
 | 
			
		||||
import org.alfresco.rest.v0.HoldsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.RMAuditService;
 | 
			
		||||
import org.alfresco.rest.v0.service.RoleService;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
@@ -86,8 +87,6 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMAuditService rmAuditService;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private HoldsAPI holdsAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RoleService roleService;
 | 
			
		||||
 | 
			
		||||
    private UserModel rmAdmin, rmManagerNoReadOnHold, rmManagerNoReadOnNode;
 | 
			
		||||
@@ -96,10 +95,11 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
 | 
			
		||||
    private RecordCategoryChild recordFolder, heldRecordFolder;
 | 
			
		||||
    private Record heldRecord;
 | 
			
		||||
    private List<AuditEntry> auditEntries;
 | 
			
		||||
    private final List<String> holdsList = asList(HOLD1, HOLD2, HOLD3);
 | 
			
		||||
    private List<String> holdsListRef = new ArrayList<>();
 | 
			
		||||
    private FileModel heldContent;
 | 
			
		||||
    private String hold1NodeRef;
 | 
			
		||||
    private String hold2NodeRef;
 | 
			
		||||
    private String hold3NodeRef;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass (alwaysRun = true)
 | 
			
		||||
    public void preconditionForAuditRemoveFromHoldTests()
 | 
			
		||||
@@ -111,10 +111,18 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
 | 
			
		||||
        privateSite = dataSite.usingUser(rmAdmin).createPrivateRandomSite();
 | 
			
		||||
 | 
			
		||||
        STEP("Create new holds.");
 | 
			
		||||
        hold1NodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), getAdminUser().getPassword(),
 | 
			
		||||
                HOLD1, HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        String hold2NodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        String hold3NodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD3, HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        hold1NodeRef = getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(HOLD1).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
 | 
			
		||||
            .getId();
 | 
			
		||||
        hold2NodeRef = getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(HOLD2).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
 | 
			
		||||
            .getId();
 | 
			
		||||
        hold3NodeRef = getRestAPIFactory()
 | 
			
		||||
            .getFilePlansAPI(rmAdmin)
 | 
			
		||||
            .createHold(Hold.builder().name(HOLD3).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
 | 
			
		||||
            .getId();
 | 
			
		||||
        holdsListRef = asList(hold1NodeRef, hold2NodeRef, hold3NodeRef);
 | 
			
		||||
 | 
			
		||||
        STEP("Create a new record category with a record folder.");
 | 
			
		||||
@@ -127,9 +135,12 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
 | 
			
		||||
        heldRecordFolder = createRecordFolder(recordCategory.getId(), PREFIX + "heldRecFolder");
 | 
			
		||||
        heldRecord = createElectronicRecord(recordFolder.getId(), PREFIX + "record");
 | 
			
		||||
 | 
			
		||||
        holdsAPI.addItemsToHolds(getAdminUser().getUsername(), getAdminUser().getPassword(),
 | 
			
		||||
                asList(heldContent.getNodeRefWithoutVersion(), heldRecordFolder.getId(), heldRecord.getId()),
 | 
			
		||||
                holdsList);
 | 
			
		||||
        holdsListRef.forEach(holdRef ->
 | 
			
		||||
        {
 | 
			
		||||
            getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(heldContent.getNodeRefWithoutVersion()).build(), holdRef);
 | 
			
		||||
            getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(heldRecordFolder.getId()).build(), holdRef);
 | 
			
		||||
            getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(heldRecord.getId()).build(), holdRef);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        STEP("Create users without rights to remove content from a hold.");
 | 
			
		||||
        rmManagerNoReadOnHold = roleService.createUserWithSiteRoleRMRoleAndPermission(privateSite,
 | 
			
		||||
@@ -179,7 +190,7 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Remove node from hold.");
 | 
			
		||||
        holdsAPI.removeItemFromHold(rmAdmin.getUsername(), rmAdmin.getPassword(), nodeId, HOLD3);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold3NodeRef, nodeId);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the audit log contains the entry for the remove from hold event.");
 | 
			
		||||
        rmAuditService.checkAuditLogForEvent(getAdminUser(), REMOVE_FROM_HOLD, rmAdmin, nodeName, nodePath,
 | 
			
		||||
@@ -198,9 +209,8 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Try to remove the record from a hold by an user with no rights.");
 | 
			
		||||
        holdsAPI.removeItemsFromHolds(rmManagerNoReadOnHold.getUsername(), rmManagerNoReadOnHold.getPassword(),
 | 
			
		||||
                SC_INTERNAL_SERVER_ERROR, Collections.singletonList(heldRecord.getId()),
 | 
			
		||||
                Collections.singletonList(hold1NodeRef));
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmManagerNoReadOnHold).deleteHoldChild(hold1NodeRef, heldRecord.getId());
 | 
			
		||||
        assertStatusCode(FORBIDDEN);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the audit log doesn't contain the entry for the unsuccessful remove from hold.");
 | 
			
		||||
        assertTrue("The list of events should not contain remove from hold entry ",
 | 
			
		||||
@@ -220,12 +230,12 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
 | 
			
		||||
        Record record = createElectronicRecord(notEmptyRecFolder.getId(), PREFIX + "record");
 | 
			
		||||
 | 
			
		||||
        STEP("Add the record folder to a hold.");
 | 
			
		||||
        holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), notEmptyRecFolder.getId(), HOLD1);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(notEmptyRecFolder.getId()).build(), hold1NodeRef);
 | 
			
		||||
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Remove record folder from hold.");
 | 
			
		||||
        holdsAPI.removeItemFromHold(rmAdmin.getUsername(), rmAdmin.getPassword(), notEmptyRecFolder.getId(), HOLD1);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold1NodeRef, notEmptyRecFolder.getId());
 | 
			
		||||
 | 
			
		||||
        STEP("Get the list of audit entries for the remove from hold event.");
 | 
			
		||||
        auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getAdminUser(), REMOVE_FROM_HOLD);
 | 
			
		||||
@@ -247,8 +257,8 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Remove record folder from multiple holds.");
 | 
			
		||||
        holdsAPI.removeItemsFromHolds(rmAdmin.getUsername(), rmAdmin.getPassword(),
 | 
			
		||||
                Collections.singletonList(heldRecordFolder.getId()), asList(HOLD1, HOLD2));
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold1NodeRef, heldRecordFolder.getId());
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold2NodeRef, heldRecordFolder.getId());
 | 
			
		||||
 | 
			
		||||
        STEP("Get the list of audit entries for the remove from hold event.");
 | 
			
		||||
        auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getAdminUser(), REMOVE_FROM_HOLD);
 | 
			
		||||
@@ -275,12 +285,12 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
 | 
			
		||||
        STEP("Add content to a hold.");
 | 
			
		||||
        FileModel heldFile = dataContent.usingAdmin().usingSite(privateSite)
 | 
			
		||||
                                           .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
        holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), heldFile.getNodeRefWithoutVersion(), HOLD1);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(heldFile.getNodeRefWithoutVersion()).build(), hold1NodeRef);
 | 
			
		||||
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Remove held content from the hold.");
 | 
			
		||||
        holdsAPI.removeItemFromHold(rmAdmin.getUsername(), rmAdmin.getPassword(), heldFile.getNodeRefWithoutVersion(), HOLD1);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold1NodeRef, heldFile.getNodeRefWithoutVersion());
 | 
			
		||||
 | 
			
		||||
        STEP("Check that an user with no Read permissions can't see the entry for the remove from hold event.");
 | 
			
		||||
        assertTrue("The list of events should not contain Remove from Hold entry ",
 | 
			
		||||
@@ -298,12 +308,12 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
 | 
			
		||||
        STEP("Add content to a hold.");
 | 
			
		||||
        FileModel heldFile = dataContent.usingAdmin().usingSite(privateSite)
 | 
			
		||||
                                        .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
        holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), heldFile.getNodeRefWithoutVersion(), HOLD1);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(heldFile.getNodeRefWithoutVersion()).build(), hold1NodeRef);
 | 
			
		||||
 | 
			
		||||
        rmAuditService.clearAuditLog();
 | 
			
		||||
 | 
			
		||||
        STEP("Remove held content from the hold.");
 | 
			
		||||
        holdsAPI.removeItemFromHold(rmAdmin.getUsername(), rmAdmin.getPassword(), heldFile.getNodeRefWithoutVersion(), HOLD1);
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold1NodeRef, heldFile.getNodeRefWithoutVersion());
 | 
			
		||||
 | 
			
		||||
        auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(rmManagerNoReadOnHold, REMOVE_FROM_HOLD);
 | 
			
		||||
 | 
			
		||||
@@ -318,7 +328,7 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
 | 
			
		||||
    @AfterClass (alwaysRun = true)
 | 
			
		||||
    public void cleanUpAuditRemoveFromHoldTests()
 | 
			
		||||
    {
 | 
			
		||||
        holdsListRef.forEach(holdRef -> holdsAPI.deleteHold(getAdminUser(), holdRef));
 | 
			
		||||
        holdsListRef.forEach(holdRef -> getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHold(holdRef));
 | 
			
		||||
        dataSite.usingAdmin().deleteSite(privateSite);
 | 
			
		||||
        asList(rmAdmin, rmManagerNoReadOnHold, rmManagerNoReadOnNode).forEach(user -> getDataUser().usingAdmin().deleteUser(user));
 | 
			
		||||
        deleteRecordCategory(recordCategory.getId());
 | 
			
		||||
 
 | 
			
		||||
@@ -60,12 +60,15 @@ import static org.testng.Assert.fail;
 | 
			
		||||
import static org.testng.AssertJUnit.assertEquals;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.NoSuchElementException;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.DataProviderClass;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.fileplan.FilePlan;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.fileplan.FilePlanProperties;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.Hold;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldCollection;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryCollection;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryProperties;
 | 
			
		||||
@@ -514,5 +517,97 @@ public class FilePlanTests extends BaseRMRestTest
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * <pre>
 | 
			
		||||
     * Given that a file plan exists
 | 
			
		||||
     * When I ask the API to create a hold
 | 
			
		||||
     * Then it is created
 | 
			
		||||
     * </pre>
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void createHolds()
 | 
			
		||||
    {
 | 
			
		||||
        String holdName = "Hold" + getRandomAlphanumeric();
 | 
			
		||||
        String holdDescription = "Description" + getRandomAlphanumeric();
 | 
			
		||||
        String holdReason = "Reason" + getRandomAlphanumeric();
 | 
			
		||||
 | 
			
		||||
        // Create the hold
 | 
			
		||||
        Hold hold = Hold.builder()
 | 
			
		||||
            .name(holdName)
 | 
			
		||||
            .description(holdDescription)
 | 
			
		||||
            .reason(holdReason)
 | 
			
		||||
            .build();
 | 
			
		||||
        Hold createdHold = getRestAPIFactory().getFilePlansAPI()
 | 
			
		||||
            .createHold(hold, FILE_PLAN_ALIAS);
 | 
			
		||||
 | 
			
		||||
        // Verify the status code
 | 
			
		||||
        assertStatusCode(CREATED);
 | 
			
		||||
 | 
			
		||||
        assertEquals(createdHold.getName(), holdName);
 | 
			
		||||
        assertEquals(createdHold.getDescription(), holdDescription);
 | 
			
		||||
        assertEquals(createdHold.getReason(), holdReason);
 | 
			
		||||
        assertNotNull(createdHold.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void listHolds()
 | 
			
		||||
    {
 | 
			
		||||
        // Delete all holds
 | 
			
		||||
        getRestAPIFactory().getFilePlansAPI().getHolds(FILE_PLAN_ALIAS).getEntries().forEach(holdEntry ->
 | 
			
		||||
            getRestAPIFactory().getHoldsAPI().deleteHold(holdEntry.getEntry().getId()));
 | 
			
		||||
 | 
			
		||||
        // Add holds
 | 
			
		||||
        List<Hold> filePlanHolds = new ArrayList<>();
 | 
			
		||||
        for (int i = 0; i < NUMBER_OF_CHILDREN; i++)
 | 
			
		||||
        {
 | 
			
		||||
            String holdName = "Hold name " + getRandomAlphanumeric();
 | 
			
		||||
            String holdDescription = "Hold Description " + getRandomAlphanumeric();
 | 
			
		||||
            String holdReason = "Reason " + getRandomAlphanumeric();
 | 
			
		||||
            // Create a hold
 | 
			
		||||
            Hold hold = Hold.builder()
 | 
			
		||||
                .name(holdName)
 | 
			
		||||
                .description(holdDescription)
 | 
			
		||||
                .reason(holdReason)
 | 
			
		||||
                .build();
 | 
			
		||||
            Hold createdHold = getRestAPIFactory().getFilePlansAPI()
 | 
			
		||||
                .createHold(hold, FILE_PLAN_ALIAS);
 | 
			
		||||
            assertNotNull(createdHold.getId());
 | 
			
		||||
            filePlanHolds.add(createdHold);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Get holds of a file plan
 | 
			
		||||
        HoldCollection holdCollection = getRestAPIFactory().getFilePlansAPI()
 | 
			
		||||
            .getHolds(FILE_PLAN_ALIAS);
 | 
			
		||||
 | 
			
		||||
        // Check status code
 | 
			
		||||
        assertStatusCode(OK);
 | 
			
		||||
 | 
			
		||||
        // Check holds against created list
 | 
			
		||||
        holdCollection.getEntries().forEach(c ->
 | 
			
		||||
            {
 | 
			
		||||
                Hold hold = c.getEntry();
 | 
			
		||||
                String holdId = hold.getId();
 | 
			
		||||
                assertNotNull(holdId);
 | 
			
		||||
                logger.info("Checking hold " + holdId);
 | 
			
		||||
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    // Find this hold in created holds list
 | 
			
		||||
                    Hold createdHold = filePlanHolds.stream()
 | 
			
		||||
                        .filter(child -> child.getId().equals(holdId))
 | 
			
		||||
                        .findFirst()
 | 
			
		||||
                        .orElseThrow();
 | 
			
		||||
 | 
			
		||||
                    assertEquals(createdHold.getName(), hold.getName());
 | 
			
		||||
                    assertEquals(createdHold.getDescription(), hold.getDescription());
 | 
			
		||||
                    assertEquals(createdHold.getReason(), hold.getReason());
 | 
			
		||||
                }
 | 
			
		||||
                catch (NoSuchElementException e)
 | 
			
		||||
                {
 | 
			
		||||
                    fail("No child element for " + hold);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
                                                   );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ import org.alfresco.dataprep.CMISUtil;
 | 
			
		||||
import org.alfresco.dataprep.ContentActions;
 | 
			
		||||
import org.alfresco.rest.model.RestNodeModel;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldEntry;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.v0.HoldEntry;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.record.Record;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,386 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.hold;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.TRANSFERS_ALIAS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAspects.FROZEN_ASPECT;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.UNFILED_RECORD_FOLDER_TYPE;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_READ_RECORDS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_MANAGER;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.CoreUtil.toContentModel;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.IMAGE_FILE;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createElectronicRecordModel;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createNonElectronicRecordModel;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.getFile;
 | 
			
		||||
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.apache.commons.httpclient.HttpStatus.SC_BAD_REQUEST;
 | 
			
		||||
import static org.springframework.http.HttpStatus.CREATED;
 | 
			
		||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
 | 
			
		||||
import static org.testng.Assert.assertEquals;
 | 
			
		||||
import static org.testng.Assert.assertTrue;
 | 
			
		||||
import static org.testng.AssertJUnit.assertFalse;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.dataprep.CMISUtil;
 | 
			
		||||
import org.alfresco.dataprep.ContentActions;
 | 
			
		||||
import org.alfresco.rest.model.RestNodeAssociationModelCollection;
 | 
			
		||||
import org.alfresco.rest.model.RestNodeModel;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.Hold;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.record.Record;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.user.UserRoles;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.RoleService;
 | 
			
		||||
import org.alfresco.utility.constants.UserRole;
 | 
			
		||||
import org.alfresco.utility.model.FileModel;
 | 
			
		||||
import org.alfresco.utility.model.SiteModel;
 | 
			
		||||
import org.alfresco.utility.model.UserModel;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.testng.annotations.AfterClass;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.DataProvider;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * V1 API tests for adding content/record folder/records to holds
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
public class AddToHoldsV1Tests extends BaseRMRestTest
 | 
			
		||||
{
 | 
			
		||||
    private static final String ACCESS_DENIED_ERROR_MESSAGE = "Access Denied.  You do not have the appropriate " +
 | 
			
		||||
        "permissions to perform this operation.";
 | 
			
		||||
    private static final String INVALID_TYPE_ERROR_MESSAGE = "Only records, record folders or content can be added to a hold.";
 | 
			
		||||
    private static final String LOCKED_FILE_ERROR_MESSAGE = "Locked content can't be added to a hold.";
 | 
			
		||||
 | 
			
		||||
    private static final String HOLD = "HOLD" + generateTestPrefix(AddToHoldsV1Tests.class);
 | 
			
		||||
    private String holdNodeRef;
 | 
			
		||||
    private SiteModel testSite;
 | 
			
		||||
    private FileModel documentHeld;
 | 
			
		||||
    private FileModel contentToAddToHold;
 | 
			
		||||
    private FileModel contentAddToHoldNoPermission;
 | 
			
		||||
    private Hold hold;
 | 
			
		||||
 | 
			
		||||
    private UserModel userAddHoldPermission;
 | 
			
		||||
    private final List<UserModel> users = new ArrayList<>();
 | 
			
		||||
    private final List<String> nodesToBeClean = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RoleService roleService;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private ContentActions contentActions;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass(alwaysRun = true)
 | 
			
		||||
    public void preconditionForAddContentToHold()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a hold.");
 | 
			
		||||
        hold = createHold(FILE_PLAN_ALIAS,
 | 
			
		||||
            Hold.builder().name(HOLD).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), getAdminUser());
 | 
			
		||||
        holdNodeRef = hold.getId();
 | 
			
		||||
        STEP("Create test files.");
 | 
			
		||||
        testSite = dataSite.usingAdmin().createPublicRandomSite();
 | 
			
		||||
        documentHeld = dataContent.usingAdmin().usingSite(testSite)
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
        contentToAddToHold = dataContent.usingAdmin().usingSite(testSite)
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
        contentAddToHoldNoPermission = dataContent.usingAdmin().usingSite(testSite)
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
 | 
			
		||||
        STEP("Add the content to the hold.");
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getHoldsAPI(getAdminUser())
 | 
			
		||||
            .addChildToHold(HoldChild.builder().id(documentHeld.getNodeRefWithoutVersion()).build(), hold.getId());
 | 
			
		||||
 | 
			
		||||
        STEP("Create users");
 | 
			
		||||
        userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
 | 
			
		||||
            UserRole.SiteCollaborator, holdNodeRef, UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
 | 
			
		||||
        users.add(userAddHoldPermission);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given a hold that contains at least one active content
 | 
			
		||||
     * When I use the existing REST API to retrieve the contents of the hold
 | 
			
		||||
     * Then I should see all the active content on hold
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void retrieveTheContentOfTheHoldUsingV1API()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Retrieve the list of children from the hold and collect the entries that have the name of the active " +
 | 
			
		||||
            "content held");
 | 
			
		||||
        List<String> documentNames = restClient.authenticateUser(getAdminUser()).withCoreAPI()
 | 
			
		||||
            .usingNode(toContentModel(holdNodeRef))
 | 
			
		||||
            .listChildren().getEntries().stream()
 | 
			
		||||
            .map(RestNodeModel::onModel)
 | 
			
		||||
            .map(RestNodeModel::getName)
 | 
			
		||||
            .filter(documentName -> documentName.equals(documentHeld.getName()))
 | 
			
		||||
            .toList();
 | 
			
		||||
 | 
			
		||||
        STEP("Check the list of active content");
 | 
			
		||||
        assertEquals(documentNames, Set.of(documentHeld.getName()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given a hold that contains at least one active content
 | 
			
		||||
     * When I use the existing REST API to retrieve the holds the content is added
 | 
			
		||||
     * Then the hold where the content held is returned
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void retrieveTheHoldWhereTheContentIsAdded()
 | 
			
		||||
    {
 | 
			
		||||
        RestNodeAssociationModelCollection holdsEntries = getRestAPIFactory()
 | 
			
		||||
            .getNodeAPI(documentHeld).usingParams("where=(assocType='rma:frozenContent')").getParents();
 | 
			
		||||
        Hold retrievedHold = getRestAPIFactory().getHoldsAPI(getAdminUser())
 | 
			
		||||
            .getHold(holdsEntries.getEntries().get(0).getModel().getId());
 | 
			
		||||
        assertEquals(retrievedHold, hold, "Holds are not equal");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Valid nodes to be added to hold
 | 
			
		||||
     */
 | 
			
		||||
    @DataProvider(name = "validNodesForAddToHold")
 | 
			
		||||
    public Object[][] getValidNodesForAddToHold()
 | 
			
		||||
    {
 | 
			
		||||
        //create electronic and nonElectronic record in record folder
 | 
			
		||||
        RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
 | 
			
		||||
        RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI();
 | 
			
		||||
        nodesToBeClean.add(recordFolder.getParentId());
 | 
			
		||||
        Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolder.getId(),
 | 
			
		||||
            getFile
 | 
			
		||||
                (IMAGE_FILE));
 | 
			
		||||
        assertStatusCode(CREATED);
 | 
			
		||||
 | 
			
		||||
        Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(),
 | 
			
		||||
            recordFolder.getId());
 | 
			
		||||
        assertStatusCode(CREATED);
 | 
			
		||||
        getRestAPIFactory().getRMUserAPI().addUserPermission(recordFolder.getId(), userAddHoldPermission,
 | 
			
		||||
            PERMISSION_FILING);
 | 
			
		||||
 | 
			
		||||
        RecordCategoryChild folderToHold = createCategoryFolderInFilePlan();
 | 
			
		||||
        getRestAPIFactory().getRMUserAPI().addUserPermission(folderToHold.getId(), userAddHoldPermission,
 | 
			
		||||
            PERMISSION_FILING);
 | 
			
		||||
        nodesToBeClean.add(folderToHold.getParentId());
 | 
			
		||||
 | 
			
		||||
        return new String[][]
 | 
			
		||||
            {       // record folder
 | 
			
		||||
                { folderToHold.getId() },
 | 
			
		||||
                //electronic record
 | 
			
		||||
                { electronicRecord.getId() },
 | 
			
		||||
                // non electronic record
 | 
			
		||||
                { nonElectronicRecord.getId() },
 | 
			
		||||
                // document from collaboration site
 | 
			
		||||
                { contentToAddToHold.getNodeRefWithoutVersion() },
 | 
			
		||||
            };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given record folder/record/document not on hold
 | 
			
		||||
     * And a hold
 | 
			
		||||
     * And file permission on the hold
 | 
			
		||||
     * And the appropriate capability to add to hold
 | 
			
		||||
     * When I use the existing REST API to add the node to the hold
 | 
			
		||||
     * Then the record folder/record/document is added to the hold
 | 
			
		||||
     * And the item is frozen
 | 
			
		||||
     *
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
    @Test(dataProvider = "validNodesForAddToHold")
 | 
			
		||||
    public void addValidNodesToHoldWithAllowedUser(String nodeId) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Add node to hold with user with permission.");
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
 | 
			
		||||
            .addChildToHold(HoldChild.builder().id(nodeId).build(), hold.getId());
 | 
			
		||||
 | 
			
		||||
        STEP("Check the node is frozen.");
 | 
			
		||||
        assertTrue(hasAspect(nodeId, FROZEN_ASPECT));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Data provider with user without correct permission to add to hold and the node ref to be added to hold
 | 
			
		||||
     *
 | 
			
		||||
     * @return object with user model and the node ref to be added to hold
 | 
			
		||||
     */
 | 
			
		||||
    @DataProvider(name = "userWithoutPermissionForAddToHold")
 | 
			
		||||
    public Object[][] getUserWithoutPermissionForAddToHold()
 | 
			
		||||
    {
 | 
			
		||||
        //create record folder
 | 
			
		||||
        RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
 | 
			
		||||
        //create a rm manager and grant read permission over the record folder created
 | 
			
		||||
        UserModel user = roleService.createUserWithRMRoleAndRMNodePermission(ROLE_RM_MANAGER.roleId,
 | 
			
		||||
            recordFolder.getId(),
 | 
			
		||||
            PERMISSION_READ_RECORDS);
 | 
			
		||||
        getRestAPIFactory().getRMUserAPI().addUserPermission(holdNodeRef, user, PERMISSION_FILING);
 | 
			
		||||
        nodesToBeClean.add(recordFolder.getParentId());
 | 
			
		||||
        return new Object[][]
 | 
			
		||||
            {       // user without write permission on the content
 | 
			
		||||
                {
 | 
			
		||||
                    roleService.createUserWithSiteRoleRMRoleAndPermission(testSite, UserRole.SiteConsumer,
 | 
			
		||||
                        holdNodeRef, UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING),
 | 
			
		||||
                    contentAddToHoldNoPermission.getNodeRefWithoutVersion()
 | 
			
		||||
                },
 | 
			
		||||
                // user with write permission on the content and without filling permission on a hold
 | 
			
		||||
                {
 | 
			
		||||
                    roleService.createUserWithSiteRoleRMRoleAndPermission(testSite, UserRole
 | 
			
		||||
                            .SiteCollaborator,
 | 
			
		||||
                        holdNodeRef, UserRoles.ROLE_RM_MANAGER, PERMISSION_READ_RECORDS),
 | 
			
		||||
                    contentAddToHoldNoPermission.getNodeRefWithoutVersion()
 | 
			
		||||
                },
 | 
			
		||||
                // user with write permission on the content, filling permission on a hold without add to
 | 
			
		||||
                // hold capability
 | 
			
		||||
                {
 | 
			
		||||
                    roleService.createUserWithSiteRoleRMRoleAndPermission(testSite, UserRole
 | 
			
		||||
                            .SiteCollaborator,
 | 
			
		||||
                        holdNodeRef, UserRoles.ROLE_RM_POWER_USER, PERMISSION_READ_RECORDS),
 | 
			
		||||
                    contentAddToHoldNoPermission.getNodeRefWithoutVersion()
 | 
			
		||||
                },
 | 
			
		||||
                //user without write permission on RM  record folder
 | 
			
		||||
                {
 | 
			
		||||
                    user, recordFolder.getId()
 | 
			
		||||
                },
 | 
			
		||||
 | 
			
		||||
            };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given a node not on hold
 | 
			
		||||
     * And a hold
 | 
			
		||||
     * And user without right permission to add to hold
 | 
			
		||||
     * When I use the existing REST API to add the node to the hold
 | 
			
		||||
     * Then the node is not added to the hold
 | 
			
		||||
     * And the node is not frozen
 | 
			
		||||
     *
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
    @Test(dataProvider = "userWithoutPermissionForAddToHold")
 | 
			
		||||
    public void addContentToHoldWithUserWithoutHoldPermission(UserModel userModel, String nodeToBeAddedToHold)
 | 
			
		||||
        throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        users.add(userModel);
 | 
			
		||||
        STEP("Add the node to the hold with user without permission.");
 | 
			
		||||
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getHoldsAPI(userModel)
 | 
			
		||||
            .addChildToHold(HoldChild.builder().id(nodeToBeAddedToHold).build(), holdNodeRef);
 | 
			
		||||
 | 
			
		||||
        assertStatusCode(FORBIDDEN);
 | 
			
		||||
        getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary(ACCESS_DENIED_ERROR_MESSAGE);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the node is not frozen.");
 | 
			
		||||
        assertFalse(hasAspect(nodeToBeAddedToHold, FROZEN_ASPECT));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Data provider with invalid node types that can be added to a hold
 | 
			
		||||
     */
 | 
			
		||||
    @DataProvider(name = "invalidNodesForAddToHold")
 | 
			
		||||
    public Object[][] getInvalidNodesForAddToHold()
 | 
			
		||||
    {
 | 
			
		||||
        //create locked file
 | 
			
		||||
        FileModel contentLocked = dataContent.usingAdmin().usingSite(testSite)
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
 | 
			
		||||
        contentActions.checkOut(getAdminUser().getUsername(), getAdminUser().getPassword(),
 | 
			
		||||
            testSite.getId(), contentLocked.getName());
 | 
			
		||||
        RecordCategory category = createRootCategory(getRandomAlphanumeric());
 | 
			
		||||
        nodesToBeClean.add(category.getId());
 | 
			
		||||
        return new Object[][]
 | 
			
		||||
            {       // file plan node id
 | 
			
		||||
                { getFilePlan(FILE_PLAN_ALIAS).getId(), SC_BAD_REQUEST, INVALID_TYPE_ERROR_MESSAGE },
 | 
			
		||||
                //transfer container
 | 
			
		||||
                { getTransferContainer(TRANSFERS_ALIAS).getId(), SC_BAD_REQUEST, INVALID_TYPE_ERROR_MESSAGE },
 | 
			
		||||
                // a record category
 | 
			
		||||
                { category.getId(), SC_BAD_REQUEST, INVALID_TYPE_ERROR_MESSAGE },
 | 
			
		||||
                // unfiled records root
 | 
			
		||||
                { getUnfiledContainer(UNFILED_RECORDS_CONTAINER_ALIAS).getId(), SC_BAD_REQUEST,
 | 
			
		||||
                    INVALID_TYPE_ERROR_MESSAGE },
 | 
			
		||||
                // an arbitrary unfiled records folder
 | 
			
		||||
                { createUnfiledContainerChild(UNFILED_RECORDS_CONTAINER_ALIAS, "Unfiled Folder " +
 | 
			
		||||
                    getRandomAlphanumeric(), UNFILED_RECORD_FOLDER_TYPE).getId(), SC_BAD_REQUEST,
 | 
			
		||||
                    INVALID_TYPE_ERROR_MESSAGE },
 | 
			
		||||
                //folder,
 | 
			
		||||
                { dataContent.usingAdmin().usingSite(testSite).createFolder().getNodeRef(), SC_BAD_REQUEST,
 | 
			
		||||
                    INVALID_TYPE_ERROR_MESSAGE },
 | 
			
		||||
                //document locked
 | 
			
		||||
                { contentLocked.getNodeRefWithoutVersion(), SC_BAD_REQUEST, LOCKED_FILE_ERROR_MESSAGE }
 | 
			
		||||
            };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given a node that is not a document/record/ record folder ( a valid node type to be added to hold)
 | 
			
		||||
     * And a hold
 | 
			
		||||
     * And user without right permission to add to hold
 | 
			
		||||
     * When I use the existing REST API to add the node to the hold
 | 
			
		||||
     * Then the node is not added to the hold
 | 
			
		||||
     * And the node is not frozen
 | 
			
		||||
     *
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
    @Test(dataProvider = "invalidNodesForAddToHold")
 | 
			
		||||
    public void addInvalidNodesToHold(String itemNodeRef, int responseCode, String errorMessage) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Add the node to the hold ");
 | 
			
		||||
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getHoldsAPI(getAdminUser())
 | 
			
		||||
            .addChildToHold(HoldChild.builder().id(itemNodeRef).build(), holdNodeRef);
 | 
			
		||||
 | 
			
		||||
        assertStatusCode(HttpStatus.valueOf(responseCode));
 | 
			
		||||
        getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary(errorMessage);
 | 
			
		||||
 | 
			
		||||
        STEP("Check node is not frozen.");
 | 
			
		||||
        assertFalse(hasAspect(itemNodeRef, FROZEN_ASPECT));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Hold createHold(String parentId, Hold hold, UserModel user)
 | 
			
		||||
    {
 | 
			
		||||
        FilePlanAPI filePlanAPI = getRestAPIFactory().getFilePlansAPI(user);
 | 
			
		||||
        return filePlanAPI.createHold(hold, parentId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @AfterClass(alwaysRun = true)
 | 
			
		||||
    public void cleanUpAddContentToHold()
 | 
			
		||||
    {
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(getAdminUser()).deleteHold(holdNodeRef);
 | 
			
		||||
        dataSite.usingAdmin().deleteSite(testSite);
 | 
			
		||||
        users.forEach(user -> getDataUser().usingAdmin().deleteUser(user));
 | 
			
		||||
        nodesToBeClean.forEach(this::deleteRecordCategory);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,186 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.hold;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
 | 
			
		||||
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
import static org.junit.Assert.assertNotNull;
 | 
			
		||||
import static org.springframework.http.HttpStatus.NOT_FOUND;
 | 
			
		||||
import static org.springframework.http.HttpStatus.NO_CONTENT;
 | 
			
		||||
import static org.springframework.http.HttpStatus.OK;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.Hold;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldDeletionReason;
 | 
			
		||||
import org.testng.annotations.AfterClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * This class contains the tests for the Holds CRUD V1 API
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
public class HoldsTests extends BaseRMRestTest
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    private final List<String> nodeRefs = new ArrayList<>();
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetHold()
 | 
			
		||||
    {
 | 
			
		||||
        String holdName = "Hold" + getRandomAlphanumeric();
 | 
			
		||||
        String holdDescription = "Description" + getRandomAlphanumeric();
 | 
			
		||||
        String holdReason = "Reason" + getRandomAlphanumeric();
 | 
			
		||||
 | 
			
		||||
        // Create the hold
 | 
			
		||||
        Hold hold = Hold.builder()
 | 
			
		||||
            .name(holdName)
 | 
			
		||||
            .description(holdDescription)
 | 
			
		||||
            .reason(holdReason)
 | 
			
		||||
            .build();
 | 
			
		||||
        Hold createdHold = getRestAPIFactory().getFilePlansAPI()
 | 
			
		||||
            .createHold(hold, FILE_PLAN_ALIAS);
 | 
			
		||||
 | 
			
		||||
        // Get the hold
 | 
			
		||||
        Hold receivedHold = getRestAPIFactory().getHoldsAPI().getHold(createdHold.getId());
 | 
			
		||||
        nodeRefs.add(receivedHold.getId());
 | 
			
		||||
 | 
			
		||||
        // Verify the status code
 | 
			
		||||
        assertStatusCode(OK);
 | 
			
		||||
 | 
			
		||||
        assertEquals(receivedHold.getName(), holdName);
 | 
			
		||||
        assertEquals(receivedHold.getDescription(), holdDescription);
 | 
			
		||||
        assertEquals(receivedHold.getReason(), holdReason);
 | 
			
		||||
        assertNotNull(receivedHold.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testUpdateHold()
 | 
			
		||||
    {
 | 
			
		||||
        String holdName = "Hold" + getRandomAlphanumeric();
 | 
			
		||||
        String holdDescription = "Description" + getRandomAlphanumeric();
 | 
			
		||||
        String holdReason = "Reason" + getRandomAlphanumeric();
 | 
			
		||||
 | 
			
		||||
        // Create the hold
 | 
			
		||||
        Hold hold = Hold.builder()
 | 
			
		||||
            .name(holdName)
 | 
			
		||||
            .description(holdDescription)
 | 
			
		||||
            .reason(holdReason)
 | 
			
		||||
            .build();
 | 
			
		||||
        Hold createdHold = getRestAPIFactory().getFilePlansAPI()
 | 
			
		||||
            .createHold(hold, FILE_PLAN_ALIAS);
 | 
			
		||||
        nodeRefs.add(createdHold.getId());
 | 
			
		||||
 | 
			
		||||
        Hold holdModel = Hold.builder()
 | 
			
		||||
            .name("Updated" + holdName)
 | 
			
		||||
            .description("Updated" + holdDescription)
 | 
			
		||||
            .reason("Updated" + holdReason)
 | 
			
		||||
            .build();
 | 
			
		||||
 | 
			
		||||
        // Update the hold
 | 
			
		||||
        Hold updatedHold = getRestAPIFactory().getHoldsAPI().updateHold(holdModel, createdHold.getId());
 | 
			
		||||
 | 
			
		||||
        // Verify the status code
 | 
			
		||||
        assertStatusCode(OK);
 | 
			
		||||
 | 
			
		||||
        assertEquals(updatedHold.getName(), "Updated" + holdName);
 | 
			
		||||
        assertEquals(updatedHold.getDescription(), "Updated" + holdDescription);
 | 
			
		||||
        assertEquals(updatedHold.getReason(), "Updated" + holdReason);
 | 
			
		||||
        assertNotNull(updatedHold.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteHold()
 | 
			
		||||
    {
 | 
			
		||||
        String holdName = "Hold" + getRandomAlphanumeric();
 | 
			
		||||
        String holdDescription = "Description" + getRandomAlphanumeric();
 | 
			
		||||
        String holdReason = "Reason" + getRandomAlphanumeric();
 | 
			
		||||
 | 
			
		||||
        // Create the hold
 | 
			
		||||
        Hold hold = Hold.builder()
 | 
			
		||||
            .name(holdName)
 | 
			
		||||
            .description(holdDescription)
 | 
			
		||||
            .reason(holdReason)
 | 
			
		||||
            .build();
 | 
			
		||||
        Hold createdHold = getRestAPIFactory().getFilePlansAPI()
 | 
			
		||||
            .createHold(hold, FILE_PLAN_ALIAS);
 | 
			
		||||
        nodeRefs.add(createdHold.getId());
 | 
			
		||||
 | 
			
		||||
        // Delete the hold
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI().deleteHold(createdHold.getId());
 | 
			
		||||
 | 
			
		||||
        // Verify the status code
 | 
			
		||||
        assertStatusCode(NO_CONTENT);
 | 
			
		||||
 | 
			
		||||
        // Try to get the hold
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI().getHold(createdHold.getId());
 | 
			
		||||
 | 
			
		||||
        // Verify the status code
 | 
			
		||||
        assertStatusCode(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteHoldWithReason()
 | 
			
		||||
    {
 | 
			
		||||
        String holdName = "Hold" + getRandomAlphanumeric();
 | 
			
		||||
        String holdDescription = "Description" + getRandomAlphanumeric();
 | 
			
		||||
        String holdReason = "Reason" + getRandomAlphanumeric();
 | 
			
		||||
 | 
			
		||||
        // Create the hold
 | 
			
		||||
        Hold hold = Hold.builder()
 | 
			
		||||
            .name(holdName)
 | 
			
		||||
            .description(holdDescription)
 | 
			
		||||
            .reason(holdReason)
 | 
			
		||||
            .build();
 | 
			
		||||
        Hold createdHold = getRestAPIFactory().getFilePlansAPI()
 | 
			
		||||
            .createHold(hold, FILE_PLAN_ALIAS);
 | 
			
		||||
        nodeRefs.add(createdHold.getId());
 | 
			
		||||
 | 
			
		||||
        // Delete the hold with the reason
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI()
 | 
			
		||||
            .deleteHoldWithReason(HoldDeletionReason.builder().reason("Example reason").build(), createdHold.getId());
 | 
			
		||||
 | 
			
		||||
        // Verify the status code
 | 
			
		||||
        assertStatusCode(OK);
 | 
			
		||||
 | 
			
		||||
        // Try to get the hold
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI().getHold(createdHold.getId());
 | 
			
		||||
 | 
			
		||||
        // Verify the status code
 | 
			
		||||
        assertStatusCode(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @AfterClass(alwaysRun = true)
 | 
			
		||||
    public void cleanUpHoldsTests()
 | 
			
		||||
    {
 | 
			
		||||
        nodeRefs.forEach(nodeRef -> getRestAPIFactory().getHoldsAPI(getAdminUser()).deleteHold(nodeRef));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,337 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.hold;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAspects.ASPECTS_VITAL_RECORD;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAspects.ASPECTS_VITAL_RECORD_DEFINITION;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.CoreUtil.createBodyForMoveCopy;
 | 
			
		||||
import static org.alfresco.utility.data.RandomData.getRandomName;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.apache.commons.httpclient.HttpStatus.SC_INTERNAL_SERVER_ERROR;
 | 
			
		||||
import static org.springframework.http.HttpStatus.CREATED;
 | 
			
		||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
 | 
			
		||||
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
 | 
			
		||||
import static org.springframework.http.HttpStatus.OK;
 | 
			
		||||
import static org.testng.Assert.assertNotNull;
 | 
			
		||||
import static org.testng.Assert.assertTrue;
 | 
			
		||||
import static org.testng.AssertJUnit.assertFalse;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
 | 
			
		||||
import jakarta.json.Json;
 | 
			
		||||
import jakarta.json.JsonObject;
 | 
			
		||||
import org.alfresco.dataprep.CMISUtil;
 | 
			
		||||
import org.alfresco.rest.core.JsonBodyGenerator;
 | 
			
		||||
import org.alfresco.rest.core.v0.BaseAPI.RM_ACTIONS;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.common.ReviewPeriod;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.Hold;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.record.Record;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolder;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolderProperties;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
 | 
			
		||||
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.DispositionScheduleService;
 | 
			
		||||
import org.alfresco.utility.Utility;
 | 
			
		||||
import org.alfresco.utility.model.FileModel;
 | 
			
		||||
import org.alfresco.utility.model.FolderModel;
 | 
			
		||||
import org.alfresco.utility.model.UserModel;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.annotations.AfterClass;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * V1 API tests to check actions on frozen content
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
public class PreventActionsOnFrozenContentV1Tests extends BaseRMRestTest
 | 
			
		||||
{
 | 
			
		||||
    private static String holdNodeRef;
 | 
			
		||||
    private static FileModel contentHeld;
 | 
			
		||||
    private static File updatedFile;
 | 
			
		||||
    private static FolderModel folderModel;
 | 
			
		||||
    private static RecordCategoryChild recordFolder;
 | 
			
		||||
    private static Record recordFrozen;
 | 
			
		||||
    private static Record recordNotHeld;
 | 
			
		||||
    private static RecordCategory categoryWithRS;
 | 
			
		||||
 | 
			
		||||
    private Hold hold;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private DispositionScheduleService dispositionScheduleService;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMRolesAndActionsAPI rmRolesAndActionsAPI;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass(alwaysRun = true)
 | 
			
		||||
    public void preconditionForPreventActionsOnFrozenContent()
 | 
			
		||||
    {
 | 
			
		||||
        String holdOne = "HOLD" + generateTestPrefix(PreventActionsOnFrozenContentV1Tests.class);
 | 
			
		||||
 | 
			
		||||
        STEP("Create a hold.");
 | 
			
		||||
        hold = createHold(FILE_PLAN_ALIAS,
 | 
			
		||||
            Hold.builder().name(holdOne).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), getAdminUser());
 | 
			
		||||
        holdNodeRef = hold.getId();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a test file.");
 | 
			
		||||
        testSite = dataSite.usingAdmin().createPublicRandomSite();
 | 
			
		||||
        contentHeld = dataContent.usingAdmin().usingSite(testSite)
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
 | 
			
		||||
        STEP("Add the file to the hold.");
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getHoldsAPI(getAdminUser())
 | 
			
		||||
            .addChildToHold(HoldChild.builder().id(contentHeld.getNodeRefWithoutVersion()).build(), hold.getId());
 | 
			
		||||
 | 
			
		||||
        STEP("Get a file resource.");
 | 
			
		||||
        updatedFile = Utility.getResourceTestDataFile("SampleTextFile_10kb.txt");
 | 
			
		||||
 | 
			
		||||
        STEP("Create a folder withing the test site .");
 | 
			
		||||
        folderModel = dataContent.usingAdmin().usingSite(testSite)
 | 
			
		||||
            .createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a record folder with some records");
 | 
			
		||||
        recordFolder = createCategoryFolderInFilePlan();
 | 
			
		||||
        recordFrozen = createElectronicRecord(recordFolder.getId(), getRandomName("elRecordFrozen"));
 | 
			
		||||
        recordNotHeld = createElectronicRecord(recordFolder.getId(), getRandomName("elRecordNotHeld"));
 | 
			
		||||
        assertStatusCode(CREATED);
 | 
			
		||||
 | 
			
		||||
        STEP("Add the record to the hold.");
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getHoldsAPI(getAdminUser())
 | 
			
		||||
            .addChildToHold(HoldChild.builder().id(recordFrozen.getId()).build(), hold.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given active content on hold
 | 
			
		||||
     * When I try to edit the properties
 | 
			
		||||
     * Or perform an action that edits the properties
 | 
			
		||||
     * Then I am not successful
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void editPropertiesForContentHeld() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Update name property of the held content");
 | 
			
		||||
        JsonObject nameUpdated = Json.createObjectBuilder().add("name", "HeldNameUpdated").build();
 | 
			
		||||
        restClient.authenticateUser(getAdminUser()).withCoreAPI().usingNode(contentHeld)
 | 
			
		||||
            .updateNode(nameUpdated.toString());
 | 
			
		||||
 | 
			
		||||
        STEP("Check the request failed.");
 | 
			
		||||
        restClient.assertStatusCodeIs(FORBIDDEN);
 | 
			
		||||
        restClient.assertLastError().containsSummary("Frozen content can't be updated.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Given active content on hold
 | 
			
		||||
     * When I try to update the content
 | 
			
		||||
     * Then I am not successful
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void updateContentForFrozenFile() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Update content of the held file");
 | 
			
		||||
        restClient.authenticateUser(getAdminUser()).withCoreAPI().usingNode(contentHeld).updateNodeContent(updatedFile);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the request failed.");
 | 
			
		||||
        restClient.assertStatusCodeIs(INTERNAL_SERVER_ERROR);
 | 
			
		||||
        restClient.assertLastError().containsSummary("Frozen content can't be updated.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Given active content on hold
 | 
			
		||||
     * When I try to delete the content
 | 
			
		||||
     * Then I am not successful
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void deleteFrozenFile() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Delete frozen file");
 | 
			
		||||
        restClient.authenticateUser(getAdminUser()).withCoreAPI().usingNode(contentHeld)
 | 
			
		||||
            .deleteNode(contentHeld.getNodeRefWithoutVersion());
 | 
			
		||||
 | 
			
		||||
        STEP("Check the request failed.");
 | 
			
		||||
        restClient.assertStatusCodeIs(FORBIDDEN);
 | 
			
		||||
        restClient.assertLastError().containsSummary("Frozen content can't be deleted.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given active content on hold
 | 
			
		||||
     * When I try to copy the content
 | 
			
		||||
     * Then I am not successful
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void copyFrozenFile()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Copy frozen file");
 | 
			
		||||
        String postBody = JsonBodyGenerator.keyValueJson("targetParentId", folderModel.getNodeRef());
 | 
			
		||||
        getRestAPIFactory().getNodeAPI(contentHeld).copyNode(postBody);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the request failed.");
 | 
			
		||||
        assertStatusCode(FORBIDDEN);
 | 
			
		||||
        getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary("Permission was denied");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given active content on hold
 | 
			
		||||
     * When I try to move the content
 | 
			
		||||
     * Then I am not successful
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void moveFrozenFile() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Move frozen file");
 | 
			
		||||
        getRestAPIFactory().getNodeAPI(contentHeld).move(createBodyForMoveCopy(folderModel.getNodeRef()));
 | 
			
		||||
 | 
			
		||||
        STEP("Check the request failed.");
 | 
			
		||||
        assertStatusCode(FORBIDDEN);
 | 
			
		||||
        getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary("Frozen content can't be moved.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given a record folder with a frozen record and another record not held
 | 
			
		||||
     * When I update the record folder and make the records as vital
 | 
			
		||||
     * Then I am successful and the records not held are marked as vital
 | 
			
		||||
     * And the frozen nodes have the vital record search properties updated
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void updateRecordFolderVitalProperties()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Update the vital record properties for the record folder");
 | 
			
		||||
        // Create the record folder properties to update
 | 
			
		||||
        RecordFolder recordFolderToUpdate = RecordFolder.builder()
 | 
			
		||||
            .properties(RecordFolderProperties.builder()
 | 
			
		||||
                .vitalRecordIndicator(true)
 | 
			
		||||
                .reviewPeriod(new ReviewPeriod("month", "1"))
 | 
			
		||||
                .build())
 | 
			
		||||
            .build();
 | 
			
		||||
 | 
			
		||||
        // Update the record folder
 | 
			
		||||
        RecordFolder updatedRecordFolder = getRestAPIFactory().getRecordFolderAPI().updateRecordFolder
 | 
			
		||||
            (recordFolderToUpdate,
 | 
			
		||||
                recordFolder.getId());
 | 
			
		||||
        assertStatusCode(OK);
 | 
			
		||||
        assertTrue(updatedRecordFolder.getAspectNames().contains(ASPECTS_VITAL_RECORD_DEFINITION));
 | 
			
		||||
 | 
			
		||||
        STEP("Check the frozen record was not marked as vital");
 | 
			
		||||
        recordFrozen = getRestAPIFactory().getRecordsAPI().getRecord(recordFrozen.getId());
 | 
			
		||||
        assertFalse(recordFrozen.getAspectNames().contains(ASPECTS_VITAL_RECORD));
 | 
			
		||||
        assertTrue(recordFrozen.getProperties().getRecordSearchVitalRecordReviewPeriod().contains("month"));
 | 
			
		||||
        assertTrue(recordFrozen.getProperties().getRecordSearchVitalRecordReviewPeriodExpression().contains("1"));
 | 
			
		||||
 | 
			
		||||
        STEP("Check the record not held was marked as vital");
 | 
			
		||||
        recordNotHeld = getRestAPIFactory().getRecordsAPI().getRecord(recordNotHeld.getId());
 | 
			
		||||
        assertTrue(recordNotHeld.getAspectNames().contains(ASPECTS_VITAL_RECORD));
 | 
			
		||||
        assertNotNull(recordNotHeld.getProperties().getReviewAsOf());
 | 
			
		||||
        assertTrue(recordNotHeld.getProperties().getRecordSearchVitalRecordReviewPeriod().contains("month"));
 | 
			
		||||
        assertTrue(recordNotHeld.getProperties().getRecordSearchVitalRecordReviewPeriodExpression().contains("1"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given a record folder with a frozen record and another record not held
 | 
			
		||||
     * When I add a disposition schedule
 | 
			
		||||
     * Then I am successful
 | 
			
		||||
     * And the record search disposition schedule properties are updated
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void createDispositionScheduleOnCategoryWithHeldChildren()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a retention schedule on the category with frozen children");
 | 
			
		||||
        RecordCategory categoryWithRS = getRestAPIFactory().getRecordCategoryAPI()
 | 
			
		||||
            .getRecordCategory(recordFolder.getParentId());
 | 
			
		||||
        dispositionScheduleService.createCategoryRetentionSchedule(categoryWithRS.getName(), false);
 | 
			
		||||
        dispositionScheduleService.addCutOffImmediatelyStep(categoryWithRS.getName());
 | 
			
		||||
        dispositionScheduleService.addDestroyWithGhostingImmediatelyAfterCutOff(categoryWithRS.getName());
 | 
			
		||||
 | 
			
		||||
        STEP("Check the record folder has a disposition schedule");
 | 
			
		||||
        RecordFolder folderWithRS = getRestAPIFactory().getRecordFolderAPI().getRecordFolder(recordFolder.getId());
 | 
			
		||||
        assertNotNull(folderWithRS.getProperties().getRecordSearchDispositionAuthority());
 | 
			
		||||
        assertNotNull(folderWithRS.getProperties().getRecordSearchDispositionInstructions());
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given a record category with a disposition schedule applied to records
 | 
			
		||||
     * And the disposition schedule has a retain step  immediately and destroy step immediately
 | 
			
		||||
     * And a complete record added to one hold
 | 
			
		||||
     * When I execute the retain action
 | 
			
		||||
     * Then the action is executed
 | 
			
		||||
     * And the record search disposition schedule properties are updated
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void retainActionOnFrozenHeldRecords()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Add a category with a disposition schedule.");
 | 
			
		||||
        categoryWithRS = createRootCategory(getRandomName("CategoryWithRS"));
 | 
			
		||||
        dispositionScheduleService.createCategoryRetentionSchedule(categoryWithRS.getName(), true);
 | 
			
		||||
        dispositionScheduleService.addRetainAfterPeriodStep(categoryWithRS.getName(), "immediately");
 | 
			
		||||
        dispositionScheduleService.addDestroyWithGhostingImmediatelyAfterCutOff(categoryWithRS.getName());
 | 
			
		||||
 | 
			
		||||
        STEP("Create record folder with a record.");
 | 
			
		||||
        RecordCategoryChild folder = createFolder(categoryWithRS.getId(), getRandomName("RecFolder"));
 | 
			
		||||
        Record record = createElectronicRecord(folder.getId(), getRandomName("elRecord"));
 | 
			
		||||
        completeRecord(record.getId());
 | 
			
		||||
 | 
			
		||||
        STEP("Add the record to the hold");
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getHoldsAPI(getAdminUser())
 | 
			
		||||
            .addChildToHold(HoldChild.builder().id(record.getId()).build(), hold.getId());
 | 
			
		||||
 | 
			
		||||
        STEP("Execute the retain action");
 | 
			
		||||
        rmRolesAndActionsAPI.executeAction(getAdminUser().getUsername(), getAdminUser().getPassword(), record.getName(),
 | 
			
		||||
            RM_ACTIONS.END_RETENTION, null, SC_INTERNAL_SERVER_ERROR);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the record search disposition properties");
 | 
			
		||||
        Record recordUpdated = getRestAPIFactory().getRecordsAPI().getRecord(record.getId());
 | 
			
		||||
        assertTrue(recordUpdated.getProperties().getRecordSearchDispositionActionName()
 | 
			
		||||
            .contains(RM_ACTIONS.END_RETENTION.getAction()));
 | 
			
		||||
        assertTrue(recordUpdated.getProperties().getRecordSearchDispositionPeriod().contains("immediately"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Hold createHold(String parentId, Hold hold, UserModel user)
 | 
			
		||||
    {
 | 
			
		||||
        FilePlanAPI filePlanAPI = getRestAPIFactory().getFilePlansAPI(user);
 | 
			
		||||
        return filePlanAPI.createHold(hold, parentId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @AfterClass(alwaysRun = true)
 | 
			
		||||
    public void cleanUpPreventActionsOnFrozenContent()
 | 
			
		||||
    {
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(getAdminUser()).deleteHold(holdNodeRef);
 | 
			
		||||
        dataSite.usingAdmin().deleteSite(testSite);
 | 
			
		||||
        deleteRecordCategory(recordFolder.getParentId());
 | 
			
		||||
        deleteRecordCategory(categoryWithRS.getId());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -52,7 +52,7 @@ import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.dataprep.CMISUtil;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldEntry;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.v0.HoldEntry;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.record.Record;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.user.UserRoles;
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,374 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.rm.community.hold;
 | 
			
		||||
 | 
			
		||||
import static java.util.Arrays.asList;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAspects.FROZEN_ASPECT;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_READ_RECORDS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_MANAGER;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.IMAGE_FILE;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createElectronicRecordModel;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createNonElectronicRecordModel;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.getFile;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.springframework.http.HttpStatus.CREATED;
 | 
			
		||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
 | 
			
		||||
import static org.testng.Assert.assertFalse;
 | 
			
		||||
import static org.testng.Assert.assertTrue;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Stream;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.dataprep.CMISUtil;
 | 
			
		||||
import org.alfresco.rest.model.RestNodeAssociationModelCollection;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.Hold;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.hold.HoldChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.record.Record;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.user.UserRoles;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.utils.CoreUtil;
 | 
			
		||||
import org.alfresco.rest.v0.service.RoleService;
 | 
			
		||||
import org.alfresco.utility.constants.UserRole;
 | 
			
		||||
import org.alfresco.utility.model.FileModel;
 | 
			
		||||
import org.alfresco.utility.model.SiteModel;
 | 
			
		||||
import org.alfresco.utility.model.UserModel;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.annotations.AfterClass;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.DataProvider;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * V1 API tests for removing content/record folder/record from holds
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
public class RemoveFromHoldsV1Tests extends BaseRMRestTest
 | 
			
		||||
{
 | 
			
		||||
    private static final String HOLD_ONE = "HOLD_ONE" + generateTestPrefix(RemoveFromHoldsV1Tests.class);
 | 
			
		||||
    private static final String HOLD_TWO = "HOLD_TWO" + generateTestPrefix(RemoveFromHoldsV1Tests.class);
 | 
			
		||||
    private static final String ACCESS_DENIED_ERROR_MESSAGE = "Access Denied.  You do not have the appropriate " +
 | 
			
		||||
        "permissions to perform this operation.";
 | 
			
		||||
 | 
			
		||||
    private SiteModel testSite;
 | 
			
		||||
    private SiteModel privateSite;
 | 
			
		||||
    private String holdNodeRefOne;
 | 
			
		||||
    private FileModel contentHeld;
 | 
			
		||||
    private FileModel contentAddToManyHolds;
 | 
			
		||||
    private List<String> holdsListRef = new ArrayList<>();
 | 
			
		||||
    private final Set<UserModel> usersToBeClean = new HashSet<>();
 | 
			
		||||
    private final Set<String> nodesToBeClean = new HashSet<>();
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RoleService roleService;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass(alwaysRun = true)
 | 
			
		||||
    public void preconditionForRemoveContentFromHold()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create two holds.");
 | 
			
		||||
 | 
			
		||||
        holdNodeRefOne = createHold(FILE_PLAN_ALIAS,
 | 
			
		||||
            Hold.builder().name(HOLD_ONE).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(),
 | 
			
		||||
            getAdminUser()).getId();
 | 
			
		||||
        String holdNodeRefTwo = createHold(FILE_PLAN_ALIAS,
 | 
			
		||||
            Hold.builder().name(HOLD_TWO).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(),
 | 
			
		||||
            getAdminUser()).getId();
 | 
			
		||||
        holdsListRef = asList(holdNodeRefOne, holdNodeRefTwo);
 | 
			
		||||
 | 
			
		||||
        STEP("Create test files.");
 | 
			
		||||
        testSite = dataSite.usingAdmin().createPublicRandomSite();
 | 
			
		||||
        privateSite = dataSite.usingAdmin().createPrivateRandomSite();
 | 
			
		||||
        contentHeld = dataContent.usingAdmin().usingSite(testSite)
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
        contentAddToManyHolds = dataContent.usingSite(testSite)
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
 | 
			
		||||
        STEP("Add content to the holds.");
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getHoldsAPI(getAdminUser())
 | 
			
		||||
            .addChildToHold(HoldChild.builder().id(contentHeld.getNodeRefWithoutVersion()).build(), holdNodeRefOne);
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getHoldsAPI(getAdminUser())
 | 
			
		||||
            .addChildToHold(HoldChild.builder().id(contentAddToManyHolds.getNodeRefWithoutVersion()).build(),
 | 
			
		||||
                holdNodeRefOne);
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getHoldsAPI(getAdminUser())
 | 
			
		||||
            .addChildToHold(HoldChild.builder().id(contentAddToManyHolds.getNodeRefWithoutVersion()).build(),
 | 
			
		||||
                holdNodeRefTwo);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Valid nodes to be removed from hold
 | 
			
		||||
     */
 | 
			
		||||
    @DataProvider(name = "validNodesToRemoveFromHold")
 | 
			
		||||
    public Object[][] getValidNodesToRemoveFromHold()
 | 
			
		||||
    {
 | 
			
		||||
        //create electronic and nonElectronic record in record folder
 | 
			
		||||
        RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
 | 
			
		||||
        RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI();
 | 
			
		||||
        nodesToBeClean.add(recordFolder.getParentId());
 | 
			
		||||
        Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolder.getId(),
 | 
			
		||||
            getFile
 | 
			
		||||
                (IMAGE_FILE));
 | 
			
		||||
        assertStatusCode(CREATED);
 | 
			
		||||
        Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(),
 | 
			
		||||
            recordFolder.getId());
 | 
			
		||||
        assertStatusCode(CREATED);
 | 
			
		||||
 | 
			
		||||
        RecordCategoryChild folderToHeld = createCategoryFolderInFilePlan();
 | 
			
		||||
        nodesToBeClean.add(folderToHeld.getParentId());
 | 
			
		||||
        Stream.of(electronicRecord.getId(), nonElectronicRecord.getId(), folderToHeld.getId())
 | 
			
		||||
            .forEach(id -> getRestAPIFactory()
 | 
			
		||||
                .getHoldsAPI(getAdminUser())
 | 
			
		||||
                .addChildToHold(HoldChild.builder().id(id).build(), holdNodeRefOne));
 | 
			
		||||
 | 
			
		||||
        return new String[][]
 | 
			
		||||
            {       // record folder
 | 
			
		||||
                { folderToHeld.getId() },
 | 
			
		||||
                //electronic record
 | 
			
		||||
                { electronicRecord.getId() },
 | 
			
		||||
                // non electronic record
 | 
			
		||||
                { nonElectronicRecord.getId() },
 | 
			
		||||
                // document from collaboration site
 | 
			
		||||
                { contentHeld.getNodeRefWithoutVersion() },
 | 
			
		||||
            };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given content/record folder/record that is held
 | 
			
		||||
     * And the corresponding hold
 | 
			
		||||
     * When I use the existing REST API to remove the node from the hold
 | 
			
		||||
     * Then the node is removed from the hold
 | 
			
		||||
     * And is no longer frozen
 | 
			
		||||
     */
 | 
			
		||||
    @Test(dataProvider = "validNodesToRemoveFromHold")
 | 
			
		||||
    public void removeContentFromHold(String nodeId) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Remove node from hold");
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getHoldsAPI(getAdminUser()).deleteHoldChild(holdNodeRefOne, nodeId);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the node is not held");
 | 
			
		||||
        assertFalse(hasAspect(nodeId, FROZEN_ASPECT));
 | 
			
		||||
 | 
			
		||||
        STEP("Check node is not in any hold");
 | 
			
		||||
        RestNodeAssociationModelCollection holdsEntries = getRestAPIFactory()
 | 
			
		||||
            .getNodeAPI(CoreUtil.toContentModel(nodeId)).usingParams("where=(assocType='rma:frozenContent')")
 | 
			
		||||
            .getParents();
 | 
			
		||||
        assertTrue(holdsEntries.getEntries().isEmpty(), "Content held is still added to a hold.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given active content that is held on many holds
 | 
			
		||||
     * When I use the existing REST API to remove the active content from one hold
 | 
			
		||||
     * Then the active content is removed from the specific hold
 | 
			
		||||
     * And is frozen
 | 
			
		||||
     * And in the other holds
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void removeContentAddedToManyHolds() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Remove content from hold. ");
 | 
			
		||||
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(getAdminUser())
 | 
			
		||||
            .deleteHoldChild(holdNodeRefOne, contentAddToManyHolds.getNodeRefWithoutVersion());
 | 
			
		||||
 | 
			
		||||
        STEP("Check the content is held. ");
 | 
			
		||||
        assertTrue(hasAspect(contentAddToManyHolds.getNodeRefWithoutVersion(), FROZEN_ASPECT));
 | 
			
		||||
 | 
			
		||||
        STEP("Check node is in hold HOLD_TWO. ");
 | 
			
		||||
 | 
			
		||||
        RestNodeAssociationModelCollection holdsEntries = getRestAPIFactory()
 | 
			
		||||
            .getNodeAPI(CoreUtil.toContentModel(contentAddToManyHolds.getNodeRefWithoutVersion()))
 | 
			
		||||
            .usingParams("where=(assocType='rma:frozenContent')").getParents();
 | 
			
		||||
        assertFalse(holdsEntries.getEntries().isEmpty(), "Content held is not held after removing from one hold.");
 | 
			
		||||
        assertTrue(holdsEntries.getEntries().stream()
 | 
			
		||||
                .anyMatch(restNodeModel -> restNodeModel.getModel().getName().equals(HOLD_TWO)),
 | 
			
		||||
            "Content held is not held after removing from one hold.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Data provider with user without right permission or capability to remove from hold a specific node
 | 
			
		||||
     *
 | 
			
		||||
     * @return user model and the node ref to be removed from hold
 | 
			
		||||
     */
 | 
			
		||||
    @DataProvider(name = "userWithoutPermissionForRemoveFromHold")
 | 
			
		||||
    public Object[][] getUserWithoutPermissionForAddToHold()
 | 
			
		||||
    {
 | 
			
		||||
        //create record folder
 | 
			
		||||
        RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
 | 
			
		||||
        nodesToBeClean.add(recordFolder.getParentId());
 | 
			
		||||
        UserModel user = roleService.createUserWithRMRole(ROLE_RM_MANAGER.roleId);
 | 
			
		||||
        getRestAPIFactory().getRMUserAPI().addUserPermission(holdNodeRefOne, user, PERMISSION_FILING);
 | 
			
		||||
        //create files that will be removed from hold
 | 
			
		||||
        FileModel contentNoHoldPerm = dataContent.usingAdmin().usingSite(testSite)
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
        FileModel contentNoHoldCap = dataContent.usingAdmin().usingSite(testSite)
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
        FileModel privateFile = dataContent.usingAdmin().usingSite(privateSite)
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
        //add files to hold
 | 
			
		||||
        asList(recordFolder.getId(), contentNoHoldCap.getNodeRefWithoutVersion(),
 | 
			
		||||
            contentNoHoldPerm.getNodeRefWithoutVersion(), privateFile.getNodeRefWithoutVersion())
 | 
			
		||||
            .forEach(id -> getRestAPIFactory()
 | 
			
		||||
                .getHoldsAPI(getAdminUser())
 | 
			
		||||
                .addChildToHold(HoldChild.builder().id(id).build(), holdNodeRefOne));
 | 
			
		||||
 | 
			
		||||
        return new Object[][]
 | 
			
		||||
            {
 | 
			
		||||
                // user with read permission on the content, with remove from hold capability and without
 | 
			
		||||
                // filling permission on a hold
 | 
			
		||||
                {
 | 
			
		||||
                    roleService.createUserWithSiteRoleRMRoleAndPermission(testSite, UserRole.SiteCollaborator,
 | 
			
		||||
                        holdNodeRefOne, UserRoles.ROLE_RM_MANAGER, PERMISSION_READ_RECORDS),
 | 
			
		||||
                    contentNoHoldPerm.getNodeRefWithoutVersion()
 | 
			
		||||
                },
 | 
			
		||||
                // user with write permission on the content, filling permission on a hold without remove from
 | 
			
		||||
                // hold capability
 | 
			
		||||
                {
 | 
			
		||||
                    roleService.createUserWithSiteRoleRMRoleAndPermission(testSite, UserRole
 | 
			
		||||
                            .SiteCollaborator,
 | 
			
		||||
                        holdNodeRefOne, UserRoles.ROLE_RM_POWER_USER, PERMISSION_FILING),
 | 
			
		||||
                    contentNoHoldCap.getNodeRefWithoutVersion()
 | 
			
		||||
                },
 | 
			
		||||
                //user without read permission on RM  record folder
 | 
			
		||||
                {
 | 
			
		||||
                    user, recordFolder.getId()
 | 
			
		||||
                },
 | 
			
		||||
                //user without read permission over the content from the private site
 | 
			
		||||
                {
 | 
			
		||||
                    user, privateFile.getNodeRefWithoutVersion()
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given node on hold in a single hold location
 | 
			
		||||
     * And the user does not have sufficient permissions or capabilities to remove the node from the hold
 | 
			
		||||
     * When the user tries to remove the node from the hold
 | 
			
		||||
     * Then it's unsuccessful
 | 
			
		||||
     *
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
    @Test(dataProvider = "userWithoutPermissionForRemoveFromHold")
 | 
			
		||||
    public void removeFromHoldWithUserWithoutPermission(UserModel userModel, String nodeIdToBeRemoved) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Update the list of users to be deleted after running the tests");
 | 
			
		||||
        usersToBeClean.add(userModel);
 | 
			
		||||
 | 
			
		||||
        STEP("Remove node from hold with user without right permission or capability");
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(userModel).deleteHoldChild(holdNodeRefOne, nodeIdToBeRemoved);
 | 
			
		||||
 | 
			
		||||
        assertStatusCode(FORBIDDEN);
 | 
			
		||||
        getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary(ACCESS_DENIED_ERROR_MESSAGE);
 | 
			
		||||
 | 
			
		||||
        STEP("Check node is frozen.");
 | 
			
		||||
        assertTrue(hasAspect(nodeIdToBeRemoved, FROZEN_ASPECT));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Data provider with user with right permission or capability to remove from hold a specific node
 | 
			
		||||
     *
 | 
			
		||||
     * @return user model and the node ref to be removed from hold
 | 
			
		||||
     */
 | 
			
		||||
    @DataProvider(name = "userWithPermissionForRemoveFromHold")
 | 
			
		||||
    public Object[][] getUserWithPermissionForAddToHold()
 | 
			
		||||
    {
 | 
			
		||||
        //create record folder
 | 
			
		||||
        RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
 | 
			
		||||
        nodesToBeClean.add(recordFolder.getParentId());
 | 
			
		||||
        UserModel user = roleService.createUserWithRMRoleAndRMNodePermission(ROLE_RM_MANAGER.roleId,
 | 
			
		||||
            recordFolder.getId(),
 | 
			
		||||
            PERMISSION_READ_RECORDS);
 | 
			
		||||
        getRestAPIFactory().getRMUserAPI().addUserPermission(holdNodeRefOne, user, PERMISSION_FILING);
 | 
			
		||||
        //create file that will be removed from hold
 | 
			
		||||
        FileModel contentPermission = dataContent.usingAdmin().usingSite(testSite)
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
 | 
			
		||||
        //add files to hold
 | 
			
		||||
        asList(recordFolder.getId(), contentPermission.getNodeRefWithoutVersion())
 | 
			
		||||
            .forEach(id -> getRestAPIFactory()
 | 
			
		||||
                .getHoldsAPI(getAdminUser())
 | 
			
		||||
                .addChildToHold(HoldChild.builder().id(id).build(), holdNodeRefOne));
 | 
			
		||||
 | 
			
		||||
        return new Object[][]
 | 
			
		||||
            {
 | 
			
		||||
                // user with write permission on the content
 | 
			
		||||
                {
 | 
			
		||||
                    roleService.createUserWithSiteRoleRMRoleAndPermission(testSite, UserRole.SiteConsumer,
 | 
			
		||||
                        holdNodeRefOne, UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING),
 | 
			
		||||
                    contentPermission.getNodeRefWithoutVersion()
 | 
			
		||||
                },
 | 
			
		||||
                //user with read permission on RM  record folder
 | 
			
		||||
                {
 | 
			
		||||
                    user, recordFolder.getId()
 | 
			
		||||
                },
 | 
			
		||||
 | 
			
		||||
            };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test(dataProvider = "userWithPermissionForRemoveFromHold")
 | 
			
		||||
    public void removeFromHoldWithUserWithPermission(UserModel userModel, String nodeIdToBeRemoved) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Update the list of users to be deleted after running the tests");
 | 
			
		||||
        usersToBeClean.add(userModel);
 | 
			
		||||
 | 
			
		||||
        STEP("Remove node from hold with user with right permission and capability");
 | 
			
		||||
        getRestAPIFactory().getHoldsAPI(userModel).deleteHoldChild(holdNodeRefOne, nodeIdToBeRemoved);
 | 
			
		||||
 | 
			
		||||
        STEP("Check node is not frozen.");
 | 
			
		||||
        assertFalse(hasAspect(nodeIdToBeRemoved, FROZEN_ASPECT));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Hold createHold(String parentId, Hold hold, UserModel user)
 | 
			
		||||
    {
 | 
			
		||||
        FilePlanAPI filePlanAPI = getRestAPIFactory().getFilePlansAPI(user);
 | 
			
		||||
        return filePlanAPI.createHold(hold, parentId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @AfterClass(alwaysRun = true)
 | 
			
		||||
    public void cleanUpRemoveContentFromHold()
 | 
			
		||||
    {
 | 
			
		||||
        holdsListRef.forEach(holdRef -> getRestAPIFactory().getHoldsAPI(getAdminUser()).deleteHold(holdRef));
 | 
			
		||||
        dataSite.usingAdmin().deleteSite(testSite);
 | 
			
		||||
        dataSite.usingAdmin().deleteSite(privateSite);
 | 
			
		||||
        usersToBeClean.forEach(user -> getDataUser().usingAdmin().deleteUser(user));
 | 
			
		||||
        nodesToBeClean.forEach(this::deleteRecordCategory);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
   <parent>
 | 
			
		||||
      <groupId>org.alfresco</groupId>
 | 
			
		||||
      <artifactId>alfresco-governance-services-community-parent</artifactId>
 | 
			
		||||
      <version>23.3.0.8</version>
 | 
			
		||||
      <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
   </parent>
 | 
			
		||||
 | 
			
		||||
   <modules>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
SOLR6_TAG=2.0.8.1
 | 
			
		||||
SOLR6_TAG=2.0.10
 | 
			
		||||
POSTGRES_TAG=15.4
 | 
			
		||||
ACTIVEMQ_TAG=5.18.3-jre17-rockylinux8
 | 
			
		||||
 
 | 
			
		||||
@@ -538,6 +538,11 @@
 | 
			
		||||
               <type>d:text</type>
 | 
			
		||||
               <mandatory>true</mandatory>
 | 
			
		||||
            </property>
 | 
			
		||||
            <property name="rma:holdDeletionReason">
 | 
			
		||||
               <title>Hold Deletion Reason</title>
 | 
			
		||||
               <type>d:text</type>
 | 
			
		||||
               <mandatory>false</mandatory>
 | 
			
		||||
            </property>
 | 
			
		||||
         </properties>
 | 
			
		||||
 | 
			
		||||
         <associations>
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,32 @@
 | 
			
		||||
       <property name="transactionService" ref="transactionService" />
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean class="org.alfresco.rm.rest.api.unfiledcontainers.UnfiledContainerEntityResource">
 | 
			
		||||
   <bean class="org.alfresco.rm.rest.api.fileplans.FilePlanHoldsRelation">
 | 
			
		||||
      <property name="apiUtils" ref="apiUtils" />
 | 
			
		||||
      <property name="nodesModelFactory" ref="nodesModelFactory" />
 | 
			
		||||
      <property name="holdService" ref="HoldService" />
 | 
			
		||||
      <property name="fileFolderService" ref="FileFolderService" />
 | 
			
		||||
      <property name="transactionService" ref="transactionService" />
 | 
			
		||||
   </bean>
 | 
			
		||||
 | 
			
		||||
   <bean class="org.alfresco.rm.rest.api.holds.HoldsEntityResource" >
 | 
			
		||||
      <property name="holdService" ref="HoldService" />
 | 
			
		||||
      <property name="apiUtils" ref="apiUtils" />
 | 
			
		||||
      <property name="nodesModelFactory" ref="nodesModelFactory" />
 | 
			
		||||
      <property name="fileFolderService" ref="FileFolderService" />
 | 
			
		||||
      <property name="transactionService" ref="transactionService" />
 | 
			
		||||
   </bean>
 | 
			
		||||
 | 
			
		||||
   <bean class="org.alfresco.rm.rest.api.holds.HoldsChildrenRelation">
 | 
			
		||||
      <property name="holdService" ref="HoldService" />
 | 
			
		||||
      <property name="apiUtils" ref="apiUtils" />
 | 
			
		||||
      <property name="nodesModelFactory" ref="nodesModelFactory" />
 | 
			
		||||
      <property name="fileFolderService" ref="FileFolderService" />
 | 
			
		||||
      <property name="transactionService" ref="transactionService" />
 | 
			
		||||
      <property name="permissionService" ref="PermissionService" />
 | 
			
		||||
   </bean>
 | 
			
		||||
 | 
			
		||||
   <bean class="org.alfresco.rm.rest.api.unfiledcontainers.UnfiledContainerEntityResource">
 | 
			
		||||
       <property name="apiUtils" ref="apiUtils" />
 | 
			
		||||
       <property name="fileFolderService" ref="FileFolderService" />
 | 
			
		||||
       <property name="nodesModelFactory" ref="nodesModelFactory" />
 | 
			
		||||
 
 | 
			
		||||
@@ -1614,6 +1614,8 @@
 | 
			
		||||
            org.alfresco.module.org_alfresco_module_rm.hold.HoldService.createHold=RM_CAP.0.rma:filePlanComponent.CreateHold
 | 
			
		||||
            org.alfresco.module.org_alfresco_module_rm.hold.HoldService.getHoldReason=RM.Read.0
 | 
			
		||||
            org.alfresco.module.org_alfresco_module_rm.hold.HoldService.setHoldReason=RM_CAP.0.rma:filePlanComponent.EditHold
 | 
			
		||||
            org.alfresco.module.org_alfresco_module_rm.hold.HoldService.setHoldDeletionReason=RM_CAP.0.rma:filePlanComponent.EditHold
 | 
			
		||||
            org.alfresco.module.org_alfresco_module_rm.hold.HoldService.updateHold=RM_CAP.0.rma:filePlanComponent.EditHold
 | 
			
		||||
            org.alfresco.module.org_alfresco_module_rm.hold.HoldService.deleteHold=RM_CAP.0.rma:filePlanComponent.DeleteHold
 | 
			
		||||
            org.alfresco.module.org_alfresco_module_rm.hold.HoldService.addToHold=RM_CAP.0.rma:filePlanComponent.AddToHold
 | 
			
		||||
            org.alfresco.module.org_alfresco_module_rm.hold.HoldService.addToHolds=RM_ALLOW
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
   <parent>
 | 
			
		||||
      <groupId>org.alfresco</groupId>
 | 
			
		||||
      <artifactId>alfresco-governance-services-community-repo-parent</artifactId>
 | 
			
		||||
      <version>23.3.0.8</version>
 | 
			
		||||
      <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
   </parent>
 | 
			
		||||
 | 
			
		||||
   <properties>
 | 
			
		||||
@@ -84,6 +84,11 @@
 | 
			
		||||
         <artifactId>junit</artifactId>
 | 
			
		||||
         <scope>test</scope>
 | 
			
		||||
      </dependency>
 | 
			
		||||
      <dependency>
 | 
			
		||||
         <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
         <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
         <scope>test</scope>
 | 
			
		||||
      </dependency>
 | 
			
		||||
      <dependency>
 | 
			
		||||
         <groupId>org.postgresql</groupId>
 | 
			
		||||
         <artifactId>postgresql</artifactId>
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,7 @@
 | 
			
		||||
 | 
			
		||||
package org.alfresco.module.org_alfresco_module_rm.audit.event;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.module.org_alfresco_module_rm.audit.event.HoldUtils.HOLD_DELETION_REASON;
 | 
			
		||||
import static org.alfresco.repo.policy.Behaviour.NotificationFrequency.EVERY_EVENT;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
@@ -77,6 +78,8 @@ public class DeleteHoldAuditEvent extends AuditEvent implements NodeServicePolic
 | 
			
		||||
    public void beforeDeleteNode(NodeRef holdNodeRef)
 | 
			
		||||
    {
 | 
			
		||||
        Map<QName, Serializable> auditProperties = HoldUtils.makePropertiesMap(holdNodeRef, nodeService);
 | 
			
		||||
        auditProperties.put(HOLD_DELETION_REASON, nodeService.getProperty(holdNodeRef, PROP_HOLD_DELETION_REASON));
 | 
			
		||||
 | 
			
		||||
        recordsManagementAuditService.auditEvent(holdNodeRef, getName(), auditProperties, null, true, false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@ class HoldUtils
 | 
			
		||||
{
 | 
			
		||||
    /** A QName to display for the hold name. */
 | 
			
		||||
    public static final QName HOLD_NAME = QName.createQName(RecordsManagementModel.RM_URI, "Hold Name");
 | 
			
		||||
    public static final QName HOLD_DELETION_REASON = QName.createQName(RecordsManagementModel.RM_URI, "Hold deletion reason");
 | 
			
		||||
    /** A QName to display for the hold node ref. */
 | 
			
		||||
    public static final QName HOLD_NODEREF = QName.createQName(RecordsManagementModel.RM_URI, "Hold NodeRef");
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -111,6 +111,24 @@ public interface HoldService
 | 
			
		||||
     */
 | 
			
		||||
    void setHoldReason(NodeRef hold, String reason);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Sets the reason for the hold deletion
 | 
			
		||||
     *
 | 
			
		||||
     * @param hold The {@link NodeRef} of the hold
 | 
			
		||||
     * @param reason {@link String} The reason for the hold
 | 
			
		||||
     */
 | 
			
		||||
    void setHoldDeletionReason(NodeRef hold, String reason);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Updates a hold with the given name, reason and description
 | 
			
		||||
     *
 | 
			
		||||
     * @param hold The {@link NodeRef} of the hold
 | 
			
		||||
     * @param name {@link String} The name of the hold
 | 
			
		||||
     * @param reason {@link String} The reason of the hold
 | 
			
		||||
     * @param description {@link String} The description of the hold
 | 
			
		||||
     */
 | 
			
		||||
    void updateHold(NodeRef hold, String name, String reason, String description);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Deletes the hold
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@ package org.alfresco.module.org_alfresco_module_rm.hold;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.model.ContentModel.ASPECT_LOCKABLE;
 | 
			
		||||
import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
 | 
			
		||||
import static org.alfresco.model.ContentModel.PROP_DESCRIPTION;
 | 
			
		||||
import static org.alfresco.model.ContentModel.PROP_NAME;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
@@ -458,11 +459,11 @@ public class HoldServiceImpl extends ServiceBaseImpl
 | 
			
		||||
 | 
			
		||||
        // create map of properties
 | 
			
		||||
        Map<QName, Serializable> properties = new HashMap<>(3);
 | 
			
		||||
        properties.put(ContentModel.PROP_NAME, name);
 | 
			
		||||
        properties.put(PROP_NAME, name);
 | 
			
		||||
        properties.put(PROP_HOLD_REASON, reason);
 | 
			
		||||
        if (description != null && !description.isEmpty())
 | 
			
		||||
        {
 | 
			
		||||
            properties.put(ContentModel.PROP_DESCRIPTION, description);
 | 
			
		||||
            properties.put(PROP_DESCRIPTION, description);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // create assoc name
 | 
			
		||||
@@ -512,6 +513,39 @@ public class HoldServiceImpl extends ServiceBaseImpl
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @see org.alfresco.module.org_alfresco_module_rm.hold.HoldService#setHoldDeletionReason(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setHoldDeletionReason(NodeRef hold, String reason)
 | 
			
		||||
    {
 | 
			
		||||
        ParameterCheck.mandatory("hold", hold);
 | 
			
		||||
        ParameterCheck.mandatory("reason", reason);
 | 
			
		||||
 | 
			
		||||
        if (nodeService.exists(hold) && isHold(hold))
 | 
			
		||||
        {
 | 
			
		||||
            nodeService.setProperty(hold, PROP_HOLD_DELETION_REASON, reason);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @see org.alfresco.module.org_alfresco_module_rm.hold.HoldService#updateHold(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.lang.String, java.lang.String) (org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.lang.String, java.lang.String)
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void updateHold(NodeRef hold, String name, String reason, String description)
 | 
			
		||||
    {
 | 
			
		||||
        ParameterCheck.mandatory("hold", hold);
 | 
			
		||||
        ParameterCheck.mandatory("name", name);
 | 
			
		||||
        ParameterCheck.mandatory("reason", reason);
 | 
			
		||||
 | 
			
		||||
        if (nodeService.exists(hold) && isHold(hold))
 | 
			
		||||
        {
 | 
			
		||||
            nodeService.setProperty(hold, PROP_NAME, name);
 | 
			
		||||
            nodeService.setProperty(hold, PROP_HOLD_REASON, reason);
 | 
			
		||||
            nodeService.setProperty(hold, PROP_DESCRIPTION, description);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @see org.alfresco.module.org_alfresco_module_rm.hold.HoldService#deleteHold(org.alfresco.service.cmr.repository.NodeRef)
 | 
			
		||||
     */
 | 
			
		||||
@@ -563,7 +597,7 @@ public class HoldServiceImpl extends ServiceBaseImpl
 | 
			
		||||
 | 
			
		||||
                if (permissionService.hasPermission(nodeRef, permission) == AccessStatus.DENIED)
 | 
			
		||||
                {
 | 
			
		||||
                    heldNames.add((String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME));
 | 
			
		||||
                    heldNames.add((String) nodeService.getProperty(nodeRef, PROP_NAME));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (AccessDeniedException ade)
 | 
			
		||||
@@ -630,7 +664,7 @@ public class HoldServiceImpl extends ServiceBaseImpl
 | 
			
		||||
        {
 | 
			
		||||
            if (!isHold(hold))
 | 
			
		||||
            {
 | 
			
		||||
                final String holdName = (String) nodeService.getProperty(hold, ContentModel.PROP_NAME);
 | 
			
		||||
                final String holdName = (String) nodeService.getProperty(hold, PROP_NAME);
 | 
			
		||||
                throw new IntegrityException(I18NUtil.getMessage("rm.hold.not-hold", holdName), null);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -688,7 +722,7 @@ public class HoldServiceImpl extends ServiceBaseImpl
 | 
			
		||||
    {
 | 
			
		||||
        if (!isRecordFolder(nodeRef) && !instanceOf(nodeRef, ContentModel.TYPE_CONTENT))
 | 
			
		||||
        {
 | 
			
		||||
            final String nodeName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
 | 
			
		||||
            final String nodeName = (String) nodeService.getProperty(nodeRef, PROP_NAME);
 | 
			
		||||
            throw new IntegrityException(I18NUtil.getMessage("rm.hold.add-to-hold-invalid-type", nodeName), null);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -795,7 +829,7 @@ public class HoldServiceImpl extends ServiceBaseImpl
 | 
			
		||||
            {
 | 
			
		||||
                if (!isHold(hold))
 | 
			
		||||
                {
 | 
			
		||||
                    final String holdName = (String) nodeService.getProperty(hold, ContentModel.PROP_NAME);
 | 
			
		||||
                    final String holdName = (String) nodeService.getProperty(hold, PROP_NAME);
 | 
			
		||||
                    throw new IntegrityException(I18NUtil.getMessage("rm.hold.not-hold", holdName), null);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,7 @@ import org.alfresco.service.namespace.QName;
 | 
			
		||||
 *
 | 
			
		||||
 * @author Roy Wetherall
 | 
			
		||||
 */
 | 
			
		||||
@SuppressWarnings("PMD.ConstantsInInterface")
 | 
			
		||||
@AlfrescoPublicApi
 | 
			
		||||
public interface RecordsManagementModel extends RecordsManagementCustomModel
 | 
			
		||||
{
 | 
			
		||||
@@ -200,6 +201,7 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel
 | 
			
		||||
    // Hold type
 | 
			
		||||
    QName TYPE_HOLD = QName.createQName(RM_URI, "hold");
 | 
			
		||||
    QName PROP_HOLD_REASON = QName.createQName(RM_URI, "holdReason");
 | 
			
		||||
    QName PROP_HOLD_DELETION_REASON = QName.createQName(RM_URI, "holdDeletionReason");
 | 
			
		||||
    //since 3.2
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    QName ASSOC_FROZEN_RECORDS = QName.createQName(RM_URI, "frozenRecords");
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,155 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rm.rest.api.fileplans;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank;
 | 
			
		||||
import static org.alfresco.util.ParameterCheck.mandatory;
 | 
			
		||||
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
 | 
			
		||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
 | 
			
		||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
 | 
			
		||||
import org.alfresco.rest.framework.WebApiDescription;
 | 
			
		||||
import org.alfresco.rest.framework.resource.RelationshipResource;
 | 
			
		||||
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
 | 
			
		||||
import org.alfresco.rm.rest.api.impl.ApiNodesModelFactory;
 | 
			
		||||
import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils;
 | 
			
		||||
import org.alfresco.rm.rest.api.model.HoldModel;
 | 
			
		||||
import org.alfresco.service.cmr.model.FileFolderService;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.transaction.TransactionService;
 | 
			
		||||
import org.springframework.beans.factory.InitializingBean;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * File plan holds relation
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
@RelationshipResource(name = "holds", entityResource = FilePlanEntityResource.class, title = "Holds in a file plan")
 | 
			
		||||
public class FilePlanHoldsRelation implements
 | 
			
		||||
    RelationshipResourceAction.Create<HoldModel>,
 | 
			
		||||
    RelationshipResourceAction.Read<HoldModel>,
 | 
			
		||||
    InitializingBean
 | 
			
		||||
{
 | 
			
		||||
    private FilePlanComponentsApiUtils apiUtils;
 | 
			
		||||
    private ApiNodesModelFactory nodesModelFactory;
 | 
			
		||||
    private HoldService holdService;
 | 
			
		||||
    private FileFolderService fileFolderService;
 | 
			
		||||
    private TransactionService transactionService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void afterPropertiesSet() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        mandatory("apiUtils", this.apiUtils);
 | 
			
		||||
        mandatory("nodesModelFactory", this.nodesModelFactory);
 | 
			
		||||
        mandatory("holdService", this.holdService);
 | 
			
		||||
        mandatory("fileFolderService", this.fileFolderService);
 | 
			
		||||
        mandatory("transactionService", this.transactionService);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @WebApiDescription(title = "Return a paged list of holds for the file plan identified by 'filePlanId'")
 | 
			
		||||
    public CollectionWithPagingInfo<HoldModel> readAll(String filePlanId, Parameters parameters)
 | 
			
		||||
    {
 | 
			
		||||
        checkNotBlank("filePlanId", filePlanId);
 | 
			
		||||
        mandatory("parameters", parameters);
 | 
			
		||||
 | 
			
		||||
        NodeRef parentNodeRef = apiUtils.lookupAndValidateNodeType(filePlanId, RecordsManagementModel.TYPE_FILE_PLAN);
 | 
			
		||||
        List<NodeRef> holds = holdService.getHolds(parentNodeRef);
 | 
			
		||||
 | 
			
		||||
        List<HoldModel> page = holds.stream()
 | 
			
		||||
            .map(hold -> fileFolderService.getFileInfo(hold))
 | 
			
		||||
            .map(nodesModelFactory::createHoldModel)
 | 
			
		||||
            .skip(parameters.getPaging().getSkipCount())
 | 
			
		||||
            .limit(parameters.getPaging().getMaxItems())
 | 
			
		||||
            .collect(Collectors.toCollection(LinkedList::new));
 | 
			
		||||
 | 
			
		||||
        int totalItems = holds.size();
 | 
			
		||||
        boolean hasMore = parameters.getPaging().getSkipCount() + parameters.getPaging().getMaxItems() < totalItems;
 | 
			
		||||
        return CollectionWithPagingInfo.asPaged(parameters.getPaging(), page, hasMore, totalItems);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @WebApiDescription(title = "Create one (or more) holds in a file plan identified by 'filePlanId'")
 | 
			
		||||
    public List<HoldModel> create(String filePlanId, List<HoldModel> holds, Parameters parameters)
 | 
			
		||||
    {
 | 
			
		||||
        checkNotBlank("filePlanId", filePlanId);
 | 
			
		||||
        mandatory("holds", holds);
 | 
			
		||||
        mandatory("parameters", parameters);
 | 
			
		||||
 | 
			
		||||
        NodeRef parentNodeRef = apiUtils.lookupAndValidateNodeType(filePlanId, RecordsManagementModel.TYPE_FILE_PLAN);
 | 
			
		||||
 | 
			
		||||
        RetryingTransactionCallback<List<NodeRef>> callback = () -> {
 | 
			
		||||
            List<NodeRef> createdNodes = new LinkedList<>();
 | 
			
		||||
            for (HoldModel nodeInfo : holds)
 | 
			
		||||
            {
 | 
			
		||||
                NodeRef newNodeRef = holdService.createHold(parentNodeRef, nodeInfo.name(), nodeInfo.reason(),
 | 
			
		||||
                    nodeInfo.description());
 | 
			
		||||
                createdNodes.add(newNodeRef);
 | 
			
		||||
            }
 | 
			
		||||
            return createdNodes;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        List<NodeRef> createdNodes = transactionService.getRetryingTransactionHelper()
 | 
			
		||||
            .doInTransaction(callback, false, true);
 | 
			
		||||
 | 
			
		||||
        return createdNodes.stream()
 | 
			
		||||
            .map(hold -> fileFolderService.getFileInfo(hold))
 | 
			
		||||
            .map(nodesModelFactory::createHoldModel)
 | 
			
		||||
            .collect(Collectors.toCollection(LinkedList::new));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setApiUtils(FilePlanComponentsApiUtils apiUtils)
 | 
			
		||||
    {
 | 
			
		||||
        this.apiUtils = apiUtils;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNodesModelFactory(ApiNodesModelFactory nodesModelFactory)
 | 
			
		||||
    {
 | 
			
		||||
        this.nodesModelFactory = nodesModelFactory;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setHoldService(HoldService holdService)
 | 
			
		||||
    {
 | 
			
		||||
        this.holdService = holdService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setFileFolderService(FileFolderService fileFolderService)
 | 
			
		||||
    {
 | 
			
		||||
        this.fileFolderService = fileFolderService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTransactionService(TransactionService transactionService)
 | 
			
		||||
    {
 | 
			
		||||
        this.transactionService = transactionService;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,207 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rm.rest.api.holds;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank;
 | 
			
		||||
import static org.alfresco.util.ParameterCheck.mandatory;
 | 
			
		||||
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
 | 
			
		||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
 | 
			
		||||
import org.alfresco.repo.node.integrity.IntegrityException;
 | 
			
		||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
 | 
			
		||||
import org.alfresco.rest.framework.WebApiDescription;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
 | 
			
		||||
import org.alfresco.rest.framework.resource.RelationshipResource;
 | 
			
		||||
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
 | 
			
		||||
import org.alfresco.rm.rest.api.impl.ApiNodesModelFactory;
 | 
			
		||||
import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils;
 | 
			
		||||
import org.alfresco.rm.rest.api.model.HoldChild;
 | 
			
		||||
import org.alfresco.service.cmr.model.FileFolderService;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.StoreRef;
 | 
			
		||||
import org.alfresco.service.cmr.security.AccessStatus;
 | 
			
		||||
import org.alfresco.service.cmr.security.PermissionService;
 | 
			
		||||
import org.alfresco.service.transaction.TransactionService;
 | 
			
		||||
import org.springframework.beans.factory.InitializingBean;
 | 
			
		||||
import org.springframework.extensions.surf.util.I18NUtil;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Hold children relation
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
@RelationshipResource(name = "children", entityResource = HoldsEntityResource.class, title = "Children of a hold")
 | 
			
		||||
public class HoldsChildrenRelation implements
 | 
			
		||||
    RelationshipResourceAction.Create<HoldChild>,
 | 
			
		||||
    RelationshipResourceAction.Read<HoldChild>,
 | 
			
		||||
    RelationshipResourceAction.Delete,
 | 
			
		||||
    InitializingBean
 | 
			
		||||
{
 | 
			
		||||
    private HoldService holdService;
 | 
			
		||||
    private FilePlanComponentsApiUtils apiUtils;
 | 
			
		||||
    private ApiNodesModelFactory nodesModelFactory;
 | 
			
		||||
    private TransactionService transactionService;
 | 
			
		||||
    private FileFolderService fileFolderService;
 | 
			
		||||
    private PermissionService permissionService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void afterPropertiesSet() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        mandatory("holdService", holdService);
 | 
			
		||||
        mandatory("apiUtils", apiUtils);
 | 
			
		||||
        mandatory("nodesModelFactory", nodesModelFactory);
 | 
			
		||||
        mandatory("transactionService", transactionService);
 | 
			
		||||
        mandatory("fileFolderService", fileFolderService);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @WebApiDescription(title = "Add one (or more) children as children of a hold identified by 'holdId'")
 | 
			
		||||
    public List<HoldChild> create(String holdId, List<HoldChild> children, Parameters parameters)
 | 
			
		||||
    {
 | 
			
		||||
        // validate parameters
 | 
			
		||||
        checkNotBlank("holdId", holdId);
 | 
			
		||||
        mandatory("children", children);
 | 
			
		||||
        mandatory("parameters", parameters);
 | 
			
		||||
 | 
			
		||||
        NodeRef parentNodeRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
 | 
			
		||||
 | 
			
		||||
        RetryingTransactionCallback<List<NodeRef>> callback = () -> {
 | 
			
		||||
            List<NodeRef> createdNodes = children.stream()
 | 
			
		||||
                .map(holdChild -> new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, holdChild.id()))
 | 
			
		||||
                .collect(Collectors.toList());
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                holdService.addToHold(parentNodeRef, createdNodes);
 | 
			
		||||
            }
 | 
			
		||||
            catch (IntegrityException exception)
 | 
			
		||||
            {
 | 
			
		||||
                // Throw 400 Bad Request when a node with id 'holdId' is not a hold or a child cannot be added to a hold
 | 
			
		||||
                throw new InvalidArgumentException(exception.getMsgId()).initCause(exception);
 | 
			
		||||
            }
 | 
			
		||||
            return createdNodes;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        List<NodeRef> nodeInfos = transactionService.getRetryingTransactionHelper()
 | 
			
		||||
            .doInTransaction(callback, false, true);
 | 
			
		||||
 | 
			
		||||
        return nodeInfos.stream()
 | 
			
		||||
            .map(nodeRef -> new HoldChild(nodeRef.getId()))
 | 
			
		||||
            .collect(Collectors.toCollection(LinkedList::new));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @WebApiDescription(title = "Return a paged list of hold children for the hold identified by 'holdId'")
 | 
			
		||||
    public CollectionWithPagingInfo<HoldChild> readAll(String holdId, Parameters parameters)
 | 
			
		||||
    {
 | 
			
		||||
        checkNotBlank("holdId", holdId);
 | 
			
		||||
        mandatory("parameters", parameters);
 | 
			
		||||
 | 
			
		||||
        NodeRef parentNodeRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
 | 
			
		||||
        List<NodeRef> children = holdService.getHeld(parentNodeRef);
 | 
			
		||||
 | 
			
		||||
        List<HoldChild> page = children.stream()
 | 
			
		||||
            .map(NodeRef::getId)
 | 
			
		||||
            .map(HoldChild::new)
 | 
			
		||||
            .skip(parameters.getPaging().getSkipCount())
 | 
			
		||||
            .limit(parameters.getPaging().getMaxItems())
 | 
			
		||||
            .collect(Collectors.toCollection(LinkedList::new));
 | 
			
		||||
 | 
			
		||||
        int totalItems = children.size();
 | 
			
		||||
        boolean hasMore = parameters.getPaging().getSkipCount() + parameters.getPaging().getMaxItems() < totalItems;
 | 
			
		||||
        return CollectionWithPagingInfo.asPaged(parameters.getPaging(), page, hasMore, totalItems);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @WebApiDescription(title = "Remove a child from a hold", description = "Remove a child with id 'childId' from a hold with id 'holdId'")
 | 
			
		||||
    public void delete(String holdId, String childId, Parameters parameters)
 | 
			
		||||
    {
 | 
			
		||||
        checkNotBlank("holdId", holdId);
 | 
			
		||||
        checkNotBlank("childId", childId);
 | 
			
		||||
        mandatory("parameters", parameters);
 | 
			
		||||
 | 
			
		||||
        NodeRef nodeRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
 | 
			
		||||
        NodeRef childRef = apiUtils.lookupByPlaceholder(childId);
 | 
			
		||||
 | 
			
		||||
        if (permissionService.hasReadPermission(childRef) == AccessStatus.DENIED)
 | 
			
		||||
        {
 | 
			
		||||
            throw new PermissionDeniedException(I18NUtil.getMessage("permissions.err_access_denied"));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        RetryingTransactionCallback<List<NodeRef>> callback = () -> {
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                holdService.removeFromHold(nodeRef, childRef);
 | 
			
		||||
            }
 | 
			
		||||
            catch (IntegrityException exception)
 | 
			
		||||
            {
 | 
			
		||||
                // Throw 400 Bad Request when a node with id 'holdId' is not a hold
 | 
			
		||||
                throw new InvalidArgumentException(exception.getMsgId()).initCause(exception);
 | 
			
		||||
            }
 | 
			
		||||
            return null;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        transactionService.getRetryingTransactionHelper().doInTransaction(callback, false, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setHoldService(HoldService holdService)
 | 
			
		||||
    {
 | 
			
		||||
        this.holdService = holdService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setApiUtils(FilePlanComponentsApiUtils apiUtils)
 | 
			
		||||
    {
 | 
			
		||||
        this.apiUtils = apiUtils;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTransactionService(TransactionService transactionService)
 | 
			
		||||
    {
 | 
			
		||||
        this.transactionService = transactionService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNodesModelFactory(ApiNodesModelFactory nodesModelFactory)
 | 
			
		||||
    {
 | 
			
		||||
        this.nodesModelFactory = nodesModelFactory;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setFileFolderService(FileFolderService fileFolderService)
 | 
			
		||||
    {
 | 
			
		||||
        this.fileFolderService = fileFolderService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setPermissionService(PermissionService permissionService)
 | 
			
		||||
    {
 | 
			
		||||
        this.permissionService = permissionService;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,184 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rm.rest.api.holds;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank;
 | 
			
		||||
import static org.alfresco.util.ParameterCheck.mandatory;
 | 
			
		||||
 | 
			
		||||
import jakarta.servlet.http.HttpServletResponse;
 | 
			
		||||
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
 | 
			
		||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
 | 
			
		||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
 | 
			
		||||
import org.alfresco.rest.framework.Operation;
 | 
			
		||||
import org.alfresco.rest.framework.WebApiDescription;
 | 
			
		||||
import org.alfresco.rest.framework.WebApiParam;
 | 
			
		||||
import org.alfresco.rest.framework.resource.EntityResource;
 | 
			
		||||
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
 | 
			
		||||
import org.alfresco.rest.framework.webscripts.WithResponse;
 | 
			
		||||
import org.alfresco.rm.rest.api.impl.ApiNodesModelFactory;
 | 
			
		||||
import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils;
 | 
			
		||||
import org.alfresco.rm.rest.api.model.HoldDeletionReason;
 | 
			
		||||
import org.alfresco.rm.rest.api.model.HoldModel;
 | 
			
		||||
import org.alfresco.service.cmr.model.FileFolderService;
 | 
			
		||||
import org.alfresco.service.cmr.model.FileInfo;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.transaction.TransactionService;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.springframework.beans.factory.InitializingBean;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Hold entity resource
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
@EntityResource(name = "holds", title = "Holds")
 | 
			
		||||
public class HoldsEntityResource implements
 | 
			
		||||
    EntityResourceAction.ReadById<HoldModel>,
 | 
			
		||||
    EntityResourceAction.Update<HoldModel>,
 | 
			
		||||
    EntityResourceAction.Delete,
 | 
			
		||||
    InitializingBean
 | 
			
		||||
{
 | 
			
		||||
    private FilePlanComponentsApiUtils apiUtils;
 | 
			
		||||
    private FileFolderService fileFolderService;
 | 
			
		||||
    private ApiNodesModelFactory nodesModelFactory;
 | 
			
		||||
    private HoldService holdService;
 | 
			
		||||
    private TransactionService transactionService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void afterPropertiesSet() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        mandatory("nodesModelFactory", nodesModelFactory);
 | 
			
		||||
        mandatory("apiUtils", apiUtils);
 | 
			
		||||
        mandatory("fileFolderService", fileFolderService);
 | 
			
		||||
        mandatory("holdService", holdService);
 | 
			
		||||
        mandatory("transactionService", transactionService);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @WebApiDescription(title = "Get hold information", description = "Get information for a hold with id 'holdId'")
 | 
			
		||||
    @WebApiParam(name = "holdId", title = "The hold id")
 | 
			
		||||
    public HoldModel readById(String holdId, Parameters parameters)
 | 
			
		||||
    {
 | 
			
		||||
        checkNotBlank("holdId", holdId);
 | 
			
		||||
        mandatory("parameters", parameters);
 | 
			
		||||
 | 
			
		||||
        NodeRef hold = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
 | 
			
		||||
        FileInfo info = fileFolderService.getFileInfo(hold);
 | 
			
		||||
        return nodesModelFactory.createHoldModel(info);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @WebApiDescription(title = "Update a hold", description = "Updates a hold with id 'holdId'")
 | 
			
		||||
    public HoldModel update(String holdId, HoldModel holdModel, Parameters parameters)
 | 
			
		||||
    {
 | 
			
		||||
        checkNotBlank("holdId", holdId);
 | 
			
		||||
        mandatory("holdModel", holdModel);
 | 
			
		||||
        mandatory("holdModel.name", holdModel.name());
 | 
			
		||||
        mandatory("holdModel.reason", holdModel.reason());
 | 
			
		||||
        mandatory("parameters", parameters);
 | 
			
		||||
 | 
			
		||||
        NodeRef nodeRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
 | 
			
		||||
 | 
			
		||||
        RetryingTransactionCallback<Void> callback = () -> {
 | 
			
		||||
            holdService.updateHold(nodeRef, holdModel.name(), holdModel.reason(), holdModel.description());
 | 
			
		||||
            return null;
 | 
			
		||||
        };
 | 
			
		||||
        transactionService.getRetryingTransactionHelper().doInTransaction(callback, false, true);
 | 
			
		||||
 | 
			
		||||
        RetryingTransactionCallback<FileInfo> readCallback = () -> fileFolderService.getFileInfo(nodeRef);
 | 
			
		||||
        FileInfo info = transactionService.getRetryingTransactionHelper().doInTransaction(readCallback, false, true);
 | 
			
		||||
 | 
			
		||||
        return nodesModelFactory.createHoldModel(info);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @WebApiDescription(title = "Delete hold", description = "Deletes a hold with id 'holdId'")
 | 
			
		||||
    public void delete(String holdId, Parameters parameters)
 | 
			
		||||
    {
 | 
			
		||||
        checkNotBlank("holdId", holdId);
 | 
			
		||||
        mandatory("parameters", parameters);
 | 
			
		||||
 | 
			
		||||
        NodeRef hold = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
 | 
			
		||||
        RetryingTransactionCallback<Void> callback = () -> {
 | 
			
		||||
            holdService.deleteHold(hold);
 | 
			
		||||
            return null;
 | 
			
		||||
        };
 | 
			
		||||
        transactionService.getRetryingTransactionHelper().doInTransaction(callback, false, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Operation("delete")
 | 
			
		||||
    @WebApiDescription(title = "Delete hold with a reason",
 | 
			
		||||
        successStatus = HttpServletResponse.SC_OK)
 | 
			
		||||
    public HoldDeletionReason deleteHoldWithReason(String holdId, HoldDeletionReason reason, Parameters parameters,
 | 
			
		||||
        WithResponse withResponse)
 | 
			
		||||
    {
 | 
			
		||||
        checkNotBlank("holdId", holdId);
 | 
			
		||||
        mandatory("reason", reason);
 | 
			
		||||
        mandatory("parameters", parameters);
 | 
			
		||||
 | 
			
		||||
        NodeRef hold = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
 | 
			
		||||
        String deletionReason = reason.reason();
 | 
			
		||||
 | 
			
		||||
        RetryingTransactionCallback<Void> callback = () -> {
 | 
			
		||||
            if (StringUtils.isNotBlank(deletionReason))
 | 
			
		||||
            {
 | 
			
		||||
                holdService.setHoldDeletionReason(hold, deletionReason);
 | 
			
		||||
            }
 | 
			
		||||
            holdService.deleteHold(hold);
 | 
			
		||||
            return null;
 | 
			
		||||
        };
 | 
			
		||||
        transactionService.getRetryingTransactionHelper().doInTransaction(callback, false, true);
 | 
			
		||||
 | 
			
		||||
        return reason;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setApiUtils(FilePlanComponentsApiUtils apiUtils)
 | 
			
		||||
    {
 | 
			
		||||
        this.apiUtils = apiUtils;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setFileFolderService(FileFolderService fileFolderService)
 | 
			
		||||
    {
 | 
			
		||||
        this.fileFolderService = fileFolderService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNodesModelFactory(ApiNodesModelFactory nodesModelFactory)
 | 
			
		||||
    {
 | 
			
		||||
        this.nodesModelFactory = nodesModelFactory;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setHoldService(HoldService holdService)
 | 
			
		||||
    {
 | 
			
		||||
        this.holdService = holdService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTransactionService(TransactionService transactionService)
 | 
			
		||||
    {
 | 
			
		||||
        this.transactionService = transactionService;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Package info that defines the Information Governance Holds REST API
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
@WebApi(name="gs", scope=Api.SCOPE.PUBLIC, version=1)
 | 
			
		||||
package org.alfresco.rm.rest.api.holds;
 | 
			
		||||
import org.alfresco.rest.framework.Api;
 | 
			
		||||
import org.alfresco.rest.framework.WebApi;
 | 
			
		||||
@@ -47,6 +47,7 @@ import org.alfresco.rest.api.model.UserInfo;
 | 
			
		||||
import org.alfresco.rest.framework.jacksonextensions.BeanPropertiesFilter;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
 | 
			
		||||
import org.alfresco.rm.rest.api.model.FilePlan;
 | 
			
		||||
import org.alfresco.rm.rest.api.model.HoldModel;
 | 
			
		||||
import org.alfresco.rm.rest.api.model.RMNode;
 | 
			
		||||
import org.alfresco.rm.rest.api.model.Record;
 | 
			
		||||
import org.alfresco.rm.rest.api.model.RecordCategory;
 | 
			
		||||
@@ -637,6 +638,21 @@ public class ApiNodesModelFactory
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates an object of type HoldModel
 | 
			
		||||
     *
 | 
			
		||||
     * @param info info of the hold
 | 
			
		||||
     * @return HoldModel object
 | 
			
		||||
     */
 | 
			
		||||
    public HoldModel createHoldModel(FileInfo info)
 | 
			
		||||
    {
 | 
			
		||||
        return new HoldModel(info.getNodeRef().getId(),
 | 
			
		||||
            (String) info.getProperties().get(ContentModel.PROP_NAME),
 | 
			
		||||
            (String) info.getProperties().get(ContentModel.PROP_DESCRIPTION),
 | 
			
		||||
            (String)  info.getProperties().get(RecordsManagementModel.PROP_HOLD_REASON));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates an object of type FilePlan
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rm.rest.api.model;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Hold Child POJO for use in the v1 REST API.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
public record HoldChild(String id)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rm.rest.api.model;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Hold Deletion Reason POJO for use in the v1 REST API.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
public record HoldDeletionReason(String reason)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
/*-
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2024 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * -
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * -
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * -
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rm.rest.api.model;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Hold POJO for use in the v1 REST API.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Damian Ujma
 | 
			
		||||
 */
 | 
			
		||||
public record HoldModel(String id, String name, String description, String reason)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
@@ -87,6 +87,7 @@ public class HoldServiceImplUnitTest extends BaseUnitTest
 | 
			
		||||
    /** test values */
 | 
			
		||||
    private static final String HOLD_NAME = "holdname";
 | 
			
		||||
    private static final String HOLD_REASON = "holdreason";
 | 
			
		||||
    private static final String HOLD_DELETION_REASON = "holddeletionreason";
 | 
			
		||||
    private static final String HOLD_DESCRIPTION = "holddescription";
 | 
			
		||||
    private static final String GENERIC_ERROR_MSG = "any error message text";
 | 
			
		||||
 | 
			
		||||
@@ -173,7 +174,7 @@ public class HoldServiceImplUnitTest extends BaseUnitTest
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test (expected=AlfrescoRuntimeException.class)
 | 
			
		||||
    public void getHold()
 | 
			
		||||
    public void testGetHold()
 | 
			
		||||
    {
 | 
			
		||||
        // setup node service interactions
 | 
			
		||||
        when(mockedNodeService.getChildByName(eq(holdContainer), eq(ContentModel.ASSOC_CONTAINS), anyString())).thenReturn(null)
 | 
			
		||||
@@ -194,19 +195,19 @@ public class HoldServiceImplUnitTest extends BaseUnitTest
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test (expected=RuntimeException.class)
 | 
			
		||||
    public void getHeldNotAHold()
 | 
			
		||||
    public void testGetHeldNotAHold()
 | 
			
		||||
    {
 | 
			
		||||
        holdService.getHeld(recordFolder);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void getHeldNoResults()
 | 
			
		||||
    public void testGetHeldNoResults()
 | 
			
		||||
    {
 | 
			
		||||
        assertTrue(holdService.getHeld(hold).isEmpty());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void getHeldWithResults()
 | 
			
		||||
    public void testGetHeldWithResults()
 | 
			
		||||
    {
 | 
			
		||||
        // setup record folder in hold
 | 
			
		||||
        List<ChildAssociationRef> holds = new ArrayList<>(2);
 | 
			
		||||
@@ -259,7 +260,7 @@ public class HoldServiceImplUnitTest extends BaseUnitTest
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void getHoldReason()
 | 
			
		||||
    public void testGetHoldReason()
 | 
			
		||||
    {
 | 
			
		||||
        // setup node service interactions
 | 
			
		||||
        when(mockedNodeService.exists(hold))
 | 
			
		||||
@@ -306,6 +307,80 @@ public class HoldServiceImplUnitTest extends BaseUnitTest
 | 
			
		||||
        verify(mockedNodeService).setProperty(hold, PROP_HOLD_REASON, HOLD_REASON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void setHoldDeletionReasonForNodeDoesNotExist()
 | 
			
		||||
    {
 | 
			
		||||
        // setup node service interactions
 | 
			
		||||
        when(mockedNodeService.exists(hold))
 | 
			
		||||
            .thenReturn(false);
 | 
			
		||||
 | 
			
		||||
        // node does not exist
 | 
			
		||||
        holdService.setHoldDeletionReason(hold, HOLD_DELETION_REASON);
 | 
			
		||||
        verify(mockedNodeService, never()).setProperty(hold, PROP_HOLD_DELETION_REASON, HOLD_DELETION_REASON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void setHoldDeletionReasonForNodeIsNotAHold()
 | 
			
		||||
    {
 | 
			
		||||
        // setup node service interactions
 | 
			
		||||
        when(mockedNodeService.exists(hold))
 | 
			
		||||
            .thenReturn(true);
 | 
			
		||||
 | 
			
		||||
        // node isn't a hold
 | 
			
		||||
        holdService.setHoldDeletionReason(recordFolder, HOLD_DELETION_REASON);
 | 
			
		||||
        verify(mockedNodeService, never()).setProperty(hold, PROP_HOLD_DELETION_REASON, HOLD_DELETION_REASON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void setHoldDeletionReason()
 | 
			
		||||
    {
 | 
			
		||||
        // setup node service interactions
 | 
			
		||||
        when(mockedNodeService.exists(hold))
 | 
			
		||||
            .thenReturn(true);
 | 
			
		||||
 | 
			
		||||
        // set hold deletion reason
 | 
			
		||||
        holdService.setHoldDeletionReason(hold, HOLD_DELETION_REASON);
 | 
			
		||||
        verify(mockedNodeService).setProperty(hold, PROP_HOLD_DELETION_REASON, HOLD_DELETION_REASON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void updateHoldThatDoesNotExist()
 | 
			
		||||
    {
 | 
			
		||||
        // setup node service interactions
 | 
			
		||||
        when(mockedNodeService.exists(hold))
 | 
			
		||||
            .thenReturn(false);
 | 
			
		||||
 | 
			
		||||
        // node does not exist
 | 
			
		||||
        holdService.updateHold(hold, HOLD_NAME, HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        verify(mockedNodeService, never()).setProperty(any(NodeRef.class), any(QName.class), any(String.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void updateHoldThatIsNotAHold()
 | 
			
		||||
    {
 | 
			
		||||
        // setup node service interactions
 | 
			
		||||
        when(mockedNodeService.exists(hold))
 | 
			
		||||
            .thenReturn(true);
 | 
			
		||||
 | 
			
		||||
        // node isn't a hold
 | 
			
		||||
        holdService.updateHold(recordFolder, HOLD_NAME, HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        verify(mockedNodeService, never()).setProperty(any(NodeRef.class), any(QName.class), any(String.class));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void updateHold()
 | 
			
		||||
    {
 | 
			
		||||
        // setup node service interactions
 | 
			
		||||
        when(mockedNodeService.exists(hold))
 | 
			
		||||
            .thenReturn(true);
 | 
			
		||||
 | 
			
		||||
        // update hold
 | 
			
		||||
        holdService.updateHold(hold, HOLD_NAME, HOLD_REASON, HOLD_DESCRIPTION);
 | 
			
		||||
        verify(mockedNodeService).setProperty(hold, ContentModel.PROP_NAME, HOLD_NAME);
 | 
			
		||||
        verify(mockedNodeService).setProperty(hold, ContentModel.PROP_DESCRIPTION, HOLD_DESCRIPTION);
 | 
			
		||||
        verify(mockedNodeService).setProperty(hold, PROP_HOLD_REASON, HOLD_REASON);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test (expected=AlfrescoRuntimeException.class)
 | 
			
		||||
    public void deleteHoldNotAHold()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-governance-services-community-repo-parent</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <build>
 | 
			
		||||
 
 | 
			
		||||
@@ -38,6 +38,8 @@ tags:
 | 
			
		||||
    description: Retrieve and manage unfiled records containers
 | 
			
		||||
  - name: unfiled-record-folders
 | 
			
		||||
    description: Retrieve and manage unfiled record folders
 | 
			
		||||
  - name: holds
 | 
			
		||||
    description: Retrieve and manage holds
 | 
			
		||||
 | 
			
		||||
paths:
 | 
			
		||||
  ## GS sites
 | 
			
		||||
@@ -418,6 +420,124 @@ paths:
 | 
			
		||||
          description: New name clashes with an existing node in the current parent container
 | 
			
		||||
        '422':
 | 
			
		||||
          description: Model integrity exception, including node name with invalid characters
 | 
			
		||||
  '/file-plans/{filePlanId}/holds':
 | 
			
		||||
    get:
 | 
			
		||||
      tags:
 | 
			
		||||
        - file-plans
 | 
			
		||||
      summary: Get all holds in a file plan
 | 
			
		||||
      description: |
 | 
			
		||||
        Returns a list of holds.
 | 
			
		||||
      operationId: getHolds
 | 
			
		||||
      parameters:
 | 
			
		||||
        - $ref: '#/parameters/filePlanIdWithAliasParam'
 | 
			
		||||
        - $ref: '#/parameters/skipCountParam'
 | 
			
		||||
        - $ref: '#/parameters/maxItemsParam'
 | 
			
		||||
      consumes:
 | 
			
		||||
        - application/json
 | 
			
		||||
      produces:
 | 
			
		||||
        - application/json
 | 
			
		||||
      responses:
 | 
			
		||||
        '200':
 | 
			
		||||
          description: Successful response
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/HoldPaging'
 | 
			
		||||
        '401':
 | 
			
		||||
          description: Authentication failed
 | 
			
		||||
        '403':
 | 
			
		||||
          description: Current user does not have permission to read **filePlanId**
 | 
			
		||||
        '404':
 | 
			
		||||
          description: "**filePlanId** does not exist"
 | 
			
		||||
        default:
 | 
			
		||||
          description: Unexpected error
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/Error'
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
        - file-plans
 | 
			
		||||
      summary: Create holds for a file plan
 | 
			
		||||
      description: |
 | 
			
		||||
        Creates a new hold.
 | 
			
		||||
 | 
			
		||||
        You must specify at least a **name** and a **reason** property.
 | 
			
		||||
 | 
			
		||||
        **Note:** You can create more than one hold by specifying a list of holds in the JSON body.
 | 
			
		||||
        For example, the following JSON body creates two holds:
 | 
			
		||||
        ```JSON
 | 
			
		||||
        [
 | 
			
		||||
        {
 | 
			
		||||
          "name":"Hold1",
 | 
			
		||||
          "description": "Description1",
 | 
			
		||||
          "reason": "Reason1"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          "name":"Hold2",
 | 
			
		||||
          "description": "Description2",
 | 
			
		||||
          "reason": "Reason2"
 | 
			
		||||
        }
 | 
			
		||||
        ]
 | 
			
		||||
        ```
 | 
			
		||||
 | 
			
		||||
        If you specify a list as input, then a paginated list rather than an entry is returned in the response body. For example:
 | 
			
		||||
 | 
			
		||||
        ```JSON
 | 
			
		||||
        {
 | 
			
		||||
          "list": {
 | 
			
		||||
            "pagination": {
 | 
			
		||||
              "count": 2,
 | 
			
		||||
              "hasMoreItems": false,
 | 
			
		||||
              "totalItems": 2,
 | 
			
		||||
              "skipCount": 0,
 | 
			
		||||
              "maxItems": 100
 | 
			
		||||
            },
 | 
			
		||||
            "entries": [
 | 
			
		||||
              {
 | 
			
		||||
                "entry": {
 | 
			
		||||
                  ...
 | 
			
		||||
                }
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                "entry": {
 | 
			
		||||
                  ...
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        ```
 | 
			
		||||
      operationId: addHold
 | 
			
		||||
      parameters:
 | 
			
		||||
        - $ref: '#/parameters/filePlanIdWithAliasParam'
 | 
			
		||||
        - in: body
 | 
			
		||||
          name: nodeBodyCreate
 | 
			
		||||
          description: The node information to create.
 | 
			
		||||
          required: true
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/HoldCreateBodyModel'
 | 
			
		||||
      consumes:
 | 
			
		||||
        - application/json
 | 
			
		||||
      produces:
 | 
			
		||||
        - application/json
 | 
			
		||||
      responses:
 | 
			
		||||
        '201':
 | 
			
		||||
          description: Successful response
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/HoldModelEntry'
 | 
			
		||||
        '400':
 | 
			
		||||
          description: |
 | 
			
		||||
            Invalid parameter: **filePlanId** is not a valid format or **HoldCreateBodyModel** is not valid
 | 
			
		||||
        '401':
 | 
			
		||||
          description: Authentication failed
 | 
			
		||||
        '403':
 | 
			
		||||
          description: Current user does not have permission to create a hold
 | 
			
		||||
        '404':
 | 
			
		||||
          description: |
 | 
			
		||||
            **filePlanId** does not exist
 | 
			
		||||
        '409':
 | 
			
		||||
          description: A hold with the name **name** already exists
 | 
			
		||||
        default:
 | 
			
		||||
          description: Unexpected error
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/Error'
 | 
			
		||||
  ## Unfiled records containers
 | 
			
		||||
  '/unfiled-containers/{unfiledContainerId}':
 | 
			
		||||
    get:
 | 
			
		||||
@@ -2092,6 +2212,289 @@ paths:
 | 
			
		||||
          description: Unexpected error
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/Error'
 | 
			
		||||
  ## Holds
 | 
			
		||||
  '/holds/{holdId}':
 | 
			
		||||
    get:
 | 
			
		||||
      tags:
 | 
			
		||||
        - holds
 | 
			
		||||
      summary: Get a hold
 | 
			
		||||
      description: |
 | 
			
		||||
        Gets information for hold with id **holdId**.
 | 
			
		||||
      operationId: getHold
 | 
			
		||||
      parameters:
 | 
			
		||||
        - $ref: '#/parameters/holdIdParam'
 | 
			
		||||
      produces:
 | 
			
		||||
        - application/json
 | 
			
		||||
      responses:
 | 
			
		||||
        '200':
 | 
			
		||||
          description: Successful response
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/HoldModelEntry'
 | 
			
		||||
        '400':
 | 
			
		||||
          description: |
 | 
			
		||||
            Invalid parameter: **holdId** is not a valid format
 | 
			
		||||
        '401':
 | 
			
		||||
          description: Authentication failed
 | 
			
		||||
        '403':
 | 
			
		||||
          description: Current user does not have permission to read **holdId**
 | 
			
		||||
        '404':
 | 
			
		||||
          description: "**holdId** does not exist"
 | 
			
		||||
        default:
 | 
			
		||||
          description: Unexpected error
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/Error'
 | 
			
		||||
    put:
 | 
			
		||||
      tags:
 | 
			
		||||
        - holds
 | 
			
		||||
      summary: Update a hold
 | 
			
		||||
      description: |
 | 
			
		||||
        Updates the hold with id **holdId**. For example, you can rename a hold:
 | 
			
		||||
        ```JSON
 | 
			
		||||
        {
 | 
			
		||||
          "name":"My new name",
 | 
			
		||||
          "description":"Existing description",
 | 
			
		||||
          "reason":"Existing reason"
 | 
			
		||||
        }
 | 
			
		||||
        ```
 | 
			
		||||
      operationId: updateHold
 | 
			
		||||
      parameters:
 | 
			
		||||
        - $ref: '#/parameters/holdIdParam'
 | 
			
		||||
        - in: body
 | 
			
		||||
          name: holdBodyUpdate
 | 
			
		||||
          description: The hold information to update.
 | 
			
		||||
          required: true
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/HoldCreateBodyModel'
 | 
			
		||||
      produces:
 | 
			
		||||
        - application/json
 | 
			
		||||
      responses:
 | 
			
		||||
        '200':
 | 
			
		||||
          description: Successful response
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/HoldModelEntry'
 | 
			
		||||
        '400':
 | 
			
		||||
          description: |
 | 
			
		||||
            Invalid parameter: the update request is invalid or **holdId** is not a valid format or **holdBodyUpdate** is invalid
 | 
			
		||||
        '401':
 | 
			
		||||
          description: Authentication failed
 | 
			
		||||
        '403':
 | 
			
		||||
          description: Current user does not have permission to update **holdId**
 | 
			
		||||
        '404':
 | 
			
		||||
          description: "**holdId** does not exist"
 | 
			
		||||
        '409':
 | 
			
		||||
          description: Updated name clashes with an existing node in the current parent folder
 | 
			
		||||
        default:
 | 
			
		||||
          description: Unexpected error
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/Error'
 | 
			
		||||
    delete:
 | 
			
		||||
      tags:
 | 
			
		||||
        - holds
 | 
			
		||||
      summary: Delete a hold
 | 
			
		||||
      description: |
 | 
			
		||||
        Deletes the hold with id **holdId**.
 | 
			
		||||
      operationId: deleteHold
 | 
			
		||||
      parameters:
 | 
			
		||||
        - $ref: '#/parameters/holdIdParam'
 | 
			
		||||
      produces:
 | 
			
		||||
        - application/json
 | 
			
		||||
      responses:
 | 
			
		||||
        '204':
 | 
			
		||||
          description: Successful response
 | 
			
		||||
        '400':
 | 
			
		||||
          description: |
 | 
			
		||||
            Invalid parameter: **holdId** is not a valid format
 | 
			
		||||
        '401':
 | 
			
		||||
          description: Authentication failed
 | 
			
		||||
        '403':
 | 
			
		||||
          description: Current user does not have permission to delete **holdId**
 | 
			
		||||
        '404':
 | 
			
		||||
          description: "**holdId** does not exist"
 | 
			
		||||
        default:
 | 
			
		||||
          description: Unexpected error
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/Error'
 | 
			
		||||
  '/holds/{holdId}/delete':
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
        - holds
 | 
			
		||||
      summary: Delete a hold with a reason
 | 
			
		||||
      description: |
 | 
			
		||||
        Deletes the hold with id **holdId** and stores a reason for deletion in the audit log.
 | 
			
		||||
        
 | 
			
		||||
        A **reason** must be specified in the request body.
 | 
			
		||||
      operationId: deleteHoldWithReason
 | 
			
		||||
      parameters:
 | 
			
		||||
        - $ref: '#/parameters/holdIdParam'
 | 
			
		||||
        - in: body
 | 
			
		||||
          name: holdDeletionReason
 | 
			
		||||
          description: Reason for deletion.
 | 
			
		||||
          required: true
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/HoldDeletionReason'
 | 
			
		||||
      produces:
 | 
			
		||||
        - application/json
 | 
			
		||||
      responses:
 | 
			
		||||
        '200':
 | 
			
		||||
          description: Successful response
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/HoldDeletionReasonEntry'
 | 
			
		||||
        '400':
 | 
			
		||||
          description: |
 | 
			
		||||
            Invalid parameter: **holdId** is not a valid format
 | 
			
		||||
        '401':
 | 
			
		||||
          description: Authentication failed
 | 
			
		||||
        '403':
 | 
			
		||||
          description: Current user does not have permission to update or delete **holdId**
 | 
			
		||||
        '404':
 | 
			
		||||
          description: "**holdId** does not exist"
 | 
			
		||||
        default:
 | 
			
		||||
          description: Unexpected error
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/Error'
 | 
			
		||||
  '/holds/{holdId}/children':
 | 
			
		||||
    post:
 | 
			
		||||
      tags:
 | 
			
		||||
        - holds
 | 
			
		||||
      summary: Add children to a hold
 | 
			
		||||
      description: |
 | 
			
		||||
        Add a child of a hold with id **holdId**.
 | 
			
		||||
 | 
			
		||||
        You must specify the child **id**.
 | 
			
		||||
        
 | 
			
		||||
        The API returns a 201 Created if the child is already a child of the hold. 
 | 
			
		||||
 | 
			
		||||
        **Note:** You can add more than one child by specifying a list of children in the JSON body.
 | 
			
		||||
        For example, the following JSON body adds two children:
 | 
			
		||||
        ```JSON
 | 
			
		||||
        [
 | 
			
		||||
          {
 | 
			
		||||
            "id":"a7c10f46-b85b-4de5-af1c-930056b736a7"
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            "id":"e0d79b71-be2b-4ce7-a846-a7c50cba20fb"
 | 
			
		||||
          }
 | 
			
		||||
        ]
 | 
			
		||||
        ```
 | 
			
		||||
 | 
			
		||||
        If you specify a list as input, then a paginated list rather than an entry is returned in the response body. For example:
 | 
			
		||||
 | 
			
		||||
        ```JSON
 | 
			
		||||
        {
 | 
			
		||||
          "list": {
 | 
			
		||||
            "pagination": {
 | 
			
		||||
              "count": 2,
 | 
			
		||||
              "hasMoreItems": false,
 | 
			
		||||
              "totalItems": 2,
 | 
			
		||||
              "skipCount": 0,
 | 
			
		||||
              "maxItems": 100
 | 
			
		||||
            },
 | 
			
		||||
            "entries": [
 | 
			
		||||
              {
 | 
			
		||||
                "entry": {
 | 
			
		||||
                  ...
 | 
			
		||||
                }
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                "entry": {
 | 
			
		||||
                  ...
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        ```
 | 
			
		||||
      operationId: addChildToHold
 | 
			
		||||
      parameters:
 | 
			
		||||
        - $ref: '#/parameters/holdIdParam'
 | 
			
		||||
        - in: body
 | 
			
		||||
          name: nodeId
 | 
			
		||||
          description: The node id.
 | 
			
		||||
          required: true
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/HoldChild'
 | 
			
		||||
      consumes:
 | 
			
		||||
        - application/json
 | 
			
		||||
      produces:
 | 
			
		||||
        - application/json
 | 
			
		||||
      responses:
 | 
			
		||||
        '201':
 | 
			
		||||
          description: Successful response
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/HoldChildEntry'
 | 
			
		||||
        '400':
 | 
			
		||||
          description: |
 | 
			
		||||
            Invalid parameter: **holdId** is not a valid format or **HoldChild** is not valid
 | 
			
		||||
        '401':
 | 
			
		||||
          description: Authentication failed
 | 
			
		||||
        '403':
 | 
			
		||||
          description: Current user does not have permission to add items to the hold
 | 
			
		||||
        '404':
 | 
			
		||||
          description: |
 | 
			
		||||
            **holdId** does not exist
 | 
			
		||||
        default:
 | 
			
		||||
          description: Unexpected error
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/Error'
 | 
			
		||||
    get:
 | 
			
		||||
      tags:
 | 
			
		||||
        - holds
 | 
			
		||||
      summary: Get children of a hold
 | 
			
		||||
      description: |
 | 
			
		||||
        Returns a list of children of a hold with id **holdId**.
 | 
			
		||||
      operationId: getHoldChildren
 | 
			
		||||
      parameters:
 | 
			
		||||
        - $ref: '#/parameters/holdIdParam'
 | 
			
		||||
        - $ref: '#/parameters/skipCountParam'
 | 
			
		||||
        - $ref: '#/parameters/maxItemsParam'
 | 
			
		||||
      consumes:
 | 
			
		||||
        - application/json
 | 
			
		||||
      produces:
 | 
			
		||||
        - application/json
 | 
			
		||||
      responses:
 | 
			
		||||
        '200':
 | 
			
		||||
          description: Successful response
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/HoldChildPaging'
 | 
			
		||||
        '401':
 | 
			
		||||
          description: Authentication failed
 | 
			
		||||
        '403':
 | 
			
		||||
          description: Current user does not have permission to read **holdId**
 | 
			
		||||
        '404':
 | 
			
		||||
          description: "**holdId** does not exist"
 | 
			
		||||
        default:
 | 
			
		||||
          description: Unexpected error
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/Error'
 | 
			
		||||
  '/holds/{holdId}/children/{holdChildId}':
 | 
			
		||||
    delete:
 | 
			
		||||
      tags:
 | 
			
		||||
        - holds
 | 
			
		||||
      summary: Delete a child of a hold
 | 
			
		||||
      description: |
 | 
			
		||||
        Deletes the relationship between a child with id **holdChildId** and a parent hold with id **holdId**.
 | 
			
		||||
      operationId: removeHoldChild
 | 
			
		||||
      parameters:
 | 
			
		||||
        - $ref: '#/parameters/holdIdParam'
 | 
			
		||||
        - $ref: '#/parameters/holdChildIdParam'
 | 
			
		||||
      produces:
 | 
			
		||||
        - application/json
 | 
			
		||||
      responses:
 | 
			
		||||
        '204':
 | 
			
		||||
          description: Successful response
 | 
			
		||||
        '400':
 | 
			
		||||
          description: |
 | 
			
		||||
            Invalid parameter: **holdChildId** or **holdId** is not a valid format
 | 
			
		||||
        '401':
 | 
			
		||||
          description: Authentication failed
 | 
			
		||||
        '403':
 | 
			
		||||
          description: Current user does not have permission to delete **holdChildId**
 | 
			
		||||
        '404':
 | 
			
		||||
          description: " **holdChildId** or **holdId** does not exist"
 | 
			
		||||
        default:
 | 
			
		||||
          description: Unexpected error
 | 
			
		||||
          schema:
 | 
			
		||||
            $ref: '#/definitions/Error'
 | 
			
		||||
 | 
			
		||||
parameters:
 | 
			
		||||
  ## File plans
 | 
			
		||||
@@ -2175,7 +2578,7 @@ parameters:
 | 
			
		||||
    description: Also include **source** (in addition to **entries**) with folder information on the parent node – the specified parent **unfiledContainerId**
 | 
			
		||||
    required: false
 | 
			
		||||
    type: boolean
 | 
			
		||||
## Unfiled record folders
 | 
			
		||||
  ## Unfiled record folders
 | 
			
		||||
  unfiledRecordFolderIdParam:
 | 
			
		||||
    name: unfiledRecordFolderId
 | 
			
		||||
    in: path
 | 
			
		||||
@@ -2446,6 +2849,19 @@ parameters:
 | 
			
		||||
    items:
 | 
			
		||||
      type: string
 | 
			
		||||
    collectionFormat: csv
 | 
			
		||||
  # Holds
 | 
			
		||||
  holdIdParam:
 | 
			
		||||
    name: holdId
 | 
			
		||||
    in: path
 | 
			
		||||
    description: The identifier of a hold.
 | 
			
		||||
    required: true
 | 
			
		||||
    type: string
 | 
			
		||||
  holdChildIdParam:
 | 
			
		||||
    name: holdChildId
 | 
			
		||||
    in: path
 | 
			
		||||
    description: The identifier of a child of a hold.
 | 
			
		||||
    required: true
 | 
			
		||||
    type: string
 | 
			
		||||
  ## Record
 | 
			
		||||
  recordIdParam:
 | 
			
		||||
    name: recordId
 | 
			
		||||
@@ -3519,6 +3935,89 @@ definitions:
 | 
			
		||||
        properties:
 | 
			
		||||
          association:
 | 
			
		||||
            $ref: '#/definitions/ChildAssociationInfo'
 | 
			
		||||
  ## Holds
 | 
			
		||||
  HoldModelEntry:
 | 
			
		||||
    type: object
 | 
			
		||||
    required:
 | 
			
		||||
      - entry
 | 
			
		||||
    properties:
 | 
			
		||||
      entry:
 | 
			
		||||
        $ref: '#/definitions/HoldModel'
 | 
			
		||||
  HoldModel:
 | 
			
		||||
    type: object
 | 
			
		||||
    properties:
 | 
			
		||||
      id:
 | 
			
		||||
        type: string
 | 
			
		||||
      name:
 | 
			
		||||
        type: string
 | 
			
		||||
      description:
 | 
			
		||||
        type: string
 | 
			
		||||
      reason:
 | 
			
		||||
        type: string
 | 
			
		||||
  HoldCreateBodyModel:
 | 
			
		||||
    type: object
 | 
			
		||||
    required:
 | 
			
		||||
      - name
 | 
			
		||||
      - reason
 | 
			
		||||
    properties:
 | 
			
		||||
      name:
 | 
			
		||||
        type: string
 | 
			
		||||
      description:
 | 
			
		||||
        type: string
 | 
			
		||||
      reason:
 | 
			
		||||
        type: string
 | 
			
		||||
  HoldPaging:
 | 
			
		||||
    type: object
 | 
			
		||||
    properties:
 | 
			
		||||
      list:
 | 
			
		||||
        type: object
 | 
			
		||||
        properties:
 | 
			
		||||
          pagination:
 | 
			
		||||
            $ref: '#/definitions/Pagination'
 | 
			
		||||
          entries:
 | 
			
		||||
            type: array
 | 
			
		||||
            items:
 | 
			
		||||
              $ref: '#/definitions/HoldModelEntry'
 | 
			
		||||
  HoldChild:
 | 
			
		||||
    type: object
 | 
			
		||||
    required:
 | 
			
		||||
      - id
 | 
			
		||||
    properties:
 | 
			
		||||
      id:
 | 
			
		||||
        type: string
 | 
			
		||||
  HoldChildEntry:
 | 
			
		||||
    type: object
 | 
			
		||||
    required:
 | 
			
		||||
      - entry
 | 
			
		||||
    properties:
 | 
			
		||||
      entry:
 | 
			
		||||
        $ref: '#/definitions/HoldChild'
 | 
			
		||||
  HoldChildPaging:
 | 
			
		||||
    type: object
 | 
			
		||||
    properties:
 | 
			
		||||
      list:
 | 
			
		||||
        type: object
 | 
			
		||||
        properties:
 | 
			
		||||
          pagination:
 | 
			
		||||
            $ref: '#/definitions/Pagination'
 | 
			
		||||
          entries:
 | 
			
		||||
            type: array
 | 
			
		||||
            items:
 | 
			
		||||
              $ref: '#/definitions/HoldChildEntry'
 | 
			
		||||
  HoldDeletionReasonEntry:
 | 
			
		||||
    type: object
 | 
			
		||||
    required:
 | 
			
		||||
      - entry
 | 
			
		||||
    properties:
 | 
			
		||||
      entry:
 | 
			
		||||
        $ref: '#/definitions/HoldDeletionReason'
 | 
			
		||||
  HoldDeletionReason:
 | 
			
		||||
    type: object
 | 
			
		||||
    required:
 | 
			
		||||
      - reason
 | 
			
		||||
    properties:
 | 
			
		||||
      reason:
 | 
			
		||||
        type: string
 | 
			
		||||
  ##
 | 
			
		||||
  RequestBodyFile:
 | 
			
		||||
    type: object
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <modules>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-amps</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
@@ -70,6 +70,11 @@
 | 
			
		||||
            <artifactId>junit</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
            <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.postgresql</groupId>
 | 
			
		||||
            <artifactId>postgresql</artifactId>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
							
								
								
									
										14
									
								
								core/pom.xml
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								core/pom.xml
									
									
									
									
									
								
							@@ -7,7 +7,7 @@
 | 
			
		||||
   <parent>
 | 
			
		||||
      <groupId>org.alfresco</groupId>
 | 
			
		||||
      <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
      <version>23.3.0.8</version>
 | 
			
		||||
      <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
   </parent>
 | 
			
		||||
 | 
			
		||||
   <dependencies>
 | 
			
		||||
@@ -126,6 +126,11 @@
 | 
			
		||||
         <artifactId>junit</artifactId>
 | 
			
		||||
         <scope>test</scope>
 | 
			
		||||
      </dependency>
 | 
			
		||||
      <dependency>
 | 
			
		||||
         <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
         <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
         <scope>test</scope>
 | 
			
		||||
      </dependency>
 | 
			
		||||
      <dependency>
 | 
			
		||||
         <groupId>org.mockito</groupId>
 | 
			
		||||
         <artifactId>mockito-core</artifactId>
 | 
			
		||||
@@ -158,6 +163,13 @@
 | 
			
		||||
               </execution>
 | 
			
		||||
            </executions>
 | 
			
		||||
         </plugin>
 | 
			
		||||
         <plugin>
 | 
			
		||||
            <groupId>org.apache.maven.plugins</groupId>
 | 
			
		||||
            <artifactId>maven-surefire-plugin</artifactId>
 | 
			
		||||
            <configuration>
 | 
			
		||||
               <skipTests>${skipCoreTests}</skipTests>
 | 
			
		||||
            </configuration>
 | 
			
		||||
         </plugin>
 | 
			
		||||
      </plugins>
 | 
			
		||||
   </build>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										59
									
								
								core/src/test/java/AllCoreUnitTestSuite.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								core/src/test/java/AllCoreUnitTestSuite.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%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 <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco;
 | 
			
		||||
 | 
			
		||||
import org.junit.experimental.categories.Categories;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.junit.runners.Suite;
 | 
			
		||||
 | 
			
		||||
@RunWith(Categories.class)
 | 
			
		||||
@Suite.SuiteClasses({
 | 
			
		||||
        org.alfresco.config.SystemPropertiesSetterBeanTest.class,
 | 
			
		||||
        org.alfresco.encryption.AlfrescoKeyStoreTest.class,
 | 
			
		||||
        org.alfresco.encryption.EncryptingOutputStreamTest.class,
 | 
			
		||||
        org.alfresco.error.AlfrescoRuntimeExceptionTest.class,
 | 
			
		||||
        org.alfresco.query.CannedQueryTest.class,
 | 
			
		||||
        org.alfresco.util.BridgeTableTest.class,
 | 
			
		||||
        org.alfresco.util.CachingDateFormatTest.class,
 | 
			
		||||
        org.alfresco.util.DynamicallySizedThreadPoolExecutorTest.class,
 | 
			
		||||
        org.alfresco.util.EqualsHelperTest.class,
 | 
			
		||||
        org.alfresco.util.GuidTest.class,
 | 
			
		||||
        org.alfresco.util.ISO8601DateFormatTest.class,
 | 
			
		||||
        org.alfresco.util.LogAdapterTest.class,
 | 
			
		||||
        org.alfresco.util.LogTeeTest.class,
 | 
			
		||||
        org.alfresco.util.PathMapperTest.class,
 | 
			
		||||
        org.alfresco.util.TempFileProviderTest.class,
 | 
			
		||||
        org.alfresco.util.VersionNumberTest.class,
 | 
			
		||||
        org.alfresco.util.collections.CollectionUtilsTest.class,
 | 
			
		||||
        org.alfresco.util.exec.ExecParameterTokenizerTest.class,
 | 
			
		||||
        org.alfresco.util.exec.RuntimeExecBeansTest.class,
 | 
			
		||||
        org.alfresco.util.exec.RuntimeExecTest.class,
 | 
			
		||||
        org.alfresco.util.random.NormalDistributionHelperTest.class,
 | 
			
		||||
        org.alfresco.util.shard.ExplicitShardingPolicyTest.class,
 | 
			
		||||
        org.alfresco.util.transaction.SpringAwareUserTransactionTest.class
 | 
			
		||||
})
 | 
			
		||||
public class AllCoreUnitTestSuite {
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
@@ -235,6 +235,11 @@
 | 
			
		||||
            <artifactId>junit</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
            <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.antlr</groupId>
 | 
			
		||||
            <artifactId>gunit</artifactId>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%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 <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco;
 | 
			
		||||
 | 
			
		||||
import org.junit.experimental.categories.Categories;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.junit.runners.Suite;
 | 
			
		||||
 | 
			
		||||
@RunWith(Categories.class)
 | 
			
		||||
@Suite.SuiteClasses({
 | 
			
		||||
        org.alfresco.opencmis.dictionary.CMISAbstractDictionaryServiceTest.class,
 | 
			
		||||
        org.alfresco.repo.content.MimetypeMapTest.class,
 | 
			
		||||
        org.alfresco.repo.content.encoding.CharsetFinderTest.class,
 | 
			
		||||
        org.alfresco.repo.dictionary.AbstractModelTest.class,
 | 
			
		||||
        org.alfresco.repo.dictionary.DictionaryComponentTest.class,
 | 
			
		||||
        org.alfresco.repo.dictionary.DictionaryDAOTest.class,
 | 
			
		||||
        org.alfresco.repo.dictionary.DiffModelTest.class,
 | 
			
		||||
        org.alfresco.repo.dictionary.constraint.ConstraintsTest.class,
 | 
			
		||||
        org.alfresco.repo.index.ShardMethodEnumTest.class,
 | 
			
		||||
        org.alfresco.repo.search.impl.parsers.CMISTest.class,
 | 
			
		||||
        org.alfresco.repo.search.impl.parsers.CMIS_FTSTest.class,
 | 
			
		||||
        org.alfresco.repo.search.impl.parsers.FTSTest.class,
 | 
			
		||||
        org.alfresco.repo.security.authentication.InMemoryTicketComponentTest.class,
 | 
			
		||||
        org.alfresco.service.cmr.repository.MLTextTest.class,
 | 
			
		||||
        org.alfresco.service.cmr.repository.NodeRefTest.class,
 | 
			
		||||
        org.alfresco.service.cmr.repository.PathTest.class,
 | 
			
		||||
        org.alfresco.service.cmr.repository.PeriodTest.class,
 | 
			
		||||
        org.alfresco.service.cmr.repository.datatype.DefaultTypeConverterTest.class,
 | 
			
		||||
        org.alfresco.service.cmr.search.StatsProcessorTest.class,
 | 
			
		||||
        org.alfresco.service.namespace.DynamicNameSpaceResolverTest.class,
 | 
			
		||||
        org.alfresco.service.namespace.QNamePatternTest.class,
 | 
			
		||||
        org.alfresco.service.namespace.QNameTest.class,
 | 
			
		||||
        org.alfresco.util.ConfigFileFinderTest.class,
 | 
			
		||||
        org.alfresco.util.ConfigSchedulerTest.class,
 | 
			
		||||
        org.alfresco.util.ISO9075Test.class,
 | 
			
		||||
        org.alfresco.util.NumericEncodingTest.class,
 | 
			
		||||
        org.alfresco.util.SearchDateConversionTest.class,
 | 
			
		||||
        org.alfresco.util.SearchLanguageConversionTest.class
 | 
			
		||||
})
 | 
			
		||||
public class AllDataModelUnitTestSuite {
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <dependencies>
 | 
			
		||||
@@ -46,6 +46,11 @@
 | 
			
		||||
            <artifactId>junit</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
            <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.mockito</groupId>
 | 
			
		||||
            <artifactId>mockito-core</artifactId>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
@@ -9,6 +9,6 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-packaging</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
</project>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-packaging</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <modules>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
SOLR6_TAG=2.0.8.1
 | 
			
		||||
SOLR6_TAG=2.0.10
 | 
			
		||||
POSTGRES_TAG=15.4
 | 
			
		||||
ACTIVEMQ_TAG=5.18.3-jre17-rockylinux8
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-packaging</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <modules>
 | 
			
		||||
 
 | 
			
		||||
@@ -27,8 +27,8 @@ fi
 | 
			
		||||
# The second parameter can be used to avoid doing a clean up if we are doing a restart test.
 | 
			
		||||
if [ "$CLEAN_UP" != "no-clean-up" ]
 | 
			
		||||
then
 | 
			
		||||
  docker-compose ${DOCKER_COMPOSES} --project-directory $(dirname "${DOCKER_COMPOSE_PATH}") kill
 | 
			
		||||
  docker-compose ${DOCKER_COMPOSES} --project-directory $(dirname "${DOCKER_COMPOSE_PATH}") rm -f
 | 
			
		||||
  docker compose ${DOCKER_COMPOSES} --project-directory $(dirname "${DOCKER_COMPOSE_PATH}") kill
 | 
			
		||||
  docker compose ${DOCKER_COMPOSES} --project-directory $(dirname "${DOCKER_COMPOSE_PATH}") rm -f
 | 
			
		||||
 | 
			
		||||
  export GENERATED_IMAGES=$(docker images | grep '^environment_' | awk '{ print $3 }')
 | 
			
		||||
  if [ -n "$GENERATED_IMAGES" ]
 | 
			
		||||
@@ -42,8 +42,7 @@ echo "Starting ACS stack in ${DOCKER_COMPOSE_PATH}"
 | 
			
		||||
export TRANSFORMERS_TAG=$(mvn help:evaluate -Dexpression=dependency.alfresco-transform-core.version -q -DforceStdout)
 | 
			
		||||
export TRANSFORM_ROUTER_TAG=$(mvn help:evaluate -Dexpression=dependency.alfresco-transform-service.version -q -DforceStdout)
 | 
			
		||||
 | 
			
		||||
# .env files are picked up from project directory correctly on docker-compose 1.23.0+
 | 
			
		||||
docker-compose ${DOCKER_COMPOSES} --project-directory $(dirname "${DOCKER_COMPOSE_PATH}") up -d
 | 
			
		||||
docker compose ${DOCKER_COMPOSES} --project-directory $(dirname "${DOCKER_COMPOSE_PATH}") up -d
 | 
			
		||||
 | 
			
		||||
if [ $? -eq 0 ]
 | 
			
		||||
then
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,8 @@ fi
 | 
			
		||||
 | 
			
		||||
echo "Killing ACS stack in ${DOCKER_COMPOSE_PATH}"
 | 
			
		||||
 | 
			
		||||
docker-compose --file ${DOCKER_COMPOSE_PATH} ps
 | 
			
		||||
docker compose --file ${DOCKER_COMPOSE_PATH} ps
 | 
			
		||||
# logs for debug
 | 
			
		||||
docker-compose --file ${DOCKER_COMPOSE_PATH} logs --no-color -t alfresco
 | 
			
		||||
docker-compose --file ${DOCKER_COMPOSE_PATH} kill
 | 
			
		||||
docker-compose --file ${DOCKER_COMPOSE_PATH} rm -fv
 | 
			
		||||
docker compose --file ${DOCKER_COMPOSE_PATH} logs --no-color -t alfresco
 | 
			
		||||
docker compose --file ${DOCKER_COMPOSE_PATH} kill
 | 
			
		||||
docker compose --file ${DOCKER_COMPOSE_PATH} rm -fv
 | 
			
		||||
@@ -51,7 +51,7 @@ else
 | 
			
		||||
   echo "Alfresco Could not start in time."
 | 
			
		||||
   echo "All started containers:"	
 | 
			
		||||
   docker ps -a	
 | 
			
		||||
   ALFCONTAINER=`docker ps -a | grep _alfresco | awk '{ print $1 }'`
 | 
			
		||||
   ALFCONTAINER=`docker ps -a | grep '\-alfresco' | awk '{ print $1 }'`
 | 
			
		||||
   echo "Last 200 lines from alfresco.log on container $ALFCONTAINER:"
 | 
			
		||||
   docker logs --tail=200 $ALFCONTAINER
 | 
			
		||||
   exit 1
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-tests</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <organization>
 | 
			
		||||
@@ -68,6 +68,16 @@
 | 
			
		||||
                </exclusion>
 | 
			
		||||
            </exclusions>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
            <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.squareup.okhttp3</groupId>
 | 
			
		||||
            <artifactId>okhttp</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
    <build>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-tests</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <developers>
 | 
			
		||||
@@ -36,6 +36,11 @@
 | 
			
		||||
            <artifactId>jakarta.mail-api</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
            <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
    <build>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-tests</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <developers>
 | 
			
		||||
@@ -44,6 +44,18 @@
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
            <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.squareup.okhttp3</groupId>
 | 
			
		||||
            <artifactId>okhttp</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.sun.mail</groupId>
 | 
			
		||||
            <artifactId>jakarta.mail</artifactId>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-tests</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
@@ -79,6 +79,18 @@
 | 
			
		||||
            <version>${commons-lang3.version}</version>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
            <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.squareup.okhttp3</groupId>
 | 
			
		||||
            <artifactId>okhttp</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.awaitility</groupId>
 | 
			
		||||
            <artifactId>awaitility</artifactId>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-tests</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <developers>
 | 
			
		||||
@@ -31,6 +31,11 @@
 | 
			
		||||
            <artifactId>webdav</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
            <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
    <build>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-packaging</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								pom.xml
									
									
									
									
									
								
							@@ -2,7 +2,7 @@
 | 
			
		||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
			
		||||
    <modelVersion>4.0.0</modelVersion>
 | 
			
		||||
    <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
    <version>23.3.0.8</version>
 | 
			
		||||
    <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    <packaging>pom</packaging>
 | 
			
		||||
    <name>Alfresco Community Repo Parent</name>
 | 
			
		||||
 | 
			
		||||
@@ -51,13 +51,13 @@
 | 
			
		||||
        <dependency.alfresco-server-root.version>7.0.1</dependency.alfresco-server-root.version>
 | 
			
		||||
        <dependency.activiti-engine.version>5.23.0</dependency.activiti-engine.version>
 | 
			
		||||
        <dependency.activiti.version>5.23.0</dependency.activiti.version>
 | 
			
		||||
        <dependency.alfresco-transform-core.version>5.1.0</dependency.alfresco-transform-core.version>
 | 
			
		||||
        <dependency.alfresco-transform-service.version>4.1.0</dependency.alfresco-transform-service.version>
 | 
			
		||||
        <dependency.alfresco-transform-core.version>5.1.1</dependency.alfresco-transform-core.version>
 | 
			
		||||
        <dependency.alfresco-transform-service.version>4.1.1</dependency.alfresco-transform-service.version>
 | 
			
		||||
        <dependency.alfresco-greenmail.version>7.0</dependency.alfresco-greenmail.version>
 | 
			
		||||
        <dependency.acs-event-model.version>0.0.27</dependency.acs-event-model.version>
 | 
			
		||||
 | 
			
		||||
        <dependency.aspectj.version>1.9.20.1</dependency.aspectj.version>
 | 
			
		||||
        <dependency.spring.version>6.0.14</dependency.spring.version>
 | 
			
		||||
        <dependency.spring.version>6.0.17</dependency.spring.version>
 | 
			
		||||
        <dependency.spring-security.version>6.2.2</dependency.spring-security.version>
 | 
			
		||||
        <dependency.antlr.version>3.5.3</dependency.antlr.version>
 | 
			
		||||
        <dependency.jackson.version>2.15.2</dependency.jackson.version>
 | 
			
		||||
@@ -81,7 +81,7 @@
 | 
			
		||||
        <dependency.slf4j.version>2.0.9</dependency.slf4j.version>
 | 
			
		||||
        <dependency.log4j.version>2.20.0</dependency.log4j.version>
 | 
			
		||||
        <dependency.groovy.version>3.0.19</dependency.groovy.version>
 | 
			
		||||
        <dependency.tika.version>2.9.1</dependency.tika.version>
 | 
			
		||||
        <dependency.tika.version>2.9.2</dependency.tika.version>
 | 
			
		||||
        <dependency.truezip.version>7.7.10</dependency.truezip.version>
 | 
			
		||||
        <dependency.poi.version>5.2.5</dependency.poi.version>
 | 
			
		||||
        <dependency.jboss.logging.version>3.5.0.Final</dependency.jboss.logging.version>
 | 
			
		||||
@@ -114,9 +114,9 @@
 | 
			
		||||
        <dependency.json-smart.version>2.5.0</dependency.json-smart.version>
 | 
			
		||||
        <alfresco.googledrive.version>4.1.0</alfresco.googledrive.version>
 | 
			
		||||
        <alfresco.aos-module.version>3.0.0</alfresco.aos-module.version>
 | 
			
		||||
        <alfresco.api-explorer.version>23.1.0</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
 | 
			
		||||
        <alfresco.api-explorer.version>23.2.0</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
 | 
			
		||||
 | 
			
		||||
        <alfresco.maven-plugin.version>2.2.0</alfresco.maven-plugin.version>
 | 
			
		||||
        <alfresco.maven-plugin.version>4.8.0</alfresco.maven-plugin.version>
 | 
			
		||||
        <license-maven-plugin.version>2.0.1</license-maven-plugin.version>
 | 
			
		||||
 | 
			
		||||
        <dependency.postgresql.version>42.6.0</dependency.postgresql.version>
 | 
			
		||||
@@ -151,7 +151,7 @@
 | 
			
		||||
        <connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection>
 | 
			
		||||
        <developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection>
 | 
			
		||||
        <url>https://github.com/Alfresco/alfresco-community-repo</url>
 | 
			
		||||
        <tag>23.3.0.8</tag>
 | 
			
		||||
        <tag>HEAD</tag>
 | 
			
		||||
    </scm>
 | 
			
		||||
 | 
			
		||||
    <distributionManagement>
 | 
			
		||||
@@ -265,6 +265,7 @@
 | 
			
		||||
                <version>${dependency.jakarta-ee-json-impl.version}</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
 | 
			
		||||
            <!-- This dependency was added to align dependency in the AI Rendition AMP [ACS-4844] -->
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>com.jayway.jsonpath</groupId>
 | 
			
		||||
                <artifactId>json-path</artifactId>
 | 
			
		||||
@@ -328,7 +329,7 @@
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>xalan</groupId>
 | 
			
		||||
                <artifactId>xalan</artifactId>
 | 
			
		||||
                <version>2.7.2-alfresco</version>
 | 
			
		||||
                <version>2.7.3-alfresco</version>
 | 
			
		||||
                <exclusions>
 | 
			
		||||
                    <!-- [ACS-544] Excluded to avoid conflict in JDK9+ as it includes javax.xml and w3c.org -->
 | 
			
		||||
                    <exclusion>
 | 
			
		||||
@@ -819,6 +820,18 @@
 | 
			
		||||
                <version>4.13.2</version>
 | 
			
		||||
                <scope>test</scope>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
                <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
                <version>5.4.0</version>
 | 
			
		||||
                <scope>test</scope>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>com.squareup.okhttp3</groupId>
 | 
			
		||||
                <artifactId>okhttp</artifactId>
 | 
			
		||||
                <version>4.12.0</version>
 | 
			
		||||
                <scope>test</scope>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>org.antlr</groupId>
 | 
			
		||||
                <artifactId>gunit</artifactId>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <dependencies>
 | 
			
		||||
@@ -66,6 +66,11 @@
 | 
			
		||||
            <artifactId>junit</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
            <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.mockito</groupId>
 | 
			
		||||
            <artifactId>mockito-core</artifactId>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
        <version>23.3.0.8</version>
 | 
			
		||||
        <version>23.3.0.27-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <dependencies>
 | 
			
		||||
@@ -627,6 +627,11 @@
 | 
			
		||||
            <artifactId>junit</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>com.epam.reportportal</groupId>
 | 
			
		||||
            <artifactId>agent-java-testng</artifactId>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.assertj</groupId>
 | 
			
		||||
            <artifactId>assertj-core</artifactId>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,28 +1,28 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Repository
 | 
			
		||||
 * %%
 | 
			
		||||
 * 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 <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
 * #%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 <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.repo.template;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
@@ -59,6 +59,7 @@ import org.apache.bsf.BSFManager;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
import org.apache.xalan.processor.TransformerFactoryImpl;
 | 
			
		||||
import org.apache.xml.utils.Constants;
 | 
			
		||||
import org.w3c.dom.Document;
 | 
			
		||||
import org.w3c.dom.Element;
 | 
			
		||||
@@ -142,6 +143,7 @@ public class XSLTProcessor extends BaseProcessor implements TemplateProcessor
 | 
			
		||||
 | 
			
		||||
        XSLTemplateModel xsltModel = (XSLTemplateModel) model;
 | 
			
		||||
        System.setProperty("org.apache.xalan.extensions.bsf.BSFManager", BSFManager.class.getName());
 | 
			
		||||
        System.setProperty("javax.xml.transform.TransformerFactory", TransformerFactoryImpl.class.getName());
 | 
			
		||||
 | 
			
		||||
        Document xslTemplate;
 | 
			
		||||
        try
 | 
			
		||||
 
 | 
			
		||||
@@ -53,8 +53,6 @@ import org.alfresco.service.cmr.transfer.TransferTarget;
 | 
			
		||||
import org.alfresco.service.cmr.transfer.TransferVersion;
 | 
			
		||||
import org.alfresco.util.HttpClientHelper;
 | 
			
		||||
import org.alfresco.util.PropertyCheck;
 | 
			
		||||
import org.alfresco.util.json.ExceptionJsonSerializer;
 | 
			
		||||
import org.alfresco.util.json.JsonSerializer;
 | 
			
		||||
import org.apache.commons.httpclient.Credentials;
 | 
			
		||||
import org.apache.commons.httpclient.HostConfiguration;
 | 
			
		||||
import org.apache.commons.httpclient.HttpClient;
 | 
			
		||||
@@ -73,8 +71,10 @@ import org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory;
 | 
			
		||||
import org.apache.commons.httpclient.protocol.Protocol;
 | 
			
		||||
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
 | 
			
		||||
import org.apache.commons.httpclient.protocol.SSLProtocolSocketFactory;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
import org.json.JSONArray;
 | 
			
		||||
import org.json.JSONObject;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -102,7 +102,6 @@ public class HttpClientTransmitterImpl implements TransferTransmitter
 | 
			
		||||
    private Protocol httpsProtocol = new Protocol(HTTPS_SCHEME_NAME, (ProtocolSocketFactory) new SSLProtocolSocketFactory(), DEFAULT_HTTPS_PORT);
 | 
			
		||||
    private Map<String,Protocol> protocolMap = null;
 | 
			
		||||
    private HttpMethodFactory httpMethodFactory = null;
 | 
			
		||||
    private JsonSerializer<Throwable, JSONObject> jsonErrorSerializer;
 | 
			
		||||
 | 
			
		||||
    private ContentService contentService;
 | 
			
		||||
 | 
			
		||||
@@ -125,7 +124,6 @@ public class HttpClientTransmitterImpl implements TransferTransmitter
 | 
			
		||||
        httpClient = new HttpClient();
 | 
			
		||||
        httpClient.setHttpConnectionManager(new MultiThreadedHttpConnectionManager());
 | 
			
		||||
        httpMethodFactory = new StandardHttpMethodFactoryImpl();
 | 
			
		||||
        jsonErrorSerializer = new ExceptionJsonSerializer();
 | 
			
		||||
 | 
			
		||||
        // Create an HTTP Proxy Host if appropriate system properties are set
 | 
			
		||||
        httpProxyHost = HttpClientHelper.createProxyHost("http.proxyHost", "http.proxyPort", DEFAULT_HTTP_PORT);
 | 
			
		||||
@@ -852,7 +850,27 @@ public class HttpClientTransmitterImpl implements TransferTransmitter
 | 
			
		||||
     */
 | 
			
		||||
    private Throwable rehydrateError(JSONObject errorJSON)
 | 
			
		||||
    {
 | 
			
		||||
        return jsonErrorSerializer.deserialize(errorJSON);
 | 
			
		||||
        if (errorJSON == null)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String errorMessage = errorJSON.optString("errorMessage", StringUtils.EMPTY);
 | 
			
		||||
        String errorId = errorJSON.optString("alfrescoMessageId", null);
 | 
			
		||||
 | 
			
		||||
        Object[] errorParams = new Object[0];
 | 
			
		||||
        JSONArray errorParamArray = errorJSON.optJSONArray("alfrescoMessageParams");
 | 
			
		||||
        if (errorParamArray != null)
 | 
			
		||||
        {
 | 
			
		||||
            int length = errorParamArray.length();
 | 
			
		||||
            errorParams = new Object[length];
 | 
			
		||||
            for (int i = 0; i < length; ++i)
 | 
			
		||||
            {
 | 
			
		||||
                errorParams[i] = errorParamArray.getString(i);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return new TransferException(errorId == null ? errorMessage : errorId, errorParams);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setContentService(ContentService contentService)
 | 
			
		||||
@@ -870,11 +888,6 @@ public class HttpClientTransmitterImpl implements TransferTransmitter
 | 
			
		||||
        this.httpMethodFactory = httpMethodFactory;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setJsonErrorSerializer(JsonSerializer<Throwable, JSONObject> jsonErrorSerializer)
 | 
			
		||||
    {
 | 
			
		||||
        this.jsonErrorSerializer = jsonErrorSerializer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNodeService(NodeService nodeService)
 | 
			
		||||
    {
 | 
			
		||||
        this.nodeService = nodeService;
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,8 @@ import org.json.JSONObject;
 | 
			
		||||
public class ExceptionJsonSerializer implements JsonSerializer<Throwable, JSONObject>
 | 
			
		||||
{
 | 
			
		||||
    private final static Log log = LogFactory.getLog(ExceptionJsonSerializer.class);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    @Override
 | 
			
		||||
    public Throwable deserialize(JSONObject errorJSON)
 | 
			
		||||
    {
 | 
			
		||||
@@ -89,38 +90,42 @@ public class ExceptionJsonSerializer implements JsonSerializer<Throwable, JSONOb
 | 
			
		||||
            catch (ClassNotFoundException e)
 | 
			
		||||
            {
 | 
			
		||||
                errorClass = Exception.class;
 | 
			
		||||
            }
 | 
			
		||||
            Constructor<?> constructor = null;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    constructor = errorClass.getConstructor(String.class, Object[].class);
 | 
			
		||||
                    createdObject = constructor.newInstance(errorId, errorParams);
 | 
			
		||||
                }
 | 
			
		||||
                catch (NoSuchMethodException e)
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        constructor = errorClass.getConstructor(String.class);
 | 
			
		||||
                        createdObject = constructor.newInstance(errorId == null ? errorMessage : errorId);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (NoSuchMethodException e1)
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            constructor = errorClass.getConstructor();
 | 
			
		||||
                            createdObject = constructor.newInstance();
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (NoSuchMethodException e2)
 | 
			
		||||
                        {
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch(Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                //We don't need to do anything here. Code below will fix things up
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (Throwable.class.isAssignableFrom(errorClass))
 | 
			
		||||
            {
 | 
			
		||||
                Constructor<?> constructor = null;
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        constructor = errorClass.getConstructor(String.class, Object[].class);
 | 
			
		||||
                        createdObject = constructor.newInstance(errorId, errorParams);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (NoSuchMethodException e)
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            constructor = errorClass.getConstructor(String.class);
 | 
			
		||||
                            createdObject = constructor.newInstance(errorId == null ? errorMessage : errorId);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (NoSuchMethodException e1)
 | 
			
		||||
                        {
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                constructor = errorClass.getConstructor();
 | 
			
		||||
                                createdObject = constructor.newInstance();
 | 
			
		||||
                            }
 | 
			
		||||
                            catch (NoSuchMethodException e2)
 | 
			
		||||
                            {
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    // We don't need to do anything here. Code below will fix things up
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (createdObject == null || !Throwable.class.isAssignableFrom(createdObject.getClass()))
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -318,13 +318,13 @@
 | 
			
		||||
    <select id="select_MinMaxAuditEntryId" parameterMap="parameter_IdMinMaxMap" resultMap="result_minMaxMap">
 | 
			
		||||
        select
 | 
			
		||||
        <if test="max != null">
 | 
			
		||||
            max(alf_audit_entry.id)
 | 
			
		||||
            max(alf_audit_entry.id) as max
 | 
			
		||||
        </if>
 | 
			
		||||
        <if test="max != null and min != null">
 | 
			
		||||
            ,
 | 
			
		||||
        </if>
 | 
			
		||||
        <if test="min != null">
 | 
			
		||||
            min(alf_audit_entry.id)
 | 
			
		||||
            min(alf_audit_entry.id) as min
 | 
			
		||||
        </if>
 | 
			
		||||
        from
 | 
			
		||||
        alf_audit_entry
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,38 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%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 <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco;
 | 
			
		||||
 | 
			
		||||
import org.junit.experimental.categories.Categories;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.junit.runners.Suite;
 | 
			
		||||
 | 
			
		||||
@RunWith(Categories.class)
 | 
			
		||||
@Suite.SuiteClasses({
 | 
			
		||||
        org.alfresco.messaging.camel.CamelComponentsTest.class,
 | 
			
		||||
        org.alfresco.messaging.camel.CamelRoutesTest.class
 | 
			
		||||
})
 | 
			
		||||
public class MessagingUnitTestSuite {
 | 
			
		||||
}
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 * #%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 
 | 
			
		||||
@@ -36,6 +36,7 @@ import java.util.HashMap;
 | 
			
		||||
import java.util.LinkedList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import jakarta.transaction.UserTransaction;
 | 
			
		||||
 | 
			
		||||
@@ -60,6 +61,7 @@ import org.alfresco.util.GUID;
 | 
			
		||||
import org.alfresco.util.Pair;
 | 
			
		||||
import org.alfresco.util.testing.category.DBTests;
 | 
			
		||||
import org.apache.commons.lang3.mutable.MutableInt;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.experimental.categories.Category;
 | 
			
		||||
import org.springframework.context.ConfigurableApplicationContext;
 | 
			
		||||
 | 
			
		||||
@@ -157,30 +159,41 @@ public class AuditDAOTest extends TestCase
 | 
			
		||||
        doAuditEntryImpl(1000);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testAuditMinMaxByApp() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        final String[] expectedExtremes = {"min", "max"};
 | 
			
		||||
        final AuditApplicationInfo appInfo = doAuditEntryImpl(12);
 | 
			
		||||
 | 
			
		||||
        final Map<String, Long> minMax = auditDAO.getAuditMinMaxByApp(appInfo.getId(), List.of(expectedExtremes));
 | 
			
		||||
 | 
			
		||||
        assertEquals(Set.of(expectedExtremes), minMax.keySet());
 | 
			
		||||
        assertNotNull(minMax.get(expectedExtremes[0]));
 | 
			
		||||
        assertNotNull(minMax.get(expectedExtremes[1]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return              Returns the name of the application
 | 
			
		||||
     */
 | 
			
		||||
    private String doAuditEntryImpl(final int count) throws Exception
 | 
			
		||||
    private AuditApplicationInfo doAuditEntryImpl(final int count) throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        final File file = AbstractContentTransformerTest.loadQuickTestFile("pdf");
 | 
			
		||||
        assertNotNull(file);
 | 
			
		||||
        final URL url = new URL("file:" + file.getAbsolutePath());
 | 
			
		||||
        final String appName = getName() + "." + System.currentTimeMillis();
 | 
			
		||||
 | 
			
		||||
        RetryingTransactionCallback<Long> createAppCallback = new RetryingTransactionCallback<Long>()
 | 
			
		||||
        RetryingTransactionCallback<AuditApplicationInfo> createAppCallback = () ->
 | 
			
		||||
        {
 | 
			
		||||
            public Long execute() throws Throwable
 | 
			
		||||
            AuditApplicationInfo appInfo = auditDAO.getAuditApplication(appName);
 | 
			
		||||
            if (appInfo == null)
 | 
			
		||||
            {
 | 
			
		||||
                AuditApplicationInfo appInfo = auditDAO.getAuditApplication(appName);
 | 
			
		||||
                if (appInfo == null)
 | 
			
		||||
                {
 | 
			
		||||
                    Long modelId = auditDAO.getOrCreateAuditModel(url).getFirst();
 | 
			
		||||
                    appInfo = auditDAO.createAuditApplication(appName, modelId);
 | 
			
		||||
                }
 | 
			
		||||
                return appInfo.getId();
 | 
			
		||||
                Long modelId = auditDAO.getOrCreateAuditModel(url).getFirst();
 | 
			
		||||
                appInfo = auditDAO.createAuditApplication(appName, modelId);
 | 
			
		||||
            }
 | 
			
		||||
            return appInfo;
 | 
			
		||||
        };
 | 
			
		||||
        final Long sessionId = txnHelper.doInTransaction(createAppCallback);
 | 
			
		||||
        final AuditApplicationInfo appInfo = txnHelper.doInTransaction(createAppCallback);
 | 
			
		||||
        final Long sessionId = appInfo.getId();
 | 
			
		||||
        
 | 
			
		||||
        final String username = "alexi";
 | 
			
		||||
        RetryingTransactionCallback<Void> createEntryCallback = new RetryingTransactionCallback<Void>()
 | 
			
		||||
@@ -203,7 +216,7 @@ public class AuditDAOTest extends TestCase
 | 
			
		||||
                "Time for " + count + " entry creations was " +
 | 
			
		||||
                ((double)(after - before)/(10E6)) + "ms");
 | 
			
		||||
        // Done
 | 
			
		||||
        return appName;
 | 
			
		||||
        return appInfo;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public synchronized void testAuditQuery() throws Exception
 | 
			
		||||
@@ -476,7 +489,7 @@ public class AuditDAOTest extends TestCase
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Some entries
 | 
			
		||||
        final String appName = doAuditEntryImpl(1);
 | 
			
		||||
        final String appName = doAuditEntryImpl(1).getName();
 | 
			
		||||
 | 
			
		||||
        final AuditQueryParameters params = new AuditQueryParameters();
 | 
			
		||||
        params.setApplicationName(appName);
 | 
			
		||||
@@ -501,8 +514,8 @@ public class AuditDAOTest extends TestCase
 | 
			
		||||
     */
 | 
			
		||||
    public void testAuditDeleteEntriesForApplication() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        final String app1 = doAuditEntryImpl(6);
 | 
			
		||||
        final String app2 = doAuditEntryImpl(18);
 | 
			
		||||
        final String app1 = doAuditEntryImpl(6).getName();
 | 
			
		||||
        final String app2 = doAuditEntryImpl(18).getName();
 | 
			
		||||
        
 | 
			
		||||
        final AuditQueryCallbackImpl resultsCallback = new AuditQueryCallbackImpl();
 | 
			
		||||
        
 | 
			
		||||
 
 | 
			
		||||
@@ -263,7 +263,7 @@ public class XSLTRenderingEngineTest extends BaseAlfrescoSpringTest
 | 
			
		||||
            fail();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    private FileInfo createXmlFile(NodeRef folder)
 | 
			
		||||
    {
 | 
			
		||||
        return createXmlFile(folder, sampleXML);
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
com.epam.reportportal.testng.ReportPortalTestNGListener
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user