mirror of
				https://github.com/Alfresco/alfresco-community-repo.git
				synced 2025-10-29 15:21:53 +00:00 
			
		
		
		
	Compare commits
	
		
			184 Commits
		
	
	
		
			17.51
			...
			hack/hacka
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					cd8ef77b3e | ||
| 
						 | 
					8622e0e102 | ||
| 
						 | 
					69170dde35 | ||
| 
						 | 
					c848024130 | ||
| 
						 | 
					553f78bb1e | ||
| 
						 | 
					9a3ceb21a8 | ||
| 
						 | 
					57d0ff62dc | ||
| 
						 | 
					42bd94c1da | ||
| 
						 | 
					c5dd6538f8 | ||
| 
						 | 
					152c036d86 | ||
| 
						 | 
					f2055f91dc | ||
| 
						 | 
					a1d7f0d479 | ||
| 
						 | 
					8476f01b35 | ||
| 
						 | 
					6c4b9e458a | ||
| 
						 | 
					0f99dec012 | ||
| 
						 | 
					06c7836e70 | ||
| 
						 | 
					2ceb7384bf | ||
| 
						 | 
					d848c83a57 | ||
| 
						 | 
					be7572a978 | ||
| 
						 | 
					ef45aaf9cc | ||
| 
						 | 
					6f834909f6 | ||
| 
						 | 
					b928598bd7 | ||
| 
						 | 
					678eeab278 | ||
| 
						 | 
					45f9bd6569 | ||
| 
						 | 
					23b8c0e7a6 | ||
| 
						 | 
					9c98f7b0fb | ||
| 
						 | 
					6e1d5c81e2 | ||
| 
						 | 
					092d895f6a | ||
| 
						 | 
					a568c87571 | ||
| 
						 | 
					3aac7be11c | ||
| 
						 | 
					700fbce572 | ||
| 
						 | 
					7be96e788b | ||
| 
						 | 
					0af001be2a | ||
| 
						 | 
					f38a36910f | ||
| 
						 | 
					972f81ab8b | ||
| 
						 | 
					1bd0dfd114 | ||
| 
						 | 
					775de0e94c | ||
| 
						 | 
					78d2ed247a | ||
| 
						 | 
					5ca3630398 | ||
| 
						 | 
					ee7383dcab | ||
| 
						 | 
					36b3dc25c0 | ||
| 
						 | 
					0b94042b6f | ||
| 
						 | 
					27d3701c8b | ||
| 
						 | 
					dc0102001f | ||
| 
						 | 
					12bc363bcd | ||
| 
						 | 
					2ab89f0d79 | ||
| 
						 | 
					807e509859 | ||
| 
						 | 
					403da286e8 | ||
| 
						 | 
					cc3f8aaff4 | ||
| 
						 | 
					be925ab67d | ||
| 
						 | 
					de4ac000dd | ||
| 
						 | 
					b2b866e0f9 | ||
| 
						 | 
					984bc151af | ||
| 
						 | 
					b057455cde | ||
| 
						 | 
					40edaccd1a | ||
| 
						 | 
					a802a17d92 | ||
| 
						 | 
					332626421b | ||
| 
						 | 
					1baf8d6fae | ||
| 
						 | 
					4bae0f2060 | ||
| 
						 | 
					0c017ac30c | ||
| 
						 | 
					cc0940e519 | ||
| 
						 | 
					0190b9060a | ||
| 
						 | 
					596e964553 | ||
| 
						 | 
					5d22e161d7 | ||
| 
						 | 
					bb27430f6a | ||
| 
						 | 
					1af879a7ed | ||
| 
						 | 
					c029f5afa3 | ||
| 
						 | 
					3b93814d76 | ||
| 
						 | 
					656ecdc41d | ||
| 
						 | 
					8150abf8b7 | ||
| 
						 | 
					cab6fd6d2c | ||
| 
						 | 
					e45211ad0f | ||
| 
						 | 
					414cba0c1a | ||
| 
						 | 
					75b74a5d77 | ||
| 
						 | 
					d3efea8873 | ||
| 
						 | 
					6c407b1ef5 | ||
| 
						 | 
					f7dcbc6551 | ||
| 
						 | 
					ed1ee00cee | ||
| 
						 | 
					bba1664fef | ||
| 
						 | 
					d675d58929 | ||
| 
						 | 
					4f37b984be | ||
| 
						 | 
					9d228add35 | ||
| 
						 | 
					58d9d0b093 | ||
| 
						 | 
					f8d66ec76d | ||
| 
						 | 
					94a47d0368 | ||
| 
						 | 
					8884cc9563 | ||
| 
						 | 
					594f02e7cd | ||
| 
						 | 
					cb29f1e9ec | ||
| 
						 | 
					59816bd071 | ||
| 
						 | 
					bb77023e1f | ||
| 
						 | 
					fa7cb58044 | ||
| 
						 | 
					4962ce1111 | ||
| 
						 | 
					20a0bb7194 | ||
| 
						 | 
					1e1bebd19c | ||
| 
						 | 
					03dedb4140 | ||
| 
						 | 
					66f6174b87 | ||
| 
						 | 
					885f21ff86 | ||
| 
						 | 
					501d9204a9 | ||
| 
						 | 
					924005e94e | ||
| 
						 | 
					3a34c42d2f | ||
| 
						 | 
					332af85227 | ||
| 
						 | 
					556c13eba0 | ||
| 
						 | 
					3caf6bf9f3 | ||
| 
						 | 
					b5fcc5370a | ||
| 
						 | 
					29007871e8 | ||
| 
						 | 
					12df503cc2 | ||
| 
						 | 
					e3a9e9c034 | ||
| 
						 | 
					d116cf397b | ||
| 
						 | 
					271c123a00 | ||
| 
						 | 
					5bae1ca9b6 | ||
| 
						 | 
					f84c82c6a2 | ||
| 
						 | 
					c639eec1df | ||
| 
						 | 
					d2e561dc95 | ||
| 
						 | 
					54347fbbee | ||
| 
						 | 
					ab0d482179 | ||
| 
						 | 
					5fed5292d9 | ||
| 
						 | 
					1e8944a310 | ||
| 
						 | 
					b97b6751cc | ||
| 
						 | 
					af97aca661 | ||
| 
						 | 
					368acf4724 | ||
| 
						 | 
					2341f0290e | ||
| 
						 | 
					2e4f5d5726 | ||
| 
						 | 
					be118c25ba | ||
| 
						 | 
					601b743388 | ||
| 
						 | 
					3c3c3b2666 | ||
| 
						 | 
					b671e17f03 | ||
| 
						 | 
					a08b134ec2 | ||
| 
						 | 
					9795349f9b | ||
| 
						 | 
					f120ba3a87 | ||
| 
						 | 
					2285dc1ecb | ||
| 
						 | 
					cbded8f967 | ||
| 
						 | 
					5e3ee41fce | ||
| 
						 | 
					6c9163ce65 | ||
| 
						 | 
					8a79d3bed1 | ||
| 
						 | 
					f1c588f1da | ||
| 
						 | 
					f38902ede9 | ||
| 
						 | 
					5f1cf5ef60 | ||
| 
						 | 
					2a41c1f14a | ||
| 
						 | 
					4f0cbd7206 | ||
| 
						 | 
					0823d5319c | ||
| 
						 | 
					001e7a4bff | ||
| 
						 | 
					aba89218e6 | ||
| 
						 | 
					e533af4ecb | ||
| 
						 | 
					4a7046211b | ||
| 
						 | 
					48e902c556 | ||
| 
						 | 
					e178428624 | ||
| 
						 | 
					7b4f7c9174 | ||
| 
						 | 
					d84424ee5b | ||
| 
						 | 
					a4ad5f9211 | ||
| 
						 | 
					9fbdc61d3c | ||
| 
						 | 
					7db6d372da | ||
| 
						 | 
					c334f14cd2 | ||
| 
						 | 
					d584b3c1a3 | ||
| 
						 | 
					b06a74c5cb | ||
| 
						 | 
					5b723e9176 | ||
| 
						 | 
					bf69340e4b | ||
| 
						 | 
					b6aeac0c4e | ||
| 
						 | 
					c1da01ba6e | ||
| 
						 | 
					ecb0d9a329 | ||
| 
						 | 
					c3189adf9f | ||
| 
						 | 
					8a7b8a7a54 | ||
| 
						 | 
					3d35eed39c | ||
| 
						 | 
					37afef846f | ||
| 
						 | 
					57a3fbd2d5 | ||
| 
						 | 
					378347ae35 | ||
| 
						 | 
					fc8ec4f993 | ||
| 
						 | 
					bd404080b0 | ||
| 
						 | 
					54ba3ea998 | ||
| 
						 | 
					13ee559a29 | ||
| 
						 | 
					69b6fc4603 | ||
| 
						 | 
					f1dc07be57 | ||
| 
						 | 
					ac9151ed86 | ||
| 
						 | 
					71080c9c7d | ||
| 
						 | 
					a929982faf | ||
| 
						 | 
					5e3d5919a0 | ||
| 
						 | 
					98a3161ef0 | ||
| 
						 | 
					74bf3146b3 | ||
| 
						 | 
					b272c89791 | ||
| 
						 | 
					632a86c5b7 | ||
| 
						 | 
					958d6b771e | ||
| 
						 | 
					b95233b18a | ||
| 
						 | 
					aa4ec88ef2 | ||
| 
						 | 
					45ecf340f1 | ||
| 
						 | 
					81830c8ad4 | 
							
								
								
									
										6
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
								
							@@ -158,3 +158,9 @@ updates:
 | 
			
		||||
    - "8.16"
 | 
			
		||||
  registries:
 | 
			
		||||
  - maven-repository-artifacts-alfresco-com-nexus-content-groups-int
 | 
			
		||||
- package-ecosystem: "docker"
 | 
			
		||||
  directory: "packaging/docker-alfresco/"
 | 
			
		||||
  schedule:
 | 
			
		||||
    interval: "daily"
 | 
			
		||||
    time: "22:00"
 | 
			
		||||
    timezone: Africa/Abidjan
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								.github/workflows/hackathon.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								.github/workflows/hackathon.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
name: Hackathon
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  sleep:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v3
 | 
			
		||||
      - run: sleep 240
 | 
			
		||||
							
								
								
									
										127
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										127
									
								
								.travis.yml
									
									
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
			
		||||
---
 | 
			
		||||
dist: focal
 | 
			
		||||
language: java
 | 
			
		||||
jdk: openjdk11
 | 
			
		||||
jdk: openjdk17
 | 
			
		||||
 | 
			
		||||
services:
 | 
			
		||||
  - docker
 | 
			
		||||
@@ -69,8 +69,8 @@ jobs:
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
        - docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContext01TestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
 | 
			
		||||
@@ -78,16 +78,16 @@ jobs:
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContext02TestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - AppContext03TestSuite"
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
        - docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContext03TestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
 | 
			
		||||
@@ -95,8 +95,8 @@ jobs:
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
        - docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContext04TestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
 | 
			
		||||
@@ -104,8 +104,8 @@ jobs:
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
        - mkdir -p "${HOME}/tmp"
 | 
			
		||||
        - cp repository/src/test/resources/realms/alfresco-realm.json "${HOME}/tmp"
 | 
			
		||||
        - export HOST_IP=$(hostname  -I | cut -f1 -d' ')
 | 
			
		||||
@@ -116,8 +116,8 @@ jobs:
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
        - docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContext06TestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
 | 
			
		||||
@@ -125,8 +125,8 @@ jobs:
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
        - docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContextExtraTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
 | 
			
		||||
@@ -134,8 +134,8 @@ jobs:
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
        - docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl repository -am -Dtest=MiscContextTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
 | 
			
		||||
@@ -143,8 +143,8 @@ jobs:
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl repository -am -Dtest=SearchTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco -Dindex.subsystem.name=solr6
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - MariaDB 10.2.18 tests"
 | 
			
		||||
@@ -152,7 +152,7 @@ jobs:
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 3307:3306 --name mariadb -e MYSQL_ROOT_PASSWORD=alfresco -e MYSQL_USER=alfresco -e MYSQL_DATABASE=alfresco -e MYSQL_PASSWORD=alfresco mariadb:10.2.18 --transaction-isolation=READ-COMMITTED --max-connections=300 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - MariaDB 10.4 tests"
 | 
			
		||||
@@ -160,7 +160,7 @@ jobs:
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 3307:3306 --name mariadb -e MYSQL_ROOT_PASSWORD=alfresco -e MYSQL_USER=alfresco -e MYSQL_DATABASE=alfresco -e MYSQL_PASSWORD=alfresco mariadb:10.4 --transaction-isolation=READ-COMMITTED --max-connections=300 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - MariaDB 10.5 tests"
 | 
			
		||||
@@ -168,7 +168,7 @@ jobs:
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 3307:3306 --name mariadb -e MYSQL_ROOT_PASSWORD=alfresco -e MYSQL_USER=alfresco -e MYSQL_DATABASE=alfresco -e MYSQL_PASSWORD=alfresco mariadb:10.5 --transaction-isolation=READ-COMMITTED --max-connections=300 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - MariaDB 10.6 tests"
 | 
			
		||||
@@ -177,7 +177,7 @@ jobs:
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 3307:3306 --name mariadb -e MYSQL_ROOT_PASSWORD=alfresco -e MYSQL_USER=alfresco -e MYSQL_DATABASE=alfresco -e MYSQL_PASSWORD=alfresco mariadb:10.6 --transaction-isolation=READ-COMMITTED --max-connections=300 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - MySQL 8 tests"
 | 
			
		||||
@@ -186,88 +186,47 @@ jobs:
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=alfresco -e MYSQL_USER=alfresco -e MYSQL_DATABASE=alfresco -e MYSQL_PASSWORD=alfresco  mysql:8 --transaction-isolation='READ-COMMITTED'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - PostgreSQL 10.9 tests"
 | 
			
		||||
    - name: "Repository - PostgreSQL 13.7 tests"
 | 
			
		||||
      if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ AND type != pull_request) OR commit_message =~ /\[db\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:10.9 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.7 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - PostgreSQL 11.7 tests"
 | 
			
		||||
      if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ AND type != pull_request) OR commit_message =~ /\[db\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:11.7 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - PostgreSQL 11.12 tests"
 | 
			
		||||
      if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ AND type != pull_request) OR commit_message =~ /\[db\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:11.12 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - PostgreSQL 12.4 tests"
 | 
			
		||||
      if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ AND type != pull_request) OR commit_message =~ /\[db\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:12.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - PostgreSQL 12.7 tests"
 | 
			
		||||
      if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ AND type != pull_request) OR commit_message =~ /\[db\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:12.7 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - PostgreSQL 13.1 tests"
 | 
			
		||||
    - name: "Repository - PostgreSQL 14.4 tests"
 | 
			
		||||
      # We only run DB tests on the latest version of PostgreSQL on feature branches
 | 
			
		||||
      if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ AND type != pull_request) OR commit_message =~ /\[db\]/
 | 
			
		||||
      if: commit_message !~ /\[skip db\]/ OR commit_message =~ /\[db\]/ OR commit_message =~ /\[latest db\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.1 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - PostgreSQL 13.3 tests"
 | 
			
		||||
      # We only run DB tests on the latest version of PostgreSQL on feature branches
 | 
			
		||||
      if: commit_message !~ /\[skip db\]/ OR commit_message =~ /\[latest db\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "Repository - Messaging tests"
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl repository -am -Dtest=CamelRoutesTest,CamelComponentsTest -DfailIfNoTests=false
 | 
			
		||||
 | 
			
		||||
    - name: "Remote-api - AppContext01TestSuite"
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContext01TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
 | 
			
		||||
    - name: "Remote-api - AppContext02TestSuite"
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
        - docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContext02TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
 | 
			
		||||
@@ -275,8 +234,8 @@ jobs:
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
        - docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContext03TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
 | 
			
		||||
@@ -284,8 +243,8 @@ jobs:
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
        - docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContext04TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
 | 
			
		||||
@@ -293,8 +252,8 @@ jobs:
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.16.1
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
 | 
			
		||||
      script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContextExtraTestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
 | 
			
		||||
 | 
			
		||||
    - name: "REST API TAS tests part1"
 | 
			
		||||
@@ -374,7 +333,7 @@ jobs:
 | 
			
		||||
      if: commit_message !~ /\[skip repo\]/
 | 
			
		||||
      install: skip
 | 
			
		||||
      before_script:
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.3 postgres -c 'max_connections=300'
 | 
			
		||||
        - docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
 | 
			
		||||
      script: travis_wait 20 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
 | 
			
		||||
 | 
			
		||||
    - name: "AGS Unit & Integration Tests 01 (PostgreSQL)"
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
   <parent>
 | 
			
		||||
      <groupId>org.alfresco</groupId>
 | 
			
		||||
      <artifactId>alfresco-community-repo-amps</artifactId>
 | 
			
		||||
      <version>17.51</version>
 | 
			
		||||
      <version>17.102-SNAPSHOT</version>
 | 
			
		||||
   </parent>
 | 
			
		||||
 | 
			
		||||
   <modules>
 | 
			
		||||
@@ -30,16 +30,20 @@
 | 
			
		||||
            <plugin>
 | 
			
		||||
               <artifactId>maven-surefire-plugin</artifactId>
 | 
			
		||||
               <configuration>
 | 
			
		||||
                  <!-- Keeping illegal-access=permit for Java 11 compatibility, even though it has no effect on JDK 17 -->
 | 
			
		||||
                  <argLine>
 | 
			
		||||
                     --illegal-access=permit
 | 
			
		||||
                     --add-opens=java.base/java.lang=ALL-UNNAMED
 | 
			
		||||
                  </argLine>
 | 
			
		||||
               </configuration>
 | 
			
		||||
            </plugin>
 | 
			
		||||
            <plugin>
 | 
			
		||||
               <artifactId>maven-failsafe-plugin</artifactId>
 | 
			
		||||
               <!-- Keeping illegal-access=permit for Java 11 compatibility, even though it has no effect on JDK 17 -->
 | 
			
		||||
               <configuration>
 | 
			
		||||
                  <argLine>
 | 
			
		||||
                     --illegal-access=permit
 | 
			
		||||
                     --add-opens=java.base/java.lang=ALL-UNNAMED
 | 
			
		||||
                  </argLine>
 | 
			
		||||
               </configuration>
 | 
			
		||||
            </plugin>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
   <parent>
 | 
			
		||||
      <groupId>org.alfresco</groupId>
 | 
			
		||||
      <artifactId>alfresco-governance-services-community-parent</artifactId>
 | 
			
		||||
      <version>17.51</version>
 | 
			
		||||
      <version>17.102-SNAPSHOT</version>
 | 
			
		||||
   </parent>
 | 
			
		||||
 | 
			
		||||
   <modules>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
   <parent>
 | 
			
		||||
      <groupId>org.alfresco</groupId>
 | 
			
		||||
      <artifactId>alfresco-governance-services-automation-community-repo</artifactId>
 | 
			
		||||
      <version>17.51</version>
 | 
			
		||||
      <version>17.102-SNAPSHOT</version>
 | 
			
		||||
   </parent>
 | 
			
		||||
 | 
			
		||||
   <build>
 | 
			
		||||
@@ -45,7 +45,7 @@
 | 
			
		||||
      <dependency>
 | 
			
		||||
         <groupId>org.slf4j</groupId>
 | 
			
		||||
         <artifactId>slf4j-reload4j</artifactId>
 | 
			
		||||
         <version>1.7.35</version>
 | 
			
		||||
         <version>${dependency.slf4j.version}</version>
 | 
			
		||||
         <scope>test</scope>
 | 
			
		||||
      </dependency>
 | 
			
		||||
      <dependency>
 | 
			
		||||
 
 | 
			
		||||
@@ -74,4 +74,27 @@ public class RecordFoldersAPI extends BaseAPI
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public HttpResponse postFolderAction(String user, String password, JSONObject requestParams, String recordFolder) {
 | 
			
		||||
        String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, recordFolder);
 | 
			
		||||
        try {
 | 
			
		||||
            requestParams.put("nodeRef", recNodeRef);
 | 
			
		||||
            return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API);
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception error) {
 | 
			
		||||
            LOGGER.error("Unable to extract response parameter", error);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public HttpResponse postRecordAction(String user, String password, JSONObject requestParams, String recordId) {
 | 
			
		||||
        try {
 | 
			
		||||
            requestParams.put("nodeRef", recordId);
 | 
			
		||||
            return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API);
 | 
			
		||||
        }
 | 
			
		||||
        catch (JSONException error) {
 | 
			
		||||
            LOGGER.error("Unable to extract response parameter", error);
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -53,9 +53,12 @@ import static org.springframework.http.HttpStatus.OK;
 | 
			
		||||
import static org.testng.Assert.assertFalse;
 | 
			
		||||
import static org.testng.Assert.assertTrue;
 | 
			
		||||
 | 
			
		||||
import java.text.SimpleDateFormat;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
import java.util.TimeZone;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
@@ -91,6 +94,7 @@ import org.alfresco.utility.model.FileModel;
 | 
			
		||||
import org.alfresco.utility.model.FolderModel;
 | 
			
		||||
import org.alfresco.utility.model.SiteModel;
 | 
			
		||||
import org.alfresco.utility.model.UserModel;
 | 
			
		||||
import org.json.JSONObject;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.springframework.http.HttpStatus;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
@@ -121,6 +125,8 @@ public class BaseRMRestTest extends RestTest
 | 
			
		||||
    @Getter(value = PROTECTED)
 | 
			
		||||
    private SearchAPI searchApi;
 | 
			
		||||
 | 
			
		||||
    protected static final String iso8601_DateFormat="yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Asserts the given status code
 | 
			
		||||
     *
 | 
			
		||||
@@ -628,8 +634,8 @@ public class BaseRMRestTest extends RestTest
 | 
			
		||||
     * Returns search results for the given search term
 | 
			
		||||
     *
 | 
			
		||||
     * @param user
 | 
			
		||||
     * @param term
 | 
			
		||||
     * @param query language
 | 
			
		||||
     * @param q
 | 
			
		||||
     * @param queryLanguage language
 | 
			
		||||
     * @return
 | 
			
		||||
     * @throws Exception
 | 
			
		||||
     */
 | 
			
		||||
@@ -956,5 +962,34 @@ public class BaseRMRestTest extends RestTest
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Helper method to get the Previous Date in the YYYY-MM-ddTHH:mm:ss.SSSXXX format
 | 
			
		||||
     * @param previousDays number of previous days while calculating the date as output
 | 
			
		||||
     * @return previousDate as String in the ISO 8601 Date Format
 | 
			
		||||
     */
 | 
			
		||||
    protected String getIso8601Date(int previousDays) {
 | 
			
		||||
        Date date = new Date(System.currentTimeMillis());
 | 
			
		||||
        Date previousDate = new Date(date.getTime() - previousDays);
 | 
			
		||||
        // Conversion
 | 
			
		||||
        SimpleDateFormat sdf= new SimpleDateFormat(iso8601_DateFormat);;
 | 
			
		||||
        sdf.setTimeZone(TimeZone.getDefault());
 | 
			
		||||
        return sdf.format(previousDate);
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Helper method to provide the Edited Disposition Date Json
 | 
			
		||||
     * The Edited Disposition Date is modified to previous date so that CUTOFF & DESTROY Steps will be enabled
 | 
			
		||||
     * @return JsonObject with the format {"name":"editDispositionActionAsOfDate","params":{"asOfDate":{"iso8601":"Previous Date"}}}
 | 
			
		||||
     */
 | 
			
		||||
    protected JSONObject editDispositionDateJson() {
 | 
			
		||||
        JSONObject requestParams = new JSONObject();
 | 
			
		||||
 | 
			
		||||
        requestParams.put("name","editDispositionActionAsOfDate");
 | 
			
		||||
        JSONObject params = new JSONObject();
 | 
			
		||||
        requestParams.put("params",params);
 | 
			
		||||
 | 
			
		||||
        JSONObject asOfDate = new JSONObject();
 | 
			
		||||
        params.put("asOfDate",asOfDate);
 | 
			
		||||
        asOfDate.put("iso8601",getIso8601Date(1));
 | 
			
		||||
        return requestParams;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,211 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.smoke;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.dataprep.CMISUtil;
 | 
			
		||||
import org.alfresco.rest.core.v0.BaseAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
 | 
			
		||||
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.RecordsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.RMAuditService;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
import org.alfresco.utility.model.UserModel;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import static org.alfresco.rest.core.v0.BaseAPI.NODE_PREFIX;
 | 
			
		||||
import static org.alfresco.rest.core.v0.BaseAPI.RM_SITE_ID;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.DELETE_PERSON;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.LOGIN_SUCCESSFUL;
 | 
			
		||||
import static org.alfresco.rest.rm.community.records.SearchRecordsTests.*;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.junit.Assert.assertFalse;
 | 
			
		||||
import static org.testng.AssertJUnit.assertTrue;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Audit Access tests
 | 
			
		||||
 * @author Kavit Shah
 | 
			
		||||
 */
 | 
			
		||||
public class AuditAccessTests extends BaseRMRestTest {
 | 
			
		||||
 | 
			
		||||
    private Optional<UserModel> deletedUser;
 | 
			
		||||
    private final String TEST_PREFIX = generateTestPrefix(AuditAccessTests.class);
 | 
			
		||||
    private static final String DELETE_USER_EVENT = "Delete User";
 | 
			
		||||
    private final String record1 = TEST_PREFIX + "RM-2967 uploaded record";
 | 
			
		||||
    private final String classifiedRecord = TEST_PREFIX + "RM-2967 classified record";
 | 
			
		||||
    private final String folderName = TEST_PREFIX + "RM-2967 folder";
 | 
			
		||||
    private final String categoryName = TEST_PREFIX + "RM-2967 category";
 | 
			
		||||
    private final String editedCategoryName = "edited " + categoryName;
 | 
			
		||||
    private final String editedFolderName = "edited " + folderName;
 | 
			
		||||
    private final String editedRecordName = "edited " + record1;
 | 
			
		||||
    private final String login_successfull = "Login Successful";
 | 
			
		||||
    private RecordCategory categoryAll;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMRolesAndActionsAPI rmRolesAndActionsAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RecordsAPI recordsAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMAuditService rmAuditService;
 | 
			
		||||
 | 
			
		||||
    @Test(priority = 1)
 | 
			
		||||
    @AlfrescoTest(jira = "RM-2967")
 | 
			
		||||
    public void deleteRMUsersShowFullAuditTest() {
 | 
			
		||||
 | 
			
		||||
        createTestPrecondition();
 | 
			
		||||
        updateCategoryMetadata();
 | 
			
		||||
        updateFolderMetadata();
 | 
			
		||||
        updateRecordMetadata();
 | 
			
		||||
 | 
			
		||||
        // delete record category and folder with rm_admin_deleted
 | 
			
		||||
        rmRolesAndActionsAPI.deleteAllItemsInContainer(deletedUser.get().getUsername(), deletedUser.get().getPassword(),
 | 
			
		||||
            RM_SITE_ID, editedFolderName);
 | 
			
		||||
        rmRolesAndActionsAPI.deleteAllItemsInContainer(deletedUser.get().getUsername(), deletedUser.get().getPassword(),
 | 
			
		||||
            RM_SITE_ID, editedCategoryName);
 | 
			
		||||
 | 
			
		||||
        // delete the user
 | 
			
		||||
        Optional.of(deletedUser).ifPresent(x -> getDataUser().deleteUser(x.get()));
 | 
			
		||||
 | 
			
		||||
        //check for RM-5235 fix
 | 
			
		||||
        List<AuditEntry> auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getDataUser().usingAdmin().getAdminUser(),
 | 
			
		||||
            DELETE_PERSON);
 | 
			
		||||
 | 
			
		||||
        assertTrue("Delete user event not found in the audit log.", auditEntries.stream().anyMatch(
 | 
			
		||||
            auditEntry -> auditEntry.getEvent().equals(DELETE_USER_EVENT)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Test(priority = 2)
 | 
			
		||||
    public void filterEventsByLoginSuccessful()
 | 
			
		||||
    {
 | 
			
		||||
        createRMSiteIfNotExists();
 | 
			
		||||
        List<AuditEntry> auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getDataUser().usingAdmin().getAdminUser(),
 | 
			
		||||
            LOGIN_SUCCESSFUL);
 | 
			
		||||
 | 
			
		||||
        assertFalse("Audit results should contain at least one Login Successful event",
 | 
			
		||||
            auditEntries.isEmpty());
 | 
			
		||||
 | 
			
		||||
        assertTrue("Audit results contain only Login Successful events",
 | 
			
		||||
            auditEntries.stream()
 | 
			
		||||
                .allMatch(e -> e.getEvent().startsWith(LOGIN_SUCCESSFUL.toString()) || e.getEvent().startsWith(login_successfull)));
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates the required precondition for the test
 | 
			
		||||
     * <p/>
 | 
			
		||||
     * See Precondition in current class JavaDoc
 | 
			
		||||
     */
 | 
			
		||||
    private void createTestPrecondition() {
 | 
			
		||||
        createRMSiteIfNotExists();
 | 
			
		||||
 | 
			
		||||
        // create "rm deleted user" user if it does not exist and assign it to RM Administrator role
 | 
			
		||||
        createDeletedUser();
 | 
			
		||||
 | 
			
		||||
        // create category and folder
 | 
			
		||||
        categoryAll = createCategoryIfDoesNotExist(categoryName,deletedUser.get());
 | 
			
		||||
        createRecordFolderInCategory(folderName,categoryAll,deletedUser.get());
 | 
			
		||||
        // upload an electronic record
 | 
			
		||||
 | 
			
		||||
        recordsAPI.uploadElectronicRecord(deletedUser.get().getUsername(), deletedUser.get().getPassword(), getDefaultElectronicRecordProperties(record1), folderName, CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
        // upload another electronic record and classify it
 | 
			
		||||
        recordsAPI.uploadElectronicRecord(deletedUser.get().getUsername(), deletedUser.get().getPassword(), getDefaultElectronicRecordProperties(classifiedRecord), folderName, CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void createDeletedUser() {
 | 
			
		||||
        // create Deleted User
 | 
			
		||||
        deletedUser = Optional.ofNullable(getDataUser().createRandomTestUser());
 | 
			
		||||
        rmRolesAndActionsAPI.assignRoleToUser(
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(),
 | 
			
		||||
            deletedUser.get().getUsername(),
 | 
			
		||||
            ADMIN
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateCategoryMetadata() {
 | 
			
		||||
        HashMap<BaseAPI.RMProperty, String> categoryProperties = new HashMap<>();
 | 
			
		||||
        categoryProperties.put(BaseAPI.RMProperty.NAME, editedCategoryName);
 | 
			
		||||
        categoryProperties.put(BaseAPI.RMProperty.TITLE, "edited " + TITLE);
 | 
			
		||||
        categoryProperties.put(BaseAPI.RMProperty.DESCRIPTION, "edited " + DESCRIPTION);
 | 
			
		||||
 | 
			
		||||
        // edit some category's properties
 | 
			
		||||
        String categoryNodeRef = NODE_PREFIX + rmRolesAndActionsAPI.getItemNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(), "/" +  categoryName);
 | 
			
		||||
        rmRolesAndActionsAPI.updateMetadata(deletedUser.get().getUsername(), deletedUser.get().getPassword(), categoryNodeRef, categoryProperties);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateFolderMetadata() {
 | 
			
		||||
        HashMap<BaseAPI.RMProperty, String> folderProperties = new HashMap<>();
 | 
			
		||||
        folderProperties.put(BaseAPI.RMProperty.NAME, editedFolderName);
 | 
			
		||||
        folderProperties.put(BaseAPI.RMProperty.TITLE, "edited " + TITLE);
 | 
			
		||||
        folderProperties.put(BaseAPI.RMProperty.DESCRIPTION, "edited " + DESCRIPTION);
 | 
			
		||||
 | 
			
		||||
        // edit some folder's properties
 | 
			
		||||
        String folderNodeRef = NODE_PREFIX + rmRolesAndActionsAPI.getItemNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(), "/" + editedCategoryName + "/" +  folderName);
 | 
			
		||||
        rmRolesAndActionsAPI.updateMetadata(deletedUser.get().getUsername(), deletedUser.get().getPassword(), folderNodeRef, folderProperties);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateRecordMetadata() {
 | 
			
		||||
        HashMap<BaseAPI.RMProperty, String> recordProperties = new HashMap<>();
 | 
			
		||||
        recordProperties.put(BaseAPI.RMProperty.NAME, editedRecordName);
 | 
			
		||||
        recordProperties.put(BaseAPI.RMProperty.TITLE, "edited " + TITLE);
 | 
			
		||||
        recordProperties.put(BaseAPI.RMProperty.AUTHOR, "edited author");
 | 
			
		||||
        recordProperties.put(BaseAPI.RMProperty.DESCRIPTION, "edited " + DESCRIPTION);
 | 
			
		||||
 | 
			
		||||
        // edit some record's properties
 | 
			
		||||
        String recordName = recordsAPI.getRecordFullName(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(), editedFolderName, record1);
 | 
			
		||||
        String recordNodeRef = NODE_PREFIX + rmRolesAndActionsAPI.getItemNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(), "/" + editedCategoryName + "/" + editedFolderName + "/" + recordName);
 | 
			
		||||
        rmRolesAndActionsAPI.updateMetadata(deletedUser.get().getUsername(), deletedUser.get().getPassword(), recordNodeRef, recordProperties);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private RecordCategory createCategoryIfDoesNotExist(String CATEGORY_ALL, UserModel deletedUser) {
 | 
			
		||||
        return createRootCategory(deletedUser, CATEGORY_ALL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private RecordCategoryChild createRecordFolderInCategory(String FOLDER_SEARCH, RecordCategory recordCategory, UserModel deletedUser) {
 | 
			
		||||
        return createFolder(deletedUser, recordCategory.getId(), FOLDER_SEARCH);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Map<BaseAPI.RMProperty, String> getDefaultElectronicRecordProperties(String recordName) {
 | 
			
		||||
        Map<BaseAPI.RMProperty, String> defaultProperties = new HashMap<>();
 | 
			
		||||
        defaultProperties.put(BaseAPI.RMProperty.NAME, recordName);
 | 
			
		||||
        defaultProperties.put(BaseAPI.RMProperty.TITLE, TITLE);
 | 
			
		||||
        defaultProperties.put(BaseAPI.RMProperty.DESCRIPTION, DESCRIPTION);
 | 
			
		||||
        defaultProperties.put(BaseAPI.RMProperty.CONTENT, TEST_CONTENT);
 | 
			
		||||
        return defaultProperties;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,104 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.smoke;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
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.rules.ActionsOnRule;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.rules.RuleDefinition;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI;
 | 
			
		||||
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.RulesAPI;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import static org.alfresco.rest.core.v0.BaseAPI.NODE_PREFIX;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.ELECTRONIC_RECORD_NAME;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.NONELECTRONIC_RECORD_NAME;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.*;
 | 
			
		||||
import static org.alfresco.utility.data.RandomData.getRandomName;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.springframework.http.HttpStatus.*;
 | 
			
		||||
public class BasicRulesIntegrationTests extends BaseRMRestTest {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMRolesAndActionsAPI rmRolesAndActionsAPI;
 | 
			
		||||
    private final static String title = "Rule to complete";
 | 
			
		||||
    private final static String description = "Rule to describe";
 | 
			
		||||
    private final String TEST_PREFIX = generateTestPrefix(CreateCategoriesTests.class);
 | 
			
		||||
    private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RulesAPI rulesAPI;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    @AlfrescoTest(jira = "RM-2794")
 | 
			
		||||
    public void basicRulesIntegration() {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        STEP("Create the RM site if doesn't exist");
 | 
			
		||||
        createRMSiteIfNotExists();
 | 
			
		||||
 | 
			
		||||
        STEP("Create RM Admin user");
 | 
			
		||||
        rmRolesAndActionsAPI.createUserAndAssignToRole(getAdminUser().getUsername(), getAdminUser().getPassword(), RM_ADMIN,
 | 
			
		||||
            getAdminUser().getPassword(),
 | 
			
		||||
            "Administrator");
 | 
			
		||||
 | 
			
		||||
        STEP("Create record categories and record folders");
 | 
			
		||||
        RecordCategory Category = createRootCategory(getRandomName("recordCategory"));
 | 
			
		||||
        String recordFolder1 = createRecordFolder(Category.getId(), getRandomName("recFolder")).getId();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        //create a rule for completing a record
 | 
			
		||||
        RuleDefinition ruleDefinition = RuleDefinition.createNewRule().title("name").description("description1")
 | 
			
		||||
            .applyToChildren(true).title(title)
 | 
			
		||||
            .actions(Collections.singletonList(ActionsOnRule.COMPLETE_RECORD.getActionValue()));
 | 
			
		||||
        rulesAPI.createRule(getAdminUser().getUsername(), getAdminUser().getPassword(), NODE_PREFIX + Category.getId(), ruleDefinition);
 | 
			
		||||
 | 
			
		||||
        RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI();
 | 
			
		||||
 | 
			
		||||
        //create two electronic record in record folder
 | 
			
		||||
        String electronicRecordId1 = createElectronicRecord(recordFolder1, ELECTRONIC_RECORD_NAME).getId();
 | 
			
		||||
        String electronicRecordId2 = createElectronicRecord(recordFolder1, ELECTRONIC_RECORD_NAME).getId();
 | 
			
		||||
        assertStatusCode(CREATED);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Update the rules for record Category
 | 
			
		||||
        rulesAPI.updateRule(getAdminUser().getUsername(), getAdminUser().getPassword(),
 | 
			
		||||
            NODE_PREFIX + Category.getId(), ruleDefinition.description("description").id(description));
 | 
			
		||||
 | 
			
		||||
        //Delete the root category and rules
 | 
			
		||||
        deleteRecordCategory(Category.getId());
 | 
			
		||||
        rulesAPI.deleteAllRulesOnContainer(getAdminUser().getUsername(), getAdminUser().getPassword(), NODE_PREFIX + Category.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,125 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.smoke;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.fileplan.FilePlan;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
 | 
			
		||||
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
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.CoreUtil.createBodyForMoveCopy;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.CoreUtil.toContentModel;
 | 
			
		||||
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
 | 
			
		||||
import static org.alfresco.utility.data.RandomData.getRandomName;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.junit.Assert.assertFalse;
 | 
			
		||||
import static org.springframework.http.HttpStatus.OK;
 | 
			
		||||
import static org.testng.Assert.assertEquals;
 | 
			
		||||
 | 
			
		||||
public class CreateCategoriesTests extends BaseRMRestTest {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMRolesAndActionsAPI rmRolesAndActionsAPI;
 | 
			
		||||
    private RecordCategory rootCategory;
 | 
			
		||||
    private final String TEST_PREFIX = generateTestPrefix(CreateCategoriesTests.class);
 | 
			
		||||
    private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
 | 
			
		||||
    private RecordCategory Category1;
 | 
			
		||||
    private RecordCategory Category2;
 | 
			
		||||
    private RecordCategory SubCategory1;
 | 
			
		||||
    private RecordCategory SubCategory2;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass(alwaysRun = true)
 | 
			
		||||
    public void preconditionForCreateCategoriesTests()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create the RM site if doesn't exist");
 | 
			
		||||
        createRMSiteIfNotExists();
 | 
			
		||||
 | 
			
		||||
        STEP("Create RM Admin user");
 | 
			
		||||
        rmRolesAndActionsAPI.createUserAndAssignToRole(getAdminUser().getUsername(), getAdminUser().getPassword(), RM_ADMIN,
 | 
			
		||||
            getAdminUser().getPassword(),
 | 
			
		||||
            "Administrator");
 | 
			
		||||
 | 
			
		||||
        STEP("Create two category");
 | 
			
		||||
        Category1 = createRootCategory(getRandomName("Category1"));
 | 
			
		||||
 | 
			
		||||
        Category2= createRootCategory(getRandomName("Category2"));
 | 
			
		||||
 | 
			
		||||
        STEP("Create Sub category");
 | 
			
		||||
        RecordCategoryChild subCategory1 = createRecordCategory(Category1.getId(), getRandomName("subCategory1"));
 | 
			
		||||
        RecordCategoryChild subCategory2 = createRecordCategory(Category2.getId(), getRandomName("subCategory2"));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Test @AlfrescoTest(jira = "RM-2756")
 | 
			
		||||
    public void createCategories() throws Exception {
 | 
			
		||||
 | 
			
		||||
        FilePlan filePlan = getRestAPIFactory().getFilePlansAPI().getFilePlan(FILE_PLAN_ALIAS);
 | 
			
		||||
 | 
			
		||||
        STEP("copy category 1 to File Plan.");
 | 
			
		||||
        getRestAPIFactory().getNodeAPI(toContentModel(Category1.getId())).copy(createBodyForMoveCopy(filePlan.getId()));
 | 
			
		||||
 | 
			
		||||
        STEP("copy category 1 to category 2");
 | 
			
		||||
        getRestAPIFactory().getNodeAPI(toContentModel(Category1.getId())).copy(createBodyForMoveCopy(Category2.getId()));
 | 
			
		||||
 | 
			
		||||
        String categoryName = "Category name " + getRandomAlphanumeric();
 | 
			
		||||
        String categoryTitle = "Category title " + getRandomAlphanumeric();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Create the root record category
 | 
			
		||||
        RecordCategory Category1 = createRootCategory(categoryName, categoryTitle);
 | 
			
		||||
 | 
			
		||||
        String newCategoryName = "Rename " + categoryName;
 | 
			
		||||
 | 
			
		||||
        // Build the properties which will be updated
 | 
			
		||||
        RecordCategory  recordCategoryUpdated = Category1.builder().name(newCategoryName).build();
 | 
			
		||||
 | 
			
		||||
        // Update the record category
 | 
			
		||||
        RecordCategory renamedRecordCategory = getRestAPIFactory().getRecordCategoryAPI().updateRecordCategory(recordCategoryUpdated,Category1.getId());
 | 
			
		||||
        // Verify the status code
 | 
			
		||||
        assertStatusCode(OK);
 | 
			
		||||
 | 
			
		||||
        // verify renamed component and editTitle component still has this parent
 | 
			
		||||
        assertEquals(renamedRecordCategory.getParentId(), filePlan.getId());
 | 
			
		||||
 | 
			
		||||
        STEP("move category 1 edited copy to File Plan");
 | 
			
		||||
        getRestAPIFactory().getNodeAPI(toContentModel(renamedRecordCategory.getId())).move(createBodyForMoveCopy(filePlan.getId()));
 | 
			
		||||
        assertStatusCode(OK);
 | 
			
		||||
 | 
			
		||||
        // delete All the categories
 | 
			
		||||
        deleteRecordCategory(Category1.getId());
 | 
			
		||||
        deleteRecordCategory(Category2.getId());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,147 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.smoke;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.common.ReviewPeriod;
 | 
			
		||||
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.RecordCategoryAPI;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI;
 | 
			
		||||
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.CoreUtil.createBodyForMoveCopy;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.CoreUtil.toContentModel;
 | 
			
		||||
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
 | 
			
		||||
import static org.alfresco.utility.data.RandomData.getRandomName;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.springframework.http.HttpStatus.*;
 | 
			
		||||
 | 
			
		||||
public class CreateFoldersTests extends BaseRMRestTest {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMRolesAndActionsAPI rmRolesAndActionsAPI;
 | 
			
		||||
 | 
			
		||||
    private final String TEST_PREFIX = generateTestPrefix(CreateCategoriesTests.class);
 | 
			
		||||
    private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
 | 
			
		||||
    private RecordCategory Category1;
 | 
			
		||||
    private RecordCategory Category2;
 | 
			
		||||
    private RecordCategoryChild recordCategoryChild;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass(alwaysRun = true)
 | 
			
		||||
    public void preconditionForCreateFolderTests() {
 | 
			
		||||
        STEP("Create the RM site if doesn't exist");
 | 
			
		||||
        createRMSiteIfNotExists();
 | 
			
		||||
 | 
			
		||||
        STEP("Create RM Admin user");
 | 
			
		||||
        rmRolesAndActionsAPI.createUserAndAssignToRole(getAdminUser().getUsername(), getAdminUser().getPassword(), RM_ADMIN,
 | 
			
		||||
            getAdminUser().getPassword(),
 | 
			
		||||
            "Administrator");
 | 
			
		||||
 | 
			
		||||
        STEP("Create two category");
 | 
			
		||||
        Category1 = createRootCategory(getRandomName("Category1"));
 | 
			
		||||
 | 
			
		||||
        Category2 = createRootCategory(getRandomName("Category2"));
 | 
			
		||||
 | 
			
		||||
        // Create a record folder inside the category 1
 | 
			
		||||
        recordCategoryChild = createRecordFolder(Category1.getId(), getRandomName("recFolder"));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    @AlfrescoTest(jira = "RM-2757")
 | 
			
		||||
    public void createFolders() throws Exception {
 | 
			
		||||
 | 
			
		||||
        // Create record category first
 | 
			
		||||
        String folderDescription = "The folder description is updated" + getRandomAlphanumeric();
 | 
			
		||||
        String folderName = "The folder name is updated" + getRandomAlphanumeric();
 | 
			
		||||
        String folderTitle = "Update title " + getRandomAlphanumeric();
 | 
			
		||||
        String location = "Location "+ getRandomAlphanumeric();
 | 
			
		||||
 | 
			
		||||
        // Create the record folder properties to update
 | 
			
		||||
        RecordFolder recordFolder = RecordFolder.builder()
 | 
			
		||||
            .name(folderName)
 | 
			
		||||
            .properties(RecordFolderProperties.builder()
 | 
			
		||||
                .title(folderTitle)
 | 
			
		||||
                .description(folderDescription)
 | 
			
		||||
                .vitalRecordIndicator(true)
 | 
			
		||||
                .reviewPeriod(new ReviewPeriod("month","1"))
 | 
			
		||||
                .location(location)
 | 
			
		||||
                .build())
 | 
			
		||||
            .build();
 | 
			
		||||
 | 
			
		||||
        // Update the record folder
 | 
			
		||||
        RecordFolder updatedRecordFolder = getRestAPIFactory().getRecordFolderAPI().updateRecordFolder(recordFolder, recordCategoryChild.getId());
 | 
			
		||||
 | 
			
		||||
        // Check the Response Status Code
 | 
			
		||||
        assertStatusCode(OK);
 | 
			
		||||
 | 
			
		||||
        STEP("copy updated Record in category 1 and category 2");
 | 
			
		||||
        getRestAPIFactory().getNodeAPI(toContentModel(updatedRecordFolder.getId())).copy(createBodyForMoveCopy(Category1.getId()));
 | 
			
		||||
        //assertStatusCode(OK);
 | 
			
		||||
        getRestAPIFactory().getNodeAPI(toContentModel(updatedRecordFolder.getId())).copy(createBodyForMoveCopy(Category2.getId()));
 | 
			
		||||
        //assertStatusCode(OK);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Delete the Updated folder
 | 
			
		||||
        RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI();
 | 
			
		||||
        String recordFolderId = updatedRecordFolder.getId();
 | 
			
		||||
        recordFolderAPI.deleteRecordFolder(recordFolderId);
 | 
			
		||||
 | 
			
		||||
        // Check the response status code
 | 
			
		||||
        assertStatusCode(NO_CONTENT);
 | 
			
		||||
 | 
			
		||||
        // Check the record folder is not found
 | 
			
		||||
        recordFolderAPI.getRecordFolder(recordFolderId);
 | 
			
		||||
 | 
			
		||||
        // Check the response status code
 | 
			
		||||
        assertStatusCode(NOT_FOUND);
 | 
			
		||||
 | 
			
		||||
        STEP("move updated Record from category 1 to category 2");
 | 
			
		||||
        getRestAPIFactory().getNodeAPI(toContentModel(updatedRecordFolder.getId())).move(createBodyForMoveCopy(Category2.getId()));
 | 
			
		||||
 | 
			
		||||
        // move category 2 to category 1
 | 
			
		||||
        getRestAPIFactory().getNodeAPI(toContentModel(Category2.getId())).move(createBodyForMoveCopy(Category1.getId()));
 | 
			
		||||
 | 
			
		||||
        // Delete the record category
 | 
			
		||||
        RecordCategoryAPI recordCategoryAPI = getRestAPIFactory().getRecordCategoryAPI();
 | 
			
		||||
        String recordCategoryId = Category1.getId();
 | 
			
		||||
        recordCategoryAPI.deleteRecordCategory(recordCategoryId);
 | 
			
		||||
 | 
			
		||||
        // Verify the status code
 | 
			
		||||
        assertStatusCode(NO_CONTENT);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,122 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.smoke;
 | 
			
		||||
 | 
			
		||||
import lombok.Getter;
 | 
			
		||||
import org.alfresco.dataprep.CMISUtil;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
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.rules.ActionsOnRule;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.rules.RuleDefinition;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChildEntry;
 | 
			
		||||
import org.alfresco.rest.rm.community.requests.gscore.api.UnfiledContainerAPI;
 | 
			
		||||
import org.alfresco.rest.v0.RulesAPI;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
import org.alfresco.utility.data.DataContent;
 | 
			
		||||
import org.alfresco.utility.data.DataSite;
 | 
			
		||||
import org.alfresco.utility.data.DataUserAIS;
 | 
			
		||||
import org.alfresco.utility.model.FileModel;
 | 
			
		||||
import org.alfresco.utility.model.FolderModel;
 | 
			
		||||
import org.alfresco.utility.model.SiteModel;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import static lombok.AccessLevel.PROTECTED;
 | 
			
		||||
import static org.alfresco.rest.core.v0.BaseAPI.NODE_PREFIX;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS;
 | 
			
		||||
import static org.alfresco.utility.data.RandomData.getRandomName;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.springframework.http.HttpStatus.CREATED;
 | 
			
		||||
 | 
			
		||||
public class DeclareDocsAsRecordsOnUpdateRuleNewVersionTests extends BaseRMRestTest {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private DataSite dataSite;
 | 
			
		||||
    private SiteModel publicSite;
 | 
			
		||||
    private RecordCategory recordCategory;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RulesAPI rulesAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    protected DataContent dataContent;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    @Getter(value = PROTECTED)
 | 
			
		||||
    protected DataUserAIS dataUser;
 | 
			
		||||
    private final static String title = "Rule to convert document as record";
 | 
			
		||||
 | 
			
		||||
    @BeforeClass (alwaysRun = true)
 | 
			
		||||
    public void setUp()
 | 
			
		||||
    {
 | 
			
		||||
        publicSite = dataSite.usingAdmin().createPublicRandomSite();
 | 
			
		||||
        recordCategory = createRootCategory(getRandomName("recordCategory"));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    @AlfrescoTest(jira = "RM-1521")
 | 
			
		||||
    public void declareDocsAsRecordsOnUpdateRuleNewVersion() {
 | 
			
		||||
        FolderModel testFolder;
 | 
			
		||||
 | 
			
		||||
        STEP("Create test collaboration site to store documents in.");
 | 
			
		||||
        publicSite = dataSite.usingAdmin().createPublicRandomSite();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a record folder with a DECLARE_AS_RECORD");
 | 
			
		||||
        RecordCategoryChild folderWithRule = createFolder(recordCategory.getId(), getRandomName("recordFolder"));
 | 
			
		||||
        RuleDefinition ruleDefinition = RuleDefinition.createNewRule().title("name").description("description")
 | 
			
		||||
            .applyToChildren(true)
 | 
			
		||||
            .actions(Collections.singletonList(ActionsOnRule.DECLARE_AS_RECORD.getActionValue()));
 | 
			
		||||
        rulesAPI.createRule(getAdminUser().getUsername(), getAdminUser().getPassword(), NODE_PREFIX + folderWithRule.getId(), ruleDefinition);
 | 
			
		||||
 | 
			
		||||
        STEP("Create a document in the collaboration site");
 | 
			
		||||
        FileModel testFile = dataContent.usingSite(publicSite)
 | 
			
		||||
            .usingAdmin()
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
        assertStatusCode(CREATED);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // verify the declared record is in Unfilled Records folder
 | 
			
		||||
        UnfiledContainerAPI unfiledContainersAPI = getRestAPIFactory().getUnfiledContainersAPI();
 | 
			
		||||
        List<UnfiledContainerChildEntry> matchingRecords = unfiledContainersAPI.getUnfiledContainerChildren(UNFILED_RECORDS_CONTAINER_ALIAS)
 | 
			
		||||
            .getEntries()
 | 
			
		||||
            .stream()
 | 
			
		||||
            .filter(e -> e.getEntry().getId().equals(testFile.getNodeRefWithoutVersion()))
 | 
			
		||||
            .collect(Collectors.toList());
 | 
			
		||||
 | 
			
		||||
        //delete rm items
 | 
			
		||||
        deleteRecordCategory(recordCategory.getId());
 | 
			
		||||
        STEP("Delete the record.");
 | 
			
		||||
        //delete created collaboration site
 | 
			
		||||
        dataSite.deleteSite(publicSite);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,238 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.smoke;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.dataprep.CMISUtil;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
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.RecordFolderCollection;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.user.UserRoles;
 | 
			
		||||
import org.alfresco.rest.v0.RecordCategoriesAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.RoleService;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
import org.alfresco.utility.Utility;
 | 
			
		||||
import org.alfresco.utility.data.DataContent;
 | 
			
		||||
import org.alfresco.utility.data.DataSite;
 | 
			
		||||
import org.alfresco.utility.model.FileModel;
 | 
			
		||||
import org.alfresco.utility.model.FileType;
 | 
			
		||||
import org.alfresco.utility.model.SiteModel;
 | 
			
		||||
import org.alfresco.utility.model.UserModel;
 | 
			
		||||
import org.json.JSONObject;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.Assert;
 | 
			
		||||
import org.testng.annotations.AfterClass;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
import java.util.concurrent.atomic.AtomicReference;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.rest.rm.community.utils.CoreUtil.toContentModel;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.springframework.test.util.AssertionErrors.assertTrue;
 | 
			
		||||
import static org.testng.Assert.*;
 | 
			
		||||
 | 
			
		||||
public class FileAsRecordTests extends BaseRMRestTest {
 | 
			
		||||
 | 
			
		||||
    private static final String CATEGORY_MANAGER = "catManager" + generateTestPrefix(FileAsRecordTests.class);
 | 
			
		||||
    private static final String CATEGORY_ADMIN = "catAdmin" + generateTestPrefix(FileAsRecordTests.class);
 | 
			
		||||
    private static final String FOLDER_MANAGER = "recordFolder" + generateTestPrefix(FileAsRecordTests.class);
 | 
			
		||||
    private static final String FOLDER_ADMIN = "recordFolder" + generateTestPrefix(FileAsRecordTests.class);
 | 
			
		||||
 | 
			
		||||
    private UserModel nonRMuser,rmManager;
 | 
			
		||||
    private SiteModel testSite;
 | 
			
		||||
    private FileModel document, documentDeclared;
 | 
			
		||||
    private RecordCategory category_manager, category_admin;
 | 
			
		||||
    private RecordCategoryChild folder_admin, folder_manager ;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private DataSite dataSite;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private DataContent dataContent;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RoleService roleService;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RecordCategoriesAPI recordCategoriesAPI;
 | 
			
		||||
    /**
 | 
			
		||||
     * Create preconditions:
 | 
			
		||||
     * <pre>
 | 
			
		||||
     *     1. RM site is created
 | 
			
		||||
     *     2. Two users: user without RM role and a user with RM manager role
 | 
			
		||||
     *     3. Two Record categories with one folder each
 | 
			
		||||
     *     4. User with RM MANAGER role has Filling permission over one category
 | 
			
		||||
     * </pre>
 | 
			
		||||
     */
 | 
			
		||||
    @BeforeClass(alwaysRun = true)
 | 
			
		||||
    public void preconditionForFileAsRecordRecordTests()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create the RM site if doesn't exist");
 | 
			
		||||
        createRMSiteIfNotExists();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a user");
 | 
			
		||||
        nonRMuser = dataUser.createRandomTestUser("testUser");
 | 
			
		||||
 | 
			
		||||
        STEP("Create a collaboration site");
 | 
			
		||||
        testSite = dataSite.usingUser(nonRMuser).createPublicRandomSite();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a document with the user without RM role");
 | 
			
		||||
        document = dataContent.usingSite(testSite)
 | 
			
		||||
            .usingUser(nonRMuser)
 | 
			
		||||
            .createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
 | 
			
		||||
        STEP("Create two categories with two folders");
 | 
			
		||||
        category_manager = createRootCategory(CATEGORY_MANAGER);
 | 
			
		||||
        category_admin = createRootCategory(CATEGORY_ADMIN);
 | 
			
		||||
        folder_admin = createFolder(category_admin.getId(),FOLDER_ADMIN);
 | 
			
		||||
        folder_manager = createFolder(category_manager.getId(),FOLDER_MANAGER);
 | 
			
		||||
 | 
			
		||||
        STEP("Create an rm user and give filling permission over CATEGORY_MANAGER record category");
 | 
			
		||||
        RecordCategory recordCategory = new RecordCategory().builder()
 | 
			
		||||
            .id(category_manager.getId())
 | 
			
		||||
            .build();
 | 
			
		||||
        rmManager = roleService.createCollaboratorWithRMRoleAndPermission(testSite, recordCategory,
 | 
			
		||||
            UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given I have selected the record folder I want to file my declared record to
 | 
			
		||||
     * When I confirm the action
 | 
			
		||||
     * Then the dialog closes
 | 
			
		||||
     * And the document is now shown as a record in the collaboration site
 | 
			
		||||
     * And if I navigated to the record folder, as any user who had the right permissions, then I would see the
 | 
			
		||||
     * record filed
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    @AlfrescoTest(jira = "RM-6780")
 | 
			
		||||
    public void checkFileAsRecordToRecordFolder() throws Exception {
 | 
			
		||||
 | 
			
		||||
        AtomicReference<RecordFolderCollection> apiChildren = new AtomicReference<>();
 | 
			
		||||
        STEP("Create a document with the user with RM role");
 | 
			
		||||
        documentDeclared = dataContent.usingSite(testSite).usingUser(rmManager)
 | 
			
		||||
            .createContent(new FileModel("checkDeclareAndFileToRecordFolder", FileType.TEXT_PLAIN));
 | 
			
		||||
 | 
			
		||||
        STEP("Declare and file into  a record folder the document uploaded");
 | 
			
		||||
 | 
			
		||||
        getRestAPIFactory().getActionsAPI(rmManager).declareAndFile(documentDeclared,
 | 
			
		||||
            Utility.buildPath(CATEGORY_MANAGER, FOLDER_MANAGER));
 | 
			
		||||
 | 
			
		||||
        STEP("Check the file is a record within the collaboration site");
 | 
			
		||||
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            Utility.sleep(1000, 40000, () ->
 | 
			
		||||
            {
 | 
			
		||||
                JSONObject collaboratorSearchJson = getSearchApi().liveSearchForDocuments(rmManager.getUsername(),
 | 
			
		||||
                    rmManager.getPassword(),
 | 
			
		||||
                    documentDeclared.getName());
 | 
			
		||||
                assertTrue("Rm Manager not able to find the document.", collaboratorSearchJson.getJSONArray("items").length() != 0);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        catch (InterruptedException e)
 | 
			
		||||
        {
 | 
			
		||||
            fail("InterruptedException received while waiting for results.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        STEP("Check the record is filed into the record folder.");
 | 
			
		||||
        // Get children from API
 | 
			
		||||
        // List children from API
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            Utility.sleep(1000, 40000, () ->
 | 
			
		||||
            {
 | 
			
		||||
                apiChildren.set((RecordFolderCollection) getRestAPIFactory()
 | 
			
		||||
                    .getRecordFolderAPI(rmManager).getRecordFolderChildren(folder_manager.getId(), "include=properties")
 | 
			
		||||
                    .assertThat().entriesListIsNotEmpty().assertThat().entriesListIsNotEmpty());
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        catch (InterruptedException e)
 | 
			
		||||
        {
 | 
			
		||||
            fail("InterruptedException received while waiting for results.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        assertEquals(apiChildren.get()
 | 
			
		||||
            .getEntries()
 | 
			
		||||
            .get(0)
 | 
			
		||||
            .getEntry()
 | 
			
		||||
            .getProperties()
 | 
			
		||||
            .getOriginalName(),documentDeclared.getName());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Given I have selected the "File As Record" action
 | 
			
		||||
     * When I confirm the action without selecting a location to file to
 | 
			
		||||
     * Then the record is declared in the unfiled folder
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    @AlfrescoTest (jira = "RM-6780")
 | 
			
		||||
    public void fileAsRecordToUnfiledRecordFolder() throws Exception {
 | 
			
		||||
        STEP("Create a document with the user without RM role");
 | 
			
		||||
        FileModel inplaceRecord = dataContent.usingSite(testSite).usingUser(rmManager)
 | 
			
		||||
            .createContent(new FileModel("declareAndFileToIntoUnfiledRecordFolder",
 | 
			
		||||
                FileType.TEXT_PLAIN));
 | 
			
		||||
 | 
			
		||||
        STEP("Click on Declare and file without selecting a record folder");
 | 
			
		||||
        getRestAPIFactory().getActionsAPI(rmManager).declareAndFile(inplaceRecord,"");
 | 
			
		||||
 | 
			
		||||
        STEP("Check the file is declared in unfiled record folder");
 | 
			
		||||
        Assert.assertTrue(isMatchingRecordInUnfiledRecords(inplaceRecord), "Record should be filed to Unfiled Records folder");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @AfterClass(alwaysRun = true)
 | 
			
		||||
    public void cleanUpForFileAsRecordRecordTests() {
 | 
			
		||||
        STEP("Delete the collaboration site");
 | 
			
		||||
        dataSite.usingUser(nonRMuser).deleteSite(testSite);
 | 
			
		||||
 | 
			
		||||
        STEP("Empty the trashcan.");
 | 
			
		||||
        restClient.authenticateUser(nonRMuser).withCoreAPI().usingTrashcan().deleteNodeFromTrashcan(toContentModel(testSite.getId()));
 | 
			
		||||
 | 
			
		||||
        getRestAPIFactory()
 | 
			
		||||
            .getUnfiledContainersAPI(rmManager)
 | 
			
		||||
            .getUnfiledContainerChildren(UNFILED_RECORDS_CONTAINER_ALIAS)
 | 
			
		||||
            .getEntries()
 | 
			
		||||
            .stream()
 | 
			
		||||
            .forEach(x -> getRestAPIFactory()
 | 
			
		||||
                .getRecordsAPI()
 | 
			
		||||
                .deleteRecord(x.getEntry().getId()));
 | 
			
		||||
 | 
			
		||||
        STEP("Cleanup Documents inside folders");
 | 
			
		||||
 | 
			
		||||
        STEP("Delete folders");
 | 
			
		||||
        getRestAPIFactory().getRecordFolderAPI().deleteRecordFolder(folder_admin.getId());
 | 
			
		||||
        getRestAPIFactory().getRecordFolderAPI().deleteRecordFolder(folder_manager.getId());
 | 
			
		||||
 | 
			
		||||
        STEP("Delete categories");
 | 
			
		||||
        recordCategoriesAPI.deleteCategory(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(), category_manager.getName());
 | 
			
		||||
        recordCategoriesAPI.deleteCategory(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(), category_admin.getName());
 | 
			
		||||
 | 
			
		||||
        STEP("Delete Users");
 | 
			
		||||
        dataUser.deleteUser(nonRMuser);
 | 
			
		||||
        dataUser.deleteUser(rmManager);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,108 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.smoke;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
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.v0.RecordFoldersAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.DispositionScheduleService;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
import org.json.JSONObject;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.annotations.AfterMethod;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.recordcategory.RetentionPeriodProperty.CREATED_DATE;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
public class FoldersDispositionScheduleTests extends BaseRMRestTest {
 | 
			
		||||
 | 
			
		||||
    private RecordCategory Category1;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private DispositionScheduleService dispositionScheduleService;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RecordFoldersAPI recordFoldersAPI;
 | 
			
		||||
    private final String TEST_PREFIX = generateTestPrefix(FoldersDispositionScheduleTests.class);
 | 
			
		||||
    private final String folderDisposition = TEST_PREFIX + "RM-2937 folder ghosting";
 | 
			
		||||
    private final String electronicRecord = "RM-2937 electronic 2 record";
 | 
			
		||||
    private final String nonElectronicRecord = "RM-2937 non-electronic record";
 | 
			
		||||
 | 
			
		||||
    @BeforeClass(alwaysRun = true)
 | 
			
		||||
    private void setUp(){
 | 
			
		||||
 | 
			
		||||
        STEP("Create the RM site if doesn't exist");
 | 
			
		||||
        createRMSiteIfNotExists();
 | 
			
		||||
 | 
			
		||||
        STEP("Create record category");
 | 
			
		||||
        Category1 = createRootCategory(getRandomName("Title"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    @AlfrescoTest (jira = "RM-2937")
 | 
			
		||||
    public void foldersDispositionScheduleWithGhosting() {
 | 
			
		||||
 | 
			
		||||
        //create retention schedule
 | 
			
		||||
        dispositionScheduleService.createCategoryRetentionSchedule(Category1.getName(), false);
 | 
			
		||||
 | 
			
		||||
        // add cut off step
 | 
			
		||||
        dispositionScheduleService.addCutOffAfterPeriodStep(Category1.getName(), "day|2", CREATED_DATE);
 | 
			
		||||
 | 
			
		||||
        // add destroy step with ghosting
 | 
			
		||||
        dispositionScheduleService.addDestroyWithGhostingImmediatelyAfterCutOff(Category1.getName());
 | 
			
		||||
 | 
			
		||||
        //create folders
 | 
			
		||||
        RecordCategoryChild FOLDER_DESTROY = createFolder(getAdminUser(),Category1.getId(),folderDisposition);
 | 
			
		||||
 | 
			
		||||
        Record elRecord = createElectronicRecord(FOLDER_DESTROY.getId(),electronicRecord);
 | 
			
		||||
        Record nonElRecord = createNonElectronicRecord(FOLDER_DESTROY.getId(),nonElectronicRecord);
 | 
			
		||||
 | 
			
		||||
        // complete records
 | 
			
		||||
        completeRecord(elRecord.getId());
 | 
			
		||||
        completeRecord(nonElRecord.getId());
 | 
			
		||||
 | 
			
		||||
        // edit disposition date
 | 
			
		||||
        recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),editDispositionDateJson(),FOLDER_DESTROY.getName());
 | 
			
		||||
 | 
			
		||||
        // cut off the FOLDER_DESTROY
 | 
			
		||||
        recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),FOLDER_DESTROY.getName());
 | 
			
		||||
 | 
			
		||||
        // Destroy the FOLDER_DESTROY
 | 
			
		||||
        recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","destroy"),FOLDER_DESTROY.getName());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @AfterMethod(alwaysRun = true)
 | 
			
		||||
    private  void deletePreconditions() {
 | 
			
		||||
        deleteRecordCategory(Category1.getId());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,116 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.smoke;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
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.v0.RecordFoldersAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.DispositionScheduleService;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
import org.alfresco.utility.Utility;
 | 
			
		||||
import org.json.JSONObject;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.annotations.AfterMethod;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.recordcategory.RetentionPeriodProperty.CREATED_DATE;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.recordcategory.RetentionPeriodProperty.CUT_OFF_DATE;
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
public class FoldersDispositionScheduleWithoutGhostRecordTests extends BaseRMRestTest {
 | 
			
		||||
 | 
			
		||||
    private RecordCategory Category1;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private DispositionScheduleService dispositionScheduleService;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RecordFoldersAPI recordFoldersAPI;
 | 
			
		||||
    private final String TEST_PREFIX = generateTestPrefix(FoldersDispositionScheduleWithoutGhostRecordTests.class);
 | 
			
		||||
    private final String folderDisposition = TEST_PREFIX + "RM-2937 folder ghosting";
 | 
			
		||||
    private final String electronicRecord = "RM-2937 electronic 2 record";
 | 
			
		||||
    private final String nonElectronicRecord = "RM-2937 non-electronic record";
 | 
			
		||||
 | 
			
		||||
    @BeforeClass(alwaysRun = true)
 | 
			
		||||
    private void setUp(){
 | 
			
		||||
 | 
			
		||||
        STEP("Create the RM site if doesn't exist");
 | 
			
		||||
        createRMSiteIfNotExists();
 | 
			
		||||
 | 
			
		||||
        STEP("Create record category");
 | 
			
		||||
        Category1 = createRootCategory(getRandomName("Title"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    @AlfrescoTest(jira="RM-2937")
 | 
			
		||||
    public void foldersDispositionScheduleWithoutGhosting() {
 | 
			
		||||
 | 
			
		||||
        //create retention schedule
 | 
			
		||||
        dispositionScheduleService.createCategoryRetentionSchedule(Category1.getName(), false);
 | 
			
		||||
 | 
			
		||||
        // add cut off step
 | 
			
		||||
        dispositionScheduleService.addCutOffAfterPeriodStep(Category1.getName(), "day|2", CREATED_DATE);
 | 
			
		||||
 | 
			
		||||
        // add destroy step with ghosting
 | 
			
		||||
        dispositionScheduleService.addDestroyWithoutGhostingAfterPeriodStep(Category1.getName(), "day|1", CUT_OFF_DATE);
 | 
			
		||||
 | 
			
		||||
        //create folders
 | 
			
		||||
        RecordCategoryChild FOLDER_DESTROY = createFolder(getAdminUser(),Category1.getId(),folderDisposition);
 | 
			
		||||
 | 
			
		||||
        Record elRecord = createElectronicRecord(FOLDER_DESTROY.getId(),electronicRecord);
 | 
			
		||||
        Record nonElRecord = createNonElectronicRecord(FOLDER_DESTROY.getId(),nonElectronicRecord);
 | 
			
		||||
 | 
			
		||||
        // complete records
 | 
			
		||||
        completeRecord(elRecord.getId());
 | 
			
		||||
        completeRecord(nonElRecord.getId());
 | 
			
		||||
 | 
			
		||||
        // edit disposition date
 | 
			
		||||
        recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),editDispositionDateJson(),FOLDER_DESTROY.getName());
 | 
			
		||||
 | 
			
		||||
        // cut off the FOLDER_DESTROY
 | 
			
		||||
        recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),FOLDER_DESTROY.getName());
 | 
			
		||||
 | 
			
		||||
        // edit disposition date
 | 
			
		||||
        recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),editDispositionDateJson(),FOLDER_DESTROY.getName());
 | 
			
		||||
 | 
			
		||||
        Utility.waitToLoopTime(5,"Waiting for Edit Disposition to be processed");
 | 
			
		||||
 | 
			
		||||
        // Destroy the FOLDER_DESTROY
 | 
			
		||||
        recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","destroy"),FOLDER_DESTROY.getName());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @AfterMethod(alwaysRun = true)
 | 
			
		||||
    private  void deletePreconditions() {
 | 
			
		||||
        deleteRecordCategory(Category1.getId());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,202 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.smoke;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.core.v0.RMEvents;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
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.v0.RMRolesAndActionsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.RecordFoldersAPI;
 | 
			
		||||
import org.alfresco.rest.v0.RecordsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.DispositionScheduleService;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
import org.alfresco.utility.Utility;
 | 
			
		||||
import org.apache.http.HttpEntity;
 | 
			
		||||
import org.apache.http.HttpResponse;
 | 
			
		||||
import org.apache.http.util.EntityUtils;
 | 
			
		||||
import org.json.JSONObject;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.DEFAULT_PASSWORD;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.recordcategory.RetentionPeriodProperty.CUT_OFF_DATE;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Contains recordsDispositionScheduleWithoutGhosting test which checks disposition schedule cut off, transfer and destroy without maintaining metadata steps applied to records
 | 
			
		||||
 * <p/>
 | 
			
		||||
 * Precondition:
 | 
			
		||||
 * <p/>
 | 
			
		||||
 * RM site created, contains an empty category "RM-2801 disposition for records". <p/>
 | 
			
		||||
 * RM user has RM admin role. <p/>
 | 
			
		||||
 * A transfer location named "transferred files" is created to which RM user has access
 | 
			
		||||
 * <p/>
 | 
			
		||||
 * <img src="doc-files/Disposition Schedule without ghosting.png" alt="Records Disposition Schedule without ghosting" />
 | 
			
		||||
 *
 | 
			
		||||
 * @author Kavit Shah
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
public class RecordsDispositionScheduleTests extends BaseRMRestTest {
 | 
			
		||||
 | 
			
		||||
    /** data prep 6services */
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMRolesAndActionsAPI rmRolesAndActionsAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RecordsAPI recordsAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RecordFoldersAPI recordFoldersAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private DispositionScheduleService dispositionScheduleService;
 | 
			
		||||
    private RecordCategory Category1;
 | 
			
		||||
    private final String TEST_PREFIX = generateTestPrefix(RecordsDispositionScheduleTests.class);
 | 
			
		||||
    private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
 | 
			
		||||
    private final String recordsCategory = TEST_PREFIX + "RM-2801 category";
 | 
			
		||||
    private final String folderDisposition = TEST_PREFIX + "RM-2801 folder";
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    @AlfrescoTest(jira="RM-2801")
 | 
			
		||||
    public void recordsDispositionScheduleWithoutGhosting() {
 | 
			
		||||
 | 
			
		||||
        // create test precondition
 | 
			
		||||
        createTestPrecondition(recordsCategory);
 | 
			
		||||
 | 
			
		||||
        // create disposition schedule
 | 
			
		||||
        dispositionScheduleService.createCategoryRetentionSchedule(Category1.getName(), true);
 | 
			
		||||
 | 
			
		||||
        // add cut off step
 | 
			
		||||
        dispositionScheduleService.addCutOffImmediatelyStep(Category1.getName());
 | 
			
		||||
 | 
			
		||||
        // add transfer step
 | 
			
		||||
        dispositionScheduleService.addTransferAfterEventStep(Category1.getName(),"transferred records","all_allowances_granted_are_terminated");
 | 
			
		||||
 | 
			
		||||
        // add destroy step without retaining metadata
 | 
			
		||||
        dispositionScheduleService.addDestroyWithoutGhostingAfterPeriodStep(Category1.getName(), "day|1", CUT_OFF_DATE);
 | 
			
		||||
 | 
			
		||||
        // create a folder and an electronic and a non-electronic record in it
 | 
			
		||||
        RecordCategoryChild FOLDER_DESTROY = createFolder(getAdminUser(),Category1.getId(),folderDisposition);
 | 
			
		||||
 | 
			
		||||
        String electronicRecord = "RM-2801 electronic record";
 | 
			
		||||
        Record elRecord = createElectronicRecord(FOLDER_DESTROY.getId(), electronicRecord);
 | 
			
		||||
        String nonElectronicRecord = "RM-2801 non-electronic record";
 | 
			
		||||
        Record nonElRecord = createNonElectronicRecord(FOLDER_DESTROY.getId(), nonElectronicRecord);
 | 
			
		||||
 | 
			
		||||
        // complete records and cut them off
 | 
			
		||||
        String nonElRecordName = recordsAPI.getRecordFullName(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(), folderDisposition, nonElectronicRecord);
 | 
			
		||||
        String elRecordName = recordsAPI.getRecordFullName(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(), folderDisposition, electronicRecord);
 | 
			
		||||
 | 
			
		||||
        // complete records and cut them off
 | 
			
		||||
        completeRecord(elRecord.getId());
 | 
			
		||||
        completeRecord(nonElRecord.getId());
 | 
			
		||||
 | 
			
		||||
        String nonElRecordNameNodeRef = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(), nonElRecordName, "/" + Category1.getName() + "/" + folderDisposition);
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),nonElRecordNameNodeRef);
 | 
			
		||||
 | 
			
		||||
        String elRecordNameNodeRef = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordName, "/" + Category1.getName() + "/" + folderDisposition);
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),elRecordNameNodeRef);
 | 
			
		||||
 | 
			
		||||
        // ensure the complete event action is displayed for both events
 | 
			
		||||
        rmRolesAndActionsAPI.completeEvent(getAdminUser().getUsername(),
 | 
			
		||||
               getAdminUser().getPassword(), nonElRecordName, RMEvents.ALL_ALLOWANCES_GRANTED_ARE_TERMINATED, Instant.now());
 | 
			
		||||
        rmRolesAndActionsAPI.completeEvent(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(), elRecordName, RMEvents.ALL_ALLOWANCES_GRANTED_ARE_TERMINATED, Instant.now());
 | 
			
		||||
 | 
			
		||||
        // Create and Complete transfer
 | 
			
		||||
        HttpResponse nonElRecordNameHttpResponse = recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","transfer"),recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
                getDataUser().usingAdmin().getAdminUser().getPassword(), nonElRecordName, "/" + Category1.getName() + "/" + folderDisposition));
 | 
			
		||||
 | 
			
		||||
        String nonElRecordNameTransferId = getTransferId(nonElRecordNameHttpResponse,nonElRecordNameNodeRef);
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","transferComplete"),nonElRecordNameTransferId);
 | 
			
		||||
 | 
			
		||||
        HttpResponse elRecordNameHttpResponse = recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","transfer"),recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
                getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordName, "/" + Category1.getName() + "/" + folderDisposition));
 | 
			
		||||
 | 
			
		||||
        String elRecordNameTransferId = getTransferId(elRecordNameHttpResponse,elRecordNameNodeRef);
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","transferComplete"),elRecordNameTransferId);
 | 
			
		||||
 | 
			
		||||
        // edit the disposition schedule date to current date
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),editDispositionDateJson(),nonElRecordNameNodeRef);
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),editDispositionDateJson(),elRecordNameNodeRef);
 | 
			
		||||
 | 
			
		||||
        Utility.waitToLoopTime(5,"Waiting for Edit Disposition to be processed");
 | 
			
		||||
 | 
			
		||||
        // destroy records
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","destroy"),nonElRecordNameNodeRef);
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","destroy"),elRecordNameNodeRef);
 | 
			
		||||
 | 
			
		||||
        // delete category
 | 
			
		||||
        deleteRecordCategory(Category1.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void createTestPrecondition(String categoryName) {
 | 
			
		||||
        createRMSiteIfNotExists();
 | 
			
		||||
 | 
			
		||||
        // create "rm admin" user if it does not exist and assign it to RM Administrator role
 | 
			
		||||
        rmRolesAndActionsAPI.createUserAndAssignToRole(
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(),
 | 
			
		||||
            RM_ADMIN, DEFAULT_PASSWORD, "Administrator");
 | 
			
		||||
 | 
			
		||||
        // create category
 | 
			
		||||
        STEP("Create two category");
 | 
			
		||||
        Category1 = createRootCategory(categoryName,"Title");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String getTransferId(HttpResponse httpResponse,String nodeRef) {
 | 
			
		||||
        HttpEntity entity = httpResponse.getEntity();
 | 
			
		||||
        String responseString = null;
 | 
			
		||||
        try {
 | 
			
		||||
            responseString = EntityUtils.toString(entity, "UTF-8");
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
        JSONObject result = new JSONObject(responseString);
 | 
			
		||||
        return result
 | 
			
		||||
            .getJSONObject("results")
 | 
			
		||||
            .get(nodeRef)
 | 
			
		||||
            .toString();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,200 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.smoke;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.core.v0.RMEvents;
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
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.v0.RMRolesAndActionsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.RecordFoldersAPI;
 | 
			
		||||
import org.alfresco.rest.v0.RecordsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.service.DispositionScheduleService;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
import org.alfresco.utility.Utility;
 | 
			
		||||
import org.apache.http.HttpEntity;
 | 
			
		||||
import org.apache.http.HttpResponse;
 | 
			
		||||
import org.apache.http.util.EntityUtils;
 | 
			
		||||
import org.json.JSONObject;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.time.Instant;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.DEFAULT_PASSWORD;
 | 
			
		||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Contains recordsDispositionScheduleWithGhosting test which checks disposition schedule cut off, transfer and destroy with maintaining record metadata steps applied to records
 | 
			
		||||
 * <p/>
 | 
			
		||||
 * Precondition:
 | 
			
		||||
 * <p/>
 | 
			
		||||
 * RM site created, contains an empty category "RM-2937 disposition for records with ghosting". <p/>
 | 
			
		||||
 * RM user has RM admin role. <p/>
 | 
			
		||||
 * A transfer location named "transferred files with ghosting" is created to which RM user has access
 | 
			
		||||
 * <p/>
 | 
			
		||||
 * <img src="doc-files/Disposition Schedule with ghosting.png" alt="Records Disposition Schedule with ghosting" />
 | 
			
		||||
 *
 | 
			
		||||
 * @author Kavit Shah
 | 
			
		||||
 */
 | 
			
		||||
public class RecordsDispositionScheduleWithGhostingTests extends BaseRMRestTest {
 | 
			
		||||
 | 
			
		||||
    /** data prep 6services */
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMRolesAndActionsAPI rmRolesAndActionsAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RecordsAPI recordsAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RecordFoldersAPI recordFoldersAPI;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private DispositionScheduleService dispositionScheduleService;
 | 
			
		||||
    private RecordCategory Category1;
 | 
			
		||||
    private final String TEST_PREFIX = generateTestPrefix(RecordsDispositionScheduleTests.class);
 | 
			
		||||
    private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
 | 
			
		||||
    private final String recordsCategory = TEST_PREFIX + "RM-2801 category";
 | 
			
		||||
    private final String folderDisposition = TEST_PREFIX + "RM-2801 folder";
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    @AlfrescoTest(jira="RM-2801")
 | 
			
		||||
    public void recordsDispositionScheduleWithGhosting() {
 | 
			
		||||
 | 
			
		||||
        // create test precondition
 | 
			
		||||
        createTestPrecondition(recordsCategory);
 | 
			
		||||
 | 
			
		||||
        // create disposition schedule
 | 
			
		||||
        dispositionScheduleService.createCategoryRetentionSchedule(Category1.getName(), true);
 | 
			
		||||
 | 
			
		||||
        // add cut off step
 | 
			
		||||
        dispositionScheduleService.addCutOffImmediatelyStep(Category1.getName());
 | 
			
		||||
 | 
			
		||||
        // add transfer step
 | 
			
		||||
        dispositionScheduleService.addTransferAfterEventStep(Category1.getName(),"transferred records","all_allowances_granted_are_terminated");
 | 
			
		||||
 | 
			
		||||
        // add destroy step without retaining metadata
 | 
			
		||||
        dispositionScheduleService.addDestroyWithGhostingImmediatelyAfterCutOff(Category1.getName());
 | 
			
		||||
 | 
			
		||||
        // create a folder and an electronic and a non-electronic record in it
 | 
			
		||||
        RecordCategoryChild FOLDER_DESTROY = createFolder(getAdminUser(),Category1.getId(),folderDisposition);
 | 
			
		||||
 | 
			
		||||
        String electronicRecord = "RM-2801 electronic record";
 | 
			
		||||
        Record elRecord = createElectronicRecord(FOLDER_DESTROY.getId(), electronicRecord);
 | 
			
		||||
        String nonElectronicRecord = "RM-2801 non-electronic record";
 | 
			
		||||
        Record nonElRecord = createNonElectronicRecord(FOLDER_DESTROY.getId(), nonElectronicRecord);
 | 
			
		||||
 | 
			
		||||
        // complete records and cut them off
 | 
			
		||||
        String nonElRecordName = recordsAPI.getRecordFullName(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(), folderDisposition, nonElectronicRecord);
 | 
			
		||||
        String elRecordName = recordsAPI.getRecordFullName(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(), folderDisposition, electronicRecord);
 | 
			
		||||
 | 
			
		||||
        // complete records and cut them off
 | 
			
		||||
        completeRecord(elRecord.getId());
 | 
			
		||||
        completeRecord(nonElRecord.getId());
 | 
			
		||||
 | 
			
		||||
        String nonElRecordNameNodeRef = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(), nonElRecordName, "/" + Category1.getName() + "/" + folderDisposition);
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),nonElRecordNameNodeRef);
 | 
			
		||||
 | 
			
		||||
        String elRecordNameNodeRef = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordName, "/" + Category1.getName() + "/" + folderDisposition);
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),elRecordNameNodeRef);
 | 
			
		||||
 | 
			
		||||
        // ensure the complete event action is displayed for both events
 | 
			
		||||
        rmRolesAndActionsAPI.completeEvent(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(), nonElRecordName, RMEvents.ALL_ALLOWANCES_GRANTED_ARE_TERMINATED, Instant.now());
 | 
			
		||||
        rmRolesAndActionsAPI.completeEvent(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(), elRecordName, RMEvents.ALL_ALLOWANCES_GRANTED_ARE_TERMINATED, Instant.now());
 | 
			
		||||
 | 
			
		||||
        // Create and Complete transfer
 | 
			
		||||
        HttpResponse nonElRecordNameHttpResponse = recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","transfer"),recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
                getDataUser().usingAdmin().getAdminUser().getPassword(), nonElRecordName, "/" + Category1.getName() + "/" + folderDisposition));
 | 
			
		||||
 | 
			
		||||
        String nonElRecordNameTransferId = getTransferId(nonElRecordNameHttpResponse,nonElRecordNameNodeRef);
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","transferComplete"),nonElRecordNameTransferId);
 | 
			
		||||
 | 
			
		||||
        HttpResponse elRecordNameHttpResponse = recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","transfer"),recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
                getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordName, "/" + Category1.getName() + "/" + folderDisposition));
 | 
			
		||||
 | 
			
		||||
        String elRecordNameTransferId = getTransferId(elRecordNameHttpResponse,elRecordNameNodeRef);
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","transferComplete"),elRecordNameTransferId);
 | 
			
		||||
 | 
			
		||||
        // edit the disposition schedule date to current date
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),editDispositionDateJson(),nonElRecordNameNodeRef);
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),editDispositionDateJson(),elRecordNameNodeRef);
 | 
			
		||||
 | 
			
		||||
        Utility.waitToLoopTime(5,"Waiting for Edit Disposition to be processed");
 | 
			
		||||
 | 
			
		||||
        // destroy records
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","destroy"),nonElRecordNameNodeRef);
 | 
			
		||||
        recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
 | 
			
		||||
            getAdminUser().getPassword(),new JSONObject().put("name","destroy"),elRecordNameNodeRef);
 | 
			
		||||
 | 
			
		||||
        // delete category
 | 
			
		||||
        deleteRecordCategory(Category1.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void createTestPrecondition(String categoryName) {
 | 
			
		||||
        createRMSiteIfNotExists();
 | 
			
		||||
 | 
			
		||||
        // create "rm admin" user if it does not exist and assign it to RM Administrator role
 | 
			
		||||
        rmRolesAndActionsAPI.createUserAndAssignToRole(
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getUsername(),
 | 
			
		||||
            getDataUser().usingAdmin().getAdminUser().getPassword(),
 | 
			
		||||
            RM_ADMIN, DEFAULT_PASSWORD, "Administrator");
 | 
			
		||||
 | 
			
		||||
        // create category
 | 
			
		||||
        STEP("Create two category");
 | 
			
		||||
        Category1 = createRootCategory(categoryName,"Title");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String getTransferId(HttpResponse httpResponse,String nodeRef) {
 | 
			
		||||
        HttpEntity entity = httpResponse.getEntity();
 | 
			
		||||
        String responseString = null;
 | 
			
		||||
        try {
 | 
			
		||||
            responseString = EntityUtils.toString(entity, "UTF-8");
 | 
			
		||||
        } catch (IOException e) {
 | 
			
		||||
            throw new RuntimeException(e);
 | 
			
		||||
        }
 | 
			
		||||
        JSONObject result = new JSONObject(responseString);
 | 
			
		||||
        return result
 | 
			
		||||
            .getJSONObject("results")
 | 
			
		||||
            .get(nodeRef)
 | 
			
		||||
            .toString();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,124 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Records Management Module
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.smoke;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.record.RecordContent;
 | 
			
		||||
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.rules.ActionsOnRule;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.rules.RuleDefinition;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainer;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChild;
 | 
			
		||||
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChildProperties;
 | 
			
		||||
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
 | 
			
		||||
import org.alfresco.rest.v0.RulesAPI;
 | 
			
		||||
import org.alfresco.test.AlfrescoTest;
 | 
			
		||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import static org.alfresco.rest.core.v0.BaseAPI.NODE_PREFIX;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.ELECTRONIC_RECORD_NAME;
 | 
			
		||||
import static org.alfresco.rest.rm.community.base.TestData.NONELECTRONIC_RECORD_NAME;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS;
 | 
			
		||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.*;
 | 
			
		||||
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;
 | 
			
		||||
import static org.springframework.http.HttpStatus.*;
 | 
			
		||||
public class UnfiledRecordsRuleTests extends BaseRMRestTest {
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RMRolesAndActionsAPI rmRolesAndActionsAPI;
 | 
			
		||||
    private final String TEST_PREFIX = generateTestPrefix(CreateCategoriesTests.class);
 | 
			
		||||
    private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
 | 
			
		||||
    private RecordCategory Category2;
 | 
			
		||||
    private RecordCategoryChild Folder2;
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RulesAPI rulesAPI;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    @AlfrescoTest(jira = "RM-2794")
 | 
			
		||||
    public void unfiledRecordsRule() {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        STEP("Create the RM site if doesn't exist");
 | 
			
		||||
        createRMSiteIfNotExists();
 | 
			
		||||
 | 
			
		||||
        STEP("Create RM Admin user");
 | 
			
		||||
        rmRolesAndActionsAPI.createUserAndAssignToRole(getAdminUser().getUsername(), getAdminUser().getPassword(), RM_ADMIN,
 | 
			
		||||
            getAdminUser().getPassword(),
 | 
			
		||||
            "Administrator");
 | 
			
		||||
 | 
			
		||||
        STEP("Create record categories and record folders");
 | 
			
		||||
        Category2 = createRootCategory(getRandomName("recordCategory"));
 | 
			
		||||
        Folder2 = createFolder(Category2.getId(), getRandomName("recordFolder"));
 | 
			
		||||
 | 
			
		||||
        STEP("Get the unfiled records container");
 | 
			
		||||
        UnfiledContainer container = getRestAPIFactory().getUnfiledContainersAPI().getUnfiledContainer(UNFILED_RECORDS_CONTAINER_ALIAS);
 | 
			
		||||
 | 
			
		||||
        // Check the response code
 | 
			
		||||
        assertStatusCode(OK);
 | 
			
		||||
 | 
			
		||||
        //create a rule
 | 
			
		||||
        RuleDefinition ruleDefinition = RuleDefinition.createNewRule().title("name").description("description")
 | 
			
		||||
            .applyToChildren(true)
 | 
			
		||||
            .actions(Collections.singletonList(ActionsOnRule.FILE_TO.getActionValue()));
 | 
			
		||||
        rulesAPI.createRule(getAdminUser().getUsername(), getAdminUser().getPassword(), NODE_PREFIX + container.getId(), ruleDefinition);
 | 
			
		||||
 | 
			
		||||
        //upload an electronic record
 | 
			
		||||
        UnfiledContainerChild electronicRecord = UnfiledContainerChild.builder()
 | 
			
		||||
            .name(ELECTRONIC_RECORD_NAME)
 | 
			
		||||
            .nodeType(CONTENT_TYPE)
 | 
			
		||||
            .content(RecordContent.builder().mimeType("text/plain").build())
 | 
			
		||||
            .build();
 | 
			
		||||
        assertStatusCode(OK);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // create a non-electronic record
 | 
			
		||||
        UnfiledContainerChild nonelectronicRecord = UnfiledContainerChild.builder()
 | 
			
		||||
            .properties(UnfiledContainerChildProperties.builder()
 | 
			
		||||
                .description(NONELECTRONIC_RECORD_NAME)
 | 
			
		||||
                .title("Title")
 | 
			
		||||
                .build())
 | 
			
		||||
            .name(NONELECTRONIC_RECORD_NAME)
 | 
			
		||||
            .nodeType(NON_ELECTRONIC_RECORD_TYPE)
 | 
			
		||||
            .build();
 | 
			
		||||
        assertStatusCode(OK);
 | 
			
		||||
 | 
			
		||||
        //delete the record created, delete the rule from UnfilledRecord page, delete the category created
 | 
			
		||||
        rulesAPI.deleteAllRulesOnContainer(getAdminUser().getUsername(), getAdminUser().getPassword(), NODE_PREFIX + container.getId());
 | 
			
		||||
        deleteRecordCategory(Category2.getId());
 | 
			
		||||
        assertStatusCode(NO_CONTENT);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
   <parent>
 | 
			
		||||
      <groupId>org.alfresco</groupId>
 | 
			
		||||
      <artifactId>alfresco-governance-services-community-parent</artifactId>
 | 
			
		||||
      <version>17.51</version>
 | 
			
		||||
      <version>17.102-SNAPSHOT</version>
 | 
			
		||||
   </parent>
 | 
			
		||||
 | 
			
		||||
   <modules>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
SOLR6_TAG=2.0.3
 | 
			
		||||
POSTGRES_TAG=13.3
 | 
			
		||||
ACTIVEMQ_TAG=5.16.1
 | 
			
		||||
POSTGRES_TAG=14.4
 | 
			
		||||
ACTIVEMQ_TAG=5.17.1-jre11-rockylinux8
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
   <parent>
 | 
			
		||||
      <groupId>org.alfresco</groupId>
 | 
			
		||||
      <artifactId>alfresco-governance-services-community-repo-parent</artifactId>
 | 
			
		||||
      <version>17.51</version>
 | 
			
		||||
      <version>17.102-SNAPSHOT</version>
 | 
			
		||||
   </parent>
 | 
			
		||||
 | 
			
		||||
   <properties>
 | 
			
		||||
@@ -434,7 +434,7 @@
 | 
			
		||||
                           </run>
 | 
			
		||||
                        </image>
 | 
			
		||||
                        <image>
 | 
			
		||||
                           <name>alfresco/alfresco-activemq:${dependency.activemq.version}</name>
 | 
			
		||||
                           <name>alfresco/alfresco-activemq:${dependency.activemq.version}-jre11-rockylinux8</name>
 | 
			
		||||
                           <run>
 | 
			
		||||
                              <ports>
 | 
			
		||||
                                 <port>${activemq.port1}:${activemq.port1}</port>
 | 
			
		||||
@@ -505,7 +505,7 @@
 | 
			
		||||
                           </run>
 | 
			
		||||
                        </image>
 | 
			
		||||
                        <image>
 | 
			
		||||
                           <name>alfresco/alfresco-activemq:${dependency.activemq.version}</name>
 | 
			
		||||
                           <name>alfresco/alfresco-activemq:${dependency.activemq.version}-jre11-rockylinux8</name>
 | 
			
		||||
                           <run>
 | 
			
		||||
                              <ports>
 | 
			
		||||
                                 <port>${activemq.port1}:${activemq.port1}</port>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-governance-services-community-repo-parent</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <build>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <modules>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-amps</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright 2005 - 2020 Alfresco Software Limited.
 | 
			
		||||
 * Copyright 2005 - 2022 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.
 | 
			
		||||
@@ -40,6 +40,7 @@ import org.json.JSONObject;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.springframework.extensions.webscripts.TestWebScriptServer;
 | 
			
		||||
import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest;
 | 
			
		||||
import org.springframework.extensions.webscripts.TestWebScriptServer.Response;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
@@ -194,13 +195,13 @@ public class SlingshotContentGetTest extends BaseWebScriptTest
 | 
			
		||||
 | 
			
		||||
        NodeRef rootFolder = createNode(companyHome, "rootFolder", ContentModel.TYPE_FOLDER);
 | 
			
		||||
 | 
			
		||||
        NodeRef doc1 = createNodeWithTextContent(rootFolder, "doc1", ContentModel.TYPE_CONTENT, "doc1 file content");
 | 
			
		||||
        NodeRef doc1 = createNodeWithTextContent(rootFolder, "doc1", ContentModel.TYPE_CONTENT, "doc1 file content", MimetypeMap.MIMETYPE_TEXT_PLAIN);
 | 
			
		||||
 | 
			
		||||
        NodeRef folderX = createNode(rootFolder, "X", ContentModel.TYPE_FOLDER);
 | 
			
		||||
        NodeRef folderY = createNode(folderX, "Y", ContentModel.TYPE_FOLDER);
 | 
			
		||||
        NodeRef folderZ = createNode(folderY, "Z", ContentModel.TYPE_FOLDER);
 | 
			
		||||
 | 
			
		||||
        NodeRef doc2 = createNodeWithTextContent(folderZ, "doc2", ContentModel.TYPE_CONTENT, "doc2 file content");
 | 
			
		||||
        NodeRef doc2 = createNodeWithTextContent(folderZ, "doc2", ContentModel.TYPE_CONTENT, "doc2 file content", MimetypeMap.MIMETYPE_TEXT_PLAIN);
 | 
			
		||||
 | 
			
		||||
        // uri with relative path at the end
 | 
			
		||||
        String uri = URL_CONTENT_DOWNLOAD + doc1.getId() + "/X/Y/Z/doc2";
 | 
			
		||||
@@ -212,7 +213,50 @@ public class SlingshotContentGetTest extends BaseWebScriptTest
 | 
			
		||||
        nodeService.deleteNode(rootFolder);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NodeRef createNodeWithTextContent(NodeRef parentNode, String nodeCmName, QName nodeType, String content)
 | 
			
		||||
    public void testForcedAttachment() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        Repository repositoryHelper = (Repository) getServer().getApplicationContext().getBean("repositoryHelper");
 | 
			
		||||
        NodeRef companyHome = repositoryHelper.getCompanyHome();
 | 
			
		||||
 | 
			
		||||
        NodeRef rootFolder = createNode(companyHome, "rootFolder", ContentModel.TYPE_FOLDER);
 | 
			
		||||
        NodeRef testhtml = createNodeWithTextContent(rootFolder, "testhtml", ContentModel.TYPE_CONTENT, "testhtml content", MimetypeMap.MIMETYPE_HTML);
 | 
			
		||||
        NodeRef testpdf = createNodeWithTextContent(rootFolder, "testpdf", ContentModel.TYPE_CONTENT, "testpdf content", MimetypeMap.MIMETYPE_PDF);
 | 
			
		||||
 | 
			
		||||
        String uri = URL_CONTENT_DOWNLOAD + testhtml.getId() + "?a=false";
 | 
			
		||||
        GetRequest req = new GetRequest(uri);
 | 
			
		||||
        Response res = sendRequest(req, 200);
 | 
			
		||||
        assertEquals("attachment", res.getHeader("Content-Disposition"));
 | 
			
		||||
        assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType());
 | 
			
		||||
 | 
			
		||||
        uri = URL_CONTENT_DOWNLOAD + testhtml.getId();
 | 
			
		||||
        res = sendRequest(new GetRequest(uri), 200);
 | 
			
		||||
        assertEquals("attachment", res.getHeader("Content-Disposition"));
 | 
			
		||||
        assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType());
 | 
			
		||||
 | 
			
		||||
        uri = URL_CONTENT_DOWNLOAD + testhtml.getId() + "?a=true";
 | 
			
		||||
        res = sendRequest(new GetRequest(uri), 200);
 | 
			
		||||
        assertEquals("attachment", res.getHeader("Content-Disposition"));
 | 
			
		||||
        assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType());
 | 
			
		||||
 | 
			
		||||
        uri = URL_CONTENT_DOWNLOAD + testpdf.getId() + "?a=false";
 | 
			
		||||
        res = sendRequest(new GetRequest(uri), 200);
 | 
			
		||||
        assertNull(res.getHeader("Content-Disposition"));
 | 
			
		||||
        assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType());
 | 
			
		||||
 | 
			
		||||
        uri = URL_CONTENT_DOWNLOAD + testpdf.getId();
 | 
			
		||||
        res = sendRequest(new GetRequest(uri), 200);
 | 
			
		||||
        assertNull(res.getHeader("Content-Disposition"));
 | 
			
		||||
        assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType());
 | 
			
		||||
 | 
			
		||||
        uri = URL_CONTENT_DOWNLOAD + testpdf.getId() + "?a=true";
 | 
			
		||||
        res = sendRequest(new GetRequest(uri), 200);
 | 
			
		||||
        assertEquals("attachment", res.getHeader("Content-Disposition"));
 | 
			
		||||
        assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType());
 | 
			
		||||
 | 
			
		||||
        nodeService.deleteNode(rootFolder);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NodeRef createNodeWithTextContent(NodeRef parentNode, String nodeCmName, QName nodeType, String content, String mimetype)
 | 
			
		||||
    {
 | 
			
		||||
        NodeRef nodeRef = createNode(parentNode, nodeCmName, nodeType);
 | 
			
		||||
 | 
			
		||||
@@ -220,7 +264,7 @@ public class SlingshotContentGetTest extends BaseWebScriptTest
 | 
			
		||||
        if (content != null)
 | 
			
		||||
        {
 | 
			
		||||
            ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
 | 
			
		||||
            writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
 | 
			
		||||
            writer.setMimetype(mimetype);
 | 
			
		||||
            writer.setEncoding("UTF-8");
 | 
			
		||||
            writer.putContent(content);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
   <parent>
 | 
			
		||||
      <groupId>org.alfresco</groupId>
 | 
			
		||||
      <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
      <version>17.51</version>
 | 
			
		||||
      <version>17.102-SNAPSHOT</version>
 | 
			
		||||
   </parent>
 | 
			
		||||
 | 
			
		||||
   <dependencies>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <dependencies>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,6 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-packaging</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
</project>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
# Fetch image based on Tomcat 9.0, Java 11 and Centos 7
 | 
			
		||||
# Fetch image based on Tomcat 9.0, Java 17 and Rocky Linux 8
 | 
			
		||||
# More infos about this image: https://github.com/Alfresco/alfresco-docker-base-tomcat
 | 
			
		||||
FROM alfresco/alfresco-base-tomcat:tomcat9-jre11-centos7-202203091924
 | 
			
		||||
FROM alfresco/alfresco-base-tomcat:tomcat9-jre17-rockylinux8-202205140719
 | 
			
		||||
 | 
			
		||||
# Set default docker_context.
 | 
			
		||||
ARG resource_path=target
 | 
			
		||||
@@ -65,12 +65,12 @@ RUN sed -i -e "s_log4j.appender.File.File\=alfresco.log_log4j.appender.File.File
 | 
			
		||||
 | 
			
		||||
# fontconfig is required by Activiti worflow diagram generator
 | 
			
		||||
# installing pinned dependencies as well
 | 
			
		||||
RUN yum install -y fontconfig-2.13.0-4.3.el7 \
 | 
			
		||||
                   dejavu-fonts-common-2.33-6.el7 \
 | 
			
		||||
                   fontpackages-filesystem-1.44-8.el7 \
 | 
			
		||||
                   freetype-2.8-14.el7_9.1 \
 | 
			
		||||
                   libpng-1.5.13-8.el7 \
 | 
			
		||||
                   dejavu-sans-fonts-2.33-6.el7 && \
 | 
			
		||||
RUN yum install -y fontconfig-2.13.1-4.el8 \
 | 
			
		||||
                   dejavu-fonts-common-2.35-7.el8 \
 | 
			
		||||
                   fontpackages-filesystem-1.44-22.el8 \
 | 
			
		||||
                   freetype-2.9.1-4.el8_3.1 \
 | 
			
		||||
                   libpng-1.6.34-5.el8 \
 | 
			
		||||
                   dejavu-sans-fonts-2.35-7.el8 && \
 | 
			
		||||
    yum clean all
 | 
			
		||||
 | 
			
		||||
# The standard configuration is to have all Tomcat files owned by root with group GROUPNAME and whilst owner has read/write privileges, 
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-packaging</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <modules>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
SOLR6_TAG=2.0.3
 | 
			
		||||
POSTGRES_TAG=13.3
 | 
			
		||||
ACTIVEMQ_TAG=5.16.1
 | 
			
		||||
POSTGRES_TAG=14.4
 | 
			
		||||
ACTIVEMQ_TAG=5.17.1-jre11-rockylinux8
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-packaging</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <modules>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-tests</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <developers>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-tests</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <developers>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-tests</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <developers>
 | 
			
		||||
@@ -106,8 +106,10 @@
 | 
			
		||||
                    <suiteXmlFiles>
 | 
			
		||||
                        <suiteXmlFile>${suiteXmlFile}</suiteXmlFile>
 | 
			
		||||
                    </suiteXmlFiles>
 | 
			
		||||
                    <!-- Keeping illegal-access=warn for Java 11 compatibility, even though it has no effect on JDK 17 -->
 | 
			
		||||
                    <argLine>
 | 
			
		||||
                        --illegal-access=warn
 | 
			
		||||
                        --add-opens=java.base/java.lang=ALL-UNNAMED
 | 
			
		||||
                    </argLine>
 | 
			
		||||
                </configuration>
 | 
			
		||||
            </plugin>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-tests</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <developers>
 | 
			
		||||
@@ -78,8 +78,10 @@
 | 
			
		||||
                    <suiteXmlFiles>
 | 
			
		||||
                        <suiteXmlFile>${suiteXmlFile}</suiteXmlFile>
 | 
			
		||||
                    </suiteXmlFiles>
 | 
			
		||||
                    <!-- Keeping illegal-access=warn for Java 11 compatibility, even though it has no effect on JDK 17 -->
 | 
			
		||||
                    <argLine>
 | 
			
		||||
                        --illegal-access=warn
 | 
			
		||||
                        --add-opens=java.base/java.lang=ALL-UNNAMED
 | 
			
		||||
                    </argLine>
 | 
			
		||||
                </configuration>
 | 
			
		||||
            </plugin>
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,11 @@ package org.alfresco.rest.rules;
 | 
			
		||||
 | 
			
		||||
import static java.util.stream.Collectors.toList;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.rules.RulesTestsUtils.*;
 | 
			
		||||
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
 | 
			
		||||
import static org.alfresco.utility.constants.UserRole.SiteConsumer;
 | 
			
		||||
import static org.alfresco.utility.constants.UserRole.SiteContributor;
 | 
			
		||||
import static org.alfresco.utility.constants.UserRole.SiteManager;
 | 
			
		||||
import static org.alfresco.utility.model.FileModel.getRandomFileModel;
 | 
			
		||||
import static org.alfresco.utility.model.FileType.TEXT_PLAIN;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
@@ -36,12 +41,17 @@ import static org.springframework.http.HttpStatus.CREATED;
 | 
			
		||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
 | 
			
		||||
import static org.springframework.http.HttpStatus.NOT_FOUND;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.stream.IntStream;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.RestTest;
 | 
			
		||||
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleModel;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleModelsCollection;
 | 
			
		||||
import org.alfresco.utility.constants.UserRole;
 | 
			
		||||
import org.alfresco.utility.model.FileModel;
 | 
			
		||||
import org.alfresco.utility.model.FolderModel;
 | 
			
		||||
import org.alfresco.utility.model.SiteModel;
 | 
			
		||||
@@ -56,6 +66,8 @@ import org.testng.annotations.Test;
 | 
			
		||||
@Test(groups = {TestGroup.RULES})
 | 
			
		||||
public class CreateRulesTests extends RestTest
 | 
			
		||||
{
 | 
			
		||||
    private static final String IGNORE_ID = "id";
 | 
			
		||||
    private static final String IGNORE_IS_SHARED = "isShared";
 | 
			
		||||
    private UserModel user;
 | 
			
		||||
    private SiteModel site;
 | 
			
		||||
    private FolderModel ruleFolder;
 | 
			
		||||
@@ -68,20 +80,26 @@ public class CreateRulesTests extends RestTest
 | 
			
		||||
        ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can create a rule. */
 | 
			
		||||
    /**
 | 
			
		||||
     * Check we can create a rule.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * Also check that the isShared field is not returned when not requested.
 | 
			
		||||
     */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
 | 
			
		||||
    public void createRule()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel ruleModel = new RestRuleModel();
 | 
			
		||||
        ruleModel.setName("ruleName");
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModelWithModifiedValues();
 | 
			
		||||
 | 
			
		||||
        RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                                       .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        RestRuleModel expectedRuleModel = createRuleModelWithModifiedValues();
 | 
			
		||||
        expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions()));
 | 
			
		||||
        expectedRuleModel.setConditions(createEmptyConditionModel());
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
 | 
			
		||||
        rule.assertThat().field("id").isNotNull()
 | 
			
		||||
            .assertThat().field("name").is("ruleName");
 | 
			
		||||
        rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
 | 
			
		||||
                .assertThat().field("id").isNotNull()
 | 
			
		||||
                .assertThat().field("isShared").isNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check creating a rule in a non-existent folder returns an error. */
 | 
			
		||||
@@ -119,8 +137,7 @@ public class CreateRulesTests extends RestTest
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void createRuleWithEmptyName()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel ruleModel = new RestRuleModel();
 | 
			
		||||
        ruleModel.setName("");
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModel("");
 | 
			
		||||
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
@@ -132,8 +149,7 @@ public class CreateRulesTests extends RestTest
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void duplicateRuleNameIsAcceptable()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel ruleModel = new RestRuleModel();
 | 
			
		||||
        ruleModel.setName("duplicateRuleName");
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModel("duplicateRuleName");
 | 
			
		||||
 | 
			
		||||
        STEP("Create two identical rules");
 | 
			
		||||
        RestRuleModel ruleA = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
 | 
			
		||||
@@ -145,7 +161,7 @@ public class CreateRulesTests extends RestTest
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check that a user without permission to view the folder cannot create a rule in it. */
 | 
			
		||||
    public void requirePermissionToCreateRule()
 | 
			
		||||
    public void requireReadPermissionToCreateRule()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a user and use them to create a private site containing a folder");
 | 
			
		||||
        UserModel privateUser = dataUser.createRandomTestUser();
 | 
			
		||||
@@ -159,7 +175,43 @@ public class CreateRulesTests extends RestTest
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(FORBIDDEN);
 | 
			
		||||
        restClient.assertLastError().containsSummary("Cannot read from this node");
 | 
			
		||||
        restClient.assertLastError().containsSummary("Insufficient permissions to manage rules");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check that a Collaborator cannot create a rule in a private folder. */
 | 
			
		||||
    public void siteCollaboratorCannotCreateRule()
 | 
			
		||||
    {
 | 
			
		||||
        testRolePermissionsWith(SiteCollaborator);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(FORBIDDEN);
 | 
			
		||||
        restClient.assertLastError().containsSummary("Insufficient permissions to manage rules");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check that a Contributor cannot create a rule in a private folder. */
 | 
			
		||||
    public void siteContributorCannotCreateRule()
 | 
			
		||||
    {
 | 
			
		||||
        testRolePermissionsWith(SiteContributor);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(FORBIDDEN);
 | 
			
		||||
        restClient.assertLastError().containsSummary("Insufficient permissions to manage rules");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check that a Consumer cannot create a rule in a private folder. */
 | 
			
		||||
    public void siteConsumerCannotCreateRule()
 | 
			
		||||
    {
 | 
			
		||||
        testRolePermissionsWith(SiteConsumer);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(FORBIDDEN);
 | 
			
		||||
        restClient.assertLastError().containsSummary("Insufficient permissions to manage rules");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check that a siteManager can create a rule in a private folder. */
 | 
			
		||||
    public void siteManagerCanCreateRule()
 | 
			
		||||
    {
 | 
			
		||||
        testRolePermissionsWith(SiteManager)
 | 
			
		||||
                .assertThat().field("id").isNotNull()
 | 
			
		||||
                .assertThat().field("name").is("testRule");
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can't create a rule under a document node. */
 | 
			
		||||
@@ -184,12 +236,7 @@ public class CreateRulesTests extends RestTest
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a list of rules in one POST request");
 | 
			
		||||
        List<String> ruleNames = List.of("ruleA", "ruleB", "ruleC");
 | 
			
		||||
        List<RestRuleModel> ruleModels = ruleNames.stream().map(ruleName ->
 | 
			
		||||
        {
 | 
			
		||||
            RestRuleModel ruleModel = new RestRuleModel();
 | 
			
		||||
            ruleModel.setName(ruleName);
 | 
			
		||||
            return ruleModel;
 | 
			
		||||
        }).collect(toList());
 | 
			
		||||
        List<RestRuleModel> ruleModels = ruleNames.stream().map(RulesTestsUtils::createRuleModel).collect(toList());
 | 
			
		||||
 | 
			
		||||
        RestRuleModelsCollection rules = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                                                   .createListOfRules(ruleModels);
 | 
			
		||||
@@ -208,12 +255,10 @@ public class CreateRulesTests extends RestTest
 | 
			
		||||
    public void createRulesWithOneError()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Try to create a three rules but the middle one has an error.");
 | 
			
		||||
        RestRuleModel ruleA = new RestRuleModel();
 | 
			
		||||
        ruleA.setName("ruleA");
 | 
			
		||||
        RestRuleModel ruleB = new RestRuleModel();
 | 
			
		||||
        RestRuleModel ruleA = createRuleModel("ruleA");
 | 
			
		||||
        RestRuleModel ruleB = createRuleModel("");
 | 
			
		||||
        // Don't set a name for Rule B.
 | 
			
		||||
        RestRuleModel ruleC = new RestRuleModel();
 | 
			
		||||
        ruleC.setName("ruleC");
 | 
			
		||||
        RestRuleModel ruleC = createRuleModel("ruleC");
 | 
			
		||||
        List<RestRuleModel> ruleModels = List.of(ruleA, ruleB, ruleC);
 | 
			
		||||
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createListOfRules(ruleModels);
 | 
			
		||||
@@ -221,4 +266,130 @@ public class CreateRulesTests extends RestTest
 | 
			
		||||
        restClient.assertStatusCodeIs(BAD_REQUEST);
 | 
			
		||||
        restClient.assertLastError().containsSummary("Rule name is a mandatory parameter");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can create a rule without description. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void createRuleWithoutDescription()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModelWithDefaultValues();
 | 
			
		||||
        UserModel admin = dataUser.getAdminUser();
 | 
			
		||||
 | 
			
		||||
        RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
            .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
        rule.assertThat().field("id").isNotNull()
 | 
			
		||||
            .assertThat().field("name").is(RULE_NAME_DEFAULT)
 | 
			
		||||
            .assertThat().field("description").isNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can create a rule without specifying triggers but with the default "inbound" value. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void createRuleWithoutTriggers()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModelWithDefaultValues();
 | 
			
		||||
        UserModel admin = dataUser.getAdminUser();
 | 
			
		||||
 | 
			
		||||
        RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
            .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
        rule.assertThat().field("id").isNotNull()
 | 
			
		||||
            .assertThat().field("name").is(RULE_NAME_DEFAULT)
 | 
			
		||||
            .assertThat().field("triggers").is(List.of("inbound"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can create a rule without error script. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void createRuleWithoutErrorScript()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModelWithDefaultValues();
 | 
			
		||||
        UserModel admin = dataUser.getAdminUser();
 | 
			
		||||
 | 
			
		||||
        RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
            .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
        rule.assertThat().field("id").isNotNull()
 | 
			
		||||
            .assertThat().field("name").is(RULE_NAME_DEFAULT)
 | 
			
		||||
            .assertThat().field("errorScript").isNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can create a rule with irrelevant isShared flag, and it doesn't have impact to the process. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void createRuleWithSharedFlag()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModelWithDefaultValues();
 | 
			
		||||
        ruleModel.setIsShared(true);
 | 
			
		||||
        UserModel admin = dataUser.getAdminUser();
 | 
			
		||||
 | 
			
		||||
        RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
            .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
        rule.assertThat().field("id").isNotNull()
 | 
			
		||||
            .assertThat().field("name").is(RULE_NAME_DEFAULT)
 | 
			
		||||
            .assertThat().field("isShared").isNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can create a rule. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
 | 
			
		||||
    public void createRuleAndIncludeFieldsInResponse()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModel("ruleName");
 | 
			
		||||
 | 
			
		||||
        RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                                       .include("isShared")
 | 
			
		||||
                                       .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
        rule.assertThat().field("isShared").isNotNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public RestRuleModel testRolePermissionsWith(UserRole userRole)
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a user and use them to create a private site containing a folder");
 | 
			
		||||
        SiteModel privateSite = dataSite.usingUser(user).createPrivateRandomSite();
 | 
			
		||||
        FolderModel privateFolder = dataContent.usingUser(user).usingSite(privateSite).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP(String.format("Add a user with '%s' role in the private site's folder", userRole.toString()));
 | 
			
		||||
        UserModel userWithRole = dataUser.createRandomTestUser();
 | 
			
		||||
        dataUser.addUserToSite(userWithRole, privateSite, userRole);
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModel("testRule", List.of(createDefaultActionModel()));
 | 
			
		||||
 | 
			
		||||
        return restClient.authenticateUser(userWithRole).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check we can create a rule with several actions.
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES})
 | 
			
		||||
    public void createRuleWithActions()
 | 
			
		||||
    {
 | 
			
		||||
        final Map<String, Serializable> copyParams =
 | 
			
		||||
                Map.of("destination-folder", "dummy-folder-node", "deep-copy", true);
 | 
			
		||||
        final RestActionBodyExecTemplateModel copyAction = createCustomActionModel("copy", copyParams);
 | 
			
		||||
        final Map<String, Serializable> checkOutParams =
 | 
			
		||||
                Map.of("destination-folder", "dummy-folder-node", "assoc-name", "cm:checkout", "assoc-type",
 | 
			
		||||
                        "cm:contains");
 | 
			
		||||
        final RestActionBodyExecTemplateModel checkOutAction = createCustomActionModel("check-out", checkOutParams);
 | 
			
		||||
        final Map<String, Serializable> scriptParams = Map.of("script-ref", "dummy-script-node-id");
 | 
			
		||||
        final RestActionBodyExecTemplateModel scriptAction = createCustomActionModel("script", scriptParams);
 | 
			
		||||
        final RestRuleModel ruleModel = createRuleModelWithDefaultValues();
 | 
			
		||||
        ruleModel.setActions(Arrays.asList(copyAction, checkOutAction, scriptAction));
 | 
			
		||||
 | 
			
		||||
        final UserModel admin = dataUser.getAdminUser();
 | 
			
		||||
 | 
			
		||||
        final RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        final RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues();
 | 
			
		||||
        expectedRuleModel.setActions(addActionContextParams(Arrays.asList(copyAction, checkOutAction, scriptAction)));
 | 
			
		||||
        expectedRuleModel.setConditions(createEmptyConditionModel());
 | 
			
		||||
        expectedRuleModel.setTriggers(List.of("inbound"));
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
        rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
 | 
			
		||||
                .assertThat().field("isShared").isNull();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,254 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Repository
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.rules;
 | 
			
		||||
 | 
			
		||||
import static java.util.stream.Collectors.toList;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
 | 
			
		||||
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
 | 
			
		||||
import static org.alfresco.utility.constants.UserRole.SiteContributor;
 | 
			
		||||
import static org.alfresco.utility.constants.UserRole.SiteManager;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
 | 
			
		||||
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.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
import java.util.stream.Stream;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.RestTest;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleModel;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleModelsCollection;
 | 
			
		||||
import org.alfresco.utility.model.FolderModel;
 | 
			
		||||
import org.alfresco.utility.model.SiteModel;
 | 
			
		||||
import org.alfresco.utility.model.TestGroup;
 | 
			
		||||
import org.alfresco.utility.model.UserModel;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests for DELETE /nodes/{nodeId}/rule-sets/{ruleSetId}/rules/{ruleId}.
 | 
			
		||||
 */
 | 
			
		||||
@Test(groups = {TestGroup.RULES})
 | 
			
		||||
public class DeleteRulesTests extends RestTest
 | 
			
		||||
{
 | 
			
		||||
    private static final String FAKE_NODE_REF = "fake-node-id";
 | 
			
		||||
 | 
			
		||||
    private UserModel user;
 | 
			
		||||
    private SiteModel site;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass(alwaysRun = true)
 | 
			
		||||
    public void dataPreparation()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a Contributor user and a public site");
 | 
			
		||||
        user = dataUser.createRandomTestUser();
 | 
			
		||||
        user.setUserRole(SiteContributor);
 | 
			
		||||
        site = dataSite.usingUser(user).createPublicRandomSite();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete previously created rule by its id (as Contributor).
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY})
 | 
			
		||||
    public void deleteSingleRuleAndGet204()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a few rules in the folder");
 | 
			
		||||
        final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        final List<RestRuleModel> createdRules = Stream.of("ruleA", "ruleB", "ruleC")
 | 
			
		||||
                .map(ruleName -> {
 | 
			
		||||
                    RestRuleModel ruleModel = createRuleModel(ruleName);
 | 
			
		||||
                    return restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                            .createSingleRule(ruleModel);
 | 
			
		||||
                })
 | 
			
		||||
                .collect(toList());
 | 
			
		||||
 | 
			
		||||
        STEP("Attempt delete one rule");
 | 
			
		||||
        final RestRuleModel ruleA = createdRules.get(0);
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().deleteRule(ruleA.getId());
 | 
			
		||||
        restClient.assertStatusCodeIs(NO_CONTENT);
 | 
			
		||||
 | 
			
		||||
        STEP("Get and check the rules from the folder after deleting one of them");
 | 
			
		||||
        final RestRuleModelsCollection rulesAfterDeletion =
 | 
			
		||||
                restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().getListOfRules();
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
        rulesAfterDeletion.assertThat().entriesListCountIs(createdRules.size() - 1);
 | 
			
		||||
        Assert.assertTrue(rulesAfterDeletion.getEntries()
 | 
			
		||||
                .stream()
 | 
			
		||||
                .noneMatch(r -> r.onModel().getId().equals(ruleA.getId()))
 | 
			
		||||
        );
 | 
			
		||||
        final Set<String> ruleIdsThatShouldBeLeft = createdRules.stream()
 | 
			
		||||
                .filter(r -> !r.getName().equals("ruleA"))
 | 
			
		||||
                .map(RestRuleModel::getId)
 | 
			
		||||
                .collect(Collectors.toSet());
 | 
			
		||||
        final Set<String> ruleIdsAfterDeletion = rulesAfterDeletion.getEntries().stream()
 | 
			
		||||
                .map(r -> r.onModel().getId())
 | 
			
		||||
                .collect(Collectors.toSet());
 | 
			
		||||
        Assert.assertEquals(ruleIdsThatShouldBeLeft, ruleIdsAfterDeletion);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Try to delete a rule in a non-existing folder and get 404.
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES})
 | 
			
		||||
    public void deleteRuleInNonExistingFolderAndGet404()
 | 
			
		||||
    {
 | 
			
		||||
        final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        final RestRuleModel testRule = createRule(ruleFolder);
 | 
			
		||||
 | 
			
		||||
        STEP("Create a non-existing folder model");
 | 
			
		||||
        final FolderModel nonExistingFolder = new FolderModel();
 | 
			
		||||
        nonExistingFolder.setNodeRef(FAKE_NODE_REF);
 | 
			
		||||
 | 
			
		||||
        STEP("Attempt delete the rule in non-existing folder");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(nonExistingFolder).usingDefaultRuleSet().deleteRule(testRule.getId());
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Try to delete a rule in a non-existing rule set and get 404.
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES})
 | 
			
		||||
    public void deleteRuleInNonExistingRuleSetAndGet404()
 | 
			
		||||
    {
 | 
			
		||||
        final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        final RestRuleModel testRule = createRule(ruleFolder);
 | 
			
		||||
 | 
			
		||||
        STEP("Attempt delete the rule in non-existing rule set");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingRuleSet(FAKE_NODE_REF).deleteRule(testRule.getId());
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Try to delete a non-existing rule and get 404.
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY})
 | 
			
		||||
    public void deleteNonExistingRuleAndGet404()
 | 
			
		||||
    {
 | 
			
		||||
        final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        STEP("Attempt delete non-existing rule");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().deleteRule(FAKE_NODE_REF);
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Try to delete an existing rule passing a wrong but existing folder and get 404.
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY})
 | 
			
		||||
    public void deleteExistingRuleFromWrongFolderAndGet404()
 | 
			
		||||
    {
 | 
			
		||||
        final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        final RestRuleModel testRule = createRule(ruleFolder);
 | 
			
		||||
 | 
			
		||||
        STEP("Create a second folder in the site");
 | 
			
		||||
        final FolderModel anotherFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Attempt delete an existing rule from a wrong but existing (second) folder");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(anotherFolder).usingDefaultRuleSet().deleteRule(testRule.getId());
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check that a user without write permission on folder cannot delete a rule inside it.
 | 
			
		||||
     */
 | 
			
		||||
    public void deleteSinglePrivateRuleWithoutPermissionAndGet403()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a user and use them to create a private site containing a folder with a rule");
 | 
			
		||||
        final UserModel privateUser = dataUser.createRandomTestUser();
 | 
			
		||||
        final SiteModel privateSite = dataSite.usingUser(privateUser).createPrivateRandomSite();
 | 
			
		||||
        final FolderModel privateFolder = dataContent.usingUser(privateUser).usingSite(privateSite).createFolder();
 | 
			
		||||
        final RestRuleModel ruleModel = createRuleModel("Private site rule");
 | 
			
		||||
        final RestRuleModel createdRule =
 | 
			
		||||
                restClient.authenticateUser(privateUser).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet()
 | 
			
		||||
                        .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        STEP("Try to delete the rule with another user");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().deleteRule(createdRule.getId());
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(FORBIDDEN);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check that a user with SiteCollaborator permissions on folder can delete a rule inside it.
 | 
			
		||||
     */
 | 
			
		||||
    public void deleteSinglePublicRuleAsCollaboratorAndGet403()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a user and use them to create a private site containing a folder with a rule");
 | 
			
		||||
        final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        final RestRuleModel testRule = createRule(ruleFolder);
 | 
			
		||||
 | 
			
		||||
        STEP("Create a manager in the private site");
 | 
			
		||||
        final UserModel siteCollaborator = dataUser.createRandomTestUser();
 | 
			
		||||
        siteCollaborator.setUserRole(SiteCollaborator);
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingSite(site).addPerson(siteCollaborator);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the manager can delete the rule");
 | 
			
		||||
        restClient.authenticateUser(siteCollaborator).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                .deleteRule(testRule.getId());
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(FORBIDDEN);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check that a user with SiteManager permissions on folder can delete a rule inside it.
 | 
			
		||||
     */
 | 
			
		||||
    public void deleteSinglePrivateRuleAsSiteManagerAndGet204()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a user and use them to create a private site containing a folder with a rule");
 | 
			
		||||
        final UserModel privateUser = dataUser.createRandomTestUser();
 | 
			
		||||
        final SiteModel privateSite = dataSite.usingUser(privateUser).createPrivateRandomSite();
 | 
			
		||||
        final FolderModel privateFolder = dataContent.usingUser(privateUser).usingSite(privateSite).createFolder();
 | 
			
		||||
        final RestRuleModel ruleModel = createRuleModel("Private site rule");
 | 
			
		||||
        final RestRuleModel createdRule =
 | 
			
		||||
                restClient.authenticateUser(privateUser).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet()
 | 
			
		||||
                        .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        STEP("Create a manager in the private site");
 | 
			
		||||
        final UserModel siteManager = dataUser.createRandomTestUser();
 | 
			
		||||
        siteManager.setUserRole(SiteManager);
 | 
			
		||||
        restClient.authenticateUser(privateUser).withCoreAPI().usingSite(privateSite).addPerson(siteManager);
 | 
			
		||||
 | 
			
		||||
        STEP("Check the manager can delete the rule");
 | 
			
		||||
        restClient.authenticateUser(siteManager).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet()
 | 
			
		||||
                .deleteRule(createdRule.getId());
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(NO_CONTENT);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private RestRuleModel createRule(FolderModel ruleFolder)
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a rule in the folder");
 | 
			
		||||
        final RestRuleModel ruleModel = createRuleModel("Test rule");
 | 
			
		||||
        return restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,210 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Repository
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.rules;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.junit.Assert.assertTrue;
 | 
			
		||||
import static org.springframework.http.HttpStatus.NOT_FOUND;
 | 
			
		||||
import static org.springframework.http.HttpStatus.OK;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.RestTest;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleModel;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleSetModel;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleSetModelsCollection;
 | 
			
		||||
import org.alfresco.utility.model.FolderModel;
 | 
			
		||||
import org.alfresco.utility.model.SiteModel;
 | 
			
		||||
import org.alfresco.utility.model.TestGroup;
 | 
			
		||||
import org.alfresco.utility.model.UserModel;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests for GET /nodes/{nodeId}/rule-sets and /nodes/{nodeId}/rule-sets/{ruleSetId}.
 | 
			
		||||
 */
 | 
			
		||||
@Test (groups = { TestGroup.RULES })
 | 
			
		||||
public class GetRuleSetsTests extends RestTest
 | 
			
		||||
{
 | 
			
		||||
    private UserModel user;
 | 
			
		||||
    private SiteModel site;
 | 
			
		||||
    private FolderModel ruleFolder;
 | 
			
		||||
    private RestRuleModel rule;
 | 
			
		||||
    private String ruleSetId;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass (alwaysRun = true)
 | 
			
		||||
    public void dataPreparation()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a user, site and folder.");
 | 
			
		||||
        user = dataUser.createRandomTestUser();
 | 
			
		||||
        site = dataSite.usingUser(user).createPublicRandomSite();
 | 
			
		||||
        ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a rule in the folder.");
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModel("ruleName");
 | 
			
		||||
        rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                                       .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        STEP("Get the rule sets for the folder and find the rule set id");
 | 
			
		||||
        RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
 | 
			
		||||
                                                         .getListOfRuleSets();
 | 
			
		||||
        ruleSets.assertThat().entriesListCountIs(1);
 | 
			
		||||
        ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get an empty list of rule sets. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getEmptyRuleSetsList()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a folder in existing site");
 | 
			
		||||
        FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Get the rule sets for the folder");
 | 
			
		||||
        RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI()
 | 
			
		||||
                                                         .usingNode(folder).getListOfRuleSets();
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
        assertTrue("Expected no rule sets to be present.", ruleSets.isEmpty());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get a list of rule sets. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
 | 
			
		||||
    public void getRuleSetsList()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Get the rule sets for the folder");
 | 
			
		||||
        RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
 | 
			
		||||
                                                         .getListOfRuleSets();
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
        ruleSets.assertThat().entriesListCountIs(1);
 | 
			
		||||
        ruleSets.getEntries().get(0).onModel()
 | 
			
		||||
                .assertThat().field("id").isNotNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get a 404 if trying to load rule sets for a folder that doesn't exist. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getRuleSetsForNonExistentFolder()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Try to load rule sets for a non-existent folder.");
 | 
			
		||||
        FolderModel nonExistentFolder = FolderModel.getRandomFolderModel();
 | 
			
		||||
        nonExistentFolder.setNodeRef("fake-id");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(nonExistentFolder).getListOfRuleSets();
 | 
			
		||||
        restClient.assertStatusCodeIs(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get the id of the folder that owns a list of rule sets. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getRuleSetsAndOwningFolders()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Get the rule sets and owning folders");
 | 
			
		||||
        RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI()
 | 
			
		||||
                                                 .usingNode(ruleFolder)
 | 
			
		||||
                                                 .include("owningFolder")
 | 
			
		||||
                                                 .getListOfRuleSets();
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
        ruleSets.getEntries().get(0).onModel()
 | 
			
		||||
                .assertThat().field("owningFolder").is(ruleFolder.getNodeRef())
 | 
			
		||||
                .assertThat().field("id").is(ruleSetId);
 | 
			
		||||
        ruleSets.assertThat().entriesListCountIs(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get the reason that a rule set is included in the list. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getRuleSetsAndInclusionType()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Get the rule sets and inclusion type");
 | 
			
		||||
        RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI()
 | 
			
		||||
                                                         .usingNode(ruleFolder)
 | 
			
		||||
                                                         .include("inclusionType")
 | 
			
		||||
                                                         .getListOfRuleSets();
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
        ruleSets.getEntries().get(0).onModel()
 | 
			
		||||
                .assertThat().field("inclusionType").is("owned")
 | 
			
		||||
                .assertThat().field("id").is(ruleSetId);
 | 
			
		||||
        ruleSets.assertThat().entriesListCountIs(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get a rule set by its id. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
 | 
			
		||||
    public void getRuleSetById()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Get the rule set using its rule set id");
 | 
			
		||||
        RestRuleSetModel ruleSet = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
 | 
			
		||||
                                             .getRuleSet(ruleSetId);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
        ruleSet.assertThat().field("id").is(ruleSetId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get a rule set using the "-default-" synonym. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getDefaultRuleSetById()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Get the default rule set for the folder");
 | 
			
		||||
        RestRuleSetModel ruleSet = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
 | 
			
		||||
                                                         .getDefaultRuleSet();
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
        ruleSet.assertThat().field("id").isNotNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get a 404 if trying to load the default rule set for a folder that doesn't exist. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getDefaultRuleSetForNonExistentFolder()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Try to load a rule set for a non-existent folder.");
 | 
			
		||||
        FolderModel nonExistentFolder = FolderModel.getRandomFolderModel();
 | 
			
		||||
        nonExistentFolder.setNodeRef("fake-id");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(nonExistentFolder).getDefaultRuleSet();
 | 
			
		||||
        restClient.assertStatusCodeIs(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get 404 for a non-existing rule set id. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getRuleSetByNonExistingId()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Get the rule set using fake rule set id");
 | 
			
		||||
        String fakeRuleSetId = "fake-rule-set-id";
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).getRuleSet(fakeRuleSetId);
 | 
			
		||||
        restClient.assertStatusCodeIs(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get the id of the folder that owns a rule set. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getRuleSetAndOwningFolder()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Get the rule set and owning folder");
 | 
			
		||||
        RestRuleSetModel ruleSet = restClient.authenticateUser(user).withCoreAPI()
 | 
			
		||||
                                             .usingNode(ruleFolder)
 | 
			
		||||
                                             .include("owningFolder")
 | 
			
		||||
                                             .getRuleSet(ruleSetId);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
        ruleSet.assertThat().field("owningFolder").is(ruleFolder.getNodeRef())
 | 
			
		||||
               .assertThat().field("id").is(ruleSetId);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -27,12 +27,14 @@ package org.alfresco.rest.rules;
 | 
			
		||||
 | 
			
		||||
import static java.util.stream.Collectors.toList;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.rules.RulesTestsUtils.*;
 | 
			
		||||
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.junit.Assert.assertTrue;
 | 
			
		||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
 | 
			
		||||
import static org.springframework.http.HttpStatus.NOT_FOUND;
 | 
			
		||||
import static org.springframework.http.HttpStatus.OK;
 | 
			
		||||
import static org.springframework.http.HttpStatus.CREATED;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.IntStream;
 | 
			
		||||
@@ -59,6 +61,8 @@ public class GetRulesTests extends RestTest
 | 
			
		||||
    private FolderModel ruleFolder;
 | 
			
		||||
    private List<RestRuleModel> createdRules;
 | 
			
		||||
    private RestRuleModel createdRuleA;
 | 
			
		||||
    private static final String IGNORE_ID = "id";
 | 
			
		||||
    private static final String IGNORE_IS_SHARED = "isShared";
 | 
			
		||||
 | 
			
		||||
    @BeforeClass(alwaysRun = true)
 | 
			
		||||
    public void dataPreparation()
 | 
			
		||||
@@ -70,8 +74,7 @@ public class GetRulesTests extends RestTest
 | 
			
		||||
 | 
			
		||||
        STEP("Create rules in the folder");
 | 
			
		||||
        createdRules = Stream.of("ruleA", "ruleB").map(ruleName -> {
 | 
			
		||||
            RestRuleModel ruleModel = new RestRuleModel();
 | 
			
		||||
            ruleModel.setName(ruleName);
 | 
			
		||||
            RestRuleModel ruleModel = createRuleModel(ruleName);
 | 
			
		||||
            return restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
 | 
			
		||||
        }).collect(toList());
 | 
			
		||||
        createdRuleA = createdRules.get(0);
 | 
			
		||||
@@ -87,11 +90,15 @@ public class GetRulesTests extends RestTest
 | 
			
		||||
        STEP("Get the rules that apply to the folder");
 | 
			
		||||
        RestRuleModelsCollection rules = restClient.authenticateUser(user).withCoreAPI().usingNode(folder).usingDefaultRuleSet().getListOfRules();
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
        restClient.assertStatusCodeIs(NOT_FOUND);
 | 
			
		||||
        assertTrue("Expected no rules to be present.", rules.isEmpty());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get all the rules for a folder. */
 | 
			
		||||
    /**
 | 
			
		||||
     * Check we can get all the rules for a folder.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * Also check that the isShared field is not returned when not requested.
 | 
			
		||||
     */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
 | 
			
		||||
    public void getRulesList()
 | 
			
		||||
    {
 | 
			
		||||
@@ -102,8 +109,9 @@ public class GetRulesTests extends RestTest
 | 
			
		||||
        rules.assertThat().entriesListCountIs(createdRules.size());
 | 
			
		||||
        IntStream.range(0, createdRules.size()).forEach(i ->
 | 
			
		||||
                rules.getEntries().get(i).onModel()
 | 
			
		||||
                         .assertThat().field("id").is(createdRules.get(i).getId())
 | 
			
		||||
                         .assertThat().field("name").is(createdRules.get(i).getName()));
 | 
			
		||||
                     .assertThat().field("id").is(createdRules.get(i).getId())
 | 
			
		||||
                     .assertThat().field("name").is(createdRules.get(i).getName())
 | 
			
		||||
                     .assertThat().field("isShared").isNull());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get a 404 if trying to load rules for a folder that doesn't exist. */
 | 
			
		||||
@@ -128,7 +136,33 @@ public class GetRulesTests extends RestTest
 | 
			
		||||
        restClient.assertStatusCodeIs(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get a rule by its id. */
 | 
			
		||||
    /** Check we can get all the rules for a folder along with the extra "include" and "other" fields. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
 | 
			
		||||
    public void getRulesListWithIncludedFields()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Get the rules that apply to the folder");
 | 
			
		||||
        RestRuleModelsCollection rules = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                                                   .include("isShared")
 | 
			
		||||
                                                   .getListOfRules();
 | 
			
		||||
 | 
			
		||||
        rules.assertThat().entriesListCountIs(createdRules.size());
 | 
			
		||||
        IntStream.range(0, createdRules.size()).forEach(i ->
 | 
			
		||||
                rules.getEntries().get(i).onModel()
 | 
			
		||||
                     .assertThat().field("isShared").isNotNull()
 | 
			
		||||
                        .assertThat().field("description").isNull()
 | 
			
		||||
                        .assertThat().field("enabled").is(false)
 | 
			
		||||
                        .assertThat().field("cascade").is(false)
 | 
			
		||||
                        .assertThat().field("asynchronous").is(false)
 | 
			
		||||
                        .assertThat().field("errorScript").isNull()
 | 
			
		||||
                        .assertThat().field("shared").isNull()
 | 
			
		||||
                        .assertThat().field("triggers").is("[inbound]"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check we can get a rule by its id.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * Also check that the isShared field is not returned when not requested.
 | 
			
		||||
     */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
 | 
			
		||||
    public void getSingleRule()
 | 
			
		||||
    {
 | 
			
		||||
@@ -138,7 +172,56 @@ public class GetRulesTests extends RestTest
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
 | 
			
		||||
        rule.assertThat().field("id").is(createdRuleA.getId())
 | 
			
		||||
            .assertThat().field("name").is(createdRuleA.getName());
 | 
			
		||||
            .assertThat().field("name").is(createdRuleA.getName())
 | 
			
		||||
            .assertThat().field("isShared").isNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get rule's other fields */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
 | 
			
		||||
    public void getRulesOtherFieldsModified()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a rule with all other fields default values modified");
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModelWithModifiedValues();
 | 
			
		||||
        ruleModel.setTriggers(List.of("update"));
 | 
			
		||||
        UserModel admin = dataUser.getAdminUser();
 | 
			
		||||
        FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(folder).usingDefaultRuleSet()
 | 
			
		||||
                .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        RestRuleModel expectedRuleModel = createRuleModelWithModifiedValues();
 | 
			
		||||
        expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions()));
 | 
			
		||||
        expectedRuleModel.setTriggers(List.of("update"));
 | 
			
		||||
        expectedRuleModel.setConditions(createEmptyConditionModel());
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
        rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
 | 
			
		||||
                .assertThat().field("id").isNotNull()
 | 
			
		||||
                .assertThat().field("isShared").isNull();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get rule's "other" fields */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
 | 
			
		||||
    public void getRulesDefaultFields()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a rule with all other fields default values");
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModelWithDefaultValues();
 | 
			
		||||
        UserModel admin = dataUser.getAdminUser();
 | 
			
		||||
        FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(folder).usingDefaultRuleSet()
 | 
			
		||||
                .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues();
 | 
			
		||||
        expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions()));
 | 
			
		||||
        expectedRuleModel.setTriggers(List.of("inbound"));
 | 
			
		||||
        expectedRuleModel.setConditions(createEmptyConditionModel());
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
        rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
 | 
			
		||||
                .assertThat().field("id").isNotNull()
 | 
			
		||||
                .assertThat().field("isShared").isNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get a 404 if trying to load a rule from a folder that doesn't exist. */
 | 
			
		||||
@@ -163,6 +246,29 @@ public class GetRulesTests extends RestTest
 | 
			
		||||
        restClient.assertStatusCodeIs(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get a 404 if trying to load an existing rule providing a wrong but existing folder */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getSingleRuleFromWrongFolder()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a folder in existing site");
 | 
			
		||||
        FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        STEP("Try to load a rule for a wrong but existing folder.");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(folder).usingDefaultRuleSet().getSingleRule(createdRuleA.getId());
 | 
			
		||||
        restClient.assertStatusCodeIs(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get a rule by its id along with any included fields. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
 | 
			
		||||
    public void getSingleRuleWithIncludedFields()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Load a particular rule");
 | 
			
		||||
        RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                                       .include("isShared")
 | 
			
		||||
                                       .getSingleRule(createdRuleA.getId());
 | 
			
		||||
 | 
			
		||||
        rule.assertThat().field("isShared").isNotNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check that a user without read permission cannot view the folder rules. */
 | 
			
		||||
    public void requireReadPermissionToGetRule()
 | 
			
		||||
    {
 | 
			
		||||
@@ -189,8 +295,7 @@ public class GetRulesTests extends RestTest
 | 
			
		||||
        UserModel privateUser = dataUser.createRandomTestUser();
 | 
			
		||||
        SiteModel privateSite = dataSite.usingUser(privateUser).createPrivateRandomSite();
 | 
			
		||||
        FolderModel privateFolder = dataContent.usingUser(privateUser).usingSite(privateSite).createFolder();
 | 
			
		||||
        RestRuleModel ruleModel = new RestRuleModel();
 | 
			
		||||
        ruleModel.setName("Private site rule");
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModel("Private site rule");
 | 
			
		||||
        restClient.authenticateUser(privateUser).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        STEP("Create a collaborator in the private site");
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,313 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.rules;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
 | 
			
		||||
import static org.springframework.http.HttpStatus.CREATED;
 | 
			
		||||
import static org.springframework.http.HttpStatus.NOT_FOUND;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.dataprep.CMISUtil;
 | 
			
		||||
import org.alfresco.rest.RestTest;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleModel;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleModelsCollection;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleSetLinkModel;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleSetModel;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleSetModelsCollection;
 | 
			
		||||
import org.alfresco.utility.model.FileModel;
 | 
			
		||||
import org.alfresco.utility.model.FolderModel;
 | 
			
		||||
import org.alfresco.utility.model.SiteModel;
 | 
			
		||||
import org.alfresco.utility.model.TestGroup;
 | 
			
		||||
import org.alfresco.utility.model.UserModel;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests for /nodes/{nodeId}/rule-set-links.
 | 
			
		||||
 */
 | 
			
		||||
@Test(groups = {TestGroup.RULES})
 | 
			
		||||
public class RuleSetLinksTests extends RestTest
 | 
			
		||||
{
 | 
			
		||||
    private UserModel user;
 | 
			
		||||
    private SiteModel site;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass(alwaysRun = true)
 | 
			
		||||
    public void dataPreparation()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a user and site.");
 | 
			
		||||
        user = dataUser.createRandomTestUser();
 | 
			
		||||
        site = dataSite.usingUser(user).createPublicRandomSite();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check we can link to folder containing a rule set.
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES})
 | 
			
		||||
    public void linkToFolderContainingRules()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create folders in existing site");
 | 
			
		||||
        final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a rule in the rule folder.");
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModel("ruleName");
 | 
			
		||||
        RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        STEP("Get the rule sets for the folder and find the rule set id");
 | 
			
		||||
        final RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
 | 
			
		||||
                .getListOfRuleSets();
 | 
			
		||||
        ruleSets.assertThat().entriesListCountIs(1);
 | 
			
		||||
        final String ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
 | 
			
		||||
 | 
			
		||||
        STEP("Link to a rule folder");
 | 
			
		||||
        final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
 | 
			
		||||
        request.setId(ruleFolder.getNodeRef());
 | 
			
		||||
        final RestRuleSetLinkModel ruleLink = restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createRuleLink(request);
 | 
			
		||||
 | 
			
		||||
        STEP("Assert link result");
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
        final RestRuleSetLinkModel expectedLink = new RestRuleSetLinkModel();
 | 
			
		||||
        expectedLink.setId(ruleSetId);
 | 
			
		||||
        ruleLink.assertThat().isEqualTo(expectedLink);
 | 
			
		||||
 | 
			
		||||
        STEP("Check if folder returns same rules");
 | 
			
		||||
        final RestRuleModelsCollection linkedRules = restClient.authenticateUser(user).withCoreAPI()
 | 
			
		||||
                .usingNode(folder)
 | 
			
		||||
                .usingDefaultRuleSet()
 | 
			
		||||
                .getListOfRules();
 | 
			
		||||
        linkedRules.assertThat().entriesListCountIs(1);
 | 
			
		||||
        linkedRules.getEntries().get(0).onModel().assertThat().isEqualTo(rule);
 | 
			
		||||
 | 
			
		||||
        STEP("Check if folder returns rule set with linked inclusionType");
 | 
			
		||||
        final RestRuleSetModelsCollection linkedRuleSets = restClient.authenticateUser(user).withCoreAPI()
 | 
			
		||||
                .usingNode(folder)
 | 
			
		||||
                .include("inclusionType")
 | 
			
		||||
                .getListOfRuleSets();
 | 
			
		||||
        linkedRuleSets.assertThat().entriesListCountIs(1);
 | 
			
		||||
        final RestRuleSetModel expectedRuleSet = new RestRuleSetModel();
 | 
			
		||||
        expectedRuleSet.setId(ruleSetId);
 | 
			
		||||
        expectedRuleSet.setInclusionType("linked");
 | 
			
		||||
        linkedRuleSets.getEntries()
 | 
			
		||||
                .get(0).onModel().assertThat().isEqualTo(expectedRuleSet);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check we can link to a rule set.
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES})
 | 
			
		||||
    public void linkToRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create folders in existing site");
 | 
			
		||||
        final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a rule in the rule folder.");
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModel("ruleName");
 | 
			
		||||
        RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        STEP("Get the rule sets for the folder and find the rule set id");
 | 
			
		||||
        final RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
 | 
			
		||||
                .getListOfRuleSets();
 | 
			
		||||
        ruleSets.assertThat().entriesListCountIs(1);
 | 
			
		||||
        final String ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
 | 
			
		||||
 | 
			
		||||
        STEP("Link to a rule set");
 | 
			
		||||
        final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
 | 
			
		||||
        request.setId(ruleSetId);
 | 
			
		||||
        final RestRuleSetLinkModel ruleLink = restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createRuleLink(request);
 | 
			
		||||
 | 
			
		||||
        STEP("Assert link result");
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
        final RestRuleSetLinkModel expectedLink = new RestRuleSetLinkModel();
 | 
			
		||||
        expectedLink.setId(ruleSetId);
 | 
			
		||||
        ruleLink.assertThat().isEqualTo(expectedLink);
 | 
			
		||||
 | 
			
		||||
        STEP("Check if folder returns same rules");
 | 
			
		||||
        final RestRuleModelsCollection linkedRules = restClient.authenticateUser(user).withCoreAPI()
 | 
			
		||||
                .usingNode(folder)
 | 
			
		||||
                .usingDefaultRuleSet()
 | 
			
		||||
                .getListOfRules();
 | 
			
		||||
        linkedRules.assertThat().entriesListCountIs(1);
 | 
			
		||||
        linkedRules.getEntries().get(0).onModel().assertThat().isEqualTo(rule);
 | 
			
		||||
 | 
			
		||||
        STEP("Check if folder returns rule set with linked inclusionType");
 | 
			
		||||
        final RestRuleSetModelsCollection likedRuleSets = restClient.authenticateUser(user).withCoreAPI()
 | 
			
		||||
                .usingNode(folder)
 | 
			
		||||
                .include("inclusionType")
 | 
			
		||||
                .getListOfRuleSets();
 | 
			
		||||
        likedRuleSets.assertThat().entriesListCountIs(1);
 | 
			
		||||
        final RestRuleSetModel expectedRuleSet = new RestRuleSetModel();
 | 
			
		||||
        expectedRuleSet.setId(ruleSetId);
 | 
			
		||||
        expectedRuleSet.setInclusionType("linked");
 | 
			
		||||
        likedRuleSets.getEntries()
 | 
			
		||||
                .get(0).onModel().assertThat().isEqualTo(expectedRuleSet);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check we get 404 when linking to a non-existing rule set/folder.
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES})
 | 
			
		||||
    public void linkToNonExistingRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a folder in existing site");
 | 
			
		||||
        final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Link to non-existing rule set");
 | 
			
		||||
        final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
 | 
			
		||||
        request.setId("dummy-rule-set-id");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createRuleLink(request);
 | 
			
		||||
 | 
			
		||||
        STEP("Assert link result is 404");
 | 
			
		||||
        restClient.assertStatusCodeIs(NOT_FOUND);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check we get bad request error when linking to a folder without rules.
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES})
 | 
			
		||||
    public void linkToFolderWithoutRules()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create 2 folders without rules in existing site");
 | 
			
		||||
        final FolderModel folder1 = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        final FolderModel folder2 = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Link to a folder without rules");
 | 
			
		||||
        final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
 | 
			
		||||
        request.setId(folder2.getNodeRef());
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(folder1).createRuleLink(request);
 | 
			
		||||
 | 
			
		||||
        STEP("Assert link result is 400");
 | 
			
		||||
        restClient.assertStatusCodeIs(BAD_REQUEST)
 | 
			
		||||
                .assertLastError().containsSummary("The target node has no rules to link.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check we get bad request error when linking from a folder which already has rules.
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES})
 | 
			
		||||
    public void linkFromFolderWithRules()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create folders in existing site");
 | 
			
		||||
        final FolderModel folder1 = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        final FolderModel folder2 = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Create rules in both folders.");
 | 
			
		||||
        RestRuleModel ruleModel1 = createRuleModel("ruleName1");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(folder1).usingDefaultRuleSet()
 | 
			
		||||
                .createSingleRule(ruleModel1);
 | 
			
		||||
        RestRuleModel ruleModel2 = createRuleModel("ruleName2");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(folder2).usingDefaultRuleSet()
 | 
			
		||||
                .createSingleRule(ruleModel2);
 | 
			
		||||
 | 
			
		||||
        STEP("Link from a folder with rules");
 | 
			
		||||
        final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
 | 
			
		||||
        request.setId(folder2.getNodeRef());
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(folder1).createRuleLink(request);
 | 
			
		||||
 | 
			
		||||
        STEP("Assert link result is 400");
 | 
			
		||||
        restClient.assertStatusCodeIs(BAD_REQUEST)
 | 
			
		||||
                .assertLastError().containsSummary(
 | 
			
		||||
                "Unable to link to a ruleset because the folder has pre-existing rules or is already linked to a ruleset.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check we get bad request error when linking to a file node.
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES})
 | 
			
		||||
    public void linkToFileNode()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a folder in existing site");
 | 
			
		||||
        final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        final FileModel fileContent = dataContent.usingUser(user).usingSite(site).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
 | 
			
		||||
 | 
			
		||||
        STEP("Link to a file node");
 | 
			
		||||
        final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
 | 
			
		||||
        request.setId(fileContent.getNodeRef());
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createRuleLink(request);
 | 
			
		||||
 | 
			
		||||
        STEP("Assert link result is 400");
 | 
			
		||||
        restClient.assertStatusCodeIs(BAD_REQUEST)
 | 
			
		||||
                .assertLastError().containsSummary("NodeId of a folder is expected!");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check we can link to a parent folder with rules.
 | 
			
		||||
     */
 | 
			
		||||
    @Test(groups = {TestGroup.REST_API, TestGroup.RULES})
 | 
			
		||||
    public void linkToParentNodeWithRules()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create parent/child folders in existing site");
 | 
			
		||||
        final FolderModel parentFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
        final FolderModel childFolder = dataContent.usingUser(user).usingSite(site).usingResource(parentFolder).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a rule in the parent folder.");
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModel("ruleName");
 | 
			
		||||
        RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(parentFolder).usingDefaultRuleSet()
 | 
			
		||||
                .createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        STEP("Get the rule sets for the folder and find the rule set id");
 | 
			
		||||
        final RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(parentFolder)
 | 
			
		||||
                .getListOfRuleSets();
 | 
			
		||||
        ruleSets.assertThat().entriesListCountIs(1);
 | 
			
		||||
        final String ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
 | 
			
		||||
 | 
			
		||||
        STEP("Link to the parent folder");
 | 
			
		||||
        final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
 | 
			
		||||
        request.setId(parentFolder.getNodeRef());
 | 
			
		||||
        final RestRuleSetLinkModel ruleLink = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolder).createRuleLink(request);
 | 
			
		||||
 | 
			
		||||
        STEP("Assert link result");
 | 
			
		||||
        restClient.assertStatusCodeIs(CREATED);
 | 
			
		||||
        final RestRuleSetLinkModel expectedLink = new RestRuleSetLinkModel();
 | 
			
		||||
        expectedLink.setId(ruleSetId);
 | 
			
		||||
        ruleLink.assertThat().isEqualTo(expectedLink);
 | 
			
		||||
 | 
			
		||||
        STEP("Check if child folder returns same rules");
 | 
			
		||||
        final RestRuleModelsCollection linkedRules = restClient.authenticateUser(user).withCoreAPI()
 | 
			
		||||
                .usingNode(childFolder)
 | 
			
		||||
                .usingDefaultRuleSet()
 | 
			
		||||
                .getListOfRules();
 | 
			
		||||
        linkedRules.assertThat().entriesListCountIs(1);
 | 
			
		||||
        linkedRules.getEntries().get(0).onModel().assertThat().isEqualTo(rule);
 | 
			
		||||
 | 
			
		||||
        STEP("Check if child folder returns rule set with linked inclusionType");
 | 
			
		||||
        final RestRuleSetModelsCollection linkedRuleSets = restClient.authenticateUser(user).withCoreAPI()
 | 
			
		||||
                .usingNode(childFolder)
 | 
			
		||||
                .include("inclusionType")
 | 
			
		||||
                .getListOfRuleSets();
 | 
			
		||||
        linkedRuleSets.assertThat().entriesListCountIs(1);
 | 
			
		||||
        final RestRuleSetModel expectedRuleSet = new RestRuleSetModel();
 | 
			
		||||
        expectedRuleSet.setId(ruleSetId);
 | 
			
		||||
        expectedRuleSet.setInclusionType("linked");
 | 
			
		||||
        linkedRuleSets.getEntries()
 | 
			
		||||
                .get(0).onModel().assertThat().isEqualTo(expectedRuleSet);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,130 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Repository
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.rules;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
 | 
			
		||||
import org.alfresco.rest.model.RestCompositeConditionDefinitionModel;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleModel;
 | 
			
		||||
 | 
			
		||||
public class RulesTestsUtils
 | 
			
		||||
{
 | 
			
		||||
    static final String RULE_NAME_DEFAULT = "ruleName";
 | 
			
		||||
    static final String RULE_DESCRIPTION_DEFAULT = "rule description";
 | 
			
		||||
    static final boolean RULE_ENABLED_DEFAULT = true;
 | 
			
		||||
    static final boolean RULE_CASCADE_DEFAULT = true;
 | 
			
		||||
    static final boolean RULE_ASYNC_DEFAULT = true;
 | 
			
		||||
    static final boolean RULE_SHARED_DEFAULT = false;
 | 
			
		||||
    static final String RULE_ERROR_SCRIPT_DEFAULT = "error-script";
 | 
			
		||||
    static final List<String> ruleTriggersDefault = List.of("inbound", "update", "outbound");
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a rule model filled with default values.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The created rule model.
 | 
			
		||||
     */
 | 
			
		||||
    public static RestRuleModel createRuleModelWithModifiedValues()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModelWithDefaultValues();
 | 
			
		||||
        ruleModel.setDescription(RULE_DESCRIPTION_DEFAULT);
 | 
			
		||||
        ruleModel.setEnabled(RULE_ENABLED_DEFAULT);
 | 
			
		||||
        ruleModel.setCascade(RULE_CASCADE_DEFAULT);
 | 
			
		||||
        ruleModel.setAsynchronous(RULE_ASYNC_DEFAULT);
 | 
			
		||||
        ruleModel.setIsShared(RULE_SHARED_DEFAULT);
 | 
			
		||||
        ruleModel.setTriggers(ruleTriggersDefault);
 | 
			
		||||
        ruleModel.setErrorScript(RULE_ERROR_SCRIPT_DEFAULT);
 | 
			
		||||
 | 
			
		||||
        return ruleModel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static RestRuleModel createRuleModelWithDefaultValues()
 | 
			
		||||
    {
 | 
			
		||||
        return createRuleModel(RULE_NAME_DEFAULT, List.of(createDefaultActionModel()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static RestRuleModel createRuleModel(String name)
 | 
			
		||||
    {
 | 
			
		||||
        return createRuleModel(name, List.of(createDefaultActionModel()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a rule model.
 | 
			
		||||
     *
 | 
			
		||||
     * @param name The name for the rule.
 | 
			
		||||
     * @param restActionModels Rule's actions.
 | 
			
		||||
     * @return The created rule model.
 | 
			
		||||
     */
 | 
			
		||||
    public static RestRuleModel createRuleModel(String name, List<RestActionBodyExecTemplateModel> restActionModels)
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel ruleModel = new RestRuleModel();
 | 
			
		||||
        ruleModel.setName(name);
 | 
			
		||||
        ruleModel.setActions(restActionModels);
 | 
			
		||||
        return ruleModel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a rule's action model.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The created action model.
 | 
			
		||||
     */
 | 
			
		||||
    public static RestActionBodyExecTemplateModel createDefaultActionModel()
 | 
			
		||||
    {
 | 
			
		||||
        RestActionBodyExecTemplateModel restActionModel = new RestActionBodyExecTemplateModel();
 | 
			
		||||
        restActionModel.setActionDefinitionId("set-property-value");
 | 
			
		||||
        restActionModel.setParams(Map.of("aspect-name", "cm:audio"));
 | 
			
		||||
        return restActionModel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static List<RestActionBodyExecTemplateModel> addActionContextParams(List<RestActionBodyExecTemplateModel> inputActions)
 | 
			
		||||
    {
 | 
			
		||||
        inputActions.forEach(inputAction -> {
 | 
			
		||||
            final Map<String, Serializable> params = new HashMap<>((Map<String, Serializable>) inputAction.getParams());
 | 
			
		||||
            params.put("actionContext", "rule");
 | 
			
		||||
            inputAction.setParams(params);
 | 
			
		||||
        });
 | 
			
		||||
        return inputActions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static RestActionBodyExecTemplateModel createCustomActionModel(String actionDefinitionId, Map<String, Serializable> params)
 | 
			
		||||
    {
 | 
			
		||||
        RestActionBodyExecTemplateModel restActionModel = new RestActionBodyExecTemplateModel();
 | 
			
		||||
        restActionModel.setActionDefinitionId(actionDefinitionId);
 | 
			
		||||
        restActionModel.setParams(params);
 | 
			
		||||
        return restActionModel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static RestCompositeConditionDefinitionModel createEmptyConditionModel()
 | 
			
		||||
    {
 | 
			
		||||
        RestCompositeConditionDefinitionModel conditions = new RestCompositeConditionDefinitionModel();
 | 
			
		||||
        conditions.setInverted(false);
 | 
			
		||||
        conditions.setBooleanMode("and");
 | 
			
		||||
        return conditions;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,232 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Repository
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.rules;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.requests.RuleSettings.IS_INHERITANCE_ENABLED;
 | 
			
		||||
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
 | 
			
		||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
 | 
			
		||||
import static org.springframework.http.HttpStatus.NOT_FOUND;
 | 
			
		||||
import static org.springframework.http.HttpStatus.OK;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.RestTest;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleSettingsModel;
 | 
			
		||||
import org.alfresco.utility.model.FolderModel;
 | 
			
		||||
import org.alfresco.utility.model.SiteModel;
 | 
			
		||||
import org.alfresco.utility.model.TestGroup;
 | 
			
		||||
import org.alfresco.utility.model.UserModel;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests for GET and PUT /nodes/{nodeId}/rule-settings/{ruleSettingKey}.
 | 
			
		||||
 */
 | 
			
		||||
@Test (groups = { TestGroup.RULES })
 | 
			
		||||
public class SetInheritanceTests extends RestTest
 | 
			
		||||
{
 | 
			
		||||
    private UserModel siteOwner;
 | 
			
		||||
    private SiteModel site;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass (alwaysRun = true)
 | 
			
		||||
    public void dataPreparation()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a user, site and folder.");
 | 
			
		||||
        siteOwner = dataUser.createRandomTestUser();
 | 
			
		||||
        site = dataSite.usingUser(siteOwner).createPrivateRandomSite();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can get the -isInheritanceEnabled- rule setting for the folder. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getIsInherited()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a folder for the test.");
 | 
			
		||||
        FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Get the -isInheritanceEnabled- rule settings for the folder.");
 | 
			
		||||
        RestRuleSettingsModel ruleSettingsModel = restClient.authenticateUser(siteOwner)
 | 
			
		||||
                                                            .withCoreAPI()
 | 
			
		||||
                                                            .usingResource(folder)
 | 
			
		||||
                                                            .usingIsInheritanceEnabledRuleSetting()
 | 
			
		||||
                                                            .retrieveSetting();
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
        RestRuleSettingsModel expected = new RestRuleSettingsModel();
 | 
			
		||||
        expected.setKey(IS_INHERITANCE_ENABLED);
 | 
			
		||||
        expected.setValue(true);
 | 
			
		||||
        ruleSettingsModel.assertThat().isEqualTo(expected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get an error when trying to get settings from a non-existent folder. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getIsInheritedFromNonExistentFolder()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Try to get the -isInheritanceEnabled- rule settings for a fake folder.");
 | 
			
		||||
        FolderModel nonExistentFolder = FolderModel.getRandomFolderModel();
 | 
			
		||||
        nonExistentFolder.setNodeRef("fake-id");
 | 
			
		||||
        restClient.authenticateUser(siteOwner)
 | 
			
		||||
                  .withCoreAPI()
 | 
			
		||||
                  .usingResource(nonExistentFolder)
 | 
			
		||||
                  .usingIsInheritanceEnabledRuleSetting()
 | 
			
		||||
                  .retrieveSetting();
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(NOT_FOUND)
 | 
			
		||||
                  .containsSummary("The entity with id: fake-id was not found");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get an error when trying to retrieve a non-existent setting. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getNonExistentSetting()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a folder for the test.");
 | 
			
		||||
        FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Try to get a fake setting from the folder.");
 | 
			
		||||
        restClient.authenticateUser(siteOwner).withCoreAPI().usingResource(folder).usingRuleSetting("-fakeRuleSetting-")
 | 
			
		||||
                  .retrieveSetting();
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(NOT_FOUND)
 | 
			
		||||
                  .containsSummary("Unrecognised rule setting key -fakeRuleSetting-");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check a user without permission for the folder cannot get the -isInheritanceEnabled- rule setting. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void getIsInheritedWithoutPermission()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a folder and a user without permission to access it.");
 | 
			
		||||
        FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
 | 
			
		||||
        UserModel noPermissionUser = dataUser.createRandomTestUser();
 | 
			
		||||
 | 
			
		||||
        STEP("Try to get the -isInheritanceEnabled- setting without permission.");
 | 
			
		||||
        restClient.authenticateUser(noPermissionUser)
 | 
			
		||||
                  .withCoreAPI()
 | 
			
		||||
                  .usingResource(folder)
 | 
			
		||||
                  .usingIsInheritanceEnabledRuleSetting()
 | 
			
		||||
                  .retrieveSetting();
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(FORBIDDEN)
 | 
			
		||||
                  .containsSummary("Cannot read from this node");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can change the -isInheritanceEnabled- rule setting for the folder. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void updateIsInherited()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a folder for the test.");
 | 
			
		||||
        FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Set -isInheritanceEnabled- to false.");
 | 
			
		||||
        RestRuleSettingsModel updateBody = new RestRuleSettingsModel();
 | 
			
		||||
        updateBody.setValue(false);
 | 
			
		||||
 | 
			
		||||
        RestRuleSettingsModel ruleSettingsModel = restClient.authenticateUser(siteOwner)
 | 
			
		||||
                                              .withCoreAPI()
 | 
			
		||||
                                              .usingResource(folder)
 | 
			
		||||
                                              .usingIsInheritanceEnabledRuleSetting()
 | 
			
		||||
                                              .updateSetting(updateBody);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
        RestRuleSettingsModel expected = new RestRuleSettingsModel();
 | 
			
		||||
        expected.setKey(IS_INHERITANCE_ENABLED);
 | 
			
		||||
        expected.setValue(false);
 | 
			
		||||
        ruleSettingsModel.assertThat().isEqualTo(expected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get an error when trying to set -isInheritanceEnabled- to something other than a boolean. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void updateInheritedWithBadValue()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a folder for the test.");
 | 
			
		||||
        FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Try to set -isInheritanceEnabled- to \"banana\".");
 | 
			
		||||
        RestRuleSettingsModel updateBody = new RestRuleSettingsModel();
 | 
			
		||||
        updateBody.setValue("banana");
 | 
			
		||||
 | 
			
		||||
        restClient.authenticateUser(siteOwner).withCoreAPI().usingResource(folder).usingIsInheritanceEnabledRuleSetting()
 | 
			
		||||
                  .updateSetting(updateBody);
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(BAD_REQUEST)
 | 
			
		||||
                  .containsSummary("Rule setting " + IS_INHERITANCE_ENABLED + " requires a boolean value.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get an error when the folder is not found. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void updateInheritedWithNonExistentFolder()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Try to set -isInheritanceEnabled- against a fake folder.");
 | 
			
		||||
        FolderModel nonExistentFolder = FolderModel.getRandomFolderModel();
 | 
			
		||||
        nonExistentFolder.setNodeRef("fake-id");
 | 
			
		||||
 | 
			
		||||
        RestRuleSettingsModel updateBody = new RestRuleSettingsModel();
 | 
			
		||||
        updateBody.setValue(true);
 | 
			
		||||
 | 
			
		||||
        restClient.authenticateUser(siteOwner).withCoreAPI().usingResource(nonExistentFolder).usingIsInheritanceEnabledRuleSetting()
 | 
			
		||||
                  .updateSetting(updateBody);
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(NOT_FOUND)
 | 
			
		||||
                  .containsSummary("The entity with id: fake-id was not found");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get an error when trying to set a non-existent setting. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void updateNonExistentSetting()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a folder for the test.");
 | 
			
		||||
        FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Try to set a fake setting on the folder.");
 | 
			
		||||
        RestRuleSettingsModel updateBody = new RestRuleSettingsModel();
 | 
			
		||||
        updateBody.setValue(true);
 | 
			
		||||
 | 
			
		||||
        restClient.authenticateUser(siteOwner).withCoreAPI().usingResource(folder).usingRuleSetting("-fakeRuleSetting-")
 | 
			
		||||
                  .updateSetting(updateBody);
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(NOT_FOUND)
 | 
			
		||||
                  .containsSummary("Unrecognised rule setting key -fakeRuleSetting-");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check a user without manage permission cannot update the -isInheritanceEnabled- rule setting. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void updateIsInheritedWithoutPermission()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a folder and a collaborator.");
 | 
			
		||||
        FolderModel folder = dataContent.usingUser(siteOwner).usingSite(site).createFolder();
 | 
			
		||||
        UserModel collaborator = dataUser.createRandomTestUser();
 | 
			
		||||
        collaborator.setUserRole(SiteCollaborator);
 | 
			
		||||
        restClient.authenticateUser(siteOwner).withCoreAPI().usingSite(site).addPerson(collaborator);
 | 
			
		||||
 | 
			
		||||
        STEP("Try to update the -isInheritanceEnabled- setting without permission.");
 | 
			
		||||
        RestRuleSettingsModel updateBody = new RestRuleSettingsModel();
 | 
			
		||||
        updateBody.setValue(true);
 | 
			
		||||
 | 
			
		||||
        restClient.authenticateUser(collaborator).withCoreAPI().usingResource(folder).usingIsInheritanceEnabledRuleSetting()
 | 
			
		||||
                  .updateSetting(updateBody);
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(FORBIDDEN)
 | 
			
		||||
                  .containsSummary("Insufficient permissions to manage rules");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,220 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Repository
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.rules;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.rules.RulesTestsUtils.createDefaultActionModel;
 | 
			
		||||
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
 | 
			
		||||
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
 | 
			
		||||
import static org.alfresco.utility.report.log.Step.STEP;
 | 
			
		||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
 | 
			
		||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
 | 
			
		||||
import static org.springframework.http.HttpStatus.NOT_FOUND;
 | 
			
		||||
import static org.springframework.http.HttpStatus.OK;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.RestTest;
 | 
			
		||||
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
 | 
			
		||||
import org.alfresco.rest.model.RestRuleModel;
 | 
			
		||||
import org.alfresco.utility.model.FolderModel;
 | 
			
		||||
import org.alfresco.utility.model.SiteModel;
 | 
			
		||||
import org.alfresco.utility.model.TestGroup;
 | 
			
		||||
import org.alfresco.utility.model.UserModel;
 | 
			
		||||
import org.testng.annotations.BeforeClass;
 | 
			
		||||
import org.testng.annotations.Test;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Tests for PUT /nodes/{nodeId}/rule-sets/{ruleSetId}/rules.
 | 
			
		||||
 */
 | 
			
		||||
@Test (groups = { TestGroup.RULES })
 | 
			
		||||
public class UpdateRulesTests extends RestTest
 | 
			
		||||
{
 | 
			
		||||
    private UserModel user;
 | 
			
		||||
    private SiteModel site;
 | 
			
		||||
    private FolderModel ruleFolder;
 | 
			
		||||
 | 
			
		||||
    @BeforeClass (alwaysRun = true)
 | 
			
		||||
    public void dataPreparation()
 | 
			
		||||
    {
 | 
			
		||||
        user = dataUser.createRandomTestUser();
 | 
			
		||||
        site = dataSite.usingUser(user).createPublicRandomSite();
 | 
			
		||||
        ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check we can update a rule.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * Also check that the isShared field is not returned when not requested.
 | 
			
		||||
     */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
 | 
			
		||||
    public void updateRule()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel rule = createAndSaveRule("Rule name");
 | 
			
		||||
 | 
			
		||||
        STEP("Try to update the rule.");
 | 
			
		||||
        RestRuleModel updatedRuleModel = createRuleModel("Updated rule name");
 | 
			
		||||
        RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                                       .updateRule(rule.getId(), updatedRuleModel);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(OK);
 | 
			
		||||
        updatedRule.assertThat().field("id").is(rule.getId())
 | 
			
		||||
                   .assertThat().field("name").is("Updated rule name")
 | 
			
		||||
                   .assertThat().field("isShared").isNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get a 404 if trying to update a rule in a folder that doesn't exist. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void updateRuleForNonExistentFolder()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel rule = createAndSaveRule("Rule name");
 | 
			
		||||
 | 
			
		||||
        STEP("Try to update a rule in a non-existent folder.");
 | 
			
		||||
        FolderModel nonExistentFolder = FolderModel.getRandomFolderModel();
 | 
			
		||||
        nonExistentFolder.setNodeRef("fake-id");
 | 
			
		||||
 | 
			
		||||
        RestRuleModel updatedRuleModel = new RestRuleModel();
 | 
			
		||||
        updatedRuleModel.setName("Updated rule name");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(nonExistentFolder).usingDefaultRuleSet()
 | 
			
		||||
                  .updateRule(rule.getId(), updatedRuleModel);
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(NOT_FOUND)
 | 
			
		||||
                                    .containsSummary("fake-id was not found");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get a 404 if trying to update a rule in a rule set that doesn't exist. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void updateRuleForNonExistentRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel rule = createAndSaveRule("Rule name");
 | 
			
		||||
 | 
			
		||||
        STEP("Try to update a rule in a non-existent rule set.");
 | 
			
		||||
        RestRuleModel updatedRuleModel = new RestRuleModel();
 | 
			
		||||
        updatedRuleModel.setName("Updated rule name");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingRuleSet("fake-id")
 | 
			
		||||
                  .updateRule(rule.getId(), updatedRuleModel);
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(NOT_FOUND)
 | 
			
		||||
                  .containsSummary("fake-id was not found");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get a 404 if trying to update a rule that doesn't exist. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void updateRuleForNonExistentRuleId()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Try to update a rule that doesn't exist.");
 | 
			
		||||
        RestRuleModel updatedRuleModel = new RestRuleModel();
 | 
			
		||||
        updatedRuleModel.setName("Updated rule name");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                  .updateRule("fake-id", updatedRuleModel);
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(NOT_FOUND)
 | 
			
		||||
                  .containsSummary("fake-id was not found");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check that a user without permission cannot update a rule. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void requirePermissionToUpdateRule()
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a user and use them to create a private site containing a folder");
 | 
			
		||||
        UserModel privateUser = dataUser.createRandomTestUser();
 | 
			
		||||
        SiteModel privateSite = dataSite.usingUser(privateUser).createPrivateRandomSite();
 | 
			
		||||
        FolderModel privateFolder = dataContent.usingUser(privateUser).usingSite(privateSite).createFolder();
 | 
			
		||||
 | 
			
		||||
        STEP("Create a collaborator and check they don't have permission to create a rule");
 | 
			
		||||
        UserModel collaborator = dataUser.createRandomTestUser();
 | 
			
		||||
        dataUser.addUserToSite(collaborator, privateSite, SiteCollaborator);
 | 
			
		||||
        RestRuleModel ruleModel = new RestRuleModel();
 | 
			
		||||
        ruleModel.setName("ruleName");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
 | 
			
		||||
 | 
			
		||||
        restClient.assertStatusCodeIs(FORBIDDEN);
 | 
			
		||||
        restClient.assertLastError().containsSummary("Insufficient permissions to manage rules");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we get an error trying to update a rule to have no name. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void updateRuleToHaveEmptyName()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel rule = createAndSaveRule("Rule name");
 | 
			
		||||
 | 
			
		||||
        STEP("Try to update the rule to have no name.");
 | 
			
		||||
        RestRuleModel updatedRuleModel = createRuleModel("");
 | 
			
		||||
        restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().updateRule(rule.getId(), updatedRuleModel);
 | 
			
		||||
 | 
			
		||||
        restClient.assertLastError().statusCodeIs(BAD_REQUEST)
 | 
			
		||||
                                    .containsSummary("Rule name is a mandatory parameter");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check that updates to the rule's id are ignored. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
 | 
			
		||||
    public void tryToUpdateRuleId()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel rule = createAndSaveRule("Rule name");
 | 
			
		||||
 | 
			
		||||
        STEP("Try to update the rule id and check it isn't changed.");
 | 
			
		||||
        RestRuleModel updatedRuleModel = createRuleModel("Rule name");
 | 
			
		||||
        updatedRuleModel.setId("new-rule-id");
 | 
			
		||||
        RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                                              .updateRule(rule.getId(), updatedRuleModel);
 | 
			
		||||
 | 
			
		||||
        updatedRule.assertThat().field("id").is(rule.getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check we can update a rule and get the included fields. */
 | 
			
		||||
    @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
 | 
			
		||||
    public void updateRuleWithIncludedFields()
 | 
			
		||||
    {
 | 
			
		||||
        RestRuleModel rule = createAndSaveRule("Rule name");
 | 
			
		||||
 | 
			
		||||
        STEP("Try to update the rule.");
 | 
			
		||||
        RestRuleModel updatedRuleModel = createRuleModel("Updated rule name");
 | 
			
		||||
        RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
                                              .include("isShared")
 | 
			
		||||
                                              .updateRule(rule.getId(), updatedRuleModel);
 | 
			
		||||
 | 
			
		||||
        updatedRule.assertThat().field("isShared").isNotNull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private RestRuleModel createAndSaveRule(String name)
 | 
			
		||||
    {
 | 
			
		||||
        return createAndSaveRule(name, List.of(createDefaultActionModel()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a rule for folder and store it.
 | 
			
		||||
     *
 | 
			
		||||
     * @param name The name for the rule.
 | 
			
		||||
     * @param restActionModels Rule's actions.
 | 
			
		||||
     * @return The created rule.
 | 
			
		||||
     */
 | 
			
		||||
    private RestRuleModel createAndSaveRule(String name, List<RestActionBodyExecTemplateModel> restActionModels)
 | 
			
		||||
    {
 | 
			
		||||
        STEP("Create a rule called " + name + ", containing actions: " + restActionModels);
 | 
			
		||||
        RestRuleModel ruleModel = createRuleModel(name, restActionModels);
 | 
			
		||||
        return restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
 | 
			
		||||
            .createSingleRule(ruleModel);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-tests</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <developers>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo-packaging</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <properties>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										69
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										69
									
								
								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>17.51</version>
 | 
			
		||||
    <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    <packaging>pom</packaging>
 | 
			
		||||
    <name>Alfresco Community Repo Parent</name>
 | 
			
		||||
 | 
			
		||||
@@ -45,18 +45,18 @@
 | 
			
		||||
 | 
			
		||||
        <dependency.alfresco-hb-data-sender.version>1.0.12</dependency.alfresco-hb-data-sender.version>
 | 
			
		||||
        <dependency.alfresco-trashcan-cleaner.version>2.4.1</dependency.alfresco-trashcan-cleaner.version>
 | 
			
		||||
        <dependency.alfresco-jlan.version>7.1</dependency.alfresco-jlan.version>
 | 
			
		||||
        <dependency.alfresco-jlan.version>7.2</dependency.alfresco-jlan.version>
 | 
			
		||||
        <dependency.alfresco-server-root.version>6.0.1</dependency.alfresco-server-root.version>
 | 
			
		||||
        <dependency.alfresco-messaging-repo.version>1.2.19</dependency.alfresco-messaging-repo.version>
 | 
			
		||||
        <dependency.alfresco-messaging-repo.version>1.2.20</dependency.alfresco-messaging-repo.version>
 | 
			
		||||
        <dependency.alfresco-log-sanitizer.version>0.2</dependency.alfresco-log-sanitizer.version>
 | 
			
		||||
        <dependency.activiti-engine.version>5.23.0</dependency.activiti-engine.version>
 | 
			
		||||
        <dependency.activiti.version>5.23.0</dependency.activiti.version>
 | 
			
		||||
        <dependency.alfresco-transform-service.version>1.5.3</dependency.alfresco-transform-service.version>
 | 
			
		||||
        <dependency.alfresco-transform-core.version>2.6.0</dependency.alfresco-transform-core.version>
 | 
			
		||||
        <dependency.alfresco-greenmail.version>6.2</dependency.alfresco-greenmail.version>
 | 
			
		||||
        <dependency.acs-event-model.version>0.0.15</dependency.acs-event-model.version>
 | 
			
		||||
        <dependency.alfresco-transform-service.version>1.5.4-A3</dependency.alfresco-transform-service.version>
 | 
			
		||||
        <dependency.alfresco-transform-core.version>2.7.0-A1</dependency.alfresco-transform-core.version>
 | 
			
		||||
        <dependency.alfresco-greenmail.version>6.4</dependency.alfresco-greenmail.version>
 | 
			
		||||
        <dependency.acs-event-model.version>0.0.16</dependency.acs-event-model.version>
 | 
			
		||||
 | 
			
		||||
        <dependency.spring.version>5.3.21</dependency.spring.version>
 | 
			
		||||
        <dependency.spring.version>5.3.22</dependency.spring.version>
 | 
			
		||||
        <dependency.antlr.version>3.5.2</dependency.antlr.version>
 | 
			
		||||
        <dependency.jackson.version>2.13.3</dependency.jackson.version>
 | 
			
		||||
        <dependency.jackson-databind.version>2.13.3</dependency.jackson-databind.version>
 | 
			
		||||
@@ -74,18 +74,18 @@
 | 
			
		||||
        <dependency.httpcore.version>4.4.15</dependency.httpcore.version>
 | 
			
		||||
        <dependency.commons-httpclient.version>3.1-HTTPCLIENT-1265</dependency.commons-httpclient.version>
 | 
			
		||||
        <dependency.xercesImpl.version>2.12.2</dependency.xercesImpl.version>
 | 
			
		||||
        <dependency.slf4j.version>1.7.35</dependency.slf4j.version>
 | 
			
		||||
        <dependency.slf4j.version>1.7.36</dependency.slf4j.version>
 | 
			
		||||
        <dependency.gytheio.version>0.16</dependency.gytheio.version>
 | 
			
		||||
        <dependency.groovy.version>3.0.11</dependency.groovy.version>
 | 
			
		||||
        <dependency.groovy.version>3.0.12</dependency.groovy.version>
 | 
			
		||||
        <dependency.tika.version>2.4.1</dependency.tika.version>
 | 
			
		||||
        <dependency.spring-security.version>5.7.2</dependency.spring-security.version>
 | 
			
		||||
        <dependency.truezip.version>7.7.10</dependency.truezip.version>
 | 
			
		||||
        <dependency.poi.version>5.2.2</dependency.poi.version>
 | 
			
		||||
        <dependency.ooxml-schemas.version>1.4</dependency.ooxml-schemas.version>
 | 
			
		||||
        <dependency.keycloak.version>15.0.2</dependency.keycloak.version>
 | 
			
		||||
        <dependency.keycloak.version>18.0.0</dependency.keycloak.version>
 | 
			
		||||
        <dependency.jboss.logging.version>3.5.0.Final</dependency.jboss.logging.version>
 | 
			
		||||
        <dependency.camel.version>3.15.0</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies (can cause dependency conflicts)-->
 | 
			
		||||
        <dependency.activemq.version>5.16.1</dependency.activemq.version>
 | 
			
		||||
        <dependency.activemq.version>5.17.1</dependency.activemq.version>
 | 
			
		||||
        <dependency.apache-compress.version>1.21</dependency.apache-compress.version>
 | 
			
		||||
        <dependency.apache.taglibs.version>1.2.5</dependency.apache.taglibs.version>
 | 
			
		||||
        <dependency.awaitility.version>4.2.0</dependency.awaitility.version>
 | 
			
		||||
@@ -109,22 +109,22 @@
 | 
			
		||||
 | 
			
		||||
        <alfresco.googledrive.version>3.2.2</alfresco.googledrive.version>
 | 
			
		||||
        <alfresco.aos-module.version>1.4.1</alfresco.aos-module.version> 
 | 
			
		||||
        <alfresco.api-explorer.version>7.2.0</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
 | 
			
		||||
        <alfresco.api-explorer.version>7.2.1</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
 | 
			
		||||
 | 
			
		||||
        <alfresco.maven-plugin.version>2.2.0</alfresco.maven-plugin.version>
 | 
			
		||||
        <license-maven-plugin.version>2.0.1.alfresco-2</license-maven-plugin.version>
 | 
			
		||||
 | 
			
		||||
        <dependency.postgresql.version>42.4.0</dependency.postgresql.version>
 | 
			
		||||
        <dependency.mysql.version>8.0.29</dependency.mysql.version>
 | 
			
		||||
        <dependency.postgresql.version>42.4.1</dependency.postgresql.version>
 | 
			
		||||
        <dependency.mysql.version>8.0.30</dependency.mysql.version>
 | 
			
		||||
        <dependency.mysql-image.version>8</dependency.mysql-image.version>
 | 
			
		||||
        <dependency.mariadb.version>2.7.4</dependency.mariadb.version>
 | 
			
		||||
        <dependency.tas-utility.version>3.0.49</dependency.tas-utility.version>
 | 
			
		||||
        <dependency.rest-assured.version>3.3.0</dependency.rest-assured.version>
 | 
			
		||||
        <dependency.tas-restapi.version>1.94</dependency.tas-restapi.version>
 | 
			
		||||
        <dependency.tas-cmis.version>1.31</dependency.tas-cmis.version>
 | 
			
		||||
        <dependency.tas-email.version>1.8</dependency.tas-email.version>
 | 
			
		||||
        <dependency.tas-webdav.version>1.6</dependency.tas-webdav.version>
 | 
			
		||||
        <dependency.tas-ftp.version>1.5</dependency.tas-ftp.version>
 | 
			
		||||
        <dependency.rest-assured.version>5.1.1</dependency.rest-assured.version>
 | 
			
		||||
        <dependency.tas-restapi.version>1.115</dependency.tas-restapi.version>
 | 
			
		||||
        <dependency.tas-cmis.version>1.32</dependency.tas-cmis.version>
 | 
			
		||||
        <dependency.tas-email.version>1.9</dependency.tas-email.version>
 | 
			
		||||
        <dependency.tas-webdav.version>1.7</dependency.tas-webdav.version>
 | 
			
		||||
        <dependency.tas-ftp.version>1.7</dependency.tas-ftp.version>
 | 
			
		||||
        <dependency.tas-dataprep.version>2.6</dependency.tas-dataprep.version>
 | 
			
		||||
 | 
			
		||||
        <!-- AGS properties shared between community and enterprise -->
 | 
			
		||||
@@ -148,7 +148,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>17.51</tag>
 | 
			
		||||
        <tag>HEAD</tag>
 | 
			
		||||
    </scm>
 | 
			
		||||
 | 
			
		||||
    <distributionManagement>
 | 
			
		||||
@@ -616,6 +616,12 @@
 | 
			
		||||
                <groupId>org.slf4j</groupId>
 | 
			
		||||
                <artifactId>slf4j-reload4j</artifactId>
 | 
			
		||||
                <version>${dependency.slf4j.version}</version>
 | 
			
		||||
                <exclusions>
 | 
			
		||||
                    <exclusion>
 | 
			
		||||
                        <groupId>ch.qos.reload4j</groupId>
 | 
			
		||||
                        <artifactId>reload4j</artifactId>
 | 
			
		||||
                    </exclusion>
 | 
			
		||||
                </exclusions>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>xerces</groupId>
 | 
			
		||||
@@ -639,7 +645,7 @@
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>com.github.junrar</groupId>
 | 
			
		||||
                <artifactId>junrar</artifactId>
 | 
			
		||||
                <version>7.5.2</version>
 | 
			
		||||
                <version>7.5.3</version>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>com.github.fge</groupId>
 | 
			
		||||
@@ -877,6 +883,17 @@
 | 
			
		||||
                <version>1.18.24</version>
 | 
			
		||||
                <scope>provided</scope>
 | 
			
		||||
            </dependency>
 | 
			
		||||
            <dependency>
 | 
			
		||||
                <groupId>org.activiti</groupId>
 | 
			
		||||
                <artifactId>activiti-spring</artifactId>
 | 
			
		||||
                <version>${dependency.activiti.version}</version>
 | 
			
		||||
                <exclusions>
 | 
			
		||||
                    <exclusion>
 | 
			
		||||
                        <groupId>commons-dbcp</groupId>
 | 
			
		||||
                        <artifactId>commons-dbcp</artifactId>
 | 
			
		||||
                    </exclusion>
 | 
			
		||||
                </exclusions>
 | 
			
		||||
            </dependency>
 | 
			
		||||
        </dependencies>
 | 
			
		||||
    </dependencyManagement>
 | 
			
		||||
 | 
			
		||||
@@ -894,7 +911,7 @@
 | 
			
		||||
                <plugin>
 | 
			
		||||
                    <groupId>io.fabric8</groupId>
 | 
			
		||||
                    <artifactId>docker-maven-plugin</artifactId>
 | 
			
		||||
                    <version>0.40.1</version>
 | 
			
		||||
                    <version>0.40.2</version>
 | 
			
		||||
                </plugin>
 | 
			
		||||
                <plugin>
 | 
			
		||||
                    <artifactId>maven-surefire-plugin</artifactId>
 | 
			
		||||
@@ -920,7 +937,7 @@
 | 
			
		||||
                <plugin>
 | 
			
		||||
                    <groupId>org.apache.maven.plugins</groupId>
 | 
			
		||||
                    <artifactId>maven-resources-plugin</artifactId>
 | 
			
		||||
                    <version>3.2.0</version>
 | 
			
		||||
                    <version>3.3.0</version>
 | 
			
		||||
                </plugin>
 | 
			
		||||
                <plugin>
 | 
			
		||||
                    <groupId>org.apache.maven.plugins</groupId>
 | 
			
		||||
@@ -929,7 +946,7 @@
 | 
			
		||||
                </plugin>
 | 
			
		||||
                <plugin>
 | 
			
		||||
                    <artifactId>maven-assembly-plugin</artifactId>
 | 
			
		||||
                    <version>3.4.1</version>
 | 
			
		||||
                    <version>3.4.2</version>
 | 
			
		||||
                </plugin>
 | 
			
		||||
                <plugin>
 | 
			
		||||
                    <groupId>org.alfresco.maven.plugin</groupId>
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
    <parent>
 | 
			
		||||
        <groupId>org.alfresco</groupId>
 | 
			
		||||
        <artifactId>alfresco-community-repo</artifactId>
 | 
			
		||||
        <version>17.51</version>
 | 
			
		||||
        <version>17.102-SNAPSHOT</version>
 | 
			
		||||
    </parent>
 | 
			
		||||
 | 
			
		||||
    <dependencies>
 | 
			
		||||
@@ -130,7 +130,7 @@
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.eclipse.jetty</groupId>
 | 
			
		||||
            <artifactId>jetty-server</artifactId>
 | 
			
		||||
            <version>8.2.0.v20160908</version>
 | 
			
		||||
            <version>10.0.11</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
            <exclusions>
 | 
			
		||||
                <exclusion>
 | 
			
		||||
@@ -142,19 +142,19 @@
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.eclipse.jetty</groupId>
 | 
			
		||||
            <artifactId>jetty-security</artifactId>
 | 
			
		||||
            <version>8.2.0.v20160908</version>
 | 
			
		||||
            <version>10.0.11</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.eclipse.jetty</groupId>
 | 
			
		||||
            <artifactId>jetty-webapp</artifactId>
 | 
			
		||||
            <version>8.2.0.v20160908</version>
 | 
			
		||||
            <version>10.0.11</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>org.alfresco.cmis.client</groupId>
 | 
			
		||||
            <artifactId>alfresco-opencmis-extension</artifactId>
 | 
			
		||||
            <version>2.0</version>
 | 
			
		||||
            <version>2.1</version>
 | 
			
		||||
            <scope>test</scope>
 | 
			
		||||
            <exclusions>
 | 
			
		||||
              <!-- Duplicates classes from jakarta.transaction:jakarta.transaction-api -->
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.web.scripts;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.repo.content.MimetypeMap;
 | 
			
		||||
import org.alfresco.service.cmr.repository.ContentReader;
 | 
			
		||||
import org.alfresco.service.cmr.repository.MimetypeService;
 | 
			
		||||
import org.springframework.extensions.webscripts.WebScriptRequest;
 | 
			
		||||
 | 
			
		||||
public class MimeTypeUtil
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the file mimetype from the file ContentReader, and if its null then set the mimetype to binary by default
 | 
			
		||||
     * and try to get the correct one from file extension
 | 
			
		||||
     *
 | 
			
		||||
     *
 | 
			
		||||
     * @param reader            reader of the file in the request
 | 
			
		||||
     * @param req               request relating to the file
 | 
			
		||||
     * @param mimetypeService   MimetypeService
 | 
			
		||||
     *
 | 
			
		||||
     * @return  mimetype of the file as a string
 | 
			
		||||
     */
 | 
			
		||||
    public static String determineMimetype(ContentReader reader, WebScriptRequest req, MimetypeService mimetypeService)
 | 
			
		||||
    {
 | 
			
		||||
        String mimetype = reader.getMimetype();
 | 
			
		||||
        if (mimetype == null || mimetype.length() == 0)
 | 
			
		||||
        {
 | 
			
		||||
            String extensionPath = req.getExtensionPath();
 | 
			
		||||
            mimetype = MimetypeMap.MIMETYPE_BINARY;
 | 
			
		||||
            int extIndex = extensionPath.lastIndexOf('.');
 | 
			
		||||
            if (extIndex != -1)
 | 
			
		||||
            {
 | 
			
		||||
                String ext = extensionPath.substring(extIndex + 1);
 | 
			
		||||
                mimetype = mimetypeService.getMimetype(ext);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return mimetype;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2016 Alfresco Software Limited
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software. 
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of 
 | 
			
		||||
@@ -26,14 +26,18 @@
 | 
			
		||||
package org.alfresco.repo.web.scripts.content;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.ServletContext;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.model.ContentModel;
 | 
			
		||||
import org.alfresco.repo.web.scripts.MimeTypeUtil;
 | 
			
		||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
 | 
			
		||||
import org.alfresco.service.cmr.repository.ContentReader;
 | 
			
		||||
import org.alfresco.service.cmr.repository.ContentService;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.namespace.NamespaceService;
 | 
			
		||||
@@ -65,6 +69,19 @@ public class ContentGet extends StreamContent implements ServletContextAware
 | 
			
		||||
    private NamespaceService namespaceService;
 | 
			
		||||
    private ContentService contentService;
 | 
			
		||||
 | 
			
		||||
    private List<String> nonAttachContentTypes = Collections.emptyList();
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param nonAttachContentTypes List<String>
 | 
			
		||||
     */
 | 
			
		||||
    public void setNonAttachContentTypes(List<String> nonAttachContentTypes)
 | 
			
		||||
    {
 | 
			
		||||
        if (nonAttachContentTypes != null && !nonAttachContentTypes.isEmpty())
 | 
			
		||||
        {
 | 
			
		||||
            this.nonAttachContentTypes = nonAttachContentTypes;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param servletContext ServletContext
 | 
			
		||||
     */
 | 
			
		||||
@@ -121,9 +138,7 @@ public class ContentGet extends StreamContent implements ServletContextAware
 | 
			
		||||
        {
 | 
			
		||||
            throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + reference.toString());
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // determine attachment
 | 
			
		||||
        boolean attach = Boolean.valueOf(req.getParameter("a"));
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        // render content
 | 
			
		||||
        QName propertyQName = ContentModel.PROP_CONTENT;
 | 
			
		||||
@@ -140,6 +155,19 @@ public class ContentGet extends StreamContent implements ServletContextAware
 | 
			
		||||
                propertyQName = QName.createQName(propertyName, namespaceService);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // determine attachment and force download for specific mimetypes - see PRODSEC-5862
 | 
			
		||||
        boolean attach = Boolean.valueOf(req.getParameter("a"));
 | 
			
		||||
        ContentReader reader = contentService.getReader(nodeRef, propertyQName);
 | 
			
		||||
        String mimetype = MimeTypeUtil.determineMimetype(reader, req, mimetypeService);
 | 
			
		||||
 | 
			
		||||
        if (!attach)
 | 
			
		||||
        {
 | 
			
		||||
            if (nonAttachContentTypes == null || !nonAttachContentTypes.contains(mimetype))
 | 
			
		||||
            {
 | 
			
		||||
                attach = true;
 | 
			
		||||
                logger.warn("Ignored a=false for " + nodeRef.getId() + " since " + mimetype + " is not in the whitelist for non-attach content types");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Stream the content
 | 
			
		||||
        streamContentLocal(req, res, nodeRef, attach, propertyQName, null);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,28 +1,28 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2016 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software. 
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of 
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is 
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * 
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * 
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * 
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.web.scripts.content;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
@@ -33,7 +33,7 @@ import java.util.Map;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.model.ContentModel;
 | 
			
		||||
import org.alfresco.repo.content.MimetypeMap;
 | 
			
		||||
import org.alfresco.repo.web.scripts.MimeTypeUtil;
 | 
			
		||||
import org.alfresco.service.cmr.repository.ContentReader;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.namespace.QName;
 | 
			
		||||
@@ -79,18 +79,7 @@ public class ContentInfo extends StreamContent
 | 
			
		||||
        delegate.setAttachment(req, res, attach, attachFileName);
 | 
			
		||||
 | 
			
		||||
        // establish mimetype
 | 
			
		||||
        String mimetype = reader.getMimetype();
 | 
			
		||||
        String extensionPath = req.getExtensionPath();
 | 
			
		||||
        if (mimetype == null || mimetype.length() == 0)
 | 
			
		||||
        {
 | 
			
		||||
            mimetype = MimetypeMap.MIMETYPE_BINARY;
 | 
			
		||||
            int extIndex = extensionPath.lastIndexOf('.');
 | 
			
		||||
            if (extIndex != -1)
 | 
			
		||||
            {
 | 
			
		||||
                String ext = extensionPath.substring(extIndex + 1);
 | 
			
		||||
                mimetype = mimetypeService.getMimetype(ext);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        String mimetype = MimeTypeUtil.determineMimetype(reader, req, mimetypeService);
 | 
			
		||||
 | 
			
		||||
        // set mimetype for the content and the character encoding + length for the stream
 | 
			
		||||
        res.setContentType(mimetype);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2016 Alfresco Software Limited
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software. 
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of 
 | 
			
		||||
@@ -30,6 +30,7 @@ import java.io.FileOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.InputStream;
 | 
			
		||||
import java.io.OutputStream;
 | 
			
		||||
import java.io.UnsupportedEncodingException;
 | 
			
		||||
import java.net.SocketException;
 | 
			
		||||
import java.net.URLEncoder;
 | 
			
		||||
import java.nio.charset.StandardCharsets;
 | 
			
		||||
@@ -43,6 +44,7 @@ import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import org.alfresco.model.ContentModel;
 | 
			
		||||
import org.alfresco.repo.content.MimetypeMap;
 | 
			
		||||
import org.alfresco.repo.content.filestore.FileContentReader;
 | 
			
		||||
import org.alfresco.repo.web.scripts.MimeTypeUtil;
 | 
			
		||||
import org.alfresco.sync.repo.events.EventPublisher;
 | 
			
		||||
import org.alfresco.repo.web.util.HttpRangeProcessor;
 | 
			
		||||
import org.alfresco.rest.framework.resource.content.CacheDirective;
 | 
			
		||||
@@ -58,6 +60,7 @@ import org.alfresco.service.namespace.QName;
 | 
			
		||||
import org.alfresco.util.TempFileProvider;
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
import org.apache.cxf.attachment.Rfc5987Util;
 | 
			
		||||
import org.springframework.context.ResourceLoaderAware;
 | 
			
		||||
import org.springframework.core.io.ResourceLoader;
 | 
			
		||||
import org.springframework.extensions.webscripts.Cache;
 | 
			
		||||
@@ -361,18 +364,7 @@ public class ContentStreamer implements ResourceLoaderAware
 | 
			
		||||
        setAttachment(req, res, attach, attachFileName);
 | 
			
		||||
    
 | 
			
		||||
        // establish mimetype
 | 
			
		||||
        String mimetype = reader.getMimetype();
 | 
			
		||||
        String extensionPath = req.getExtensionPath();
 | 
			
		||||
        if (mimetype == null || mimetype.length() == 0)
 | 
			
		||||
        {
 | 
			
		||||
            mimetype = MimetypeMap.MIMETYPE_BINARY;
 | 
			
		||||
            int extIndex = extensionPath.lastIndexOf('.');
 | 
			
		||||
            if (extIndex != -1)
 | 
			
		||||
            {
 | 
			
		||||
                String ext = extensionPath.substring(extIndex + 1);
 | 
			
		||||
                mimetype = mimetypeService.getMimetype(ext);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        String mimetype = MimeTypeUtil.determineMimetype(reader, req, mimetypeService);
 | 
			
		||||
        
 | 
			
		||||
        res.setHeader(HEADER_ACCEPT_RANGES, "bytes");
 | 
			
		||||
        try
 | 
			
		||||
@@ -482,7 +474,7 @@ public class ContentStreamer implements ResourceLoaderAware
 | 
			
		||||
 | 
			
		||||
                if (req == null)
 | 
			
		||||
                {
 | 
			
		||||
                    headerValue += "; filename*=UTF-8''" + URLEncoder.encode(attachFileName, StandardCharsets.UTF_8)
 | 
			
		||||
                    headerValue += "; filename*=UTF-8''" + encodeFilename(attachFileName)
 | 
			
		||||
                            + "; filename=\"" + filterNameForQuotedString(attachFileName) + "\"";
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
@@ -491,12 +483,12 @@ public class ContentStreamer implements ResourceLoaderAware
 | 
			
		||||
                    boolean isLegacy = (null != userAgent) && (userAgent.contains("MSIE 8") || userAgent.contains("MSIE 7"));
 | 
			
		||||
                    if (isLegacy)
 | 
			
		||||
                    {
 | 
			
		||||
                        headerValue += "; filename=\"" + URLEncoder.encode(attachFileName, StandardCharsets.UTF_8);
 | 
			
		||||
                        headerValue += "; filename=\"" + encodeFilename(attachFileName);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        headerValue += "; filename=\"" + filterNameForQuotedString(attachFileName) + "\"; filename*=UTF-8''"
 | 
			
		||||
                                + URLEncoder.encode(attachFileName, StandardCharsets.UTF_8);
 | 
			
		||||
                                + encodeFilename(attachFileName);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -506,6 +498,21 @@ public class ContentStreamer implements ResourceLoaderAware
 | 
			
		||||
            res.setHeader("Content-Disposition", headerValue);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private String encodeFilename(String attachFileName)
 | 
			
		||||
    {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            return Rfc5987Util.encode(attachFileName);
 | 
			
		||||
        }
 | 
			
		||||
        catch (UnsupportedEncodingException e)
 | 
			
		||||
        {
 | 
			
		||||
            if (logger.isInfoEnabled())
 | 
			
		||||
                logger.info(e.getMessage() + " Changing encoder from Rfc5987Util to java.net.URLEncoder.");
 | 
			
		||||
 | 
			
		||||
            return URLEncoder.encode(attachFileName, StandardCharsets.UTF_8);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    protected String filterNameForQuotedString(String s)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -78,7 +78,7 @@ public abstract class AbstractRuleWebScript extends DeclarativeWebScript
 | 
			
		||||
    private static final String RULE_OUTBOUND = "outbound";
 | 
			
		||||
    private static final String ACTION_CHECK_OUT = "check-out";
 | 
			
		||||
 | 
			
		||||
    private static final String CANNOT_CREATE_RULE = "cannot.create.rule.checkout.outbound";
 | 
			
		||||
    public static final String CANNOT_CREATE_RULE = "cannot.create.rule.checkout.outbound";
 | 
			
		||||
    
 | 
			
		||||
    protected NodeService nodeService;
 | 
			
		||||
    protected RuleService ruleService;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										66
									
								
								remote-api/src/main/java/org/alfresco/rest/api/RuleSets.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								remote-api/src/main/java/org/alfresco/rest/api/RuleSets.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSet;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSetLink;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Paging;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Rule sets API.
 | 
			
		||||
 */
 | 
			
		||||
@Experimental
 | 
			
		||||
public interface RuleSets
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Get rule sets for a folder.
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderNodeId Folder node ID
 | 
			
		||||
     * @param paging {@link Paging} information
 | 
			
		||||
     * @param includes List of fields to include in the rule set
 | 
			
		||||
     * @return {@link CollectionWithPagingInfo} containing a list page of rule sets
 | 
			
		||||
     */
 | 
			
		||||
    CollectionWithPagingInfo<RuleSet> getRuleSets(String folderNodeId, List<String> includes, Paging paging);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the rule set with the given ID and check associations with the folder node.
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderNodeId Folder node ID
 | 
			
		||||
     * @param ruleSetId Rule set ID
 | 
			
		||||
     * @param includes List of fields to include in the rule set
 | 
			
		||||
     * @return {@link RuleSet} definition
 | 
			
		||||
     */
 | 
			
		||||
    RuleSet getRuleSetById(String folderNodeId, String ruleSetId, List<String> includes);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Link a rule set to a folder
 | 
			
		||||
     */
 | 
			
		||||
    RuleSetLink linkToRuleSet(String folderNodeId, String linkToNodeId);
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,54 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSetting;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Rule settings API.
 | 
			
		||||
 */
 | 
			
		||||
@Experimental
 | 
			
		||||
public interface RuleSettings
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the rule setting with the given key.
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderId Folder node ID
 | 
			
		||||
     * @param ruleSettingKey Rule setting key
 | 
			
		||||
     * @return {@link RuleSetting} The retrieved rule setting object.
 | 
			
		||||
     */
 | 
			
		||||
    RuleSetting getRuleSetting(String folderId, String ruleSettingKey);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the rule setting against the specified folder.
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderId The folder to update.
 | 
			
		||||
     * @param ruleSetting The new rule setting.
 | 
			
		||||
     * @return The updated rule setting object.
 | 
			
		||||
     */
 | 
			
		||||
    RuleSetting setRuleSetting(String folderId, RuleSetting ruleSetting);
 | 
			
		||||
}
 | 
			
		||||
@@ -26,6 +26,8 @@
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.model.rules.Rule;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
 | 
			
		||||
@@ -33,8 +35,6 @@ import org.alfresco.rest.framework.resource.parameters.Paging;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.rule.RuleServiceException;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Folder node rules API.
 | 
			
		||||
 *
 | 
			
		||||
@@ -47,10 +47,11 @@ public interface Rules
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderNodeId - folder node ID
 | 
			
		||||
     * @param ruleSetId - rule set ID
 | 
			
		||||
     * @param includes - The list of optional fields to include in the response.
 | 
			
		||||
     * @param paging - {@link Paging} information
 | 
			
		||||
     * @return {@link CollectionWithPagingInfo} containing a list page of folder rules
 | 
			
		||||
     */
 | 
			
		||||
    CollectionWithPagingInfo<Rule> getRules(String folderNodeId, String ruleSetId, Paging paging);
 | 
			
		||||
    CollectionWithPagingInfo<Rule> getRules(String folderNodeId, String ruleSetId, List<String> includes, Paging paging);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get rule for rule's ID and check associations with folder node and rule set node
 | 
			
		||||
@@ -58,9 +59,10 @@ public interface Rules
 | 
			
		||||
     * @param folderNodeId - folder node ID
 | 
			
		||||
     * @param ruleSetId - rule set ID
 | 
			
		||||
     * @param ruleId - rule ID
 | 
			
		||||
     * @param includes - The list of optional fields to include in the response.
 | 
			
		||||
     * @return {@link Rule} definition
 | 
			
		||||
     */
 | 
			
		||||
    Rule getRuleById(String folderNodeId, String ruleSetId, String ruleId);
 | 
			
		||||
    Rule getRuleById(String folderNodeId, String ruleSetId, String ruleId, List<String> includes);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create new rules (and potentially a rule set if "_default_" is supplied).
 | 
			
		||||
@@ -68,11 +70,24 @@ public interface Rules
 | 
			
		||||
     * @param folderNodeId The node id of a folder.
 | 
			
		||||
     * @param ruleSetId The id of a rule set (or "_default_" to use/create the default rule set for the folder).
 | 
			
		||||
     * @param rule The definition of the rule.
 | 
			
		||||
     * @param includes The list of optional fields to include in the response.
 | 
			
		||||
     * @return The newly created rules.
 | 
			
		||||
     * @throws InvalidArgumentException If the nodes are not the expected types, or the rule set does not correspond to the folder.
 | 
			
		||||
     * @throws RuleServiceException If the folder is already linked to another rule set.
 | 
			
		||||
     */
 | 
			
		||||
    List<Rule> createRules(String folderNodeId, String ruleSetId, List<Rule> rule);
 | 
			
		||||
    List<Rule> createRules(String folderNodeId, String ruleSetId, List<Rule> rule, List<String> includes);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update a rule.
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderNodeId The id of a folder.
 | 
			
		||||
     * @param ruleSetId The id of a rule set within the folder (or "_default_" to use the default rule set for the folder).
 | 
			
		||||
     * @param ruleId The rule id.
 | 
			
		||||
     * @param rule The new version of the rule.
 | 
			
		||||
     * @param includes The list of optional fields to include in the response.
 | 
			
		||||
     * @return The newly updated rule.
 | 
			
		||||
     */
 | 
			
		||||
    Rule updateRuleById(String folderNodeId, String ruleSetId, String ruleId, Rule rule, List<String> includes);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete rule for rule's ID and check associations with folder node and rule set node
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2021 Alfresco Software Limited
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software. 
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of 
 | 
			
		||||
@@ -713,6 +713,7 @@ public class CustomModelsImpl implements CustomModels
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            NodeRef nodeRef = customModelService.createDownloadNode(modelName, withForm);
 | 
			
		||||
            nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, modelName + DownloadsImpl.DEFAULT_ARCHIVE_EXTENSION);
 | 
			
		||||
            return new CustomModelDownload(nodeRef);
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception ex)
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,156 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.NotFoundException;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.action.ActionService;
 | 
			
		||||
import org.alfresco.service.cmr.action.ParameterDefinition;
 | 
			
		||||
import org.alfresco.service.cmr.action.ParameterizedItemDefinition;
 | 
			
		||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
 | 
			
		||||
import org.alfresco.service.cmr.dictionary.DictionaryException;
 | 
			
		||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.StoreRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
 | 
			
		||||
import org.alfresco.service.namespace.NamespaceService;
 | 
			
		||||
import org.alfresco.service.namespace.QName;
 | 
			
		||||
import org.json.JSONArray;
 | 
			
		||||
import org.json.JSONException;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public class ActionParameterConverter
 | 
			
		||||
{
 | 
			
		||||
    private final DictionaryService dictionaryService;
 | 
			
		||||
    private final ActionService actionService;
 | 
			
		||||
    private final NamespaceService namespaceService;
 | 
			
		||||
 | 
			
		||||
    public ActionParameterConverter(DictionaryService dictionaryService, ActionService actionService,
 | 
			
		||||
                                    NamespaceService namespaceService)
 | 
			
		||||
    {
 | 
			
		||||
        this.dictionaryService = dictionaryService;
 | 
			
		||||
        this.actionService = actionService;
 | 
			
		||||
        this.namespaceService = namespaceService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Map<String, Serializable> getConvertedParams(Map<String, Serializable> params, String name)
 | 
			
		||||
    {
 | 
			
		||||
        final Map<String, Serializable> parameters = new HashMap<>(params.size());
 | 
			
		||||
        final ParameterizedItemDefinition definition = actionService.getActionDefinition(name);
 | 
			
		||||
        if (definition == null)
 | 
			
		||||
        {
 | 
			
		||||
            throw new NotFoundException(NotFoundException.DEFAULT_MESSAGE_ID, new String[]{name});
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (Map.Entry<String, Serializable> param : params.entrySet())
 | 
			
		||||
        {
 | 
			
		||||
            final ParameterDefinition paramDef = definition.getParameterDefintion(param.getKey());
 | 
			
		||||
            if (paramDef == null && !definition.getAdhocPropertiesAllowed())
 | 
			
		||||
            {
 | 
			
		||||
                throw new InvalidArgumentException(InvalidArgumentException.DEFAULT_MESSAGE_ID, new String[]{param.getKey(), name});
 | 
			
		||||
            }
 | 
			
		||||
            if (paramDef != null)
 | 
			
		||||
            {
 | 
			
		||||
                final QName typeQName = paramDef.getType();
 | 
			
		||||
                parameters.put(param.getKey(), convertValue(typeQName, param.getValue()));
 | 
			
		||||
            } else
 | 
			
		||||
            {
 | 
			
		||||
                parameters.put(param.getKey(), param.getValue().toString());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return parameters;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Serializable convertParamFromServiceModel(Serializable param)
 | 
			
		||||
    {
 | 
			
		||||
        if (param instanceof QName)
 | 
			
		||||
        {
 | 
			
		||||
            return ((QName) param).toPrefixString(namespaceService);
 | 
			
		||||
        }
 | 
			
		||||
        else if (param instanceof NodeRef) {
 | 
			
		||||
            return ((NodeRef) param).getId();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return param;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Serializable convertValue(QName typeQName, Object propertyValue) throws JSONException
 | 
			
		||||
    {
 | 
			
		||||
        Serializable value;
 | 
			
		||||
 | 
			
		||||
        final DataTypeDefinition typeDef = dictionaryService.getDataType(typeQName);
 | 
			
		||||
        if (typeDef == null)
 | 
			
		||||
        {
 | 
			
		||||
            throw new NotFoundException(NotFoundException.DEFAULT_MESSAGE_ID, new String[]{typeQName.toPrefixString()});
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (propertyValue instanceof JSONArray)
 | 
			
		||||
        {
 | 
			
		||||
            final String javaClassName = typeDef.getJavaClassName();
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                Class.forName(javaClassName);
 | 
			
		||||
            } catch (ClassNotFoundException e)
 | 
			
		||||
            {
 | 
			
		||||
                throw new DictionaryException("Java class " + javaClassName + " of property type " + typeDef.getName() + " is invalid", e);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            final int length = ((JSONArray) propertyValue).length();
 | 
			
		||||
            final List<Serializable> list = new ArrayList<>(length);
 | 
			
		||||
            for (int i = 0; i < length; i++)
 | 
			
		||||
            {
 | 
			
		||||
                list.add(convertValue(typeQName, ((JSONArray) propertyValue).get(i)));
 | 
			
		||||
            }
 | 
			
		||||
            value = (Serializable) list;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            if (typeQName.equals(DataTypeDefinition.QNAME) && typeQName.toString().contains(":"))
 | 
			
		||||
            {
 | 
			
		||||
                value = QName.createQName(propertyValue.toString(), namespaceService);
 | 
			
		||||
            }
 | 
			
		||||
            else if (typeQName.isMatch(DataTypeDefinition.NODE_REF))
 | 
			
		||||
            {
 | 
			
		||||
                value = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, propertyValue.toString());
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                value = (Serializable) DefaultTypeConverter.INSTANCE.convert(dictionaryService.getDataType(typeQName), propertyValue);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,85 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.repo.web.scripts.rule.AbstractRuleWebScript.CANNOT_CREATE_RULE;
 | 
			
		||||
import static org.alfresco.service.cmr.rule.RuleType.OUTBOUND;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.repo.action.CompositeActionImpl;
 | 
			
		||||
import org.alfresco.repo.action.RuntimeActionService;
 | 
			
		||||
import org.alfresco.repo.action.access.ActionAccessRestriction;
 | 
			
		||||
import org.alfresco.repo.action.executer.CheckOutActionExecuter;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.action.Action;
 | 
			
		||||
import org.alfresco.service.cmr.rule.Rule;
 | 
			
		||||
import org.apache.commons.collections.CollectionUtils;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public class ActionPermissionValidator
 | 
			
		||||
{
 | 
			
		||||
    private final RuntimeActionService runtimeActionService;
 | 
			
		||||
 | 
			
		||||
    public ActionPermissionValidator(RuntimeActionService runtimeActionService)
 | 
			
		||||
    {
 | 
			
		||||
        this.runtimeActionService = runtimeActionService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Rule validateRulePermissions(Rule rule)
 | 
			
		||||
    {
 | 
			
		||||
        final List<Action> actions = ((CompositeActionImpl) rule.getAction()).getActions();
 | 
			
		||||
 | 
			
		||||
        checkRestrictedAccessActions(actions);
 | 
			
		||||
        checkRuleOutboundHasNoCheckOutAction(rule, actions);
 | 
			
		||||
        return rule;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void checkRestrictedAccessActions(List<Action> actions) {
 | 
			
		||||
        actions.forEach(action -> {
 | 
			
		||||
            ActionAccessRestriction.setActionContext(action, ActionAccessRestriction.RULE_ACTION_CONTEXT);
 | 
			
		||||
            runtimeActionService.verifyActionAccessRestrictions(action);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void checkRuleOutboundHasNoCheckOutAction(Rule rule, List<Action> actions) {
 | 
			
		||||
        //TODO: rule types should never be empty in final implementation
 | 
			
		||||
        if (CollectionUtils.isNotEmpty(rule.getRuleTypes()) && rule.getRuleTypes().contains(OUTBOUND))
 | 
			
		||||
        {
 | 
			
		||||
            for (Action action : actions)
 | 
			
		||||
            {
 | 
			
		||||
                if (action.getActionDefinitionName().equalsIgnoreCase(CheckOutActionExecuter.NAME))
 | 
			
		||||
                {
 | 
			
		||||
                    throw new InvalidArgumentException(CANNOT_CREATE_RULE);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -23,122 +23,53 @@
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.impl;
 | 
			
		||||
import static org.alfresco.service.cmr.security.AccessStatus.ALLOWED;
 | 
			
		||||
import static org.alfresco.service.cmr.security.PermissionService.CHANGE_PERMISSIONS;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.model.ContentModel;
 | 
			
		||||
import org.alfresco.repo.rule.RuleModel;
 | 
			
		||||
import org.alfresco.rest.api.Nodes;
 | 
			
		||||
import org.alfresco.rest.api.Rules;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.Rule;
 | 
			
		||||
import org.alfresco.rest.api.model.Node;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSet;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.ListPage;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Paging;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeService;
 | 
			
		||||
import org.alfresco.service.cmr.rule.RuleService;
 | 
			
		||||
import org.alfresco.service.cmr.security.AccessStatus;
 | 
			
		||||
import org.alfresco.service.cmr.security.PermissionService;
 | 
			
		||||
import org.alfresco.service.namespace.QName;
 | 
			
		||||
 | 
			
		||||
/** Responsible for validating nodes when working with rules. */
 | 
			
		||||
@Experimental
 | 
			
		||||
public class RulesImpl implements Rules
 | 
			
		||||
public class NodeValidator
 | 
			
		||||
{
 | 
			
		||||
    private static final String RULE_SET_EXPECTED_TYPE_NAME = "rule set";
 | 
			
		||||
 | 
			
		||||
    private Nodes nodes;
 | 
			
		||||
 | 
			
		||||
    private PermissionService permissionService;
 | 
			
		||||
 | 
			
		||||
    private RuleService ruleService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public CollectionWithPagingInfo<Rule> getRules(final String folderNodeId, final String ruleSetId, final Paging paging)
 | 
			
		||||
    {
 | 
			
		||||
        final NodeRef folderNodeRef = validateFolderNode(folderNodeId);
 | 
			
		||||
        validateRuleSetNode(ruleSetId, folderNodeRef);
 | 
			
		||||
 | 
			
		||||
        final List<Rule> rules = ruleService.getRules(folderNodeRef).stream()
 | 
			
		||||
            .map(Rule::from)
 | 
			
		||||
            .collect(Collectors.toList());
 | 
			
		||||
 | 
			
		||||
        return ListPage.of(rules, paging);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Rule getRuleById(final String folderNodeId, final String ruleSetId, final String ruleId)
 | 
			
		||||
    {
 | 
			
		||||
        final NodeRef folderNodeRef = validateFolderNode(folderNodeId);
 | 
			
		||||
        final NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef);
 | 
			
		||||
        final NodeRef ruleNodeRef = validateRuleNode(ruleId, ruleSetNodeRef);
 | 
			
		||||
 | 
			
		||||
        return Rule.from(ruleService.getRule(ruleNodeRef));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<Rule> createRules(final String folderNodeId, final String ruleSetId, final List<Rule> rules)
 | 
			
		||||
    {
 | 
			
		||||
        final NodeRef folderNodeRef = validateFolderNode(folderNodeId);
 | 
			
		||||
        // Don't validate the ruleset node if -default- is passed since we may need to create it.
 | 
			
		||||
        if (RuleSet.isNotDefaultId(ruleSetId))
 | 
			
		||||
        {
 | 
			
		||||
            validateRuleSetNode(ruleSetId, folderNodeRef);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return rules.stream()
 | 
			
		||||
                    .map(rule -> rule.toServiceModel(nodes))
 | 
			
		||||
                    .map(rule -> ruleService.saveRule(folderNodeRef, rule))
 | 
			
		||||
                    .map(Rule::from)
 | 
			
		||||
                    .collect(Collectors.toList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void deleteRuleById(String folderNodeId, String ruleSetId, String ruleId)
 | 
			
		||||
    {
 | 
			
		||||
        final NodeRef folderNodeRef = validateFolderNode(folderNodeId);
 | 
			
		||||
        final NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef);
 | 
			
		||||
        final NodeRef ruleNodeRef = validateRuleNode(ruleId, ruleSetNodeRef);
 | 
			
		||||
        final org.alfresco.service.cmr.rule.Rule rule = ruleService.getRule(ruleNodeRef);
 | 
			
		||||
        ruleService.removeRule(folderNodeRef, rule);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNodes(Nodes nodes)
 | 
			
		||||
    {
 | 
			
		||||
        this.nodes = nodes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setPermissionService(PermissionService permissionService)
 | 
			
		||||
    {
 | 
			
		||||
        this.permissionService = permissionService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRuleService(RuleService ruleService)
 | 
			
		||||
    {
 | 
			
		||||
        this.ruleService = ruleService;
 | 
			
		||||
    }
 | 
			
		||||
    private PermissionService permissionService;
 | 
			
		||||
    private NodeService nodeService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Validates if folder node exists and user have permission to read from it.
 | 
			
		||||
     * Validates if folder node exists and the user has permission to use it.
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderNodeId - folder node ID
 | 
			
		||||
     * @param requireChangePermission - Whether to require change permission or just read permission.
 | 
			
		||||
     * @return folder node reference
 | 
			
		||||
     * @throws InvalidArgumentException if node is not of an expected type
 | 
			
		||||
     * @throws PermissionDeniedException if user doesn't have right to read from folder
 | 
			
		||||
     * @throws PermissionDeniedException if the user doesn't have the appropriate permission for the folder.
 | 
			
		||||
     */
 | 
			
		||||
    private NodeRef validateFolderNode(final String folderNodeId)
 | 
			
		||||
    public NodeRef validateFolderNode(final String folderNodeId, boolean requireChangePermission)
 | 
			
		||||
    {
 | 
			
		||||
        final NodeRef nodeRef = nodes.validateOrLookupNode(folderNodeId, null);
 | 
			
		||||
        if (permissionService.hasReadPermission(nodeRef) != AccessStatus.ALLOWED) {
 | 
			
		||||
            throw new PermissionDeniedException("Cannot read from this node!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        validatePermission(requireChangePermission, nodeRef);
 | 
			
		||||
        verifyNodeType(nodeRef, ContentModel.TYPE_FOLDER, null);
 | 
			
		||||
 | 
			
		||||
        return nodeRef;
 | 
			
		||||
@@ -152,21 +83,38 @@ public class RulesImpl implements Rules
 | 
			
		||||
     * @return rule set node reference
 | 
			
		||||
     * @throws InvalidArgumentException in case of not matching associated folder node
 | 
			
		||||
     */
 | 
			
		||||
    private NodeRef validateRuleSetNode(final String ruleSetId, final NodeRef associatedFolderNodeRef)
 | 
			
		||||
    public NodeRef validateRuleSetNode(final String ruleSetId, final NodeRef associatedFolderNodeRef)
 | 
			
		||||
    {
 | 
			
		||||
        if (RuleSet.isDefaultId(ruleSetId))
 | 
			
		||||
        {
 | 
			
		||||
            return ruleService.getRuleSetNode(associatedFolderNodeRef);
 | 
			
		||||
            final NodeRef ruleSetNodeRef = ruleService.getRuleSetNode(associatedFolderNodeRef);
 | 
			
		||||
            if (ruleSetNodeRef == null)
 | 
			
		||||
            {
 | 
			
		||||
                //folder doesn't have a -default- rule set
 | 
			
		||||
                throw new RelationshipResourceNotFoundException(associatedFolderNodeRef.getId(), ruleSetId);
 | 
			
		||||
            }
 | 
			
		||||
            return ruleSetNodeRef;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        final NodeRef ruleSetNodeRef = validateNode(ruleSetId, ContentModel.TYPE_SYSTEM_FOLDER, RULE_SET_EXPECTED_TYPE_NAME);
 | 
			
		||||
        if (!ruleService.isRuleSetAssociatedWithFolder(ruleSetNodeRef, associatedFolderNodeRef)) {
 | 
			
		||||
        if (!ruleService.isRuleSetAssociatedWithFolder(ruleSetNodeRef, associatedFolderNodeRef))
 | 
			
		||||
        {
 | 
			
		||||
            throw new InvalidArgumentException("Rule set is not associated with folder node!");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ruleSetNodeRef;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NodeRef validateRuleSetNode(String linkToNodeId, boolean requireChangePermission)
 | 
			
		||||
    {
 | 
			
		||||
        final Node ruleSetNode = nodes.getNode(linkToNodeId);
 | 
			
		||||
        final ChildAssociationRef primaryParent = nodeService.getPrimaryParent(ruleSetNode.getNodeRef());
 | 
			
		||||
        final NodeRef parentNode = primaryParent.getParentRef();
 | 
			
		||||
        validatePermission(requireChangePermission, parentNode);
 | 
			
		||||
        return parentNode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Validates if rule node exists and associated rule set node matches.
 | 
			
		||||
     *
 | 
			
		||||
@@ -175,7 +123,7 @@ public class RulesImpl implements Rules
 | 
			
		||||
     * @return rule node reference
 | 
			
		||||
     * @throws InvalidArgumentException in case of not matching associated rule set node
 | 
			
		||||
     */
 | 
			
		||||
    private NodeRef validateRuleNode(final String ruleId, final NodeRef associatedRuleSetNodeRef)
 | 
			
		||||
    public NodeRef validateRuleNode(final String ruleId, final NodeRef associatedRuleSetNodeRef)
 | 
			
		||||
    {
 | 
			
		||||
        final NodeRef ruleNodeRef = validateNode(ruleId, RuleModel.TYPE_RULE, null);
 | 
			
		||||
        if (associatedRuleSetNodeRef != null && !ruleService.isRuleAssociatedWithRuleSet(ruleNodeRef, associatedRuleSetNodeRef))
 | 
			
		||||
@@ -194,11 +142,79 @@ public class RulesImpl implements Rules
 | 
			
		||||
        return nodeRef;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void verifyNodeType(final NodeRef nodeRef, final QName expectedType, final String expectedTypeName) {
 | 
			
		||||
    private void validatePermission(boolean requireChangePermission, NodeRef nodeRef)
 | 
			
		||||
    {
 | 
			
		||||
        if (requireChangePermission)
 | 
			
		||||
        {
 | 
			
		||||
            if (permissionService.hasPermission(nodeRef, CHANGE_PERMISSIONS) != ALLOWED)
 | 
			
		||||
            {
 | 
			
		||||
                throw new PermissionDeniedException("Insufficient permissions to manage rules.");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            if (permissionService.hasReadPermission(nodeRef) != ALLOWED)
 | 
			
		||||
            {
 | 
			
		||||
                throw new PermissionDeniedException("Cannot read from this node!");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void verifyNodeType(final NodeRef nodeRef, final QName expectedType, final String expectedTypeName)
 | 
			
		||||
    {
 | 
			
		||||
        final Set<QName> expectedTypes = Set.of(expectedType);
 | 
			
		||||
        if (!nodes.nodeMatches(nodeRef, expectedTypes, null)) {
 | 
			
		||||
            final String expectedTypeLocalName = (expectedTypeName != null)? expectedTypeName : expectedType.getLocalName();
 | 
			
		||||
        if (!nodes.nodeMatches(nodeRef, expectedTypes, null))
 | 
			
		||||
        {
 | 
			
		||||
            final String expectedTypeLocalName = (expectedTypeName != null) ? expectedTypeName : expectedType.getLocalName();
 | 
			
		||||
            throw new InvalidArgumentException(String.format("NodeId of a %s is expected!", expectedTypeLocalName));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isRuleSetNode(String nodeId) {
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            validateNode(nodeId, ContentModel.TYPE_SYSTEM_FOLDER, RULE_SET_EXPECTED_TYPE_NAME);
 | 
			
		||||
            return true;
 | 
			
		||||
        } catch (InvalidArgumentException e) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef)
 | 
			
		||||
    {
 | 
			
		||||
        if (ruleSetNodeRef == null && folderNodeRef != null)
 | 
			
		||||
        {
 | 
			
		||||
            final NodeRef ruleSetNode = ruleService.getRuleSetNode(folderNodeRef);
 | 
			
		||||
            return ruleSetNode != null && ruleService.isRuleSetShared(ruleSetNode);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            return isRuleSetNotNullAndShared(ruleSetNodeRef);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef)
 | 
			
		||||
    {
 | 
			
		||||
        return ruleSetNodeRef != null && ruleService.isRuleSetShared(ruleSetNodeRef);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setPermissionService(PermissionService permissionService)
 | 
			
		||||
    {
 | 
			
		||||
        this.permissionService = permissionService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRuleService(RuleService ruleService)
 | 
			
		||||
    {
 | 
			
		||||
        this.ruleService = ruleService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNodes(Nodes nodes)
 | 
			
		||||
    {
 | 
			
		||||
        this.nodes = nodes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNodeService(NodeService nodeService)
 | 
			
		||||
    {
 | 
			
		||||
        this.nodeService = nodeService;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.model.rules.Rule;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.rule.RuleService;
 | 
			
		||||
 | 
			
		||||
/** Responsible for creating {@link Rule} objects. */
 | 
			
		||||
@Experimental
 | 
			
		||||
public class RuleLoader
 | 
			
		||||
{
 | 
			
		||||
    public static final String IS_SHARED = "isShared";
 | 
			
		||||
    private RuleService ruleService;
 | 
			
		||||
    private NodeValidator nodeValidator;
 | 
			
		||||
 | 
			
		||||
    public Rule loadRule(org.alfresco.service.cmr.rule.Rule ruleModel, List<String> includes)
 | 
			
		||||
    {
 | 
			
		||||
        Rule rule = Rule.from(ruleModel);
 | 
			
		||||
        if (includes != null && includes.contains(IS_SHARED))
 | 
			
		||||
        {
 | 
			
		||||
            NodeRef ruleSet = ruleService.getRuleSetNode(ruleModel.getNodeRef());
 | 
			
		||||
            boolean isShared = nodeValidator.isRuleSetNotNullAndShared(ruleSet);
 | 
			
		||||
            rule.setIsShared(isShared);
 | 
			
		||||
        }
 | 
			
		||||
        return rule;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRuleService(RuleService ruleService)
 | 
			
		||||
    {
 | 
			
		||||
        this.ruleService = ruleService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNodeValidator(NodeValidator nodeValidator)
 | 
			
		||||
    {
 | 
			
		||||
        this.nodeValidator = nodeValidator;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,90 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.InclusionType.INHERITED;
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.InclusionType.LINKED;
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.InclusionType.OWNED;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSet;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeService;
 | 
			
		||||
 | 
			
		||||
/** Responsible for converting a NodeRef into a {@link RuleSet} object. */
 | 
			
		||||
@Experimental
 | 
			
		||||
public class RuleSetLoader
 | 
			
		||||
{
 | 
			
		||||
    protected static final String OWNING_FOLDER = "owningFolder";
 | 
			
		||||
    protected static final String INCLUSION_TYPE = "inclusionType";
 | 
			
		||||
    private NodeService nodeService;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load a rule set for the given node ref.
 | 
			
		||||
     *
 | 
			
		||||
     * @param ruleSetNodeRef The rule set node.
 | 
			
		||||
     * @param includes A list of fields to include.
 | 
			
		||||
     * @return The rule set object.
 | 
			
		||||
     */
 | 
			
		||||
    public RuleSet loadRuleSet(NodeRef ruleSetNodeRef, NodeRef folderNodeRef, List<String> includes)
 | 
			
		||||
    {
 | 
			
		||||
        String ruleSetId = ruleSetNodeRef.getId();
 | 
			
		||||
        RuleSet ruleSet = RuleSet.of(ruleSetId);
 | 
			
		||||
 | 
			
		||||
        if (includes != null)
 | 
			
		||||
        {
 | 
			
		||||
            NodeRef parentRef = nodeService.getPrimaryParent(ruleSetNodeRef).getParentRef();
 | 
			
		||||
            if (includes.contains(OWNING_FOLDER))
 | 
			
		||||
            {
 | 
			
		||||
                ruleSet.setOwningFolder(parentRef);
 | 
			
		||||
            }
 | 
			
		||||
            if (includes.contains(INCLUSION_TYPE))
 | 
			
		||||
            {
 | 
			
		||||
                // In the case that a rule set applies to the given folder for multiple reasons then priority is given to owned, then linked, then inherited.
 | 
			
		||||
                if (parentRef.equals(folderNodeRef))
 | 
			
		||||
                {
 | 
			
		||||
                    ruleSet.setInclusionType(OWNED);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    boolean linked = nodeService.getParentAssocs(ruleSetNodeRef)
 | 
			
		||||
                                           .stream().map(ChildAssociationRef::getParentRef)
 | 
			
		||||
                                           .anyMatch(folderNodeRef::equals);
 | 
			
		||||
                    ruleSet.setInclusionType(linked ? LINKED : INHERITED);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ruleSet;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNodeService(NodeService nodeService)
 | 
			
		||||
    {
 | 
			
		||||
        this.nodeService = nodeService;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,134 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import static java.util.stream.Collectors.toList;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.repo.rule.RuleModel;
 | 
			
		||||
import org.alfresco.repo.rule.RuntimeRuleService;
 | 
			
		||||
import org.alfresco.rest.api.RuleSets;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSet;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSetLink;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.ListPage;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Paging;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeService;
 | 
			
		||||
import org.alfresco.service.cmr.rule.RuleService;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public class RuleSetsImpl implements RuleSets
 | 
			
		||||
{
 | 
			
		||||
    private RuleSetLoader ruleSetLoader;
 | 
			
		||||
    private RuleService ruleService;
 | 
			
		||||
    private NodeValidator validator;
 | 
			
		||||
    private NodeService nodeService;
 | 
			
		||||
    private RuntimeRuleService runtimeRuleService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public CollectionWithPagingInfo<RuleSet> getRuleSets(String folderNodeId, List<String> includes, Paging paging)
 | 
			
		||||
    {
 | 
			
		||||
        NodeRef folderNode = validator.validateFolderNode(folderNodeId, false);
 | 
			
		||||
 | 
			
		||||
        NodeRef ruleSetNode = ruleService.getRuleSetNode(folderNode);
 | 
			
		||||
        List<RuleSet> ruleSets = Optional.ofNullable(ruleSetNode)
 | 
			
		||||
                                         .map(nodeRef -> ruleSetLoader.loadRuleSet(nodeRef, folderNode, includes))
 | 
			
		||||
                                                                      .stream().collect(toList());
 | 
			
		||||
 | 
			
		||||
        return ListPage.of(ruleSets, paging);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public RuleSet getRuleSetById(String folderNodeId, String ruleSetId, List<String> includes)
 | 
			
		||||
    {
 | 
			
		||||
        NodeRef folderNode = validator.validateFolderNode(folderNodeId, false);
 | 
			
		||||
        NodeRef ruleSetNode = validator.validateRuleSetNode(ruleSetId, folderNode);
 | 
			
		||||
 | 
			
		||||
        return ruleSetLoader.loadRuleSet(ruleSetNode, folderNode, includes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public RuleSetLink linkToRuleSet(String folderNodeId, String linkToNodeId)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId,true);
 | 
			
		||||
        final boolean isRuleSetNode = validator.isRuleSetNode(linkToNodeId);
 | 
			
		||||
        final NodeRef linkToNodeRef = isRuleSetNode
 | 
			
		||||
                ? validator.validateRuleSetNode(linkToNodeId, true)
 | 
			
		||||
                : validator.validateFolderNode(linkToNodeId, true);
 | 
			
		||||
 | 
			
		||||
        //The target node should have pre-existing rules to link to
 | 
			
		||||
        if (!ruleService.hasRules(linkToNodeRef)) {
 | 
			
		||||
            throw new InvalidArgumentException("The target node has no rules to link.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //The folder shouldn't have any pre-existing rules
 | 
			
		||||
        if (ruleService.hasRules(folderNodeRef)) {
 | 
			
		||||
            throw new InvalidArgumentException("Unable to link to a ruleset because the folder has pre-existing rules or is already linked to a ruleset.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Create the destination folder as a secondary child of the first
 | 
			
		||||
        NodeRef ruleSetNodeRef = runtimeRuleService.getSavedRuleFolderAssoc(linkToNodeRef).getChildRef();
 | 
			
		||||
        // The required aspect will automatically be added to the node
 | 
			
		||||
        nodeService.addChild(folderNodeRef, ruleSetNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER);
 | 
			
		||||
 | 
			
		||||
        RuleSetLink ruleSetLink = new RuleSetLink();
 | 
			
		||||
        ruleSetLink.setId(ruleSetNodeRef.getId());
 | 
			
		||||
 | 
			
		||||
        return ruleSetLink;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRuleSetLoader(RuleSetLoader ruleSetLoader)
 | 
			
		||||
    {
 | 
			
		||||
        this.ruleSetLoader = ruleSetLoader;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setValidator(NodeValidator validator)
 | 
			
		||||
    {
 | 
			
		||||
        this.validator = validator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRuleService(RuleService ruleService)
 | 
			
		||||
    {
 | 
			
		||||
        this.ruleService = ruleService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNodeService(NodeService nodeService)
 | 
			
		||||
    {
 | 
			
		||||
        this.nodeService = nodeService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRuntimeRuleService(RuntimeRuleService runtimeRuleService)
 | 
			
		||||
    {
 | 
			
		||||
        this.runtimeRuleService = runtimeRuleService;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,107 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.repo.rule.RuleModel.ASPECT_IGNORE_INHERITED_RULES;
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.RuleSetting.IS_INHERITANCE_ENABLED_KEY;
 | 
			
		||||
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.RuleSettings;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSetting;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.NotFoundException;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeService;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public class RuleSettingsImpl implements RuleSettings
 | 
			
		||||
{
 | 
			
		||||
    private NodeValidator validator;
 | 
			
		||||
    private NodeService nodeService;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public RuleSetting getRuleSetting(String folderId, String ruleSettingKey)
 | 
			
		||||
    {
 | 
			
		||||
        NodeRef folderNode = validator.validateFolderNode(folderId, false);
 | 
			
		||||
        switch (ruleSettingKey)
 | 
			
		||||
        {
 | 
			
		||||
            case IS_INHERITANCE_ENABLED_KEY:
 | 
			
		||||
                return getIsInheritanceEnabled(folderNode);
 | 
			
		||||
            default:
 | 
			
		||||
                throw new NotFoundException("Unrecognised rule setting key " + ruleSettingKey);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private RuleSetting getIsInheritanceEnabled(NodeRef folderNode)
 | 
			
		||||
    {
 | 
			
		||||
        boolean inheritanceDisabled = nodeService.hasAspect(folderNode, ASPECT_IGNORE_INHERITED_RULES);
 | 
			
		||||
        return RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(!inheritanceDisabled).create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public RuleSetting setRuleSetting(String folderId, RuleSetting ruleSetting)
 | 
			
		||||
    {
 | 
			
		||||
        NodeRef folderNode = validator.validateFolderNode(folderId, true);
 | 
			
		||||
 | 
			
		||||
        switch (ruleSetting.getKey())
 | 
			
		||||
        {
 | 
			
		||||
            case IS_INHERITANCE_ENABLED_KEY:
 | 
			
		||||
                return updateIsInheritanceEnabled(folderNode, ruleSetting.getValue());
 | 
			
		||||
            default:
 | 
			
		||||
                throw new NotFoundException("Unrecognised rule setting key " + ruleSetting.getKey());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private RuleSetting updateIsInheritanceEnabled(NodeRef folderNode, Object value)
 | 
			
		||||
    {
 | 
			
		||||
        if (!(value instanceof Boolean))
 | 
			
		||||
        {
 | 
			
		||||
            throw new IllegalArgumentException("Rule setting " + IS_INHERITANCE_ENABLED_KEY + " requires a boolean value.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((boolean) value)
 | 
			
		||||
        {
 | 
			
		||||
            nodeService.removeAspect(folderNode, ASPECT_IGNORE_INHERITED_RULES);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            nodeService.addAspect(folderNode, ASPECT_IGNORE_INHERITED_RULES, Collections.emptyMap());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(value).create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setValidator(NodeValidator validator)
 | 
			
		||||
    {
 | 
			
		||||
        this.validator = validator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNodeService(NodeService nodeService)
 | 
			
		||||
    {
 | 
			
		||||
        this.nodeService = nodeService;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,177 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.Nodes;
 | 
			
		||||
import org.alfresco.rest.api.Rules;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.Rule;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSet;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.ListPage;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Paging;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.action.CompositeAction;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.rule.RuleService;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public class RulesImpl implements Rules
 | 
			
		||||
{
 | 
			
		||||
    private static final Logger LOGGER = LoggerFactory.getLogger(RulesImpl.class);
 | 
			
		||||
 | 
			
		||||
    private Nodes nodes;
 | 
			
		||||
    private RuleService ruleService;
 | 
			
		||||
    private NodeValidator validator;
 | 
			
		||||
    private RuleLoader ruleLoader;
 | 
			
		||||
    private ActionParameterConverter actionParameterConverter;
 | 
			
		||||
    private ActionPermissionValidator actionPermissionValidator;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public CollectionWithPagingInfo<Rule> getRules(final String folderNodeId,
 | 
			
		||||
                                                   final String ruleSetId,
 | 
			
		||||
                                                   final List<String> includes,
 | 
			
		||||
                                                   final Paging paging)
 | 
			
		||||
    {
 | 
			
		||||
        final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, false);
 | 
			
		||||
        validator.validateRuleSetNode(ruleSetId, folderNodeRef);
 | 
			
		||||
 | 
			
		||||
        final List<Rule> rules = ruleService.getRules(folderNodeRef).stream()
 | 
			
		||||
                .map(ruleModel -> loadRuleAndConvertActionParams(ruleModel, includes))
 | 
			
		||||
                .collect(Collectors.toList());
 | 
			
		||||
 | 
			
		||||
        return ListPage.of(rules, paging);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Rule getRuleById(final String folderNodeId, final String ruleSetId, final String ruleId, final List<String> includes)
 | 
			
		||||
    {
 | 
			
		||||
        final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, false);
 | 
			
		||||
        final NodeRef ruleSetNodeRef = validator.validateRuleSetNode(ruleSetId, folderNodeRef);
 | 
			
		||||
        final NodeRef ruleNodeRef = validator.validateRuleNode(ruleId, ruleSetNodeRef);
 | 
			
		||||
 | 
			
		||||
        return loadRuleAndConvertActionParams(ruleService.getRule(ruleNodeRef), includes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<Rule> createRules(final String folderNodeId, final String ruleSetId, final List<Rule> rules, final List<String> includes)
 | 
			
		||||
    {
 | 
			
		||||
        final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, true);
 | 
			
		||||
        // Don't validate the ruleset node if -default- is passed since we may need to create it.
 | 
			
		||||
        if (RuleSet.isNotDefaultId(ruleSetId))
 | 
			
		||||
        {
 | 
			
		||||
            validator.validateRuleSetNode(ruleSetId, folderNodeRef);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return rules.stream()
 | 
			
		||||
                .map(this::mapToServiceModelAndValidateActions)
 | 
			
		||||
                .map(rule -> ruleService.saveRule(folderNodeRef, rule))
 | 
			
		||||
                .map(rule -> loadRuleAndConvertActionParams(rule, includes))
 | 
			
		||||
                .collect(Collectors.toList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public Rule updateRuleById(String folderNodeId, String ruleSetId, String ruleId, Rule rule, List<String> includes)
 | 
			
		||||
    {
 | 
			
		||||
        LOGGER.debug("Updating rule in folder {}, rule set {}, rule {} to {}", folderNodeId, ruleSetId, ruleId, rule);
 | 
			
		||||
 | 
			
		||||
        NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, true);
 | 
			
		||||
        NodeRef ruleSetNodeRef = validator.validateRuleSetNode(ruleSetId, folderNodeRef);
 | 
			
		||||
        validator.validateRuleNode(ruleId, ruleSetNodeRef);
 | 
			
		||||
 | 
			
		||||
        return ruleLoader.loadRule(ruleService.saveRule(folderNodeRef, mapToServiceModelAndValidateActions(rule)), includes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void deleteRuleById(String folderNodeId, String ruleSetId, String ruleId)
 | 
			
		||||
    {
 | 
			
		||||
        final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, true);
 | 
			
		||||
        final NodeRef ruleSetNodeRef = validator.validateRuleSetNode(ruleSetId, folderNodeRef);
 | 
			
		||||
        final NodeRef ruleNodeRef = validator.validateRuleNode(ruleId, ruleSetNodeRef);
 | 
			
		||||
        final org.alfresco.service.cmr.rule.Rule rule = ruleService.getRule(ruleNodeRef);
 | 
			
		||||
        ruleService.removeRule(folderNodeRef, rule);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private org.alfresco.service.cmr.rule.Rule mapToServiceModelAndValidateActions(Rule rule)
 | 
			
		||||
    {
 | 
			
		||||
        final org.alfresco.service.cmr.rule.Rule serviceModelRule = rule.toServiceModel(nodes);
 | 
			
		||||
        final CompositeAction compositeAction = (CompositeAction) serviceModelRule.getAction();
 | 
			
		||||
        compositeAction.getActions().forEach(action -> action.setParameterValues(
 | 
			
		||||
                actionParameterConverter.getConvertedParams(action.getParameterValues(), action.getActionDefinitionName())));
 | 
			
		||||
 | 
			
		||||
        return actionPermissionValidator.validateRulePermissions(serviceModelRule);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Rule loadRuleAndConvertActionParams(org.alfresco.service.cmr.rule.Rule ruleModel, List<String> includes)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        final Rule rule = ruleLoader.loadRule(ruleModel, includes);
 | 
			
		||||
        rule.getActions()
 | 
			
		||||
                .forEach(a -> a.setParams(a.getParams().entrySet()
 | 
			
		||||
                                .stream()
 | 
			
		||||
                                .collect(Collectors
 | 
			
		||||
                                        .toMap(Map.Entry::getKey, e -> actionParameterConverter.convertParamFromServiceModel(e.getValue())))
 | 
			
		||||
                        )
 | 
			
		||||
                );
 | 
			
		||||
        return rule;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setNodes(Nodes nodes)
 | 
			
		||||
    {
 | 
			
		||||
        this.nodes = nodes;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRuleService(RuleService ruleService)
 | 
			
		||||
    {
 | 
			
		||||
        this.ruleService = ruleService;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setValidator(NodeValidator validator)
 | 
			
		||||
    {
 | 
			
		||||
        this.validator = validator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRuleLoader(RuleLoader ruleLoader)
 | 
			
		||||
    {
 | 
			
		||||
        this.ruleLoader = ruleLoader;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setActionParameterConverter(ActionParameterConverter actionParameterConverter)
 | 
			
		||||
    {
 | 
			
		||||
        this.actionParameterConverter = actionParameterConverter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setActionPermissionValidator(ActionPermissionValidator actionPermissionValidator)
 | 
			
		||||
    {
 | 
			
		||||
        this.actionPermissionValidator = actionPermissionValidator;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,169 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.model.rules;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.repo.action.ActionImpl;
 | 
			
		||||
import org.alfresco.repo.action.CompositeActionImpl;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.util.GUID;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public class Action
 | 
			
		||||
{
 | 
			
		||||
    private String actionDefinitionId;
 | 
			
		||||
    private Map<String, Serializable> params;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Converts service POJO action to REST model action.
 | 
			
		||||
     *
 | 
			
		||||
     * @param actionModel - {@link org.alfresco.service.cmr.action.Action} service POJO
 | 
			
		||||
     * @return {@link Action} REST model
 | 
			
		||||
     */
 | 
			
		||||
    public static Action from(final org.alfresco.service.cmr.action.Action actionModel)
 | 
			
		||||
    {
 | 
			
		||||
        if (actionModel == null)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        final Action.Builder builder = builder().actionDefinitionId(actionModel.getActionDefinitionName());
 | 
			
		||||
        if (actionModel.getParameterValues() != null)
 | 
			
		||||
        {
 | 
			
		||||
            builder.params(new HashMap<>(actionModel.getParameterValues()));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return builder.create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert the REST model object to the equivalent service POJO.
 | 
			
		||||
     *
 | 
			
		||||
     * @param nodeRef The node reference.
 | 
			
		||||
     * @return The action service POJO.
 | 
			
		||||
     */
 | 
			
		||||
    public org.alfresco.service.cmr.action.Action toServiceModel(final NodeRef nodeRef)
 | 
			
		||||
    {
 | 
			
		||||
        return new ActionImpl(nodeRef, GUID.generate(), this.actionDefinitionId, params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Convert the REST model objects to composite action service POJO.
 | 
			
		||||
     *
 | 
			
		||||
     * @param actions List of actions.
 | 
			
		||||
     * @return The composite action service POJO.
 | 
			
		||||
     */
 | 
			
		||||
    public static org.alfresco.service.cmr.action.Action toCompositeAction(final List<Action> actions) {
 | 
			
		||||
        if (actions == null)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        final org.alfresco.service.cmr.action.CompositeAction compositeAction = new CompositeActionImpl(null, GUID.generate());
 | 
			
		||||
        actions.forEach(action -> compositeAction.addAction(action.toServiceModel(null)));
 | 
			
		||||
        return compositeAction;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getActionDefinitionId()
 | 
			
		||||
    {
 | 
			
		||||
        return actionDefinitionId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setActionDefinitionId(String actionDefinitionId)
 | 
			
		||||
    {
 | 
			
		||||
        this.actionDefinitionId = actionDefinitionId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Map<String, Serializable> getParams()
 | 
			
		||||
    {
 | 
			
		||||
        return params;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setParams(Map<String, Serializable> params)
 | 
			
		||||
    {
 | 
			
		||||
        this.params = params;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString()
 | 
			
		||||
    {
 | 
			
		||||
        return "Action{" + "actionDefinitionId='" + actionDefinitionId + '\'' + ", params=" + params + '}';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object o)
 | 
			
		||||
    {
 | 
			
		||||
        if (this == o)
 | 
			
		||||
            return true;
 | 
			
		||||
        if (o == null || getClass() != o.getClass())
 | 
			
		||||
            return false;
 | 
			
		||||
        Action action = (Action) o;
 | 
			
		||||
        return Objects.equals(actionDefinitionId, action.actionDefinitionId) && Objects.equals(params, action.params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode()
 | 
			
		||||
    {
 | 
			
		||||
        return Objects.hash(actionDefinitionId, params);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Builder builder()
 | 
			
		||||
    {
 | 
			
		||||
        return new Builder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Builder
 | 
			
		||||
    {
 | 
			
		||||
        private String actionDefinitionId;
 | 
			
		||||
        private Map<String, Serializable> params;
 | 
			
		||||
 | 
			
		||||
        public Builder actionDefinitionId(String actionDefinitionId)
 | 
			
		||||
        {
 | 
			
		||||
            this.actionDefinitionId = actionDefinitionId;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder params(Map<String, Serializable> params)
 | 
			
		||||
        {
 | 
			
		||||
            this.params = params;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Action create() {
 | 
			
		||||
            final Action action = new Action();
 | 
			
		||||
            action.setActionDefinitionId(actionDefinitionId);
 | 
			
		||||
            action.setParams(params);
 | 
			
		||||
            return action;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,230 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.model.rules;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.action.ActionCondition;
 | 
			
		||||
import org.apache.commons.collections.CollectionUtils;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public class CompositeCondition
 | 
			
		||||
{
 | 
			
		||||
    private boolean inverted;
 | 
			
		||||
    private ConditionOperator booleanMode = ConditionOperator.AND;
 | 
			
		||||
    private List<CompositeCondition> compositeConditions;
 | 
			
		||||
    private List<SimpleCondition> simpleConditions;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Converts Action conditions (service POJO) list to composite condition (REST model).
 | 
			
		||||
     *
 | 
			
		||||
     * @param actionConditions - list of {@link ActionCondition} service POJOs
 | 
			
		||||
     * @return {@link CompositeCondition} REST model
 | 
			
		||||
     */
 | 
			
		||||
    public static CompositeCondition from(final List<ActionCondition> actionConditions)
 | 
			
		||||
    {
 | 
			
		||||
        if (actionConditions == null)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        final CompositeCondition conditions = new CompositeCondition();
 | 
			
		||||
        conditions.compositeConditions = new ArrayList<>();
 | 
			
		||||
        // group action conditions by inversion flag
 | 
			
		||||
        actionConditions.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(ActionCondition::getInvertCondition))
 | 
			
		||||
            // map action condition sub lists
 | 
			
		||||
            .forEach((inverted, actionConditionsPart) -> Optional.ofNullable(CompositeCondition.ofActionConditions(actionConditionsPart, inverted, ConditionOperator.AND))
 | 
			
		||||
                // if composite condition present add to final list
 | 
			
		||||
                .ifPresent(compositeCondition -> conditions.compositeConditions.add(compositeCondition)));
 | 
			
		||||
 | 
			
		||||
        if (conditions.compositeConditions.isEmpty()) {
 | 
			
		||||
            conditions.compositeConditions = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return conditions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static CompositeCondition ofActionConditions(final List<ActionCondition> actionConditions, final boolean inverted, final ConditionOperator conditionOperator)
 | 
			
		||||
    {
 | 
			
		||||
        if (actionConditions == null)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ofSimpleConditions(SimpleCondition.listOf(actionConditions), inverted, conditionOperator);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates a composite condition instance of simple conditions.
 | 
			
		||||
     *
 | 
			
		||||
     * @param simpleConditions - list of {@link SimpleCondition}
 | 
			
		||||
     * @param inverted - determines if condition should be inverted
 | 
			
		||||
     * @param conditionOperator - determines the operation, see {@link ConditionOperator}
 | 
			
		||||
     * @return {@link CompositeCondition}
 | 
			
		||||
     */
 | 
			
		||||
    public static CompositeCondition ofSimpleConditions(final List<SimpleCondition> simpleConditions, final boolean inverted, final ConditionOperator conditionOperator)
 | 
			
		||||
    {
 | 
			
		||||
        return of(simpleConditions, null, inverted, conditionOperator);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static CompositeCondition of(final List<SimpleCondition> simpleConditions, final List<CompositeCondition> compositeConditions,
 | 
			
		||||
        final boolean inverted, final ConditionOperator conditionOperator)
 | 
			
		||||
    {
 | 
			
		||||
        if (CollectionUtils.isEmpty(simpleConditions) && CollectionUtils.isEmpty(compositeConditions))
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return builder()
 | 
			
		||||
            .inverted(inverted)
 | 
			
		||||
            .booleanMode(conditionOperator)
 | 
			
		||||
            .simpleConditions(simpleConditions)
 | 
			
		||||
            .compositeConditions(compositeConditions)
 | 
			
		||||
            .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isInverted()
 | 
			
		||||
    {
 | 
			
		||||
        return inverted;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setInverted(boolean inverted)
 | 
			
		||||
    {
 | 
			
		||||
        this.inverted = inverted;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getBooleanMode()
 | 
			
		||||
    {
 | 
			
		||||
        if (booleanMode == null)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return booleanMode.name().toLowerCase();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setBooleanMode(ConditionOperator booleanMode)
 | 
			
		||||
    {
 | 
			
		||||
        this.booleanMode = booleanMode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<CompositeCondition> getCompositeConditions()
 | 
			
		||||
    {
 | 
			
		||||
        return compositeConditions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setCompositeConditions(List<CompositeCondition> compositeConditions)
 | 
			
		||||
    {
 | 
			
		||||
        this.compositeConditions = compositeConditions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<SimpleCondition> getSimpleConditions()
 | 
			
		||||
    {
 | 
			
		||||
        return simpleConditions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSimpleConditions(List<SimpleCondition> simpleConditions)
 | 
			
		||||
    {
 | 
			
		||||
        this.simpleConditions = simpleConditions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString()
 | 
			
		||||
    {
 | 
			
		||||
        return "CompositeCondition{" + "inverted=" + inverted + ", booleanMode=" + booleanMode + ", compositeConditions=" + compositeConditions + ", simpleConditions="
 | 
			
		||||
            + simpleConditions + '}';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object o)
 | 
			
		||||
    {
 | 
			
		||||
        if (this == o)
 | 
			
		||||
            return true;
 | 
			
		||||
        if (o == null || getClass() != o.getClass())
 | 
			
		||||
            return false;
 | 
			
		||||
        CompositeCondition that = (CompositeCondition) o;
 | 
			
		||||
        return inverted == that.inverted && booleanMode == that.booleanMode && Objects.equals(compositeConditions, that.compositeConditions) && Objects.equals(
 | 
			
		||||
            simpleConditions, that.simpleConditions);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode()
 | 
			
		||||
    {
 | 
			
		||||
        return Objects.hash(inverted, booleanMode, compositeConditions, simpleConditions);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Builder builder()
 | 
			
		||||
    {
 | 
			
		||||
        return new Builder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Builder
 | 
			
		||||
    {
 | 
			
		||||
        private boolean inverted;
 | 
			
		||||
        private ConditionOperator booleanMode = ConditionOperator.AND;
 | 
			
		||||
        private List<CompositeCondition> compositeConditions;
 | 
			
		||||
        private List<SimpleCondition> simpleConditions;
 | 
			
		||||
 | 
			
		||||
        public Builder inverted(boolean inverted)
 | 
			
		||||
        {
 | 
			
		||||
            this.inverted = inverted;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder booleanMode(ConditionOperator booleanMode)
 | 
			
		||||
        {
 | 
			
		||||
            this.booleanMode = booleanMode;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder compositeConditions(List<CompositeCondition> compositeConditions)
 | 
			
		||||
        {
 | 
			
		||||
            this.compositeConditions = compositeConditions;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder simpleConditions(List<SimpleCondition> simpleConditions)
 | 
			
		||||
        {
 | 
			
		||||
            this.simpleConditions = simpleConditions;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public CompositeCondition create()
 | 
			
		||||
        {
 | 
			
		||||
            final CompositeCondition condition = new CompositeCondition();
 | 
			
		||||
            condition.setInverted(inverted);
 | 
			
		||||
            condition.setBooleanMode(booleanMode);
 | 
			
		||||
            condition.setCompositeConditions(compositeConditions);
 | 
			
		||||
            condition.setSimpleConditions(simpleConditions);
 | 
			
		||||
            return condition;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.model.rules;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public enum ConditionOperator
 | 
			
		||||
{
 | 
			
		||||
    AND, OR
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,59 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api.model.rules;
 | 
			
		||||
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonValue;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
 | 
			
		||||
/** The reason why a rule set applies to a folder. */
 | 
			
		||||
@Experimental
 | 
			
		||||
public enum InclusionType
 | 
			
		||||
{
 | 
			
		||||
    OWNED, INHERITED, LINKED;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Load an InclusionType from a given string (case insensitively).
 | 
			
		||||
     *
 | 
			
		||||
     * @param inclusionType The given string.
 | 
			
		||||
     * @return The inclusion type.
 | 
			
		||||
     */
 | 
			
		||||
    public static InclusionType from(String inclusionType)
 | 
			
		||||
    {
 | 
			
		||||
        return InclusionType.valueOf(inclusionType.toUpperCase());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The lower case version of the inclusion type.
 | 
			
		||||
     *
 | 
			
		||||
     * @return A lowercase string.
 | 
			
		||||
     */
 | 
			
		||||
    @JsonValue
 | 
			
		||||
    public String toString()
 | 
			
		||||
    {
 | 
			
		||||
        return super.toString().toLowerCase();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -26,19 +26,16 @@
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.model.rules;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.model.ContentModel;
 | 
			
		||||
import org.alfresco.repo.action.ActionImpl;
 | 
			
		||||
import org.alfresco.repo.action.executer.SetPropertyValueActionExecuter;
 | 
			
		||||
import org.alfresco.repo.action.executer.ScriptActionExecuter;
 | 
			
		||||
import org.alfresco.rest.api.Nodes;
 | 
			
		||||
import org.alfresco.rest.framework.resource.UniqueId;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.action.Action;
 | 
			
		||||
import org.alfresco.service.cmr.action.CompositeAction;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.util.GUID;
 | 
			
		||||
 | 
			
		||||
@@ -47,16 +44,57 @@ public class Rule
 | 
			
		||||
{
 | 
			
		||||
    private String id;
 | 
			
		||||
    private String name;
 | 
			
		||||
    private String description;
 | 
			
		||||
    private boolean enabled;
 | 
			
		||||
    private boolean cascade;
 | 
			
		||||
    private boolean asynchronous;
 | 
			
		||||
    private Boolean isShared;
 | 
			
		||||
    private String errorScript;
 | 
			
		||||
    private List<RuleTrigger> triggers = List.of(RuleTrigger.INBOUND);
 | 
			
		||||
    private CompositeCondition conditions;
 | 
			
		||||
    private List<Action> actions;
 | 
			
		||||
 | 
			
		||||
    public static Rule from(final org.alfresco.service.cmr.rule.Rule ruleModel) {
 | 
			
		||||
        if (ruleModel == null) {
 | 
			
		||||
    /**
 | 
			
		||||
     * Converts service POJO rule to REST model rule.
 | 
			
		||||
     *
 | 
			
		||||
     * @param ruleModel - {@link org.alfresco.service.cmr.rule.Rule} service POJO
 | 
			
		||||
     * @return {@link Rule} REST model
 | 
			
		||||
     */
 | 
			
		||||
    public static Rule from(final org.alfresco.service.cmr.rule.Rule ruleModel)
 | 
			
		||||
    {
 | 
			
		||||
        if (ruleModel == null)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return builder()
 | 
			
		||||
                .setId(ruleModel.getNodeRef().getId())
 | 
			
		||||
                .setName(ruleModel.getTitle())
 | 
			
		||||
                .createRule();
 | 
			
		||||
        final Rule.Builder builder = builder()
 | 
			
		||||
            .name(ruleModel.getTitle())
 | 
			
		||||
            .description(ruleModel.getDescription())
 | 
			
		||||
            .enabled(!ruleModel.getRuleDisabled())
 | 
			
		||||
            .cascade(ruleModel.isAppliedToChildren())
 | 
			
		||||
            .asynchronous(ruleModel.getExecuteAsynchronously());
 | 
			
		||||
 | 
			
		||||
        if (ruleModel.getNodeRef() != null) {
 | 
			
		||||
            builder.id(ruleModel.getNodeRef().getId());
 | 
			
		||||
        }
 | 
			
		||||
        if (ruleModel.getRuleTypes() != null)
 | 
			
		||||
        {
 | 
			
		||||
            builder.triggers(ruleModel.getRuleTypes().stream().map(RuleTrigger::of).collect(Collectors.toList()));
 | 
			
		||||
        }
 | 
			
		||||
        if (ruleModel.getAction() != null)
 | 
			
		||||
        {
 | 
			
		||||
            builder.conditions(CompositeCondition.from(ruleModel.getAction().getActionConditions()));
 | 
			
		||||
            if (ruleModel.getAction().getCompensatingAction() != null && ruleModel.getAction().getCompensatingAction().getParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF) != null)
 | 
			
		||||
            {
 | 
			
		||||
                builder.errorScript(ruleModel.getAction().getCompensatingAction().getParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF).toString());
 | 
			
		||||
            }
 | 
			
		||||
            if (ruleModel.getAction() instanceof CompositeAction && ((CompositeAction) ruleModel.getAction()).getActions() != null)
 | 
			
		||||
            {
 | 
			
		||||
                builder.actions(((CompositeAction) ruleModel.getAction()).getActions().stream().map(Action::from).collect(Collectors.toList()));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return builder.create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -67,20 +105,25 @@ public class Rule
 | 
			
		||||
     */
 | 
			
		||||
    public org.alfresco.service.cmr.rule.Rule toServiceModel(Nodes nodes)
 | 
			
		||||
    {
 | 
			
		||||
        org.alfresco.service.cmr.rule.Rule ruleModel = new org.alfresco.service.cmr.rule.Rule();
 | 
			
		||||
        if (id != null)
 | 
			
		||||
        {
 | 
			
		||||
            NodeRef nodeRef = nodes.validateOrLookupNode(id, null);
 | 
			
		||||
            ruleModel.setNodeRef(nodeRef);
 | 
			
		||||
        }
 | 
			
		||||
        final org.alfresco.service.cmr.rule.Rule ruleModel = new org.alfresco.service.cmr.rule.Rule();
 | 
			
		||||
        final NodeRef nodeRef = (id != null) ? nodes.validateOrLookupNode(id, null) : null;
 | 
			
		||||
        ruleModel.setNodeRef(nodeRef);
 | 
			
		||||
        ruleModel.setTitle(name);
 | 
			
		||||
 | 
			
		||||
        // TODO: Once we have actions working properly then this needs to be replaced.
 | 
			
		||||
        Map<String, Serializable> parameters = Map.of(
 | 
			
		||||
                SetPropertyValueActionExecuter.PARAM_PROPERTY, ContentModel.PROP_TITLE,
 | 
			
		||||
                SetPropertyValueActionExecuter.PARAM_VALUE, "UPDATED:" + GUID.generate());
 | 
			
		||||
        Action action = new ActionImpl(null, GUID.generate(), SetPropertyValueActionExecuter.NAME, parameters);
 | 
			
		||||
        ruleModel.setAction(action);
 | 
			
		||||
        ruleModel.setDescription(description);
 | 
			
		||||
        ruleModel.setRuleDisabled(!enabled);
 | 
			
		||||
        ruleModel.applyToChildren(cascade);
 | 
			
		||||
        ruleModel.setExecuteAsynchronously(asynchronous);
 | 
			
		||||
        if (triggers != null)
 | 
			
		||||
        {
 | 
			
		||||
            ruleModel.setRuleTypes(triggers.stream().map(RuleTrigger::getValue).collect(Collectors.toList()));
 | 
			
		||||
        }
 | 
			
		||||
        ruleModel.setAction(Action.toCompositeAction(actions));
 | 
			
		||||
        if (errorScript != null)
 | 
			
		||||
        {
 | 
			
		||||
            final org.alfresco.service.cmr.action.Action compensatingAction = new ActionImpl(null, GUID.generate(), ScriptActionExecuter.NAME);
 | 
			
		||||
            compensatingAction.setParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF, errorScript);
 | 
			
		||||
            ruleModel.getAction().setCompensatingAction(compensatingAction);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ruleModel;
 | 
			
		||||
    }
 | 
			
		||||
@@ -106,68 +149,243 @@ public class Rule
 | 
			
		||||
        this.name = name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO: Added stub for actions as it's a required field. Replace this implementation when we implement support for actions.
 | 
			
		||||
    public List<Void> getActions()
 | 
			
		||||
    public String getDescription()
 | 
			
		||||
    {
 | 
			
		||||
        return Collections.emptyList();
 | 
			
		||||
        return description;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setDescription(String description)
 | 
			
		||||
    {
 | 
			
		||||
        this.description = description;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isEnabled()
 | 
			
		||||
    {
 | 
			
		||||
        return enabled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setEnabled(boolean enabled)
 | 
			
		||||
    {
 | 
			
		||||
        this.enabled = enabled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isCascade()
 | 
			
		||||
    {
 | 
			
		||||
        return cascade;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setCascade(boolean cascade)
 | 
			
		||||
    {
 | 
			
		||||
        this.cascade = cascade;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isAsynchronous()
 | 
			
		||||
    {
 | 
			
		||||
        return asynchronous;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setAsynchronous(boolean asynchronous)
 | 
			
		||||
    {
 | 
			
		||||
        this.asynchronous = asynchronous;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getErrorScript()
 | 
			
		||||
    {
 | 
			
		||||
        return errorScript;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setErrorScript(String errorScript)
 | 
			
		||||
    {
 | 
			
		||||
        this.errorScript = errorScript;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Boolean isIsShared()
 | 
			
		||||
    {
 | 
			
		||||
        return isShared;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setIsShared(Boolean shared)
 | 
			
		||||
    {
 | 
			
		||||
        this.isShared = shared;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<String> getTriggers()
 | 
			
		||||
    {
 | 
			
		||||
        if (triggers == null)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        return triggers.stream().map(RuleTrigger::getValue).collect(Collectors.toList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setTriggers(List<String> triggers)
 | 
			
		||||
    {
 | 
			
		||||
        if (triggers != null)
 | 
			
		||||
        {
 | 
			
		||||
            this.triggers = triggers.stream().map(RuleTrigger::of).collect(Collectors.toList());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRuleTriggers(List<RuleTrigger> triggers)
 | 
			
		||||
    {
 | 
			
		||||
        this.triggers = triggers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public CompositeCondition getConditions()
 | 
			
		||||
    {
 | 
			
		||||
        return conditions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setConditions(CompositeCondition conditions)
 | 
			
		||||
    {
 | 
			
		||||
        this.conditions = conditions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<Action> getActions()
 | 
			
		||||
    {
 | 
			
		||||
        return actions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setActions(List<Action> actions)
 | 
			
		||||
    {
 | 
			
		||||
        this.actions = actions;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString()
 | 
			
		||||
    {
 | 
			
		||||
        return "Rule{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", description='" + description + '\'' + ", enabled=" + enabled + ", cascade=" + cascade
 | 
			
		||||
            + ", asynchronous=" + asynchronous + ", isShared=" + isShared + ", errorScript='" + errorScript + '\'' + ", triggers=" + triggers + ", conditions=" + conditions
 | 
			
		||||
            + ", actions=" + actions + '}';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object o)
 | 
			
		||||
    {
 | 
			
		||||
        if (this == o)
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (!(o instanceof Rule))
 | 
			
		||||
        {
 | 
			
		||||
        if (o == null || getClass() != o.getClass())
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        Rule rule = (Rule) o;
 | 
			
		||||
        return Objects.equals(id, rule.id) &&
 | 
			
		||||
                Objects.equals(name, rule.name);
 | 
			
		||||
        return enabled == rule.enabled
 | 
			
		||||
                && cascade == rule.cascade
 | 
			
		||||
                && asynchronous == rule.asynchronous
 | 
			
		||||
                && Objects.equals(isShared, rule.isShared)
 | 
			
		||||
                && Objects.equals(id, rule.id)
 | 
			
		||||
                && Objects.equals(name, rule.name)
 | 
			
		||||
                && Objects.equals(description, rule.description)
 | 
			
		||||
                && Objects.equals(errorScript, rule.errorScript)
 | 
			
		||||
                && Objects.equals(triggers, rule.triggers)
 | 
			
		||||
                && Objects.equals(conditions, rule.conditions)
 | 
			
		||||
                && Objects.equals(actions, rule.actions);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode()
 | 
			
		||||
    {
 | 
			
		||||
        return Objects.hash(id, name);
 | 
			
		||||
        return Objects.hash(id, name, description, enabled, cascade, asynchronous, isShared, errorScript, triggers, conditions, actions);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString()
 | 
			
		||||
    public static Builder builder()
 | 
			
		||||
    {
 | 
			
		||||
        return "Rule{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static RuleBuilder builder()
 | 
			
		||||
    {
 | 
			
		||||
        return new RuleBuilder();
 | 
			
		||||
        return new Builder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Builder class. */
 | 
			
		||||
    public static class RuleBuilder
 | 
			
		||||
    public static class Builder
 | 
			
		||||
    {
 | 
			
		||||
        private String id;
 | 
			
		||||
        private String name;
 | 
			
		||||
        private String description;
 | 
			
		||||
        private boolean enabled;
 | 
			
		||||
        private boolean cascade;
 | 
			
		||||
        private boolean asynchronous;
 | 
			
		||||
        private Boolean isShared;
 | 
			
		||||
        private String errorScript;
 | 
			
		||||
        private List<RuleTrigger> triggers = List.of(RuleTrigger.INBOUND);
 | 
			
		||||
        private CompositeCondition conditions;
 | 
			
		||||
        private List<Action> actions;
 | 
			
		||||
 | 
			
		||||
        public RuleBuilder setId(String id)
 | 
			
		||||
        public Builder id(String id)
 | 
			
		||||
        {
 | 
			
		||||
            this.id = id;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RuleBuilder setName(String name)
 | 
			
		||||
        public Builder name(String name)
 | 
			
		||||
        {
 | 
			
		||||
            this.name = name;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Rule createRule()
 | 
			
		||||
        public Builder description(String description)
 | 
			
		||||
        {
 | 
			
		||||
            this.description = description;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder enabled(boolean enabled)
 | 
			
		||||
        {
 | 
			
		||||
            this.enabled = enabled;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder cascade(boolean cascade)
 | 
			
		||||
        {
 | 
			
		||||
            this.cascade = cascade;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder asynchronous(boolean asynchronous)
 | 
			
		||||
        {
 | 
			
		||||
            this.asynchronous = asynchronous;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder isShared(Boolean isShared)
 | 
			
		||||
        {
 | 
			
		||||
            this.isShared = isShared;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder errorScript(String errorScript)
 | 
			
		||||
        {
 | 
			
		||||
            this.errorScript = errorScript;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder triggers(List<RuleTrigger> triggers)
 | 
			
		||||
        {
 | 
			
		||||
            this.triggers = triggers;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder conditions(CompositeCondition conditions)
 | 
			
		||||
        {
 | 
			
		||||
            this.conditions = conditions;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder actions(List<Action> actions)
 | 
			
		||||
        {
 | 
			
		||||
            this.actions = actions;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Rule create()
 | 
			
		||||
        {
 | 
			
		||||
            Rule rule = new Rule();
 | 
			
		||||
            rule.setId(id);
 | 
			
		||||
            rule.setName(name);
 | 
			
		||||
            rule.setDescription(description);
 | 
			
		||||
            rule.setEnabled(enabled);
 | 
			
		||||
            rule.setCascade(cascade);
 | 
			
		||||
            rule.setAsynchronous(asynchronous);
 | 
			
		||||
            rule.setIsShared(isShared);
 | 
			
		||||
            rule.setErrorScript(errorScript);
 | 
			
		||||
            rule.setRuleTriggers(triggers);
 | 
			
		||||
            rule.setConditions(conditions);
 | 
			
		||||
            rule.setActions(actions);
 | 
			
		||||
            return rule;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,11 @@
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.model.rules;
 | 
			
		||||
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.StringJoiner;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public class RuleSet
 | 
			
		||||
@@ -34,21 +38,14 @@ public class RuleSet
 | 
			
		||||
    public static final String DEFAULT_ID = "-default-";
 | 
			
		||||
 | 
			
		||||
    private String id;
 | 
			
		||||
    private NodeRef owningFolder;
 | 
			
		||||
    private InclusionType inclusionType;
 | 
			
		||||
 | 
			
		||||
    public static RuleSet of(String id)
 | 
			
		||||
    {
 | 
			
		||||
        final RuleSet ruleSet = new RuleSet();
 | 
			
		||||
        ruleSet.id = id;
 | 
			
		||||
 | 
			
		||||
        return ruleSet;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isNotDefaultId() {
 | 
			
		||||
        return isNotDefaultId(this.id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean isDefaultId() {
 | 
			
		||||
        return isDefaultId(this.id);
 | 
			
		||||
        return builder()
 | 
			
		||||
            .id(id)
 | 
			
		||||
            .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static boolean isNotDefaultId(final String id) {
 | 
			
		||||
@@ -69,9 +66,93 @@ public class RuleSet
 | 
			
		||||
        this.id = id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NodeRef getOwningFolder()
 | 
			
		||||
    {
 | 
			
		||||
        return owningFolder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setOwningFolder(NodeRef owningFolder)
 | 
			
		||||
    {
 | 
			
		||||
        this.owningFolder = owningFolder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public InclusionType getInclusionType()
 | 
			
		||||
    {
 | 
			
		||||
        return inclusionType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setInclusionType(InclusionType inclusionType)
 | 
			
		||||
    {
 | 
			
		||||
        this.inclusionType = inclusionType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString()
 | 
			
		||||
    {
 | 
			
		||||
        return "RuleSet{" + "id='" + id + '\'' + '}';
 | 
			
		||||
        return "RuleSet{"
 | 
			
		||||
                + new StringJoiner(", ")
 | 
			
		||||
                    .add("id='" + id + "'")
 | 
			
		||||
                    .add("owningFolder='" + owningFolder + "'")
 | 
			
		||||
                    .add("inclusionType='" + inclusionType + "'")
 | 
			
		||||
                    .toString()
 | 
			
		||||
                + '}';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object o)
 | 
			
		||||
    {
 | 
			
		||||
        if (this == o)
 | 
			
		||||
            return true;
 | 
			
		||||
        if (o == null || getClass() != o.getClass())
 | 
			
		||||
            return false;
 | 
			
		||||
        RuleSet ruleSet = (RuleSet) o;
 | 
			
		||||
        return Objects.equals(id, ruleSet.id)
 | 
			
		||||
                && Objects.equals(owningFolder, ruleSet.owningFolder)
 | 
			
		||||
                && inclusionType == ruleSet.inclusionType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode()
 | 
			
		||||
    {
 | 
			
		||||
        return Objects.hash(id, owningFolder, inclusionType);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Builder builder()
 | 
			
		||||
    {
 | 
			
		||||
        return new Builder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Builder
 | 
			
		||||
    {
 | 
			
		||||
        private String id;
 | 
			
		||||
        private NodeRef owningFolder;
 | 
			
		||||
        private InclusionType inclusionType;
 | 
			
		||||
 | 
			
		||||
        public Builder id(String id)
 | 
			
		||||
        {
 | 
			
		||||
            this.id = id;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder owningFolder(NodeRef owningFolder)
 | 
			
		||||
        {
 | 
			
		||||
            this.owningFolder = owningFolder;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder inclusionType(InclusionType inclusionType)
 | 
			
		||||
        {
 | 
			
		||||
            this.inclusionType = inclusionType;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RuleSet create()
 | 
			
		||||
        {
 | 
			
		||||
            final RuleSet ruleSet = new RuleSet();
 | 
			
		||||
            ruleSet.setId(id);
 | 
			
		||||
            ruleSet.setOwningFolder(owningFolder);
 | 
			
		||||
            ruleSet.setInclusionType(inclusionType);
 | 
			
		||||
            return ruleSet;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,46 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.model.rules;
 | 
			
		||||
 | 
			
		||||
public class RuleSetLink
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * This id is referring to the node id of the linked-to-folder which contains the ruleset(s)
 | 
			
		||||
     */
 | 
			
		||||
    private String id;
 | 
			
		||||
 | 
			
		||||
    public void setId(String id)
 | 
			
		||||
    {
 | 
			
		||||
        this.id = id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getId()
 | 
			
		||||
    {
 | 
			
		||||
        return id;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,126 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api.model.rules;
 | 
			
		||||
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.StringJoiner;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.framework.resource.UniqueId;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public class RuleSetting
 | 
			
		||||
{
 | 
			
		||||
    public static final String IS_INHERITANCE_ENABLED_KEY = "-isInheritanceEnabled-";
 | 
			
		||||
 | 
			
		||||
    private String key;
 | 
			
		||||
    private Object value;
 | 
			
		||||
 | 
			
		||||
    @UniqueId
 | 
			
		||||
    public String getKey()
 | 
			
		||||
    {
 | 
			
		||||
        return key;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setKey(String key)
 | 
			
		||||
    {
 | 
			
		||||
        this.key = key;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Object getValue()
 | 
			
		||||
    {
 | 
			
		||||
        return value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setValue(Object value)
 | 
			
		||||
    {
 | 
			
		||||
        this.value = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString()
 | 
			
		||||
    {
 | 
			
		||||
        return "RuleSetting{"
 | 
			
		||||
                + new StringJoiner(", ")
 | 
			
		||||
                    .add("key=" + key)
 | 
			
		||||
                    .add("value=" + value.toString())
 | 
			
		||||
                    .toString()
 | 
			
		||||
                + "}";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object o)
 | 
			
		||||
    {
 | 
			
		||||
        if (this == o)
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (!(o instanceof RuleSetting))
 | 
			
		||||
        {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        RuleSetting that = (RuleSetting) o;
 | 
			
		||||
        return Objects.equals(key, that.key)
 | 
			
		||||
                && Objects.equals(value, that.value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode()
 | 
			
		||||
    {
 | 
			
		||||
        return Objects.hash(key, value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static RuleSetting.Builder builder()
 | 
			
		||||
    {
 | 
			
		||||
        return new RuleSetting.Builder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Builder
 | 
			
		||||
    {
 | 
			
		||||
        private String key;
 | 
			
		||||
        private Object value;
 | 
			
		||||
 | 
			
		||||
        public RuleSetting.Builder key(String key)
 | 
			
		||||
        {
 | 
			
		||||
            this.key = key;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RuleSetting.Builder value(Object value)
 | 
			
		||||
        {
 | 
			
		||||
            this.value = value;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RuleSetting create()
 | 
			
		||||
        {
 | 
			
		||||
            final RuleSetting ruleSetting = new RuleSetting();
 | 
			
		||||
            ruleSetting.setKey(key);
 | 
			
		||||
            ruleSetting.setValue(value);
 | 
			
		||||
            return ruleSetting;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.model.rules;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public enum RuleTrigger
 | 
			
		||||
{
 | 
			
		||||
    INBOUND, UPDATE, OUTBOUND;
 | 
			
		||||
 | 
			
		||||
    public String getValue()
 | 
			
		||||
    {
 | 
			
		||||
        return this.name().toLowerCase();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static RuleTrigger of(final String value)
 | 
			
		||||
    {
 | 
			
		||||
        return RuleTrigger.valueOf(value.toUpperCase());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,277 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.model.rules;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.repo.action.evaluator.CompareMimeTypeEvaluator;
 | 
			
		||||
import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator;
 | 
			
		||||
import org.alfresco.repo.action.evaluator.HasAspectEvaluator;
 | 
			
		||||
import org.alfresco.repo.action.evaluator.HasChildEvaluator;
 | 
			
		||||
import org.alfresco.repo.action.evaluator.HasTagEvaluator;
 | 
			
		||||
import org.alfresco.repo.action.evaluator.HasVersionHistoryEvaluator;
 | 
			
		||||
import org.alfresco.repo.action.evaluator.InCategoryEvaluator;
 | 
			
		||||
import org.alfresco.repo.action.evaluator.IsSubTypeEvaluator;
 | 
			
		||||
import org.alfresco.repo.action.evaluator.NoConditionEvaluator;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.action.ActionCondition;
 | 
			
		||||
import org.apache.commons.collections.CollectionUtils;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public class SimpleCondition
 | 
			
		||||
{
 | 
			
		||||
    private static final String COMPARATOR_EQUALS = "equals";
 | 
			
		||||
 | 
			
		||||
    private String field;
 | 
			
		||||
    private String comparator;
 | 
			
		||||
    private String parameter;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Converts list of service POJO action conditions to list of REST model simple conditions.
 | 
			
		||||
     *
 | 
			
		||||
     * @param actionConditions - list of {@link ActionCondition} service POJOs
 | 
			
		||||
     * @return list of {@link SimpleCondition} REST models
 | 
			
		||||
     */
 | 
			
		||||
    public static List<SimpleCondition> listOf(final List<ActionCondition> actionConditions)
 | 
			
		||||
    {
 | 
			
		||||
        if (CollectionUtils.isEmpty(actionConditions))
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return actionConditions.stream()
 | 
			
		||||
            .map(SimpleCondition::from)
 | 
			
		||||
            .filter(Objects::nonNull)
 | 
			
		||||
            .collect(Collectors.toList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Creates simple condition REST model instance from service POJO action condition.
 | 
			
		||||
     *
 | 
			
		||||
     * @param actionCondition - {@link ActionCondition} service POJO
 | 
			
		||||
     * @return {@link SimpleCondition} REST model
 | 
			
		||||
     */
 | 
			
		||||
    public static SimpleCondition from(final ActionCondition actionCondition)
 | 
			
		||||
    {
 | 
			
		||||
        if (actionCondition == null || actionCondition.getActionConditionDefinitionName() == null || actionCondition.getParameterValues() == null)
 | 
			
		||||
        {
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (actionCondition.getActionConditionDefinitionName())
 | 
			
		||||
        {
 | 
			
		||||
        case ComparePropertyValueEvaluator.NAME:
 | 
			
		||||
            return createComparePropertyValueCondition(actionCondition);
 | 
			
		||||
        case CompareMimeTypeEvaluator.NAME:
 | 
			
		||||
            return createCompareMimeTypeCondition(actionCondition);
 | 
			
		||||
        case HasAspectEvaluator.NAME:
 | 
			
		||||
            return createHasAspectCondition(actionCondition);
 | 
			
		||||
        case HasChildEvaluator.NAME:
 | 
			
		||||
            return createHasChildCondition(actionCondition);
 | 
			
		||||
        case HasTagEvaluator.NAME:
 | 
			
		||||
            return createHasTagCondition(actionCondition);
 | 
			
		||||
        case HasVersionHistoryEvaluator.NAME:
 | 
			
		||||
            return createHasVersionHistoryCondition(actionCondition);
 | 
			
		||||
        case InCategoryEvaluator.NAME:
 | 
			
		||||
            return createInCategoryCondition(actionCondition);
 | 
			
		||||
        case IsSubTypeEvaluator.NAME:
 | 
			
		||||
            return createIsSubtypeCondition(actionCondition);
 | 
			
		||||
        case NoConditionEvaluator.NAME:
 | 
			
		||||
        default:
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getField()
 | 
			
		||||
    {
 | 
			
		||||
        return field;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setField(String field)
 | 
			
		||||
    {
 | 
			
		||||
        this.field = field;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getComparator()
 | 
			
		||||
    {
 | 
			
		||||
        return comparator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setComparator(String comparator)
 | 
			
		||||
    {
 | 
			
		||||
        this.comparator = comparator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getParameter()
 | 
			
		||||
    {
 | 
			
		||||
        return parameter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setParameter(String parameter)
 | 
			
		||||
    {
 | 
			
		||||
        this.parameter = parameter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public String toString()
 | 
			
		||||
    {
 | 
			
		||||
        return "SimpleCondition{" + "field='" + field + '\'' + ", comparator='" + comparator + '\'' + ", parameter='" + parameter + '\'' + '}';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(Object o)
 | 
			
		||||
    {
 | 
			
		||||
        if (this == o)
 | 
			
		||||
            return true;
 | 
			
		||||
        if (o == null || getClass() != o.getClass())
 | 
			
		||||
            return false;
 | 
			
		||||
        SimpleCondition that = (SimpleCondition) o;
 | 
			
		||||
        return Objects.equals(field, that.field) && Objects.equals(comparator, that.comparator) && Objects.equals(parameter, that.parameter);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public int hashCode()
 | 
			
		||||
    {
 | 
			
		||||
        return Objects.hash(field, comparator, parameter);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static SimpleCondition createComparePropertyValueCondition(final ActionCondition actionCondition) {
 | 
			
		||||
        final SimpleCondition.Builder builder = builder();
 | 
			
		||||
        if (actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY) != null)
 | 
			
		||||
        {
 | 
			
		||||
            builder.field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY).toString().toLowerCase());
 | 
			
		||||
        } else {
 | 
			
		||||
            builder.field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY).toString().toLowerCase());
 | 
			
		||||
        }
 | 
			
		||||
        return builder
 | 
			
		||||
            .comparator(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_OPERATION).toString().toLowerCase())
 | 
			
		||||
            .parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString())
 | 
			
		||||
            .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static SimpleCondition createCompareMimeTypeCondition(final ActionCondition actionCondition) {
 | 
			
		||||
        return builder()
 | 
			
		||||
            .field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY).toString().toLowerCase())
 | 
			
		||||
            .comparator(COMPARATOR_EQUALS)
 | 
			
		||||
            .parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString())
 | 
			
		||||
            .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static SimpleCondition createHasAspectCondition(final ActionCondition actionCondition) {
 | 
			
		||||
        return builder()
 | 
			
		||||
            .field(HasAspectEvaluator.PARAM_ASPECT)
 | 
			
		||||
            .comparator(COMPARATOR_EQUALS)
 | 
			
		||||
            .parameter(actionCondition.getParameterValues().get(HasAspectEvaluator.PARAM_ASPECT).toString())
 | 
			
		||||
            .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static SimpleCondition createHasChildCondition(final ActionCondition actionCondition) {
 | 
			
		||||
        final SimpleCondition.Builder builder = builder();
 | 
			
		||||
        if (actionCondition.getParameterValues().get(HasChildEvaluator.PARAM_ASSOC_TYPE) != null)
 | 
			
		||||
        {
 | 
			
		||||
            builder.field(actionCondition.getParameterValues().get(HasChildEvaluator.PARAM_ASSOC_TYPE).toString().toLowerCase());
 | 
			
		||||
        } else {
 | 
			
		||||
            builder.field(actionCondition.getParameterValues().get(HasChildEvaluator.PARAM_ASSOC_NAME).toString().toLowerCase());
 | 
			
		||||
        }
 | 
			
		||||
        return builder
 | 
			
		||||
            .comparator(COMPARATOR_EQUALS)
 | 
			
		||||
            .parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString())
 | 
			
		||||
            .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static SimpleCondition createHasTagCondition(final ActionCondition actionCondition) {
 | 
			
		||||
        return builder()
 | 
			
		||||
            .field(HasTagEvaluator.PARAM_TAG)
 | 
			
		||||
            .comparator(COMPARATOR_EQUALS)
 | 
			
		||||
            .parameter(actionCondition.getParameterValues().get(HasTagEvaluator.PARAM_TAG).toString())
 | 
			
		||||
            .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static SimpleCondition createHasVersionHistoryCondition(final ActionCondition actionCondition) {
 | 
			
		||||
        return builder()
 | 
			
		||||
            .field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY).toString().toLowerCase())
 | 
			
		||||
            .comparator(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_OPERATION).toString().toLowerCase())
 | 
			
		||||
            .parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString())
 | 
			
		||||
            .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static SimpleCondition createInCategoryCondition(final ActionCondition actionCondition) {
 | 
			
		||||
        return builder()
 | 
			
		||||
            .field(actionCondition.getParameterValues().get(InCategoryEvaluator.PARAM_CATEGORY_ASPECT).toString().toLowerCase())
 | 
			
		||||
            .comparator(COMPARATOR_EQUALS)
 | 
			
		||||
            .parameter(actionCondition.getParameterValues().get(InCategoryEvaluator.PARAM_CATEGORY_VALUE).toString())
 | 
			
		||||
            .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static SimpleCondition createIsSubtypeCondition(final ActionCondition actionCondition) {
 | 
			
		||||
        return builder()
 | 
			
		||||
            .field(IsSubTypeEvaluator.PARAM_TYPE)
 | 
			
		||||
            .comparator(COMPARATOR_EQUALS)
 | 
			
		||||
            .parameter(actionCondition.getParameterValues().get(IsSubTypeEvaluator.PARAM_TYPE).toString())
 | 
			
		||||
            .create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Builder builder()
 | 
			
		||||
    {
 | 
			
		||||
        return new Builder();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static class Builder
 | 
			
		||||
    {
 | 
			
		||||
        private String field;
 | 
			
		||||
        private String comparator;
 | 
			
		||||
        private String parameter;
 | 
			
		||||
 | 
			
		||||
        public Builder field(String field)
 | 
			
		||||
        {
 | 
			
		||||
            this.field = field;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder comparator(String comparator)
 | 
			
		||||
        {
 | 
			
		||||
            this.comparator = comparator;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder parameter(String parameter)
 | 
			
		||||
        {
 | 
			
		||||
            this.parameter = parameter;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public SimpleCondition create() {
 | 
			
		||||
            final SimpleCondition condition = new SimpleCondition();
 | 
			
		||||
            condition.setField(field);
 | 
			
		||||
            condition.setComparator(comparator);
 | 
			
		||||
            condition.setParameter(parameter);
 | 
			
		||||
            return condition;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,74 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.nodes;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.stream.Collectors;
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.RuleSets;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSetLink;
 | 
			
		||||
import org.alfresco.rest.framework.WebApiDescription;
 | 
			
		||||
import org.alfresco.rest.framework.WebApiParam;
 | 
			
		||||
import org.alfresco.rest.framework.core.ResourceParameter;
 | 
			
		||||
import org.alfresco.rest.framework.resource.RelationshipResource;
 | 
			
		||||
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
 | 
			
		||||
import org.alfresco.util.PropertyCheck;
 | 
			
		||||
import org.springframework.beans.factory.InitializingBean;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@RelationshipResource(name = "rule-set-links", entityResource = NodesEntityResource.class, title = "Linking to a rule set")
 | 
			
		||||
public class NodeRuleSetLinksRelation implements InitializingBean, RelationshipResourceAction.Create<RuleSetLink>
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    private final RuleSets ruleSets;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void afterPropertiesSet() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        PropertyCheck.mandatory(this, "ruleSets", ruleSets);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @WebApiParam(name = "ruleSetLinkRequest", title = "Request body - rule set id",
 | 
			
		||||
            description = "Request body with rule set id", kind = ResourceParameter.KIND.HTTP_BODY_OBJECT)
 | 
			
		||||
    @WebApiDescription(title = "Link a rule set to a folder node",
 | 
			
		||||
            description = "Submits a request to link a rule set to folder",
 | 
			
		||||
            successStatus = HttpServletResponse.SC_CREATED)
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<RuleSetLink> create(String nodeId, List<RuleSetLink> ruleSetLinksBody, Parameters parameters)
 | 
			
		||||
    {
 | 
			
		||||
        return ruleSetLinksBody.stream()
 | 
			
		||||
                .map(r -> ruleSets.linkToRuleSet(nodeId, r.getId()))
 | 
			
		||||
                .collect(Collectors.toList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NodeRuleSetLinksRelation(RuleSets ruleSets)
 | 
			
		||||
    {
 | 
			
		||||
        this.ruleSets = ruleSets;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -26,15 +26,84 @@
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.nodes;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.RuleSets;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSet;
 | 
			
		||||
import org.alfresco.rest.framework.WebApiDescription;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
 | 
			
		||||
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.Paging;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.util.PropertyCheck;
 | 
			
		||||
import org.springframework.beans.factory.InitializingBean;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Folder node rule sets.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
@Experimental
 | 
			
		||||
@RelationshipResource(name = "rule-sets", entityResource = NodesEntityResource.class, title = "Folder node rule sets")
 | 
			
		||||
public class NodeRuleSetsRelation
 | 
			
		||||
public class NodeRuleSetsRelation implements RelationshipResourceAction.Read<RuleSet>,
 | 
			
		||||
                                             RelationshipResourceAction.ReadById<RuleSet>,
 | 
			
		||||
                                             InitializingBean
 | 
			
		||||
{
 | 
			
		||||
    private RuleSets ruleSets;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void afterPropertiesSet() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        PropertyCheck.mandatory(this, "ruleSets", ruleSets);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * List rule sets for given folder.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * - GET /nodes/{folderNodeId}/rule-sets
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderNodeId The id of the folder node.
 | 
			
		||||
     * @param parameters Contains paging information and information about which fields to include
 | 
			
		||||
     * @return {@link CollectionWithPagingInfo} containing a page of rule sets
 | 
			
		||||
     */
 | 
			
		||||
    @WebApiDescription (
 | 
			
		||||
            title = "Get rule sets for a folder",
 | 
			
		||||
            description = "Returns a paged list of rule sets for given node",
 | 
			
		||||
            successStatus = HttpServletResponse.SC_OK
 | 
			
		||||
    )
 | 
			
		||||
    @Override
 | 
			
		||||
    public CollectionWithPagingInfo<RuleSet> readAll(String folderNodeId, Parameters parameters)
 | 
			
		||||
    {
 | 
			
		||||
        return ruleSets.getRuleSets(folderNodeId, parameters.getInclude(), parameters.getPaging());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get single folder rule for given node's, rule set's and rule's IDs.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * - GET /nodes/{folderNodeId}/rule-sets/{ruleSetId}
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderNodeId - entity resource context for this relationship
 | 
			
		||||
     * @param ruleSetId - rule set node ID (associated with folder node)
 | 
			
		||||
     * @param parameters Contains information about which fields to include
 | 
			
		||||
     * @return {@link RuleSet} definition
 | 
			
		||||
     * @throws RelationshipResourceNotFoundException in case resource was not found
 | 
			
		||||
     */
 | 
			
		||||
    @WebApiDescription (
 | 
			
		||||
            title = "Get rule set",
 | 
			
		||||
            description = "Returns a single rule set for the given node",
 | 
			
		||||
            successStatus = HttpServletResponse.SC_OK
 | 
			
		||||
    )
 | 
			
		||||
    @Override
 | 
			
		||||
    public RuleSet readById(String folderNodeId, String ruleSetId, Parameters parameters) throws RelationshipResourceNotFoundException
 | 
			
		||||
    {
 | 
			
		||||
        return ruleSets.getRuleSetById(folderNodeId, ruleSetId, parameters.getInclude());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRuleSets(RuleSets ruleSets)
 | 
			
		||||
    {
 | 
			
		||||
        this.ruleSets = ruleSets;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,104 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api.nodes;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.RuleSettings;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSetting;
 | 
			
		||||
import org.alfresco.rest.framework.WebApiDescription;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
 | 
			
		||||
import org.alfresco.rest.framework.resource.RelationshipResource;
 | 
			
		||||
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Parameters;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.util.PropertyCheck;
 | 
			
		||||
import org.springframework.beans.factory.InitializingBean;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Folder node rule settings (rule inheritance).
 | 
			
		||||
 */
 | 
			
		||||
@Experimental
 | 
			
		||||
@RelationshipResource (name = "rule-settings", entityResource = NodesEntityResource.class, title = "Folder rule settings")
 | 
			
		||||
public class NodeRuleSettingsRelation implements RelationshipResourceAction.ReadById<RuleSetting>,
 | 
			
		||||
                                                 RelationshipResourceAction.Update<RuleSetting>,
 | 
			
		||||
                                                 InitializingBean
 | 
			
		||||
{
 | 
			
		||||
    private RuleSettings ruleSettings;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void afterPropertiesSet() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        PropertyCheck.mandatory(this, "ruleSettings", ruleSettings);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the given configuration value for the specified folder.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * - GET /nodes/{folderId}/rule-settings/{ruleSettingKey}
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderId The id of the folder.
 | 
			
		||||
     * @param ruleSettingKey The setting to retrieve.
 | 
			
		||||
     * @param parameters Unused.
 | 
			
		||||
     * @return {@link RuleSetting} The current value of the setting.
 | 
			
		||||
     */
 | 
			
		||||
    @WebApiDescription (
 | 
			
		||||
            title = "Get a folder node rule setting",
 | 
			
		||||
            description = "Returns the specified rule setting for the given folder",
 | 
			
		||||
            successStatus = HttpServletResponse.SC_OK
 | 
			
		||||
    )
 | 
			
		||||
    @Override
 | 
			
		||||
    public RuleSetting readById(String folderId, String ruleSettingKey, Parameters parameters) throws RelationshipResourceNotFoundException
 | 
			
		||||
    {
 | 
			
		||||
        return ruleSettings.getRuleSetting(folderId, ruleSettingKey);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the value of a rule setting for the specified folder.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * PUT /nodes/{folderId}/rule-settings/{ruleSettingKey}
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderId The id of the folder.
 | 
			
		||||
     * @param ruleSetting The new value of the rule setting.
 | 
			
		||||
     * @param parameters Unused.
 | 
			
		||||
     * @return The updated rule setting.
 | 
			
		||||
     */
 | 
			
		||||
    @WebApiDescription (
 | 
			
		||||
            title = "Update folder node rule setting",
 | 
			
		||||
            description = "Update a rule setting for given node",
 | 
			
		||||
            successStatus = HttpServletResponse.SC_OK
 | 
			
		||||
    )
 | 
			
		||||
    @Override
 | 
			
		||||
    public RuleSetting update(String folderId, RuleSetting ruleSetting, Parameters parameters)
 | 
			
		||||
    {
 | 
			
		||||
        return ruleSettings.setRuleSetting(folderId, ruleSetting);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRuleSettings(RuleSettings ruleSettings)
 | 
			
		||||
    {
 | 
			
		||||
        this.ruleSettings = ruleSettings;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -26,6 +26,9 @@
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.nodes;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.Rules;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.Rule;
 | 
			
		||||
import org.alfresco.rest.framework.WebApiDescription;
 | 
			
		||||
@@ -38,17 +41,18 @@ import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.util.PropertyCheck;
 | 
			
		||||
import org.springframework.beans.factory.InitializingBean;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Folder node's rules.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
@Experimental
 | 
			
		||||
@RelationshipResource(name = "rules", entityResource = NodeRuleSetsRelation.class, title = "Folder node rules")
 | 
			
		||||
public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>, RelationshipResourceAction.ReadById<Rule>,
 | 
			
		||||
        RelationshipResourceAction.Create<Rule>, RelationshipResourceAction.Delete, InitializingBean
 | 
			
		||||
public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>,
 | 
			
		||||
                                          RelationshipResourceAction.ReadById<Rule>,
 | 
			
		||||
                                          RelationshipResourceAction.Create<Rule>,
 | 
			
		||||
                                          RelationshipResourceAction.Update<Rule>,
 | 
			
		||||
                                          RelationshipResourceAction.Delete,
 | 
			
		||||
                                          InitializingBean
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    private Rules rules;
 | 
			
		||||
@@ -78,7 +82,7 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>,
 | 
			
		||||
    {
 | 
			
		||||
        final String ruleSetId = parameters.getRelationshipId();
 | 
			
		||||
 | 
			
		||||
        return rules.getRules(folderNodeId, ruleSetId, parameters.getPaging());
 | 
			
		||||
        return rules.getRules(folderNodeId, ruleSetId, parameters.getInclude(), parameters.getPaging());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -102,11 +106,13 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>,
 | 
			
		||||
    {
 | 
			
		||||
        final String ruleId = parameters.getRelationship2Id();
 | 
			
		||||
 | 
			
		||||
        return rules.getRuleById(folderNodeId, ruleSetId, ruleId);
 | 
			
		||||
        return rules.getRuleById(folderNodeId, ruleSetId, ruleId, parameters.getInclude());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create one or more rules inside a given folder and rule set.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * POST /nodes/{folderNodeId}/rule-sets/{ruleSetId}/rules
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderNodeId The folder in which to create the rule.
 | 
			
		||||
     * @param ruleList The list of rules to create.
 | 
			
		||||
@@ -123,12 +129,31 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>,
 | 
			
		||||
    {
 | 
			
		||||
        final String ruleSetId = parameters.getRelationshipId();
 | 
			
		||||
 | 
			
		||||
        return rules.createRules(folderNodeId, ruleSetId, ruleList);
 | 
			
		||||
        return rules.createRules(folderNodeId, ruleSetId, ruleList, parameters.getInclude());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRules(Rules rules)
 | 
			
		||||
    /**
 | 
			
		||||
     * Update the specified folder rule.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * PUT /nodes/{folderNodeId}/rule-sets/{ruleSetId}/rules/{ruleId}
 | 
			
		||||
     *
 | 
			
		||||
     * @param folderNodeId The id of the folder containing the rule.
 | 
			
		||||
     * @param rule The updated rule.
 | 
			
		||||
     * @param parameters List of parameters including the rule set id and rule id.
 | 
			
		||||
     * @return The updated rule.
 | 
			
		||||
     * @throws RelationshipResourceNotFoundException in case resource was not found
 | 
			
		||||
     */
 | 
			
		||||
    @WebApiDescription (
 | 
			
		||||
            title = "Update folder node rule",
 | 
			
		||||
            description = "Update a single rule definition for given node's, rule set's and rule's IDs",
 | 
			
		||||
            successStatus = HttpServletResponse.SC_OK
 | 
			
		||||
    )
 | 
			
		||||
    @Override
 | 
			
		||||
    public Rule update(String folderNodeId, Rule rule, Parameters parameters)
 | 
			
		||||
    {
 | 
			
		||||
        this.rules = rules;
 | 
			
		||||
        String ruleSetId = parameters.getRelationshipId();
 | 
			
		||||
        String ruleId = parameters.getRelationship2Id();
 | 
			
		||||
        return rules.updateRuleById(folderNodeId, ruleSetId, ruleId, rule, parameters.getInclude());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -152,4 +177,9 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>,
 | 
			
		||||
        final String ruleId = parameters.getRelationship2Id();
 | 
			
		||||
        rules.deleteRuleById(folderNodeId, ruleSetId, ruleId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setRules(Rules rules)
 | 
			
		||||
    {
 | 
			
		||||
        this.rules = rules;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -121,8 +121,8 @@ public class ResourceLookupDictionary implements ResourceLocator
 | 
			
		||||
                    return resource;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            logger.warn("Unable to locate resource resource for :"+entityResource+" "+relationResource==null?"":relationResource+" "+property==null?"":property);
 | 
			
		||||
            throw new NotFoundException("Unable to locate resource resource for :"+entityResource+" "+(relationResource==null?"":relationResource+" "+property==null?"":property));
 | 
			
		||||
            logger.warn("Unable to locate resource for: "+entityResource+" "+relationResource==null ? "" : relationResource+" "+property==null ? "" : property);
 | 
			
		||||
            throw new NotFoundException("Unable to locate resource for: "+entityResource+" "+(relationResource==null ? "" : relationResource+" "+property==null ? "" : property));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
@@ -160,8 +160,8 @@ public class ResourceLookupDictionary implements ResourceLocator
 | 
			
		||||
                  return resource;
 | 
			
		||||
              }
 | 
			
		||||
          }
 | 
			
		||||
          logger.warn("Unable to locate resource resource for :"+entityResource+" "+relationResource==null?"":relationResource);
 | 
			
		||||
          throw new NotFoundException("Unable to locate resource resource for :"+entityResource+" "+(relationResource==null?"":relationResource));
 | 
			
		||||
          logger.warn("Unable to locate resource for: "+entityResource+" "+relationResource==null ? "" : relationResource);
 | 
			
		||||
          throw new NotFoundException("Unable to locate resource for: "+entityResource+" "+relationResource==null ? "" : relationResource);
 | 
			
		||||
        } 
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -79,6 +79,7 @@ public class ResourceWebScriptPut extends AbstractResourceWebScript implements P
 | 
			
		||||
        final Map<String, String> resourceVars = locator.parseTemplateVars(req.getServiceMatch().getTemplateVars());
 | 
			
		||||
        final String entityId = resourceVars.get(ResourceLocator.ENTITY_ID);
 | 
			
		||||
        final String relationshipId = resourceVars.get(ResourceLocator.RELATIONSHIP_ID);
 | 
			
		||||
        final String relationship2Id = resourceVars.get(ResourceLocator.RELATIONSHIP2_ID);
 | 
			
		||||
 | 
			
		||||
        final RecognizedParams params = getRecognizedParams(req);
 | 
			
		||||
        final ResourceOperation operation = resourceMeta.getOperation(HttpMethod.PUT);
 | 
			
		||||
@@ -99,9 +100,16 @@ public class ResourceWebScriptPut extends AbstractResourceWebScript implements P
 | 
			
		||||
                if (StringUtils.isBlank(relationshipId))
 | 
			
		||||
                {
 | 
			
		||||
                    throw new UnsupportedResourceOperationException("PUT is executed against the instance URL");                  
 | 
			
		||||
                } else
 | 
			
		||||
                }
 | 
			
		||||
                Object putRel = extractJsonContent(req, assistant.getJsonHelper(), resourceMeta.getObjectType(operation));
 | 
			
		||||
                if (StringUtils.isNotBlank(relationship2Id))
 | 
			
		||||
                {
 | 
			
		||||
                    ResourceWebScriptHelper.setUniqueId(putRel, relationship2Id);
 | 
			
		||||
                    return Params.valueOf(false, entityId, relationshipId, relationship2Id,
 | 
			
		||||
                            putRel, null, null, params, null, req);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    Object putRel = extractJsonContent(req, assistant.getJsonHelper(), resourceMeta.getObjectType(operation));
 | 
			
		||||
                    ResourceWebScriptHelper.setUniqueId(putRel,relationshipId);
 | 
			
		||||
                    return Params.valueOf(entityId, params, putRel, req);
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -850,10 +850,65 @@
 | 
			
		||||
        </property>
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean id="rules" class="org.alfresco.rest.api.impl.RulesImpl">
 | 
			
		||||
    <bean id="nodeValidator" class="org.alfresco.rest.api.impl.rules.NodeValidator">
 | 
			
		||||
        <property name="nodes" ref="Nodes" />
 | 
			
		||||
        <property name="permissionService" ref="PermissionService"/>
 | 
			
		||||
        <property name="permissionService" ref="PermissionService" />
 | 
			
		||||
        <property name="ruleService" ref="RuleService" />
 | 
			
		||||
        <property name="nodeService" ref="NodeService"/>
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean class="org.alfresco.rest.api.nodes.NodeRulesRelation">
 | 
			
		||||
        <property name="rules" ref="Rules" />
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean id="ruleSetLoader" class="org.alfresco.rest.api.impl.rules.RuleSetLoader">
 | 
			
		||||
        <property name="nodeService" ref="NodeService" />
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean id="ruleSets" class="org.alfresco.rest.api.impl.rules.RuleSetsImpl">
 | 
			
		||||
        <property name="ruleSetLoader" ref="ruleSetLoader" />
 | 
			
		||||
        <property name="validator" ref="nodeValidator" />
 | 
			
		||||
        <property name="ruleService" ref="RuleService" />
 | 
			
		||||
        <property name="nodeService" ref="NodeService"/>
 | 
			
		||||
        <property name="runtimeRuleService" ref="ruleService"/>
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean id="RuleSets" class="org.springframework.aop.framework.ProxyFactoryBean">
 | 
			
		||||
        <property name="proxyInterfaces" value="org.alfresco.rest.api.RuleSets" />
 | 
			
		||||
        <property name="target" ref="ruleSets" />
 | 
			
		||||
        <property name="interceptorNames">
 | 
			
		||||
            <list>
 | 
			
		||||
                <idref bean="legacyExceptionInterceptor" />
 | 
			
		||||
            </list>
 | 
			
		||||
        </property>
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean id="ruleLoader" class="org.alfresco.rest.api.impl.rules.RuleLoader">
 | 
			
		||||
        <property name="ruleService" ref="RuleService" />
 | 
			
		||||
        <property name="nodeValidator" ref="nodeValidator" />
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean class="org.alfresco.rest.api.nodes.NodeRuleSetsRelation">
 | 
			
		||||
        <property name="ruleSets" ref="RuleSets" />
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean id="actionParameterConverter" class="org.alfresco.rest.api.impl.rules.ActionParameterConverter">
 | 
			
		||||
        <constructor-arg name="actionService" ref="ActionService"/>
 | 
			
		||||
        <constructor-arg name="dictionaryService" ref="DictionaryService"/>
 | 
			
		||||
        <constructor-arg name="namespaceService" ref="NamespaceService"/>
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean id="actionPermissionValidator" class="org.alfresco.rest.api.impl.rules.ActionPermissionValidator">
 | 
			
		||||
        <constructor-arg name="runtimeActionService" ref="actionService"/>
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean id="rules" class="org.alfresco.rest.api.impl.rules.RulesImpl">
 | 
			
		||||
        <property name="nodes" ref="Nodes" />
 | 
			
		||||
        <property name="validator" ref="nodeValidator"/>
 | 
			
		||||
        <property name="ruleService" ref="RuleService" />
 | 
			
		||||
        <property name="ruleLoader" ref="ruleLoader"/>
 | 
			
		||||
        <property name="actionParameterConverter" ref="actionParameterConverter"/>
 | 
			
		||||
        <property name="actionPermissionValidator" ref="actionPermissionValidator"/>
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean id="Rules" class="org.springframework.aop.framework.ProxyFactoryBean">
 | 
			
		||||
@@ -866,8 +921,27 @@
 | 
			
		||||
        </property>
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean class="org.alfresco.rest.api.nodes.NodeRulesRelation">
 | 
			
		||||
        <property name="rules" ref="Rules" />
 | 
			
		||||
    <bean class="org.alfresco.rest.api.nodes.NodeRuleSetLinksRelation">
 | 
			
		||||
        <constructor-arg name="ruleSets" ref="RuleSets" />
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean id="ruleSettings" class="org.alfresco.rest.api.impl.rules.RuleSettingsImpl">
 | 
			
		||||
        <property name="validator" ref="nodeValidator" />
 | 
			
		||||
        <property name="nodeService" ref="NodeService" />
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean id="RuleSettings" class="org.springframework.aop.framework.ProxyFactoryBean">
 | 
			
		||||
        <property name="proxyInterfaces" value="org.alfresco.rest.api.RuleSettings" />
 | 
			
		||||
        <property name="target" ref="ruleSettings" />
 | 
			
		||||
        <property name="interceptorNames">
 | 
			
		||||
            <list>
 | 
			
		||||
                <idref bean="legacyExceptionInterceptor" />
 | 
			
		||||
            </list>
 | 
			
		||||
        </property>
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean class="org.alfresco.rest.api.nodes.NodeRuleSettingsRelation">
 | 
			
		||||
        <property name="ruleSettings" ref="RuleSettings" />
 | 
			
		||||
    </bean>
 | 
			
		||||
 | 
			
		||||
    <bean id="publicapi.mimeTypePropertyLookup" class="org.alfresco.rest.api.lookups.MimeTypePropertyLookup">
 | 
			
		||||
 
 | 
			
		||||
@@ -249,6 +249,7 @@
 | 
			
		||||
      <property name="delegate" ref="webscript.content.streamer" />
 | 
			
		||||
      <property name="contentService" ref="contentService" />
 | 
			
		||||
      <property name="repository" ref="repositoryHelper" />
 | 
			
		||||
      <property name="nonAttachContentTypes" value="#{T(java.util.Arrays).asList('${content.nonAttach.mimetypes}')}" />
 | 
			
		||||
   </bean>
 | 
			
		||||
   
 | 
			
		||||
   <!--  Content Info -->
 | 
			
		||||
 
 | 
			
		||||
@@ -48,9 +48,8 @@ import org.junit.runners.Suite;
 | 
			
		||||
    org.alfresco.repo.webdav.RenameShuffleDetectionTest.class,
 | 
			
		||||
    org.alfresco.repo.webdav.WebDAVHelperTest.class,
 | 
			
		||||
    org.alfresco.repo.webdav.WebDAVLockServiceImplTest.class,
 | 
			
		||||
    org.alfresco.rest.api.RulesUnitTests.class,
 | 
			
		||||
    org.alfresco.rest.api.impl.ContentStorageInformationImplTest.class,
 | 
			
		||||
    org.alfresco.rest.api.impl.RulesImplTest.class,
 | 
			
		||||
    org.alfresco.rest.api.nodes.NodeRulesRelationTest.class,
 | 
			
		||||
    org.alfresco.rest.api.nodes.NodeStorageInfoRelationTest.class,
 | 
			
		||||
    org.alfresco.rest.api.search.ResultMapperTests.class,
 | 
			
		||||
    org.alfresco.rest.api.search.SearchApiWebscriptTests.class,
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Share Services AMP
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2016 Alfresco Software Limited
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software. 
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of 
 | 
			
		||||
@@ -66,13 +66,17 @@ public class ContentGetTest extends BaseWebScriptTest
 | 
			
		||||
    {
 | 
			
		||||
        super.setUp();
 | 
			
		||||
 | 
			
		||||
        this.authenticationService = (MutableAuthenticationService) getServer().getApplicationContext()
 | 
			
		||||
                .getBean("AuthenticationService");
 | 
			
		||||
        this.authenticationService = (MutableAuthenticationService)getServer().getApplicationContext().getBean("AuthenticationService");
 | 
			
		||||
        this.personService = (PersonService) getServer().getApplicationContext().getBean("PersonService");
 | 
			
		||||
        this.nodeService = (NodeService) getServer().getApplicationContext().getBean("NodeService");
 | 
			
		||||
        this.contentService = (ContentService) getServer().getApplicationContext().getBean("ContentService");
 | 
			
		||||
        AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
 | 
			
		||||
        createUser(USER_ONE);
 | 
			
		||||
 | 
			
		||||
        Repository repositoryHelper = (Repository) getServer().getApplicationContext().getBean("repositoryHelper");
 | 
			
		||||
        NodeRef companyHome = repositoryHelper.getCompanyHome();
 | 
			
		||||
 | 
			
		||||
        rootFolder = createNode(companyHome, "rootFolder", ContentModel.TYPE_FOLDER);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void createUser(String userName)
 | 
			
		||||
@@ -117,18 +121,13 @@ public class ContentGetTest extends BaseWebScriptTest
 | 
			
		||||
     */
 | 
			
		||||
    public void testRelativePath() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        Repository repositoryHelper = (Repository) getServer().getApplicationContext().getBean("repositoryHelper");
 | 
			
		||||
        NodeRef companyHome = repositoryHelper.getCompanyHome();
 | 
			
		||||
 | 
			
		||||
        rootFolder = createNode(companyHome, "rootFolder", ContentModel.TYPE_FOLDER);
 | 
			
		||||
 | 
			
		||||
        NodeRef doc1 = createNodeWithTextContent(rootFolder, "doc1", ContentModel.TYPE_CONTENT, "doc1 file content");
 | 
			
		||||
        NodeRef doc1 = createNodeWithTextContent(rootFolder, "doc1", ContentModel.TYPE_CONTENT, "doc1 file content", MimetypeMap.MIMETYPE_TEXT_PLAIN);
 | 
			
		||||
 | 
			
		||||
        NodeRef folderX = createNode(rootFolder, "X", ContentModel.TYPE_FOLDER);
 | 
			
		||||
        NodeRef folderY = createNode(folderX, "Y", ContentModel.TYPE_FOLDER);
 | 
			
		||||
        NodeRef folderZ = createNode(folderY, "Z", ContentModel.TYPE_FOLDER);
 | 
			
		||||
 | 
			
		||||
        NodeRef doc2 = createNodeWithTextContent(folderZ, "doc2", ContentModel.TYPE_CONTENT, "doc2 file content");
 | 
			
		||||
        NodeRef doc2 = createNodeWithTextContent(folderZ, "doc2", ContentModel.TYPE_CONTENT, "doc2 file content", MimetypeMap.MIMETYPE_TEXT_PLAIN);
 | 
			
		||||
 | 
			
		||||
        // uri with relative path at the end
 | 
			
		||||
        String uri = URL_CONTENT_DOWNLOAD + doc1.getId() + "/X/Y/Z/doc2";
 | 
			
		||||
@@ -138,7 +137,46 @@ public class ContentGetTest extends BaseWebScriptTest
 | 
			
		||||
        Assert.assertEquals("doc2 file content", resp.getContentAsString());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NodeRef createNodeWithTextContent(NodeRef parentNode, String nodeCmName, QName nodeType, String content)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public void testForcedAttachment() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        NodeRef testhtml = createNodeWithTextContent(rootFolder, "testhtml", ContentModel.TYPE_CONTENT, "testhtml content", MimetypeMap.MIMETYPE_HTML);
 | 
			
		||||
        NodeRef testpdf = createNodeWithTextContent(rootFolder, "testpdf", ContentModel.TYPE_CONTENT, "testpdf content", MimetypeMap.MIMETYPE_PDF);
 | 
			
		||||
 | 
			
		||||
        String uri = URL_CONTENT_DOWNLOAD + testhtml.getId() + "?a=false";
 | 
			
		||||
        GetRequest req = new GetRequest(uri);
 | 
			
		||||
        Response res = sendRequest(req, 200);
 | 
			
		||||
        assertEquals("attachment", res.getHeader("Content-Disposition"));
 | 
			
		||||
        assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType());
 | 
			
		||||
 | 
			
		||||
        uri = URL_CONTENT_DOWNLOAD + testhtml.getId();
 | 
			
		||||
        res = sendRequest(new GetRequest(uri), 200);
 | 
			
		||||
        assertEquals("attachment", res.getHeader("Content-Disposition"));
 | 
			
		||||
        assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType());
 | 
			
		||||
 | 
			
		||||
        uri = URL_CONTENT_DOWNLOAD + testhtml.getId() + "?a=true";
 | 
			
		||||
        res = sendRequest(new GetRequest(uri), 200);
 | 
			
		||||
        assertEquals("attachment", res.getHeader("Content-Disposition"));
 | 
			
		||||
        assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType());
 | 
			
		||||
 | 
			
		||||
        uri = URL_CONTENT_DOWNLOAD + testpdf.getId() + "?a=false";
 | 
			
		||||
        res = sendRequest(new GetRequest(uri), 200);
 | 
			
		||||
        assertNull(res.getHeader("Content-Disposition"));
 | 
			
		||||
        assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType());
 | 
			
		||||
 | 
			
		||||
        uri = URL_CONTENT_DOWNLOAD + testpdf.getId();
 | 
			
		||||
        res = sendRequest(new GetRequest(uri), 200);
 | 
			
		||||
        assertNull(res.getHeader("Content-Disposition"));
 | 
			
		||||
        assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType());
 | 
			
		||||
 | 
			
		||||
        uri = URL_CONTENT_DOWNLOAD + testpdf.getId() + "?a=true";
 | 
			
		||||
        res = sendRequest(new GetRequest(uri), 200);
 | 
			
		||||
        assertEquals("attachment", res.getHeader("Content-Disposition"));
 | 
			
		||||
        assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public NodeRef createNodeWithTextContent(NodeRef parentNode, String nodeCmName, QName nodeType, String content, String mimetype)
 | 
			
		||||
    {
 | 
			
		||||
        NodeRef nodeRef = createNode(parentNode, nodeCmName, nodeType);
 | 
			
		||||
 | 
			
		||||
@@ -146,7 +184,7 @@ public class ContentGetTest extends BaseWebScriptTest
 | 
			
		||||
        if (content != null)
 | 
			
		||||
        {
 | 
			
		||||
            ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
 | 
			
		||||
            writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
 | 
			
		||||
            writer.setMimetype(mimetype);
 | 
			
		||||
            writer.setEncoding("UTF-8");
 | 
			
		||||
            writer.putContent(content);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,28 +1,28 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2016 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software. 
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of 
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is 
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 * 
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 * 
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Lesser General Public License for more details.
 | 
			
		||||
 * 
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 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.web.util;
 | 
			
		||||
 | 
			
		||||
import java.io.BufferedReader;
 | 
			
		||||
@@ -32,6 +32,7 @@ import java.io.InputStreamReader;
 | 
			
		||||
import java.net.InetAddress;
 | 
			
		||||
import java.net.ServerSocket;
 | 
			
		||||
import java.net.Socket;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.Date;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.ServletContext;
 | 
			
		||||
@@ -44,7 +45,8 @@ import org.alfresco.util.TempFileProvider;
 | 
			
		||||
import org.alfresco.util.WebApplicationContextLoader;
 | 
			
		||||
import org.apache.commons.logging.Log;
 | 
			
		||||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
import org.eclipse.jetty.security.HashLoginService;
 | 
			
		||||
import org.eclipse.jetty.http.UriCompliance;
 | 
			
		||||
import org.eclipse.jetty.server.HttpConnectionFactory;
 | 
			
		||||
import org.eclipse.jetty.server.Server;
 | 
			
		||||
import org.eclipse.jetty.webapp.WebAppContext;
 | 
			
		||||
import org.springframework.beans.BeanUtils;
 | 
			
		||||
@@ -145,6 +147,8 @@ public abstract class AbstractJettyComponent implements JettyComponent
 | 
			
		||||
		    
 | 
			
		||||
		    configureWebAppContext(webAppContext);
 | 
			
		||||
 | 
			
		||||
			ignoreAmbiguousLinks(server);
 | 
			
		||||
 | 
			
		||||
		    server.start();
 | 
			
		||||
 | 
			
		||||
			if(logger.isDebugEnabled())
 | 
			
		||||
@@ -203,15 +207,27 @@ public abstract class AbstractJettyComponent implements JettyComponent
 | 
			
		||||
				}
 | 
			
		||||
			}    
 | 
			
		||||
		});
 | 
			
		||||
	    
 | 
			
		||||
	    // with a login-config in web.xml, jetty seems to require this in order to start successfully
 | 
			
		||||
	    webAppContext.getSecurityHandler().setLoginService(new HashLoginService());
 | 
			
		||||
 | 
			
		||||
	    // arbitrary temporary file location
 | 
			
		||||
	    File tmp = new File(TempFileProvider.getSystemTempDir(), String.valueOf(System.currentTimeMillis()));
 | 
			
		||||
	    webAppContext.setResourceBase(tmp.getAbsolutePath());		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * In newer jetty versions there is a stricter check for links e.g. "//" is not allowed, which clashes
 | 
			
		||||
	 * with some of our tests, because even a NodeRef triggers it - "workspace://..."
 | 
			
		||||
	 * Since Jetty is only used in tests it's alright to block this behaviour.
 | 
			
		||||
	 *
 | 
			
		||||
	 * @param server
 | 
			
		||||
	 */
 | 
			
		||||
	private void ignoreAmbiguousLinks(Server server) {
 | 
			
		||||
		Arrays.stream(server.getConnectors())
 | 
			
		||||
				.flatMap(c -> c.getConnectionFactories().stream())
 | 
			
		||||
				.filter(cf -> cf instanceof HttpConnectionFactory)
 | 
			
		||||
				.map(cf -> (HttpConnectionFactory) cf)
 | 
			
		||||
				.forEach(hcf -> hcf.getHttpConfiguration().setUriCompliance(UriCompliance.RFC3986));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void shutdown()
 | 
			
		||||
	{
 | 
			
		||||
		try
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.impl.rules.NodeValidatorTest;
 | 
			
		||||
import org.alfresco.rest.api.impl.rules.RuleSetsImplTest;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.ActionTest;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.CompositeConditionTest;
 | 
			
		||||
import org.alfresco.rest.api.impl.rules.RulesImplTest;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleTest;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.SimpleConditionTest;
 | 
			
		||||
import org.alfresco.rest.api.nodes.NodeRulesRelationTest;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.junit.runners.Suite;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
@RunWith(Suite.class)
 | 
			
		||||
@Suite.SuiteClasses({
 | 
			
		||||
    NodeRulesRelationTest.class,
 | 
			
		||||
    RulesImplTest.class,
 | 
			
		||||
    RuleSetsImplTest.class,
 | 
			
		||||
    NodeValidatorTest.class,
 | 
			
		||||
    RuleTest.class,
 | 
			
		||||
    ActionTest.class,
 | 
			
		||||
    SimpleConditionTest.class,
 | 
			
		||||
    CompositeConditionTest.class
 | 
			
		||||
})
 | 
			
		||||
public class RulesUnitTests
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@@ -1,527 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.impl;
 | 
			
		||||
 | 
			
		||||
import static java.util.Collections.emptyList;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.RuleSet.DEFAULT_ID;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.any;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.eq;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.isNull;
 | 
			
		||||
import static org.mockito.BDDMockito.given;
 | 
			
		||||
import static org.mockito.BDDMockito.then;
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import junit.framework.TestCase;
 | 
			
		||||
import org.alfresco.rest.api.Nodes;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.Rule;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Paging;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.StoreRef;
 | 
			
		||||
import org.alfresco.service.cmr.rule.RuleService;
 | 
			
		||||
import org.alfresco.service.cmr.security.AccessStatus;
 | 
			
		||||
import org.alfresco.service.cmr.security.PermissionService;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.MockitoAnnotations;
 | 
			
		||||
import org.mockito.junit.MockitoJUnitRunner;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
@RunWith(MockitoJUnitRunner.class)
 | 
			
		||||
public class RulesImplTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    private static final String FOLDER_NODE_ID = "dummy-folder-node-id";
 | 
			
		||||
    private static final String RULE_SET_ID = "dummy-rule-set-id";
 | 
			
		||||
    private static final String RULE_ID = "dummy-rule-id";
 | 
			
		||||
    private static final NodeRef folderNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_NODE_ID);
 | 
			
		||||
    private static final NodeRef ruleSetNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
 | 
			
		||||
    private static final NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID);
 | 
			
		||||
    private static final Paging paging = Paging.DEFAULT;
 | 
			
		||||
    private static final String RULE_NAME = "Rule name";
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private Nodes nodesMock;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private PermissionService permissionServiceMock;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private RuleService ruleServiceMock;
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private RulesImpl rules;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setUp() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        MockitoAnnotations.openMocks(this);
 | 
			
		||||
 | 
			
		||||
        given(nodesMock.validateOrLookupNode(eq(FOLDER_NODE_ID), any())).willReturn(folderNodeRef);
 | 
			
		||||
        given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
 | 
			
		||||
        given(nodesMock.nodeMatches(any(), any(), any())).willReturn(true);
 | 
			
		||||
        given(permissionServiceMock.hasReadPermission(any())).willReturn(AccessStatus.ALLOWED);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRules()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
 | 
			
		||||
        given(ruleServiceMock.getRules(any())).willReturn(List.of(createRule(RULE_ID)));
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging);
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_SET_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().getRules(folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        assertThat(rulesPage)
 | 
			
		||||
                .isNotNull()
 | 
			
		||||
            .extracting(CollectionWithPagingInfo::getCollection)
 | 
			
		||||
                .isNotNull()
 | 
			
		||||
            .extracting(Collection::size)
 | 
			
		||||
                .isEqualTo(1);
 | 
			
		||||
        assertThat(rulesPage.getCollection().stream().findFirst().orElse(null))
 | 
			
		||||
                .isNotNull()
 | 
			
		||||
            .extracting(Rule::getId)
 | 
			
		||||
                .isEqualTo(RULE_ID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRulesForDefaultRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.getRules(any())).willReturn(List.of(createRule(RULE_ID)));
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, DEFAULT_ID, paging);
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().getRules(folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        assertThat(rulesPage)
 | 
			
		||||
                .isNotNull()
 | 
			
		||||
            .extracting(CollectionWithPagingInfo::getCollection)
 | 
			
		||||
                .isNotNull()
 | 
			
		||||
            .extracting(Collection::size)
 | 
			
		||||
                .isEqualTo(1);
 | 
			
		||||
        assertThat(rulesPage.getCollection().stream().findFirst().orElse(null))
 | 
			
		||||
                .isNotNull()
 | 
			
		||||
            .extracting(Rule::getId)
 | 
			
		||||
                .isEqualTo(RULE_ID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRulesForNotExistingFolderNode()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodesMock.nodeMatches(eq(folderNodeRef), any(), any())).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
            () -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging));
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRulesForNotExistingRuleSetNode()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodesMock.nodeMatches(eq(folderNodeRef), any(), any())).willReturn(true);
 | 
			
		||||
        given(nodesMock.nodeMatches(eq(ruleSetNodeRef), any(), any())).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
            () -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging));
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRulesForNotAssociatedRuleSetToFolder()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
            () -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging));
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRulesWithoutReadPermission()
 | 
			
		||||
    {
 | 
			
		||||
        given(permissionServiceMock.hasReadPermission(any())).willReturn(AccessStatus.DENIED);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(
 | 
			
		||||
            () -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging));
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRuleById()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
 | 
			
		||||
        given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(true);
 | 
			
		||||
        given(ruleServiceMock.getRule(any())).willReturn(createRule(RULE_ID));
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        final Rule rule = rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID);
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_SET_ID);
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(ruleNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().getRule(ruleNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        assertThat(rule)
 | 
			
		||||
                .isNotNull()
 | 
			
		||||
            .extracting(Rule::getId)
 | 
			
		||||
                .isEqualTo(RULE_ID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRuleByIdForDefaultRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        final String defaultRuleSetId = "-default-";
 | 
			
		||||
        given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
 | 
			
		||||
        given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef);
 | 
			
		||||
        given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(true);
 | 
			
		||||
        given(ruleServiceMock.getRule(any())).willReturn(createRule(RULE_ID));
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        final Rule rule = rules.getRuleById(FOLDER_NODE_ID, defaultRuleSetId, RULE_ID);
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(ruleNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().getRule(eq(ruleNodeRef));
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        assertThat(rule)
 | 
			
		||||
                .isNotNull()
 | 
			
		||||
            .extracting(Rule::getId)
 | 
			
		||||
                .isEqualTo(RULE_ID);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRuleByIdForNotAssociatedRuleToRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
 | 
			
		||||
        given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
 | 
			
		||||
        given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
            () -> rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Create a single rule. */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveRules()
 | 
			
		||||
    {
 | 
			
		||||
        Rule ruleBody = mock(Rule.class);
 | 
			
		||||
        List<Rule> ruleList = List.of(ruleBody);
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
 | 
			
		||||
        org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class);
 | 
			
		||||
        given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody);
 | 
			
		||||
        org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class);
 | 
			
		||||
        given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule);
 | 
			
		||||
        given(serviceRule.getNodeRef()).willReturn(ruleNodeRef);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        List<Rule> actual = rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList);
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock));
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        List<Rule> expected = List.of(Rule.from(serviceRule));
 | 
			
		||||
        assertThat(actual).isEqualTo(expected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Check that when passing the default rule set then we don't perform any validation around the rule set node. */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveRules_defaultRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        Rule ruleBody = mock(Rule.class);
 | 
			
		||||
        List<Rule> ruleList = List.of(ruleBody);
 | 
			
		||||
        org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class);
 | 
			
		||||
        given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody);
 | 
			
		||||
        org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class);
 | 
			
		||||
        given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule);
 | 
			
		||||
        given(serviceRule.getNodeRef()).willReturn(ruleNodeRef);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        List<Rule> actual = rules.createRules(folderNodeRef.getId(), DEFAULT_ID, ruleList);
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock));
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        List<Rule> expected = List.of(Rule.from(serviceRule));
 | 
			
		||||
        assertThat(actual).isEqualTo(expected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveRules_ruleSetNotAssociatedWithFolder()
 | 
			
		||||
    {
 | 
			
		||||
        Rule rule = Rule.builder().setName(RULE_NAME)
 | 
			
		||||
                                  .createRule();
 | 
			
		||||
        List<Rule> ruleList = List.of(rule);
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef)).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
                () -> rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList));
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveRules_emptyRuleList()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
 | 
			
		||||
        List<Rule> ruleList = emptyList();
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        List<Rule> actual = this.rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList);
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        assertThat(actual).isEqualTo(emptyList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Create three rules in a single call and check they are all passed to the RuleService. */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSaveRules_createMultipleRules()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
 | 
			
		||||
        List<Rule> ruleBodyList = new ArrayList<>();
 | 
			
		||||
        List<Rule> expected = new ArrayList<>();
 | 
			
		||||
        for (String ruleId : List.of("A", "B", "C"))
 | 
			
		||||
        {
 | 
			
		||||
            Rule ruleBody = mock(Rule.class);
 | 
			
		||||
            ruleBodyList.add(ruleBody);
 | 
			
		||||
            org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class);
 | 
			
		||||
            given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody);
 | 
			
		||||
            org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class);
 | 
			
		||||
            given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule);
 | 
			
		||||
            NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, ruleId);
 | 
			
		||||
            given(serviceRule.getNodeRef()).willReturn(ruleNodeRef);
 | 
			
		||||
            expected.add(Rule.from(serviceRule));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        List<Rule> actual = rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleBodyList);
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        for (Rule ruleBody : ruleBodyList)
 | 
			
		||||
        {
 | 
			
		||||
            then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock));
 | 
			
		||||
        }
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        assertThat(actual).isEqualTo(expected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteRuleById() {
 | 
			
		||||
        given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
 | 
			
		||||
        given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
 | 
			
		||||
        given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(true);
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
 | 
			
		||||
        org.alfresco.service.cmr.rule.Rule rule = createRule(RULE_ID);
 | 
			
		||||
        given(ruleServiceMock.getRule(any())).willReturn(rule);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID);
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_SET_ID);
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(ruleNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().getRule(ruleNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().removeRule(folderNodeRef, rule);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteRuleById_NonExistingRuleId() {
 | 
			
		||||
        given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
 | 
			
		||||
        given(nodesMock.validateNode(RULE_ID)).willThrow(new EntityNotFoundException(RULE_ID));
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
 | 
			
		||||
                () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_SET_ID);
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteRuleById_RuleIdNotInRuleSet() {
 | 
			
		||||
        given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
 | 
			
		||||
        given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
 | 
			
		||||
        given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
                () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_SET_ID);
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(ruleNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteRuleById_NonExistingRuleSetId() {
 | 
			
		||||
        given(nodesMock.validateNode(RULE_SET_ID)).willThrow(new EntityNotFoundException(RULE_SET_ID));
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
 | 
			
		||||
                () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_SET_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteRuleById_RuleSetNotInFolder() {
 | 
			
		||||
        given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
                () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_SET_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteRuleById_NonExistingFolderId() {
 | 
			
		||||
        given(nodesMock.validateOrLookupNode(FOLDER_NODE_ID, null)).willThrow(new EntityNotFoundException(RULE_ID));
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
 | 
			
		||||
                () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static org.alfresco.service.cmr.rule.Rule createRule(final String id) {
 | 
			
		||||
        final org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule();
 | 
			
		||||
        rule.setNodeRef(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id));
 | 
			
		||||
 | 
			
		||||
        return rule;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,592 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
import static org.junit.Assert.assertEquals;
 | 
			
		||||
import static org.junit.Assert.assertTrue;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.any;
 | 
			
		||||
import static org.mockito.BDDMockito.given;
 | 
			
		||||
import static org.mockito.BDDMockito.then;
 | 
			
		||||
import static org.mockito.Mockito.times;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.repo.action.executer.AddFeaturesActionExecuter;
 | 
			
		||||
import org.alfresco.repo.action.executer.CheckInActionExecuter;
 | 
			
		||||
import org.alfresco.repo.action.executer.CheckOutActionExecuter;
 | 
			
		||||
import org.alfresco.repo.action.executer.CopyActionExecuter;
 | 
			
		||||
import org.alfresco.repo.action.executer.LinkCategoryActionExecuter;
 | 
			
		||||
import org.alfresco.repo.action.executer.MoveActionExecuter;
 | 
			
		||||
import org.alfresco.repo.action.executer.RemoveFeaturesActionExecuter;
 | 
			
		||||
import org.alfresco.repo.action.executer.ScriptActionExecuter;
 | 
			
		||||
import org.alfresco.repo.action.executer.SetPropertyValueActionExecuter;
 | 
			
		||||
import org.alfresco.repo.action.executer.SimpleWorkflowActionExecuter;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.action.ActionDefinition;
 | 
			
		||||
import org.alfresco.service.cmr.action.ActionService;
 | 
			
		||||
import org.alfresco.service.cmr.action.ParameterDefinition;
 | 
			
		||||
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
 | 
			
		||||
import org.alfresco.service.cmr.dictionary.DictionaryService;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.namespace.NamespaceService;
 | 
			
		||||
import org.alfresco.service.namespace.QName;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.junit.MockitoJUnitRunner;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
@RunWith(MockitoJUnitRunner.class)
 | 
			
		||||
public class ActionParameterConverterTest
 | 
			
		||||
{
 | 
			
		||||
    private static final String VERSIONABLE = "versionable";
 | 
			
		||||
    private static final String VERSIONABLE_ASPECT = NamespaceService.CONTENT_MODEL_PREFIX + QName.NAMESPACE_PREFIX + VERSIONABLE;
 | 
			
		||||
    private static final String CHECKOUT = "checkout";
 | 
			
		||||
    private static final String CHECKOUT_ASPECT = NamespaceService.CONTENT_MODEL_PREFIX + QName.NAMESPACE_PREFIX + CHECKOUT;
 | 
			
		||||
    private static final String CONTAINS = "contains";
 | 
			
		||||
    private static final String CONTAINS_ASPECT = NamespaceService.CONTENT_MODEL_PREFIX + QName.NAMESPACE_PREFIX + CONTAINS;
 | 
			
		||||
    private static final String CLASSIFIABLE = "generalclassifiable";
 | 
			
		||||
    private static final String CLASSIFIABLE_ASPECT = NamespaceService.CONTENT_MODEL_PREFIX + QName.NAMESPACE_PREFIX + CLASSIFIABLE;
 | 
			
		||||
    private static final String IDENTIFIER = "identifier";
 | 
			
		||||
    private static final String IDENTIFIER_ASPECT = NamespaceService.CONTENT_MODEL_PREFIX + QName.NAMESPACE_PREFIX + IDENTIFIER;
 | 
			
		||||
 | 
			
		||||
    private static final String DUMMY_FOLDER_NODE_ID = "dummy-folder-node";
 | 
			
		||||
    private static final String DUMMY_SCRIPT_NODE_ID = "dummy-script-ref";
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private DictionaryService dictionaryService;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ActionService actionService;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private NamespaceService namespaceService;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ActionDefinition actionDefinition;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ParameterDefinition actionDefinitionParam1;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ParameterDefinition actionDefinitionParam2;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ParameterDefinition actionDefinitionParam3;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private DataTypeDefinition dataTypeDefinition1;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private DataTypeDefinition dataTypeDefinition2;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private DataTypeDefinition dataTypeDefinition3;
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private ActionParameterConverter objectUnderTest;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testAddAspectConversion()
 | 
			
		||||
    {
 | 
			
		||||
        final String name = AddFeaturesActionExecuter.NAME;
 | 
			
		||||
        final String aspectNameKey = AddFeaturesActionExecuter.PARAM_ASPECT_NAME;
 | 
			
		||||
        final Map<String, Serializable> params = Map.of(aspectNameKey, VERSIONABLE_ASPECT);
 | 
			
		||||
 | 
			
		||||
        given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(aspectNameKey)).willReturn(actionDefinitionParam1);
 | 
			
		||||
        final QName qname = DataTypeDefinition.QNAME;
 | 
			
		||||
        given(actionDefinitionParam1.getType()).willReturn(qname);
 | 
			
		||||
        given(dictionaryService.getDataType(qname)).willReturn(dataTypeDefinition1);
 | 
			
		||||
        given(namespaceService.getNamespaceURI(any())).willReturn(NamespaceService.DICTIONARY_MODEL_1_0_URI);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
 | 
			
		||||
 | 
			
		||||
        then(actionService).should().getActionDefinition(name);
 | 
			
		||||
        then(actionService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(aspectNameKey);
 | 
			
		||||
        then(actionDefinition).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(dictionaryService).should().getDataType(qname);
 | 
			
		||||
        then(dictionaryService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(namespaceService).should().getNamespaceURI(any());
 | 
			
		||||
        then(namespaceService).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        final Serializable convertedParam = convertedParams.get(aspectNameKey);
 | 
			
		||||
        assertTrue(convertedParam instanceof QName);
 | 
			
		||||
        assertEquals(VERSIONABLE, ((QName) convertedParam).getLocalName());
 | 
			
		||||
        assertEquals(VERSIONABLE_ASPECT, ((QName) convertedParam).getPrefixString());
 | 
			
		||||
        assertEquals(NamespaceService.DICTIONARY_MODEL_1_0_URI, ((QName) convertedParam).getNamespaceURI());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCopyConversion()
 | 
			
		||||
    {
 | 
			
		||||
        final String name = CopyActionExecuter.NAME;
 | 
			
		||||
        final String destinationFolderKey = CopyActionExecuter.PARAM_DESTINATION_FOLDER;
 | 
			
		||||
        final String deepCopyKey = CopyActionExecuter.PARAM_DEEP_COPY;
 | 
			
		||||
        final Map<String, Serializable> params = Map.of(destinationFolderKey, DUMMY_FOLDER_NODE_ID, deepCopyKey, true);
 | 
			
		||||
 | 
			
		||||
        given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(destinationFolderKey)).willReturn(actionDefinitionParam1);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(deepCopyKey)).willReturn(actionDefinitionParam2);
 | 
			
		||||
        final QName nodeRef = DataTypeDefinition.NODE_REF;
 | 
			
		||||
        given(actionDefinitionParam1.getType()).willReturn(nodeRef);
 | 
			
		||||
        final QName bool = DataTypeDefinition.BOOLEAN;
 | 
			
		||||
        given(actionDefinitionParam2.getType()).willReturn(bool);
 | 
			
		||||
 | 
			
		||||
        given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
 | 
			
		||||
        given(dictionaryService.getDataType(bool)).willReturn(dataTypeDefinition2);
 | 
			
		||||
        given(dataTypeDefinition2.getJavaClassName()).willReturn(Boolean.class.getName());
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
 | 
			
		||||
 | 
			
		||||
        then(actionService).should().getActionDefinition(name);
 | 
			
		||||
        then(actionService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(destinationFolderKey);
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(deepCopyKey);
 | 
			
		||||
        then(actionDefinition).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(dictionaryService).should(times(2)).getDataType(bool);
 | 
			
		||||
        then(dictionaryService).should().getDataType(nodeRef);
 | 
			
		||||
        then(dictionaryService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(namespaceService).shouldHaveNoInteractions();
 | 
			
		||||
 | 
			
		||||
        final Serializable convertedCopyParam = convertedParams.get(destinationFolderKey);
 | 
			
		||||
        assertTrue(convertedCopyParam instanceof NodeRef);
 | 
			
		||||
        assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedCopyParam).getStoreRef());
 | 
			
		||||
        assertEquals(DUMMY_FOLDER_NODE_ID, ((NodeRef) convertedCopyParam).getId());
 | 
			
		||||
        final Serializable convertedDeepCopyParam = convertedParams.get(deepCopyKey);
 | 
			
		||||
        assertThat(convertedDeepCopyParam instanceof Boolean).isTrue();
 | 
			
		||||
        assertTrue(((Boolean) convertedDeepCopyParam));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testExecuteScriptConversion()
 | 
			
		||||
    {
 | 
			
		||||
        final String name = ScriptActionExecuter.NAME;
 | 
			
		||||
        final String executeScriptKey = ScriptActionExecuter.PARAM_SCRIPTREF;
 | 
			
		||||
        final Map<String, Serializable> params = Map.of(executeScriptKey, DUMMY_SCRIPT_NODE_ID);
 | 
			
		||||
 | 
			
		||||
        given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(executeScriptKey)).willReturn(actionDefinitionParam1);
 | 
			
		||||
        final QName scriptNodeRef = DataTypeDefinition.NODE_REF;
 | 
			
		||||
        given(actionDefinitionParam1.getType()).willReturn(scriptNodeRef);
 | 
			
		||||
 | 
			
		||||
        given(dictionaryService.getDataType(scriptNodeRef)).willReturn(dataTypeDefinition1);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
 | 
			
		||||
 | 
			
		||||
        then(actionService).should().getActionDefinition(name);
 | 
			
		||||
        then(actionService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(executeScriptKey);
 | 
			
		||||
        then(actionDefinition).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(dictionaryService).should().getDataType(scriptNodeRef);
 | 
			
		||||
        then(dictionaryService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(namespaceService).shouldHaveNoInteractions();
 | 
			
		||||
 | 
			
		||||
        final Serializable convertedCopyParam = convertedParams.get(executeScriptKey);
 | 
			
		||||
        assertTrue(convertedCopyParam instanceof NodeRef);
 | 
			
		||||
        assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedCopyParam).getStoreRef());
 | 
			
		||||
        assertEquals(DUMMY_SCRIPT_NODE_ID, ((NodeRef) convertedCopyParam).getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testMoveConversion()
 | 
			
		||||
    {
 | 
			
		||||
        final String name = MoveActionExecuter.NAME;
 | 
			
		||||
        final String destinationFolderKey = MoveActionExecuter.PARAM_DESTINATION_FOLDER;
 | 
			
		||||
        final Map<String, Serializable> params = Map.of(destinationFolderKey, DUMMY_FOLDER_NODE_ID);
 | 
			
		||||
 | 
			
		||||
        given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(destinationFolderKey)).willReturn(actionDefinitionParam1);
 | 
			
		||||
        final QName nodeRef = DataTypeDefinition.NODE_REF;
 | 
			
		||||
        given(actionDefinitionParam1.getType()).willReturn(nodeRef);
 | 
			
		||||
 | 
			
		||||
        given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
 | 
			
		||||
 | 
			
		||||
        then(actionService).should().getActionDefinition(name);
 | 
			
		||||
        then(actionService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(destinationFolderKey);
 | 
			
		||||
        then(actionDefinition).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(dictionaryService).should().getDataType(nodeRef);
 | 
			
		||||
        then(dictionaryService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(namespaceService).shouldHaveNoInteractions();
 | 
			
		||||
 | 
			
		||||
        final Serializable convertedCopyParam = convertedParams.get(destinationFolderKey);
 | 
			
		||||
        assertTrue(convertedCopyParam instanceof NodeRef);
 | 
			
		||||
        assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedCopyParam).getStoreRef());
 | 
			
		||||
        assertEquals(DUMMY_FOLDER_NODE_ID, ((NodeRef) convertedCopyParam).getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCheckInConversion()
 | 
			
		||||
    {
 | 
			
		||||
        final String name = CheckInActionExecuter.NAME;
 | 
			
		||||
        final String descriptionKey = CheckInActionExecuter.PARAM_DESCRIPTION;
 | 
			
		||||
        final String minorChangeKey = CheckInActionExecuter.PARAM_MINOR_CHANGE;
 | 
			
		||||
        String description = "dummy description";
 | 
			
		||||
        final Map<String, Serializable> params = Map.of(descriptionKey, description, minorChangeKey, true);
 | 
			
		||||
 | 
			
		||||
        given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(descriptionKey)).willReturn(actionDefinitionParam1);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(minorChangeKey)).willReturn(actionDefinitionParam2);
 | 
			
		||||
        final QName text = DataTypeDefinition.TEXT;
 | 
			
		||||
        given(actionDefinitionParam1.getType()).willReturn(text);
 | 
			
		||||
        final QName bool = DataTypeDefinition.BOOLEAN;
 | 
			
		||||
        given(actionDefinitionParam2.getType()).willReturn(bool);
 | 
			
		||||
 | 
			
		||||
        given(dictionaryService.getDataType(text)).willReturn(dataTypeDefinition1);
 | 
			
		||||
        given(dataTypeDefinition1.getJavaClassName()).willReturn(String.class.getName());
 | 
			
		||||
        given(dictionaryService.getDataType(bool)).willReturn(dataTypeDefinition2);
 | 
			
		||||
        given(dataTypeDefinition2.getJavaClassName()).willReturn(Boolean.class.getName());
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
 | 
			
		||||
 | 
			
		||||
        then(actionService).should().getActionDefinition(name);
 | 
			
		||||
        then(actionService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(descriptionKey);
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(minorChangeKey);
 | 
			
		||||
        then(actionDefinition).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(dictionaryService).should(times(2)).getDataType(bool);
 | 
			
		||||
        then(dictionaryService).should(times(2)).getDataType(text);
 | 
			
		||||
        then(dictionaryService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(namespaceService).shouldHaveNoInteractions();
 | 
			
		||||
 | 
			
		||||
        final Serializable convertedDescriptionParam = convertedParams.get(descriptionKey);
 | 
			
		||||
        assertTrue(convertedDescriptionParam instanceof String);
 | 
			
		||||
        assertEquals(description, convertedDescriptionParam);
 | 
			
		||||
        final Serializable convertedMinorChangeParam = convertedParams.get(minorChangeKey);
 | 
			
		||||
        assertTrue(convertedMinorChangeParam instanceof Boolean);
 | 
			
		||||
        assertTrue((Boolean) convertedMinorChangeParam);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCheckOutConversion()
 | 
			
		||||
    {
 | 
			
		||||
        final String name = CheckOutActionExecuter.NAME;
 | 
			
		||||
        final String destinationFolderKey = CheckOutActionExecuter.PARAM_DESTINATION_FOLDER;
 | 
			
		||||
        final String assocNameKey = CheckOutActionExecuter.PARAM_ASSOC_QNAME;
 | 
			
		||||
        final String assocTypeKey = CheckOutActionExecuter.PARAM_ASSOC_TYPE_QNAME;
 | 
			
		||||
        final Map<String, Serializable> params =
 | 
			
		||||
                Map.of(destinationFolderKey, DUMMY_FOLDER_NODE_ID, assocNameKey, CHECKOUT_ASPECT, assocTypeKey, CONTAINS_ASPECT);
 | 
			
		||||
 | 
			
		||||
        given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(destinationFolderKey)).willReturn(actionDefinitionParam1);
 | 
			
		||||
        final QName nodeRef = DataTypeDefinition.NODE_REF;
 | 
			
		||||
        given(actionDefinitionParam1.getType()).willReturn(nodeRef);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(assocNameKey)).willReturn(actionDefinitionParam2);
 | 
			
		||||
        final QName qname = DataTypeDefinition.QNAME;
 | 
			
		||||
        given(actionDefinitionParam2.getType()).willReturn(qname);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(assocTypeKey)).willReturn(actionDefinitionParam3);
 | 
			
		||||
        given(actionDefinitionParam3.getType()).willReturn(qname);
 | 
			
		||||
 | 
			
		||||
        given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
 | 
			
		||||
        given(dictionaryService.getDataType(qname)).willReturn(dataTypeDefinition2);
 | 
			
		||||
        given(namespaceService.getNamespaceURI(any())).willReturn(NamespaceService.DICTIONARY_MODEL_1_0_URI);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
 | 
			
		||||
 | 
			
		||||
        then(actionService).should().getActionDefinition(name);
 | 
			
		||||
        then(actionService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(destinationFolderKey);
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(assocNameKey);
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(assocTypeKey);
 | 
			
		||||
        then(actionDefinition).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(dictionaryService).should(times(2)).getDataType(qname);
 | 
			
		||||
        then(dictionaryService).should().getDataType(nodeRef);
 | 
			
		||||
        then(dictionaryService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(namespaceService).should(times(2)).getNamespaceURI(any());
 | 
			
		||||
        then(namespaceService).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        final Serializable convertedDestinationParam = convertedParams.get(destinationFolderKey);
 | 
			
		||||
        assertTrue(convertedDestinationParam instanceof NodeRef);
 | 
			
		||||
        assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedDestinationParam).getStoreRef());
 | 
			
		||||
        assertEquals(DUMMY_FOLDER_NODE_ID, ((NodeRef) convertedDestinationParam).getId());
 | 
			
		||||
        final Serializable convertedAssocNameParam = convertedParams.get(assocNameKey);
 | 
			
		||||
        assertTrue(convertedAssocNameParam instanceof QName);
 | 
			
		||||
        assertEquals(CHECKOUT, ((QName) convertedAssocNameParam).getLocalName());
 | 
			
		||||
        assertEquals(CHECKOUT_ASPECT, ((QName) convertedAssocNameParam).getPrefixString());
 | 
			
		||||
        assertEquals(NamespaceService.DICTIONARY_MODEL_1_0_URI, ((QName) convertedAssocNameParam).getNamespaceURI());
 | 
			
		||||
        final Serializable convertedAssocTypeParam = convertedParams.get(assocTypeKey);
 | 
			
		||||
        assertTrue(convertedAssocTypeParam instanceof QName);
 | 
			
		||||
        assertEquals(CONTAINS, ((QName) convertedAssocTypeParam).getLocalName());
 | 
			
		||||
        assertEquals(CONTAINS_ASPECT, ((QName) convertedAssocTypeParam).getPrefixString());
 | 
			
		||||
        assertEquals(NamespaceService.DICTIONARY_MODEL_1_0_URI, ((QName) convertedAssocTypeParam).getNamespaceURI());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCategoryLinkConversion()
 | 
			
		||||
    {
 | 
			
		||||
        final String name = LinkCategoryActionExecuter.NAME;
 | 
			
		||||
        final String categoryAspectKey = LinkCategoryActionExecuter.PARAM_CATEGORY_ASPECT;
 | 
			
		||||
        final String categoryValueKey = LinkCategoryActionExecuter.PARAM_CATEGORY_VALUE;
 | 
			
		||||
        final Map<String, Serializable> params = Map.of(categoryAspectKey, CLASSIFIABLE_ASPECT, categoryValueKey, DUMMY_FOLDER_NODE_ID);
 | 
			
		||||
 | 
			
		||||
        given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(categoryAspectKey)).willReturn(actionDefinitionParam1);
 | 
			
		||||
        final QName qname = DataTypeDefinition.QNAME;
 | 
			
		||||
        given(actionDefinitionParam1.getType()).willReturn(qname);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(categoryValueKey)).willReturn(actionDefinitionParam2);
 | 
			
		||||
        final QName nodeRef = DataTypeDefinition.NODE_REF;
 | 
			
		||||
        given(actionDefinitionParam2.getType()).willReturn(nodeRef);
 | 
			
		||||
 | 
			
		||||
        given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
 | 
			
		||||
        given(dictionaryService.getDataType(qname)).willReturn(dataTypeDefinition2);
 | 
			
		||||
        given(namespaceService.getNamespaceURI(any())).willReturn(NamespaceService.DICTIONARY_MODEL_1_0_URI);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
 | 
			
		||||
 | 
			
		||||
        then(actionService).should().getActionDefinition(name);
 | 
			
		||||
        then(actionService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(categoryAspectKey);
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(categoryValueKey);
 | 
			
		||||
        then(actionDefinition).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(dictionaryService).should().getDataType(qname);
 | 
			
		||||
        then(dictionaryService).should().getDataType(nodeRef);
 | 
			
		||||
        then(dictionaryService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(namespaceService).should().getNamespaceURI(any());
 | 
			
		||||
        then(namespaceService).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        final Serializable convertedCatValueParam = convertedParams.get(categoryAspectKey);
 | 
			
		||||
        assertTrue(convertedCatValueParam instanceof QName);
 | 
			
		||||
        assertEquals(CLASSIFIABLE, ((QName) convertedCatValueParam).getLocalName());
 | 
			
		||||
        assertEquals(CLASSIFIABLE_ASPECT, ((QName) convertedCatValueParam).getPrefixString());
 | 
			
		||||
        assertEquals(NamespaceService.DICTIONARY_MODEL_1_0_URI, ((QName) convertedCatValueParam).getNamespaceURI());
 | 
			
		||||
        final Serializable convertedDestinationParam = convertedParams.get(categoryValueKey);
 | 
			
		||||
        assertTrue(convertedDestinationParam instanceof NodeRef);
 | 
			
		||||
        assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedDestinationParam).getStoreRef());
 | 
			
		||||
        assertEquals(DUMMY_FOLDER_NODE_ID, ((NodeRef) convertedDestinationParam).getId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testRemoveAspectConversion()
 | 
			
		||||
    {
 | 
			
		||||
        final String name = RemoveFeaturesActionExecuter.NAME;
 | 
			
		||||
        final String aspectNameKey = RemoveFeaturesActionExecuter.PARAM_ASPECT_NAME;
 | 
			
		||||
        final Map<String, Serializable> params = Map.of(aspectNameKey, VERSIONABLE_ASPECT);
 | 
			
		||||
 | 
			
		||||
        given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(aspectNameKey)).willReturn(actionDefinitionParam1);
 | 
			
		||||
        final QName qname = DataTypeDefinition.QNAME;
 | 
			
		||||
        given(actionDefinitionParam1.getType()).willReturn(qname);
 | 
			
		||||
        given(dictionaryService.getDataType(qname)).willReturn(dataTypeDefinition1);
 | 
			
		||||
        given(namespaceService.getNamespaceURI(any())).willReturn(NamespaceService.DICTIONARY_MODEL_1_0_URI);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
 | 
			
		||||
 | 
			
		||||
        then(actionService).should().getActionDefinition(name);
 | 
			
		||||
        then(actionService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(aspectNameKey);
 | 
			
		||||
        then(actionDefinition).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(dictionaryService).should().getDataType(qname);
 | 
			
		||||
        then(dictionaryService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(namespaceService).should().getNamespaceURI(any());
 | 
			
		||||
        then(namespaceService).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        final Serializable convertedParam = convertedParams.get(aspectNameKey);
 | 
			
		||||
        assertTrue(convertedParam instanceof QName);
 | 
			
		||||
        assertEquals(VERSIONABLE, ((QName) convertedParam).getLocalName());
 | 
			
		||||
        assertEquals(VERSIONABLE_ASPECT, ((QName) convertedParam).getPrefixString());
 | 
			
		||||
        assertEquals(NamespaceService.DICTIONARY_MODEL_1_0_URI, ((QName) convertedParam).getNamespaceURI());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testAddWorkflowConversion()
 | 
			
		||||
    {
 | 
			
		||||
        final String name = SimpleWorkflowActionExecuter.NAME;
 | 
			
		||||
        final String approveStepKey = SimpleWorkflowActionExecuter.PARAM_APPROVE_STEP;
 | 
			
		||||
        final String approveFolderKey = SimpleWorkflowActionExecuter.PARAM_APPROVE_FOLDER;
 | 
			
		||||
        final String approveMoveKey = SimpleWorkflowActionExecuter.PARAM_APPROVE_MOVE;
 | 
			
		||||
        final String rejectStepKey = SimpleWorkflowActionExecuter.PARAM_REJECT_STEP;
 | 
			
		||||
        final String rejectFolderKey = SimpleWorkflowActionExecuter.PARAM_REJECT_FOLDER;
 | 
			
		||||
        final String rejectMoveKey = SimpleWorkflowActionExecuter.PARAM_REJECT_MOVE;
 | 
			
		||||
        final String approve = "Approve";
 | 
			
		||||
        final String reject = "Reject";
 | 
			
		||||
        final Map<String, Serializable> params =
 | 
			
		||||
                Map.of(approveStepKey, approve, approveFolderKey, DUMMY_FOLDER_NODE_ID, approveMoveKey, true,
 | 
			
		||||
                        rejectStepKey, reject, rejectFolderKey, DUMMY_FOLDER_NODE_ID, rejectMoveKey, true);
 | 
			
		||||
 | 
			
		||||
        given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(rejectStepKey)).willReturn(actionDefinitionParam1);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(approveStepKey)).willReturn(actionDefinitionParam1);
 | 
			
		||||
        final QName text = DataTypeDefinition.TEXT;
 | 
			
		||||
        given(actionDefinitionParam1.getType()).willReturn(text, text);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(rejectFolderKey)).willReturn(actionDefinitionParam2);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(approveFolderKey)).willReturn(actionDefinitionParam2);
 | 
			
		||||
        final QName nodeRef = DataTypeDefinition.NODE_REF;
 | 
			
		||||
        given(actionDefinitionParam2.getType()).willReturn(nodeRef, nodeRef);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(rejectMoveKey)).willReturn(actionDefinitionParam3);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(approveMoveKey)).willReturn(actionDefinitionParam3);
 | 
			
		||||
        final QName bool = DataTypeDefinition.BOOLEAN;
 | 
			
		||||
        given(actionDefinitionParam3.getType()).willReturn(bool, bool);
 | 
			
		||||
 | 
			
		||||
        given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
 | 
			
		||||
        given(dictionaryService.getDataType(text)).willReturn(dataTypeDefinition2);
 | 
			
		||||
        given(dataTypeDefinition2.getJavaClassName()).willReturn(String.class.getName());
 | 
			
		||||
        given(dictionaryService.getDataType(bool)).willReturn(dataTypeDefinition3);
 | 
			
		||||
        given(dataTypeDefinition3.getJavaClassName()).willReturn(Boolean.class.getName());
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
 | 
			
		||||
 | 
			
		||||
        then(actionService).should().getActionDefinition(name);
 | 
			
		||||
        then(actionService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(approveStepKey);
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(approveFolderKey);
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(approveMoveKey);
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(rejectStepKey);
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(rejectFolderKey);
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(rejectMoveKey);
 | 
			
		||||
        then(actionDefinition).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(dictionaryService).should(times(4)).getDataType(text);
 | 
			
		||||
        then(dictionaryService).should(times(2)).getDataType(nodeRef);
 | 
			
		||||
        then(dictionaryService).should(times(4)).getDataType(bool);
 | 
			
		||||
        then(dictionaryService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(namespaceService).shouldHaveNoInteractions();
 | 
			
		||||
 | 
			
		||||
        final Serializable convertedApproveStepParam = convertedParams.get(approveStepKey);
 | 
			
		||||
        assertTrue(convertedApproveStepParam instanceof String);
 | 
			
		||||
        assertEquals(approve, convertedApproveStepParam);
 | 
			
		||||
        final Serializable convertedRejectStepParam = convertedParams.get(rejectStepKey);
 | 
			
		||||
        assertTrue(convertedRejectStepParam instanceof String);
 | 
			
		||||
        assertEquals(reject, convertedRejectStepParam);
 | 
			
		||||
        final Serializable convertedApproveFolderParam = convertedParams.get(approveFolderKey);
 | 
			
		||||
        assertTrue(convertedApproveFolderParam instanceof NodeRef);
 | 
			
		||||
        assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedApproveFolderParam).getStoreRef());
 | 
			
		||||
        assertEquals(DUMMY_FOLDER_NODE_ID, ((NodeRef) convertedApproveFolderParam).getId());
 | 
			
		||||
        final Serializable convertedRejectFolderParam = convertedParams.get(rejectFolderKey);
 | 
			
		||||
        assertTrue(convertedRejectFolderParam instanceof NodeRef);
 | 
			
		||||
        assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedRejectFolderParam).getStoreRef());
 | 
			
		||||
        assertEquals(DUMMY_FOLDER_NODE_ID, ((NodeRef) convertedRejectFolderParam).getId());
 | 
			
		||||
        final Serializable convertedApproveMoveParam = convertedParams.get(approveMoveKey);
 | 
			
		||||
        assertTrue(convertedApproveMoveParam instanceof Boolean);
 | 
			
		||||
        assertTrue((Boolean) convertedApproveMoveParam);
 | 
			
		||||
        final Serializable convertedRejectMoveParam = convertedParams.get(rejectMoveKey);
 | 
			
		||||
        assertTrue(convertedRejectMoveParam instanceof Boolean);
 | 
			
		||||
        assertTrue((Boolean) convertedRejectMoveParam);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSetPropertyConversion()
 | 
			
		||||
    {
 | 
			
		||||
        final String name = SetPropertyValueActionExecuter.NAME;
 | 
			
		||||
        final String propertyNameKey = SetPropertyValueActionExecuter.PARAM_PROPERTY;
 | 
			
		||||
        final String propertyValueKey = SetPropertyValueActionExecuter.PARAM_VALUE;
 | 
			
		||||
        final String propertyTypeKey = "prop_type";
 | 
			
		||||
        final String dummy_key_value = "dummy_key_value";
 | 
			
		||||
        final String propType = "d:text";
 | 
			
		||||
        final Map<String, Serializable> params =
 | 
			
		||||
                Map.of(propertyNameKey, IDENTIFIER_ASPECT, propertyValueKey, dummy_key_value, propertyTypeKey, propType);
 | 
			
		||||
 | 
			
		||||
        given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(propertyNameKey)).willReturn(actionDefinitionParam1);
 | 
			
		||||
        final QName qname = DataTypeDefinition.QNAME;
 | 
			
		||||
        given(actionDefinitionParam1.getType()).willReturn(qname);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(propertyValueKey)).willReturn(actionDefinitionParam2);
 | 
			
		||||
        final QName any = DataTypeDefinition.ANY;
 | 
			
		||||
        given(actionDefinitionParam2.getType()).willReturn(any);
 | 
			
		||||
        given(actionDefinition.getParameterDefintion(propertyTypeKey)).willReturn(null);
 | 
			
		||||
        given(actionDefinition.getAdhocPropertiesAllowed()).willReturn(true);
 | 
			
		||||
 | 
			
		||||
        given(dictionaryService.getDataType(qname)).willReturn(dataTypeDefinition1);
 | 
			
		||||
        given(dictionaryService.getDataType(any)).willReturn(dataTypeDefinition2);
 | 
			
		||||
        given(dataTypeDefinition2.getJavaClassName()).willReturn(Object.class.getName());
 | 
			
		||||
        given(namespaceService.getNamespaceURI(any())).willReturn(NamespaceService.DICTIONARY_MODEL_1_0_URI);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
 | 
			
		||||
 | 
			
		||||
        then(actionService).should().getActionDefinition(name);
 | 
			
		||||
        then(actionService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(propertyNameKey);
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(propertyValueKey);
 | 
			
		||||
        then(actionDefinition).should().getParameterDefintion(propertyTypeKey);
 | 
			
		||||
        then(actionDefinition).should().getAdhocPropertiesAllowed();
 | 
			
		||||
        then(actionDefinition).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(dictionaryService).should().getDataType(qname);
 | 
			
		||||
        then(dictionaryService).should(times(2)).getDataType(any);
 | 
			
		||||
        then(dictionaryService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(namespaceService).should().getNamespaceURI(any());
 | 
			
		||||
        then(namespaceService).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        final Serializable convertedPropNameParam = convertedParams.get(propertyNameKey);
 | 
			
		||||
        assertTrue(convertedPropNameParam instanceof QName);
 | 
			
		||||
        assertEquals(IDENTIFIER, ((QName) convertedPropNameParam).getLocalName());
 | 
			
		||||
        assertEquals(IDENTIFIER_ASPECT, ((QName) convertedPropNameParam).getPrefixString());
 | 
			
		||||
        assertEquals(NamespaceService.DICTIONARY_MODEL_1_0_URI, ((QName) convertedPropNameParam).getNamespaceURI());
 | 
			
		||||
 | 
			
		||||
        final Serializable convertedPropValParam = convertedParams.get(propertyValueKey);
 | 
			
		||||
        assertTrue(convertedPropValParam instanceof String);
 | 
			
		||||
        assertEquals(dummy_key_value, convertedPropValParam);
 | 
			
		||||
        final Serializable convertedPropTypeParam = convertedParams.get(propertyTypeKey);
 | 
			
		||||
        assertTrue(convertedPropTypeParam instanceof String);
 | 
			
		||||
        assertEquals(propType, convertedPropTypeParam);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testQnameServiceModelParamConversion() {
 | 
			
		||||
        given(namespaceService.getPrefixes(any())).willReturn(List.of("cm"));
 | 
			
		||||
        final String qname = "{cm-dummy-prefix}audio";
 | 
			
		||||
        final Serializable qnameParam = QName.createQName(qname);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Serializable convertedParam = objectUnderTest.convertParamFromServiceModel(qnameParam);
 | 
			
		||||
 | 
			
		||||
        then(namespaceService).should().getPrefixes(any());
 | 
			
		||||
        then(namespaceService).shouldHaveNoMoreInteractions();
 | 
			
		||||
        assertEquals("cm:audio", convertedParam);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testNodeRefServiceModelParamConversion() {
 | 
			
		||||
        //given
 | 
			
		||||
        final Serializable nodeRefParam = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_FOLDER_NODE_ID);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Serializable convertedParam = objectUnderTest.convertParamFromServiceModel(nodeRefParam);
 | 
			
		||||
 | 
			
		||||
        then(namespaceService).shouldHaveNoInteractions();
 | 
			
		||||
        assertEquals(DUMMY_FOLDER_NODE_ID, convertedParam);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testOtherServiceModelParamConversion() {
 | 
			
		||||
        //given
 | 
			
		||||
        final Serializable dummyStringParam = "dummy-param";
 | 
			
		||||
        //when
 | 
			
		||||
        final Serializable convertedParam = objectUnderTest.convertParamFromServiceModel(dummyStringParam);
 | 
			
		||||
 | 
			
		||||
        then(namespaceService).shouldHaveNoInteractions();
 | 
			
		||||
        assertEquals(dummyStringParam, convertedParam);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,117 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.service.cmr.rule.RuleType.INBOUND;
 | 
			
		||||
import static org.alfresco.service.cmr.rule.RuleType.OUTBOUND;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 | 
			
		||||
import static org.mockito.BDDMockito.then;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import junit.framework.TestCase;
 | 
			
		||||
import org.alfresco.repo.action.ActionImpl;
 | 
			
		||||
import org.alfresco.repo.action.CompositeActionImpl;
 | 
			
		||||
import org.alfresco.repo.action.RuntimeActionService;
 | 
			
		||||
import org.alfresco.repo.action.executer.CheckOutActionExecuter;
 | 
			
		||||
import org.alfresco.repo.action.executer.CopyActionExecuter;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.action.Action;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.StoreRef;
 | 
			
		||||
import org.alfresco.service.cmr.rule.Rule;
 | 
			
		||||
import org.assertj.core.api.Assertions;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.junit.MockitoJUnitRunner;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
@RunWith(MockitoJUnitRunner.class)
 | 
			
		||||
public class ActionPermissionValidatorTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    private static final String DUMMY_NODE_ID = "dummy-node-id";
 | 
			
		||||
    @Mock
 | 
			
		||||
    private RuntimeActionService runtimeActionService;
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private ActionPermissionValidator objectUnderTest;
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testPositiveRulePermissionValidation()
 | 
			
		||||
    {
 | 
			
		||||
        //given
 | 
			
		||||
        final CompositeActionImpl compositeAction =
 | 
			
		||||
                new CompositeActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "composite-id");
 | 
			
		||||
        final Action action1 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-1",
 | 
			
		||||
                CopyActionExecuter.NAME);
 | 
			
		||||
        compositeAction.addAction(action1);
 | 
			
		||||
        final Action action2 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-2",
 | 
			
		||||
                CheckOutActionExecuter.NAME);
 | 
			
		||||
        compositeAction.addAction(action2);
 | 
			
		||||
        final Rule inputRule = new Rule();
 | 
			
		||||
        inputRule.setAction(compositeAction);
 | 
			
		||||
        inputRule.setRuleTypes(List.of(INBOUND));
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final Rule validatedRule = objectUnderTest.validateRulePermissions(inputRule);
 | 
			
		||||
 | 
			
		||||
        then(runtimeActionService).should().verifyActionAccessRestrictions(action1);
 | 
			
		||||
        then(runtimeActionService).should().verifyActionAccessRestrictions(action2);
 | 
			
		||||
        then(runtimeActionService).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        ((CompositeActionImpl) validatedRule.getAction()).getActions()
 | 
			
		||||
                .forEach(action -> Assertions.assertThat(action.getParameterValue("actionContext")).isEqualTo("rule"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testNegativeRulePermissionValidation()
 | 
			
		||||
    {
 | 
			
		||||
        //given
 | 
			
		||||
        final CompositeActionImpl compositeAction =
 | 
			
		||||
                new CompositeActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "composite-id");
 | 
			
		||||
        final Action action1 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-1",
 | 
			
		||||
                CopyActionExecuter.NAME);
 | 
			
		||||
        compositeAction.addAction(action1);
 | 
			
		||||
        final Action action2 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-2",
 | 
			
		||||
                CheckOutActionExecuter.NAME);
 | 
			
		||||
        compositeAction.addAction(action2);
 | 
			
		||||
        final Rule inputRule = new Rule();
 | 
			
		||||
        inputRule.setAction(compositeAction);
 | 
			
		||||
        inputRule.setRuleTypes(List.of(OUTBOUND));
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(() -> objectUnderTest.validateRulePermissions(inputRule));
 | 
			
		||||
 | 
			
		||||
        then(runtimeActionService).should().verifyActionAccessRestrictions(action1);
 | 
			
		||||
        then(runtimeActionService).should().verifyActionAccessRestrictions(action2);
 | 
			
		||||
        then(runtimeActionService).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,441 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.model.ContentModel.TYPE_FOLDER;
 | 
			
		||||
import static org.alfresco.model.ContentModel.TYPE_SYSTEM_FOLDER;
 | 
			
		||||
import static org.alfresco.repo.rule.RuleModel.TYPE_RULE;
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.RuleSet.DEFAULT_ID;
 | 
			
		||||
import static org.alfresco.service.cmr.security.AccessStatus.ALLOWED;
 | 
			
		||||
import static org.alfresco.service.cmr.security.AccessStatus.DENIED;
 | 
			
		||||
import static org.alfresco.service.cmr.security.PermissionService.CHANGE_PERMISSIONS;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.any;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.eq;
 | 
			
		||||
import static org.mockito.BDDMockito.given;
 | 
			
		||||
import static org.mockito.BDDMockito.then;
 | 
			
		||||
import static org.mockito.Mockito.reset;
 | 
			
		||||
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.model.ContentModel;
 | 
			
		||||
import org.alfresco.rest.api.Nodes;
 | 
			
		||||
import org.alfresco.rest.api.model.Node;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
 | 
			
		||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeService;
 | 
			
		||||
import org.alfresco.service.cmr.repository.StoreRef;
 | 
			
		||||
import org.alfresco.service.cmr.rule.RuleService;
 | 
			
		||||
import org.alfresco.service.cmr.security.PermissionService;
 | 
			
		||||
import org.junit.Assert;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.MockitoAnnotations;
 | 
			
		||||
 | 
			
		||||
public class NodeValidatorTest
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    private static final String FOLDER_NODE_ID = "dummy-folder-node-id";
 | 
			
		||||
    private static final String LINK_TO_NODE_ID = "dummy-link-to-node-id";
 | 
			
		||||
    private static final String RULE_SET_ID = "dummy-rule-set-id";
 | 
			
		||||
    private static final String RULE_ID = "dummy-rule-id";
 | 
			
		||||
    private static final String PARENT_NODE_ID = "dummy-parent-node-id";
 | 
			
		||||
    private static final NodeRef folderNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_NODE_ID);
 | 
			
		||||
    private static final NodeRef ruleSetNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
 | 
			
		||||
    private static final NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID);
 | 
			
		||||
    private static final NodeRef parentNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_NODE_ID);
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private Nodes nodesMock;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private Node ruleSetNodeMock;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private PermissionService permissionServiceMock;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private RuleService ruleServiceMock;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private NodeService nodeServiceMock;
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ChildAssociationRef primaryParentMock;
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private NodeValidator nodeValidator;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setUp() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        MockitoAnnotations.openMocks(this);
 | 
			
		||||
        given(nodesMock.validateOrLookupNode(eq(FOLDER_NODE_ID), any())).willReturn(folderNodeRef);
 | 
			
		||||
        given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
 | 
			
		||||
        given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
 | 
			
		||||
        given(nodesMock.nodeMatches(any(), any(), any())).willReturn(true);
 | 
			
		||||
        given(permissionServiceMock.hasReadPermission(any())).willReturn(ALLOWED);
 | 
			
		||||
        given(permissionServiceMock.hasPermission(any(), any())).willReturn(ALLOWED);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateFolderNode()
 | 
			
		||||
    {
 | 
			
		||||
        // when
 | 
			
		||||
        final NodeRef nodeRef = nodeValidator.validateFolderNode(FOLDER_NODE_ID, false);
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(folderNodeRef, Set.of(TYPE_FOLDER), null);
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
 | 
			
		||||
        assertThat(nodeRef).isNotNull().isEqualTo(folderNodeRef);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateFolderNode_notExistingFolder()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodesMock.validateOrLookupNode(any(), any())).willThrow(new EntityNotFoundException(FOLDER_NODE_ID));
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
 | 
			
		||||
            () -> nodeValidator.validateFolderNode(FOLDER_NODE_ID, false));
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateFolderNode_notMatchingTypeFolder()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodesMock.nodeMatches(any(), eq(Set.of(TYPE_FOLDER)), any())).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
            () -> nodeValidator.validateFolderNode(FOLDER_NODE_ID, false));
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(folderNodeRef, Set.of(TYPE_FOLDER), null);
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateFolderNode_noReadPermission()
 | 
			
		||||
    {
 | 
			
		||||
        given(permissionServiceMock.hasReadPermission(any())).willReturn(DENIED);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(
 | 
			
		||||
            () -> nodeValidator.validateFolderNode(FOLDER_NODE_ID, false));
 | 
			
		||||
 | 
			
		||||
        then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateFolderNode_noChangePermission()
 | 
			
		||||
    {
 | 
			
		||||
        given(permissionServiceMock.hasPermission(any(), any())).willReturn(DENIED);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(() ->
 | 
			
		||||
            nodeValidator.validateFolderNode(folderNodeRef.getId(), true));
 | 
			
		||||
 | 
			
		||||
        then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS);
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void validateRuleSetNode()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        final NodeRef nodeRef = nodeValidator.validateRuleSetNode(RULE_SET_ID, folderNodeRef);
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_SET_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(ruleSetNodeRef, Set.of(TYPE_SYSTEM_FOLDER), null);
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
 | 
			
		||||
        assertThat(nodeRef).isNotNull().isEqualTo(ruleSetNodeRef);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateRuleSetNodeNoParentId()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodesMock.getNode(any())).willReturn(ruleSetNodeMock);
 | 
			
		||||
        given(nodeServiceMock.getPrimaryParent(any())).willReturn(primaryParentMock);
 | 
			
		||||
        given(primaryParentMock.getParentRef()).willReturn(parentNodeRef);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        final NodeRef nodeRef = nodeValidator.validateRuleSetNode(LINK_TO_NODE_ID,true);
 | 
			
		||||
 | 
			
		||||
        assertThat(nodeRef).isNotNull().isEqualTo(parentNodeRef);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void validateRuleSetNode_defaultId()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        final NodeRef nodeRef = nodeValidator.validateRuleSetNode(DEFAULT_ID, folderNodeRef);
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(nodesMock).shouldHaveNoInteractions();
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
 | 
			
		||||
        assertThat(nodeRef).isNotNull().isEqualTo(ruleSetNodeRef);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateRuleSetNode_notExistingRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodesMock.validateNode(RULE_SET_ID)).willThrow(new EntityNotFoundException(RULE_SET_ID));
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
 | 
			
		||||
            () -> nodeValidator.validateRuleSetNode(RULE_SET_ID, folderNodeRef));
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_SET_ID);
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateRuleSetNode_notMatchingTypeSystemFolder()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodesMock.nodeMatches(any(), eq(Set.of(TYPE_SYSTEM_FOLDER)), any())).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
            () -> nodeValidator.validateRuleSetNode(RULE_SET_ID, folderNodeRef));
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_SET_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(ruleSetNodeRef, Set.of(TYPE_SYSTEM_FOLDER), null);
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateRuleSetNode_notExistingDefaultRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.getRuleSetNode(folderNodeRef)).willReturn(null);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(RelationshipResourceNotFoundException.class).isThrownBy(
 | 
			
		||||
            () -> nodeValidator.validateRuleSetNode(DEFAULT_ID, folderNodeRef));
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(nodesMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateRuleSetNode_notAssociatedRuleSetToFolder()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
            () -> nodeValidator.validateRuleSetNode(RULE_SET_ID, folderNodeRef));
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void validateRuleNode()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(true);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        final NodeRef nodeRef = nodeValidator.validateRuleNode(RULE_ID, ruleSetNodeRef);
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(ruleNodeRef, Set.of(TYPE_RULE), null);
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
 | 
			
		||||
        assertThat(nodeRef).isNotNull().isEqualTo(ruleNodeRef);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void validateRuleNode_nullRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        // when
 | 
			
		||||
        final NodeRef nodeRef = nodeValidator.validateRuleNode(RULE_ID, null);
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(ruleNodeRef, Set.of(TYPE_RULE), null);
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        then(permissionServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
 | 
			
		||||
        assertThat(nodeRef).isNotNull().isEqualTo(ruleNodeRef);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateRuleNode_notExistingRule()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodesMock.validateNode(RULE_ID)).willThrow(new EntityNotFoundException(RULE_ID));
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
 | 
			
		||||
            () -> nodeValidator.validateRuleNode(RULE_ID, ruleSetNodeRef));
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_ID);
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateRuleNode_notMatchingTypeRule()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodesMock.nodeMatches(any(), eq(Set.of(TYPE_RULE)), any())).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
            () -> nodeValidator.validateRuleNode(RULE_ID, ruleSetNodeRef));
 | 
			
		||||
 | 
			
		||||
        then(nodesMock).should().validateNode(RULE_ID);
 | 
			
		||||
        then(nodesMock).should().nodeMatches(ruleNodeRef, Set.of(TYPE_RULE), null);
 | 
			
		||||
        then(nodesMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testValidateRuleNode_notAssociatedRuleToRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
            () -> nodeValidator.validateRuleNode(RULE_ID, ruleSetNodeRef));
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testIsRuleSetNode()
 | 
			
		||||
    {
 | 
			
		||||
        //resetting mock to bypass setup method
 | 
			
		||||
        resetNodesMock();
 | 
			
		||||
 | 
			
		||||
        boolean actual = nodeValidator.isRuleSetNode(RULE_SET_ID);
 | 
			
		||||
        Assert.assertTrue(actual);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testIsNotRuleSetNode()
 | 
			
		||||
    {
 | 
			
		||||
        //resetting mock to bypass setup method
 | 
			
		||||
        resetNodesMock();
 | 
			
		||||
 | 
			
		||||
        //using an id that doesn't belong to a ruleset node
 | 
			
		||||
        boolean actual = nodeValidator.isRuleSetNode(FOLDER_NODE_ID);
 | 
			
		||||
        Assert.assertFalse(actual);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testIsRuleSetNotNullAndShared()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.isRuleSetShared(any())).willReturn(true);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        final boolean shared = nodeValidator.isRuleSetNotNullAndShared(ruleSetNodeRef);
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        assertThat(shared).isTrue();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testIsRuleSetNotNullAndShared_nullRuleSetNode()
 | 
			
		||||
    {
 | 
			
		||||
        // when
 | 
			
		||||
        final boolean shared = nodeValidator.isRuleSetNotNullAndShared(null);
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
 | 
			
		||||
        assertThat(shared).isFalse();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testIsRuleSetNotNullAndShared_withoutRuleSetAndWithFolder()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        nodeValidator.isRuleSetNotNullAndShared(null, folderNodeRef);
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testIsRuleSetNotNullAndShared_withRuleSetAndWithFolder()
 | 
			
		||||
    {
 | 
			
		||||
        // when
 | 
			
		||||
        nodeValidator.isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef);
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void resetNodesMock() {
 | 
			
		||||
        reset(nodesMock);
 | 
			
		||||
        given(nodesMock.validateOrLookupNode(eq(FOLDER_NODE_ID), any())).willReturn(folderNodeRef);
 | 
			
		||||
        given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
 | 
			
		||||
        given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
 | 
			
		||||
        given(nodesMock.nodeMatches(ruleSetNodeRef, Set.of(ContentModel.TYPE_SYSTEM_FOLDER), null)).willReturn(true);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,121 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import static java.util.Collections.emptyList;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.api.impl.rules.RuleLoader.IS_SHARED;
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.RuleTrigger.OUTBOUND;
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.RuleTrigger.UPDATE;
 | 
			
		||||
import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
import static org.mockito.BDDMockito.given;
 | 
			
		||||
import static org.mockito.MockitoAnnotations.openMocks;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.rest.api.model.rules.Rule;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.rule.RuleService;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
 | 
			
		||||
/** Unit tests for {@link RuleLoader}. */
 | 
			
		||||
public class RuleLoaderTest
 | 
			
		||||
{
 | 
			
		||||
    private static final String NODE_ID = "node-id";
 | 
			
		||||
    private static final NodeRef NODE_REF = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, NODE_ID);
 | 
			
		||||
    private static final String TITLE = "title";
 | 
			
		||||
    private static final String DESCRIPTION = "description";
 | 
			
		||||
    private static final boolean ENABLED = true;
 | 
			
		||||
    private static final boolean CASCADE = true;
 | 
			
		||||
    private static final boolean EXECUTE_ASYNCHRONOUSLY = false;
 | 
			
		||||
    private static final List<String> TRIGGERS = List.of("update", "outbound");
 | 
			
		||||
    private static final NodeRef RULE_SET_NODE = new NodeRef("rule://set/");
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private RuleLoader ruleLoader;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private RuleService ruleServiceMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private NodeValidator nodeValidatorMock;
 | 
			
		||||
    private org.alfresco.service.cmr.rule.Rule serviceRule = createServiceRule();
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    public void setUp()
 | 
			
		||||
    {
 | 
			
		||||
        openMocks(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLoadRule()
 | 
			
		||||
    {
 | 
			
		||||
        Rule rule = ruleLoader.loadRule(serviceRule, emptyList());
 | 
			
		||||
 | 
			
		||||
        Rule expected = Rule.builder().id(NODE_ID)
 | 
			
		||||
                            .name(TITLE)
 | 
			
		||||
                            .description(DESCRIPTION)
 | 
			
		||||
                            .enabled(ENABLED)
 | 
			
		||||
                            .cascade(CASCADE)
 | 
			
		||||
                            .asynchronous(EXECUTE_ASYNCHRONOUSLY)
 | 
			
		||||
                            .triggers(List.of(UPDATE, OUTBOUND)).create();
 | 
			
		||||
        assertThat(rule).isEqualTo(expected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLoadRule_noExceptionWithNullInclude()
 | 
			
		||||
    {
 | 
			
		||||
        ruleLoader.loadRule(serviceRule, null);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLoadRule_includeIsShared()
 | 
			
		||||
    {
 | 
			
		||||
        // Simulate the rule set being shared.
 | 
			
		||||
        given(ruleServiceMock.getRuleSetNode(NODE_REF)).willReturn(RULE_SET_NODE);
 | 
			
		||||
        given(nodeValidatorMock.isRuleSetNotNullAndShared(RULE_SET_NODE)).willReturn(true);
 | 
			
		||||
 | 
			
		||||
        Rule rule = ruleLoader.loadRule(serviceRule, List.of(IS_SHARED));
 | 
			
		||||
 | 
			
		||||
        assertThat(rule).extracting("isShared").isEqualTo(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private org.alfresco.service.cmr.rule.Rule createServiceRule()
 | 
			
		||||
    {
 | 
			
		||||
        org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule();
 | 
			
		||||
        rule.setNodeRef(NODE_REF);
 | 
			
		||||
        rule.setTitle(TITLE);
 | 
			
		||||
        rule.setDescription(DESCRIPTION);
 | 
			
		||||
        rule.setRuleDisabled(!ENABLED);
 | 
			
		||||
        rule.applyToChildren(CASCADE);
 | 
			
		||||
        rule.setExecuteAsynchronously(EXECUTE_ASYNCHRONOUSLY);
 | 
			
		||||
        rule.setRuleTypes(TRIGGERS);
 | 
			
		||||
        return rule;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,133 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.api.impl.rules.RuleSetLoader.INCLUSION_TYPE;
 | 
			
		||||
import static org.alfresco.rest.api.impl.rules.RuleSetLoader.OWNING_FOLDER;
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.InclusionType.INHERITED;
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.InclusionType.LINKED;
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.InclusionType.OWNED;
 | 
			
		||||
import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE;
 | 
			
		||||
import static org.mockito.BDDMockito.given;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import junit.framework.TestCase;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSet;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeService;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.junit.MockitoJUnitRunner;
 | 
			
		||||
 | 
			
		||||
/** Unit tests for {@link RuleSetLoader}. */
 | 
			
		||||
@Experimental
 | 
			
		||||
@RunWith (MockitoJUnitRunner.class)
 | 
			
		||||
public class RuleSetLoaderTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    private static final String FOLDER_ID = "dummy-folder-id";
 | 
			
		||||
    private static final String RULE_SET_ID = "dummy-rule-set-id";
 | 
			
		||||
    private static final NodeRef FOLDER_NODE = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_ID);
 | 
			
		||||
    private static final NodeRef RULE_SET_NODE = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
 | 
			
		||||
    private static final String LINKING_FOLDER_ID = "linking-folder";
 | 
			
		||||
    private static final NodeRef LINKING_FOLDER = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, LINKING_FOLDER_ID);
 | 
			
		||||
    private static final NodeRef INHERITING_FOLDER = new NodeRef("inheriting://folder/");
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private RuleSetLoader ruleSetLoader;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private NodeService nodeServiceMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ChildAssociationRef ruleSetAssociationMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ChildAssociationRef linkAssociationMock;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setUp()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleSetAssociationMock.getParentRef()).willReturn(FOLDER_NODE);
 | 
			
		||||
        given(nodeServiceMock.getPrimaryParent(RULE_SET_NODE)).willReturn(ruleSetAssociationMock);
 | 
			
		||||
 | 
			
		||||
        given(linkAssociationMock.getParentRef()).willReturn(LINKING_FOLDER);
 | 
			
		||||
        given(nodeServiceMock.getParentAssocs(RULE_SET_NODE)).willReturn(List.of(ruleSetAssociationMock, linkAssociationMock));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLoadRuleSet_noIncludes()
 | 
			
		||||
    {
 | 
			
		||||
        // Call the method under test.
 | 
			
		||||
        RuleSet actual = ruleSetLoader.loadRuleSet(RULE_SET_NODE, FOLDER_NODE, null);
 | 
			
		||||
 | 
			
		||||
        RuleSet expected = RuleSet.builder().id(RULE_SET_ID).create();
 | 
			
		||||
        assertEquals(expected, actual);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLoadRuleSet_includeOwningFolder()
 | 
			
		||||
    {
 | 
			
		||||
        // Call the method under test.
 | 
			
		||||
        RuleSet actual = ruleSetLoader.loadRuleSet(RULE_SET_NODE, FOLDER_NODE, List.of(OWNING_FOLDER));
 | 
			
		||||
 | 
			
		||||
        RuleSet expected = RuleSet.builder().id(RULE_SET_ID).owningFolder(FOLDER_NODE).create();
 | 
			
		||||
        assertEquals(expected, actual);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLoadRuleSet_includeInclusionType()
 | 
			
		||||
    {
 | 
			
		||||
        // Call the method under test.
 | 
			
		||||
        RuleSet actual = ruleSetLoader.loadRuleSet(RULE_SET_NODE, FOLDER_NODE, List.of(INCLUSION_TYPE));
 | 
			
		||||
 | 
			
		||||
        RuleSet expected = RuleSet.builder().id(RULE_SET_ID).inclusionType(OWNED).create();
 | 
			
		||||
        assertEquals(expected, actual);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLoadRuleSet_linkedInclusionType()
 | 
			
		||||
    {
 | 
			
		||||
        // Call the method under test.
 | 
			
		||||
        RuleSet actual = ruleSetLoader.loadRuleSet(RULE_SET_NODE, LINKING_FOLDER, List.of(INCLUSION_TYPE));
 | 
			
		||||
 | 
			
		||||
        RuleSet expected = RuleSet.builder().id(RULE_SET_ID).inclusionType(LINKED).create();
 | 
			
		||||
        assertEquals(expected, actual);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLoadRuleSet_inheritedInclusionType()
 | 
			
		||||
    {
 | 
			
		||||
        // Call the method under test.
 | 
			
		||||
        RuleSet actual = ruleSetLoader.loadRuleSet(RULE_SET_NODE, INHERITING_FOLDER, List.of(INCLUSION_TYPE));
 | 
			
		||||
 | 
			
		||||
        RuleSet expected = RuleSet.builder().id(RULE_SET_ID).inclusionType(INHERITED).create();
 | 
			
		||||
        assertEquals(expected, actual);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,236 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import static java.util.Collections.emptyList;
 | 
			
		||||
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.any;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.anyBoolean;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.eq;
 | 
			
		||||
import static org.mockito.BDDMockito.given;
 | 
			
		||||
import static org.mockito.BDDMockito.then;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import junit.framework.TestCase;
 | 
			
		||||
import org.alfresco.repo.rule.RuleModel;
 | 
			
		||||
import org.alfresco.repo.rule.RuntimeRuleService;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSet;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Paging;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeService;
 | 
			
		||||
import org.alfresco.service.cmr.repository.StoreRef;
 | 
			
		||||
import org.alfresco.service.cmr.rule.RuleService;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.MockitoAnnotations;
 | 
			
		||||
import org.mockito.junit.MockitoJUnitRunner;
 | 
			
		||||
 | 
			
		||||
/** Unit tests for {@link RuleSetsImpl}. */
 | 
			
		||||
@Experimental
 | 
			
		||||
@RunWith (MockitoJUnitRunner.class)
 | 
			
		||||
public class RuleSetsImplTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    private static final String FOLDER_ID = "dummy-folder-id";
 | 
			
		||||
    private static final String LINK_TO_NODE_ID = "dummy-link-to-node-id";
 | 
			
		||||
    private static final String RULE_SET_ID = "dummy-rule-set-id";
 | 
			
		||||
    private static final NodeRef FOLDER_NODE = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_ID);
 | 
			
		||||
    private static final NodeRef LINK_TO_NODE = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, LINK_TO_NODE_ID);
 | 
			
		||||
    private static final NodeRef RULE_SET_NODE = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
 | 
			
		||||
    private static final Paging PAGING = Paging.DEFAULT;
 | 
			
		||||
    private static final List<String> INCLUDES = List.of("dummy-includes");
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private RuleSetsImpl ruleSets;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private RuleSetLoader ruleSetLoaderMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private NodeValidator nodeValidatorMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private NodeService nodeServiceMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private RuleService ruleServiceMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private RuntimeRuleService runtimeRuleServiceMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private RuleSet ruleSetMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ChildAssociationRef assocRef;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setUp()
 | 
			
		||||
    {
 | 
			
		||||
        MockitoAnnotations.openMocks(this);
 | 
			
		||||
 | 
			
		||||
        given(nodeValidatorMock.validateFolderNode(eq(LINK_TO_NODE_ID), anyBoolean())).willReturn(LINK_TO_NODE);
 | 
			
		||||
        given(nodeValidatorMock.validateRuleSetNode(LINK_TO_NODE_ID,true)).willReturn(LINK_TO_NODE);
 | 
			
		||||
        given(nodeValidatorMock.validateFolderNode(eq(FOLDER_ID), anyBoolean())).willReturn(FOLDER_NODE);
 | 
			
		||||
        given(nodeValidatorMock.validateRuleSetNode(RULE_SET_ID, FOLDER_NODE)).willReturn(RULE_SET_NODE);
 | 
			
		||||
 | 
			
		||||
        given(ruleServiceMock.getRuleSetNode(FOLDER_NODE)).willReturn(RULE_SET_NODE);
 | 
			
		||||
        given(ruleSetLoaderMock.loadRuleSet(RULE_SET_NODE, FOLDER_NODE, INCLUDES)).willReturn(ruleSetMock);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRuleSets()
 | 
			
		||||
    {
 | 
			
		||||
        // Call the method under test.
 | 
			
		||||
        CollectionWithPagingInfo<RuleSet> actual = ruleSets.getRuleSets(FOLDER_ID, INCLUDES, PAGING);
 | 
			
		||||
 | 
			
		||||
        then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID, false);
 | 
			
		||||
        then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().getRuleSetNode(FOLDER_NODE);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        Collection<RuleSet> expected = List.of(ruleSetMock);
 | 
			
		||||
        assertEquals(expected, actual.getCollection());
 | 
			
		||||
        assertEquals(PAGING, actual.getPaging());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetZeroRuleSets()
 | 
			
		||||
    {
 | 
			
		||||
        // Simulate no rule sets for the folder.
 | 
			
		||||
        given(ruleServiceMock.getRuleSetNode(FOLDER_NODE)).willReturn(null);
 | 
			
		||||
 | 
			
		||||
        // Call the method under test.
 | 
			
		||||
        CollectionWithPagingInfo<RuleSet> actual = ruleSets.getRuleSets(FOLDER_ID, INCLUDES, PAGING);
 | 
			
		||||
 | 
			
		||||
        then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID, false);
 | 
			
		||||
        then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().getRuleSetNode(FOLDER_NODE);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        assertEquals(emptyList(), actual.getCollection());
 | 
			
		||||
        assertEquals(PAGING, actual.getPaging());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRuleSetById()
 | 
			
		||||
    {
 | 
			
		||||
        // Call the method under test.
 | 
			
		||||
        RuleSet actual = ruleSets.getRuleSetById(FOLDER_ID, RULE_SET_ID, INCLUDES);
 | 
			
		||||
 | 
			
		||||
        then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID, false);
 | 
			
		||||
        then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE);
 | 
			
		||||
        then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        assertEquals(ruleSetMock, actual);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLinkToFolderRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        NodeRef childNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "dummy-child-id");
 | 
			
		||||
 | 
			
		||||
        given(ruleServiceMock.hasRules(any(NodeRef.class))).willReturn(true, false);
 | 
			
		||||
        given(runtimeRuleServiceMock.getSavedRuleFolderAssoc(any(NodeRef.class))).willReturn(assocRef);
 | 
			
		||||
        given(assocRef.getChildRef()).willReturn(childNodeRef);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        String actual = ruleSets.linkToRuleSet(FOLDER_ID,LINK_TO_NODE_ID).getId();
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().hasRules(LINK_TO_NODE);
 | 
			
		||||
        then(ruleServiceMock).should().hasRules(FOLDER_NODE);
 | 
			
		||||
        then(runtimeRuleServiceMock).should().getSavedRuleFolderAssoc(LINK_TO_NODE);
 | 
			
		||||
        then(runtimeRuleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(nodeServiceMock).should().addChild(FOLDER_NODE, childNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER);
 | 
			
		||||
        then(nodeServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        assertEquals(childNodeRef.getId(),actual);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLinkToRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        NodeRef childNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "dummy-child-id");
 | 
			
		||||
 | 
			
		||||
        given(nodeValidatorMock.isRuleSetNode(any())).willReturn(true);
 | 
			
		||||
        given(ruleServiceMock.hasRules(any(NodeRef.class))).willReturn(true, false);
 | 
			
		||||
        given(runtimeRuleServiceMock.getSavedRuleFolderAssoc(any(NodeRef.class))).willReturn(assocRef);
 | 
			
		||||
        given(assocRef.getChildRef()).willReturn(childNodeRef);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        String actual = ruleSets.linkToRuleSet(FOLDER_ID,LINK_TO_NODE_ID).getId();
 | 
			
		||||
 | 
			
		||||
        then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID,true);
 | 
			
		||||
        then(nodeValidatorMock).should().isRuleSetNode(LINK_TO_NODE_ID);
 | 
			
		||||
        then(nodeValidatorMock).should().validateRuleSetNode(LINK_TO_NODE_ID,true);
 | 
			
		||||
        then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().hasRules(LINK_TO_NODE);
 | 
			
		||||
        then(ruleServiceMock).should().hasRules(FOLDER_NODE);
 | 
			
		||||
        then(runtimeRuleServiceMock).should().getSavedRuleFolderAssoc(LINK_TO_NODE);
 | 
			
		||||
        then(runtimeRuleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(nodeServiceMock).should().addChild(FOLDER_NODE, childNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER);
 | 
			
		||||
        then(nodeServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
 | 
			
		||||
        assertEquals(childNodeRef.getId(),actual);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLinkToRuleSet_targetFolderHasNoRules()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.hasRules(LINK_TO_NODE)).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
                () -> ruleSets.linkToRuleSet(FOLDER_ID, LINK_TO_NODE_ID)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        then(nodeServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().hasRules(LINK_TO_NODE);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(runtimeRuleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testLinkToRuleSet_folderShouldntHavePreExistingRules()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.hasRules(any(NodeRef.class))).willReturn(true, true);
 | 
			
		||||
 | 
			
		||||
        //when
 | 
			
		||||
        assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
 | 
			
		||||
                () -> ruleSets.linkToRuleSet(FOLDER_ID, LINK_TO_NODE_ID));
 | 
			
		||||
 | 
			
		||||
        then(nodeServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().hasRules(LINK_TO_NODE);
 | 
			
		||||
        then(ruleServiceMock).should().hasRules(FOLDER_NODE);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(runtimeRuleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,145 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import static java.util.Collections.emptyMap;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.repo.rule.RuleModel.ASPECT_IGNORE_INHERITED_RULES;
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.RuleSetting.IS_INHERITANCE_ENABLED_KEY;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.anyBoolean;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.eq;
 | 
			
		||||
import static org.mockito.BDDMockito.given;
 | 
			
		||||
import static org.mockito.BDDMockito.then;
 | 
			
		||||
 | 
			
		||||
import junit.framework.TestCase;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.RuleSetting;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.NotFoundException;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeService;
 | 
			
		||||
import org.alfresco.service.cmr.repository.StoreRef;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.junit.MockitoJUnitRunner;
 | 
			
		||||
 | 
			
		||||
/** Unit tests for {@link RuleSettingsImpl}. */
 | 
			
		||||
@Experimental
 | 
			
		||||
@RunWith (MockitoJUnitRunner.class)
 | 
			
		||||
public class RuleSettingsImplTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    private static final String FOLDER_ID = "dummy-folder-id";
 | 
			
		||||
    private static final NodeRef FOLDER_NODE = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_ID);
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private RuleSettingsImpl ruleSettings;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private NodeValidator nodeValidatorMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private NodeService nodeServiceMock;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setUp()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodeValidatorMock.validateFolderNode(eq(FOLDER_ID), anyBoolean())).willReturn(FOLDER_NODE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRuleSetting_disabled()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodeServiceMock.hasAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES)).willReturn(true);
 | 
			
		||||
 | 
			
		||||
        // Call the method under test.
 | 
			
		||||
        RuleSetting ruleSetting = ruleSettings.getRuleSetting(FOLDER_ID, IS_INHERITANCE_ENABLED_KEY);
 | 
			
		||||
 | 
			
		||||
        RuleSetting expected = RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(false).create();
 | 
			
		||||
        assertEquals(expected, ruleSetting);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRuleSetting_enabled()
 | 
			
		||||
    {
 | 
			
		||||
        given(nodeServiceMock.hasAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES)).willReturn(false);
 | 
			
		||||
 | 
			
		||||
        // Call the method under test.
 | 
			
		||||
        RuleSetting ruleSetting = ruleSettings.getRuleSetting(FOLDER_ID, IS_INHERITANCE_ENABLED_KEY);
 | 
			
		||||
 | 
			
		||||
        RuleSetting expected = RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(true).create();
 | 
			
		||||
        assertEquals(expected, ruleSetting);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRuleSetting_unrecognisedKey()
 | 
			
		||||
    {
 | 
			
		||||
        assertThatExceptionOfType(NotFoundException.class)
 | 
			
		||||
                .isThrownBy(() -> ruleSettings.getRuleSetting(FOLDER_ID, "-fakeSetting-"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSetRuleSetting_enable()
 | 
			
		||||
    {
 | 
			
		||||
        RuleSetting ruleSetting = RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(true).create();
 | 
			
		||||
 | 
			
		||||
        // Call the method under test.
 | 
			
		||||
        RuleSetting actual = ruleSettings.setRuleSetting(FOLDER_ID, ruleSetting);
 | 
			
		||||
 | 
			
		||||
        assertEquals(ruleSetting, actual);
 | 
			
		||||
        then(nodeServiceMock).should().removeAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSetRuleSetting_disable()
 | 
			
		||||
    {
 | 
			
		||||
        RuleSetting ruleSetting = RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(false).create();
 | 
			
		||||
 | 
			
		||||
        // Call the method under test.
 | 
			
		||||
        RuleSetting actual = ruleSettings.setRuleSetting(FOLDER_ID, ruleSetting);
 | 
			
		||||
 | 
			
		||||
        assertEquals(ruleSetting, actual);
 | 
			
		||||
        then(nodeServiceMock).should().addAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES, emptyMap());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSetRuleSetting_unrecognisedKey()
 | 
			
		||||
    {
 | 
			
		||||
        RuleSetting ruleSetting = RuleSetting.builder().key("-fakeSetting-").value(true).create();
 | 
			
		||||
        assertThatExceptionOfType(NotFoundException.class)
 | 
			
		||||
                .isThrownBy(() -> ruleSettings.setRuleSetting(FOLDER_ID, ruleSetting));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testSetRuleSetting_nonBooleanValue()
 | 
			
		||||
    {
 | 
			
		||||
        RuleSetting ruleSetting = RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(123456).create();
 | 
			
		||||
 | 
			
		||||
        assertThatExceptionOfType(IllegalArgumentException.class)
 | 
			
		||||
                .isThrownBy(() -> ruleSettings.setRuleSetting(FOLDER_ID, ruleSetting));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,628 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.impl.rules;
 | 
			
		||||
 | 
			
		||||
import static java.util.Collections.emptyList;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.rest.api.model.rules.RuleSet.DEFAULT_ID;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.any;
 | 
			
		||||
import static org.mockito.ArgumentMatchers.anyBoolean;
 | 
			
		||||
import static org.mockito.BDDMockito.given;
 | 
			
		||||
import static org.mockito.BDDMockito.then;
 | 
			
		||||
import static org.mockito.Mockito.mock;
 | 
			
		||||
import static org.mockito.Mockito.times;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.stream.IntStream;
 | 
			
		||||
 | 
			
		||||
import junit.framework.TestCase;
 | 
			
		||||
import org.alfresco.repo.action.ActionImpl;
 | 
			
		||||
import org.alfresco.repo.action.CompositeActionImpl;
 | 
			
		||||
import org.alfresco.rest.api.Nodes;
 | 
			
		||||
import org.alfresco.rest.api.model.rules.Rule;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
 | 
			
		||||
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
 | 
			
		||||
import org.alfresco.rest.framework.resource.parameters.Paging;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.action.CompositeAction;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.StoreRef;
 | 
			
		||||
import org.alfresco.service.cmr.rule.RuleService;
 | 
			
		||||
import org.junit.Before;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.junit.runner.RunWith;
 | 
			
		||||
import org.mockito.InjectMocks;
 | 
			
		||||
import org.mockito.Mock;
 | 
			
		||||
import org.mockito.Mockito;
 | 
			
		||||
import org.mockito.junit.MockitoJUnitRunner;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
@RunWith(MockitoJUnitRunner.class)
 | 
			
		||||
public class RulesImplTest extends TestCase
 | 
			
		||||
{
 | 
			
		||||
    private static final String FOLDER_NODE_ID = "dummy-folder-node-id";
 | 
			
		||||
    private static final String RULE_SET_ID = "dummy-rule-set-id";
 | 
			
		||||
    private static final String RULE_ID = "dummy-rule-id";
 | 
			
		||||
    private static final NodeRef FOLDER_NODE_REF = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_NODE_ID);
 | 
			
		||||
    private static final NodeRef RULE_SET_NODE_REF = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
 | 
			
		||||
    private static final NodeRef RULE_NODE_REF = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID);
 | 
			
		||||
    private static final Paging PAGING = Paging.DEFAULT;
 | 
			
		||||
    private static final List<String> INCLUDE = emptyList();
 | 
			
		||||
    private static final String ACTION_DEFINITION_NAME = "actionDefinitionName";
 | 
			
		||||
    private static final Map<String, Serializable> DUMMY_PARAMS = Map.of("dummy-key", "dummy-value");
 | 
			
		||||
 | 
			
		||||
    @Mock
 | 
			
		||||
    private Nodes nodesMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private NodeValidator nodeValidatorMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private RuleService ruleServiceMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private RuleLoader ruleLoaderMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ActionParameterConverter actionParameterConverterMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private ActionPermissionValidator actionPermissionValidatorMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private org.alfresco.service.cmr.rule.Rule serviceRuleMock;
 | 
			
		||||
    @Mock
 | 
			
		||||
    private Rule ruleMock;
 | 
			
		||||
    private org.alfresco.service.cmr.rule.Rule ruleModel = createRule(RULE_ID);
 | 
			
		||||
    private CompositeAction compositeAction = new CompositeActionImpl(RULE_NODE_REF, "compositeActionId");
 | 
			
		||||
 | 
			
		||||
    @InjectMocks
 | 
			
		||||
    private RulesImpl rules;
 | 
			
		||||
 | 
			
		||||
    @Before
 | 
			
		||||
    @Override
 | 
			
		||||
    public void setUp() throws Exception
 | 
			
		||||
    {
 | 
			
		||||
        given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
 | 
			
		||||
        given(nodeValidatorMock.validateRuleSetNode(any(), any())).willReturn(RULE_SET_NODE_REF);
 | 
			
		||||
        given(nodeValidatorMock.validateRuleNode(any(), any())).willReturn(RULE_NODE_REF);
 | 
			
		||||
 | 
			
		||||
        given(ruleServiceMock.getRule(RULE_NODE_REF)).willReturn(ruleModel);
 | 
			
		||||
        given(ruleServiceMock.getRules(FOLDER_NODE_REF)).willReturn(List.of(ruleModel));
 | 
			
		||||
 | 
			
		||||
        given(ruleLoaderMock.loadRule(ruleModel, INCLUDE)).willReturn(ruleMock);
 | 
			
		||||
 | 
			
		||||
        compositeAction.addAction(new ActionImpl(FOLDER_NODE_REF, "actionId", ACTION_DEFINITION_NAME, DUMMY_PARAMS));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRules()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleLoaderMock.loadRule(ruleModel, emptyList())).willReturn(ruleMock);
 | 
			
		||||
        // when
 | 
			
		||||
        final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING);
 | 
			
		||||
 | 
			
		||||
        then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
 | 
			
		||||
        then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
        then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().getRules(FOLDER_NODE_REF);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleLoaderMock).should().loadRule(ruleModel, emptyList());
 | 
			
		||||
        then(ruleLoaderMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        assertThat(rulesPage)
 | 
			
		||||
                .isNotNull()
 | 
			
		||||
                .extracting(CollectionWithPagingInfo::getCollection)
 | 
			
		||||
                .isNotNull()
 | 
			
		||||
                .extracting(Collection::size)
 | 
			
		||||
                .isEqualTo(1);
 | 
			
		||||
        assertThat(rulesPage.getCollection().stream().findFirst().get()).isEqualTo(ruleMock);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRules_emptyResult()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleServiceMock.getRules(any())).willReturn(emptyList());
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING);
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).should().getRules(FOLDER_NODE_REF);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        assertThat(rulesPage)
 | 
			
		||||
                .isNotNull()
 | 
			
		||||
                .extracting(CollectionWithPagingInfo::getCollection)
 | 
			
		||||
                .isNotNull()
 | 
			
		||||
                .extracting(Collection::isEmpty)
 | 
			
		||||
                .isEqualTo(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRules_invalidFolder()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : folderValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRules_invalidRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : ruleSetValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
 | 
			
		||||
            given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
 | 
			
		||||
            then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRuleById()
 | 
			
		||||
    {
 | 
			
		||||
        // when
 | 
			
		||||
        final Rule rule = rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID, INCLUDE);
 | 
			
		||||
 | 
			
		||||
        then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
 | 
			
		||||
        then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
        then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
 | 
			
		||||
        then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(nodesMock).shouldHaveNoInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().getRule(RULE_NODE_REF);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        assertThat(rule).isEqualTo(ruleMock);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRuleById_invalidFolder()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : folderValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID, INCLUDE));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRuleById_invalidRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : ruleSetValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
 | 
			
		||||
            given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID, INCLUDE));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
 | 
			
		||||
            then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testGetRuleById_invalidRule()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : ruleValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
 | 
			
		||||
            given(nodeValidatorMock.validateRuleSetNode(any(), any())).willReturn(RULE_SET_NODE_REF);
 | 
			
		||||
            given(nodeValidatorMock.validateRuleNode(any(), any())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID, INCLUDE));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
 | 
			
		||||
            then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
            then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a single rule.
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCreateRules()
 | 
			
		||||
    {
 | 
			
		||||
        List<Rule> ruleList = List.of(ruleMock);
 | 
			
		||||
        given(ruleMock.toServiceModel(nodesMock)).willReturn(serviceRuleMock);
 | 
			
		||||
        given(serviceRuleMock.getAction()).willReturn(compositeAction);
 | 
			
		||||
        given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMock)).willAnswer(arg -> arg.getArguments()[1]);
 | 
			
		||||
        given(ruleLoaderMock.loadRule(serviceRuleMock, INCLUDE)).willReturn(ruleMock);
 | 
			
		||||
        given(actionPermissionValidatorMock.validateRulePermissions(any())).willAnswer(arg -> arg.getArguments()[0]);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        List<Rule> actual = rules.createRules(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), ruleList, INCLUDE);
 | 
			
		||||
 | 
			
		||||
        then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
        then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
        then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionParameterConverterMock).should().getConvertedParams(DUMMY_PARAMS, ACTION_DEFINITION_NAME);
 | 
			
		||||
        then(actionParameterConverterMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionPermissionValidatorMock).should().validateRulePermissions(serviceRuleMock);
 | 
			
		||||
        then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleMock.toServiceModel(nodesMock));
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        List<Rule> expected = List.of(ruleMock);
 | 
			
		||||
        assertThat(actual).isEqualTo(expected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check that when passing the default rule set then we don't perform any validation around the rule set node.
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCreateRules_defaultRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        List<Rule> ruleList = List.of(ruleMock);
 | 
			
		||||
        given(ruleMock.toServiceModel(nodesMock)).willReturn(serviceRuleMock);
 | 
			
		||||
        given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMock)).willAnswer(arg -> arg.getArguments()[1]);
 | 
			
		||||
        given(ruleLoaderMock.loadRule(serviceRuleMock, INCLUDE)).willReturn(ruleMock);
 | 
			
		||||
        given(serviceRuleMock.getAction()).willReturn(compositeAction);
 | 
			
		||||
        given(actionPermissionValidatorMock.validateRulePermissions(any())).willAnswer(arg -> arg.getArguments()[0]);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        List<Rule> actual = rules.createRules(FOLDER_NODE_REF.getId(), DEFAULT_ID, ruleList, INCLUDE);
 | 
			
		||||
 | 
			
		||||
        then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
        then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionParameterConverterMock).should().getConvertedParams(DUMMY_PARAMS, ACTION_DEFINITION_NAME);
 | 
			
		||||
        then(actionParameterConverterMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionPermissionValidatorMock).should().validateRulePermissions(serviceRuleMock);
 | 
			
		||||
        then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleMock.toServiceModel(nodesMock));
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        List<Rule> expected = List.of(ruleMock);
 | 
			
		||||
        assertThat(actual).isEqualTo(expected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCreateRules_emptyRuleList()
 | 
			
		||||
    {
 | 
			
		||||
        List<Rule> ruleList = emptyList();
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        List<Rule> actual = rules.createRules(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), ruleList, INCLUDE);
 | 
			
		||||
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        assertThat(actual).isEqualTo(emptyList());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create three rules in a single call and check they are all passed to the RuleService.
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCreateRules_createMultipleRules()
 | 
			
		||||
    {
 | 
			
		||||
        List<Rule> ruleBodyList = new ArrayList<>();
 | 
			
		||||
        List<Rule> expected = new ArrayList<>();
 | 
			
		||||
        IntStream.range(0, 3).forEach(i -> {
 | 
			
		||||
            Rule ruleBodyMock = mock(Rule.class);
 | 
			
		||||
            ruleBodyList.add(ruleBodyMock);
 | 
			
		||||
            org.alfresco.service.cmr.rule.Rule serviceRuleMockInner = mock(org.alfresco.service.cmr.rule.Rule.class);
 | 
			
		||||
            given(ruleBodyMock.toServiceModel(nodesMock)).willReturn(serviceRuleMockInner);
 | 
			
		||||
            final CompositeAction compositeActionInner = new CompositeActionImpl(RULE_NODE_REF, "compositeActionInnerId");
 | 
			
		||||
            compositeActionInner.addAction(new ActionImpl(FOLDER_NODE_REF, "actionInnerId", ACTION_DEFINITION_NAME, DUMMY_PARAMS));
 | 
			
		||||
            given(serviceRuleMockInner.getAction()).willReturn(compositeActionInner);
 | 
			
		||||
            given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMockInner)).willAnswer(arg -> arg.getArguments()[1]);
 | 
			
		||||
            Rule ruleMockInner = mock(Rule.class);
 | 
			
		||||
            given(ruleLoaderMock.loadRule(serviceRuleMockInner, INCLUDE)).willReturn(ruleMockInner);
 | 
			
		||||
            expected.add(ruleMockInner);
 | 
			
		||||
            given(actionPermissionValidatorMock.validateRulePermissions(any())).willAnswer(arg -> arg.getArguments()[0]);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        List<Rule> actual = rules.createRules(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), ruleBodyList, INCLUDE);
 | 
			
		||||
 | 
			
		||||
        then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
        then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
        then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        for (Rule ruleBody : ruleBodyList)
 | 
			
		||||
        {
 | 
			
		||||
            then(actionPermissionValidatorMock).should().validateRulePermissions(ruleBody.toServiceModel(nodesMock));
 | 
			
		||||
            then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleBody.toServiceModel(nodesMock));
 | 
			
		||||
        }
 | 
			
		||||
        then(actionParameterConverterMock).should(times(3)).getConvertedParams(DUMMY_PARAMS, ACTION_DEFINITION_NAME);
 | 
			
		||||
        then(actionParameterConverterMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        assertThat(actual).isEqualTo(expected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCreateRules_invalidFolder()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : folderValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.createRules(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), emptyList(), INCLUDE));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testCreateRules_invalidRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : ruleSetValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
 | 
			
		||||
            given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.createRules(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), emptyList(), INCLUDE));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
            then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check that we can update a rule.
 | 
			
		||||
     */
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testUpdateRuleById()
 | 
			
		||||
    {
 | 
			
		||||
        given(ruleMock.toServiceModel(nodesMock)).willReturn(serviceRuleMock);
 | 
			
		||||
        given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMock)).willAnswer(a -> a.getArguments()[1]);
 | 
			
		||||
        given(serviceRuleMock.getAction()).willReturn(compositeAction);
 | 
			
		||||
        given(ruleLoaderMock.loadRule(serviceRuleMock, INCLUDE)).willReturn(ruleMock);
 | 
			
		||||
        given(actionPermissionValidatorMock.validateRulePermissions(any())).willAnswer(arg -> arg.getArguments()[0]);
 | 
			
		||||
 | 
			
		||||
        // when
 | 
			
		||||
        Rule updatedRule = rules.updateRuleById(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), RULE_ID, ruleMock, INCLUDE);
 | 
			
		||||
 | 
			
		||||
        then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
        then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
        then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
 | 
			
		||||
        then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, serviceRuleMock);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionParameterConverterMock).should().getConvertedParams(DUMMY_PARAMS, ACTION_DEFINITION_NAME);
 | 
			
		||||
        then(actionParameterConverterMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(actionPermissionValidatorMock).should().validateRulePermissions(serviceRuleMock);
 | 
			
		||||
        then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        assertThat(updatedRule).isEqualTo(ruleMock);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testUpdateRuleById_invalidFolder()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : folderValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.updateRuleById(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), RULE_ID, mock(Rule.class), INCLUDE));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testUpdateRuleById_invalidRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : ruleSetValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
 | 
			
		||||
            given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.updateRuleById(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), RULE_ID, mock(Rule.class), INCLUDE));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
            then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testUpdateRuleById_invalidRule()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : ruleValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
 | 
			
		||||
            given(nodeValidatorMock.validateRuleSetNode(any(), any())).willReturn(RULE_SET_NODE_REF);
 | 
			
		||||
            given(nodeValidatorMock.validateRuleNode(any(), any())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.updateRuleById(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), RULE_ID, mock(Rule.class), INCLUDE));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
            then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
            then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteRuleById()
 | 
			
		||||
    {
 | 
			
		||||
        //when
 | 
			
		||||
        rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID);
 | 
			
		||||
 | 
			
		||||
        then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
        then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
        then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
 | 
			
		||||
        then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
        then(nodesMock).shouldHaveNoInteractions();
 | 
			
		||||
        then(ruleServiceMock).should().getRule(RULE_NODE_REF);
 | 
			
		||||
        then(ruleServiceMock).should().removeRule(FOLDER_NODE_REF, ruleModel);
 | 
			
		||||
        then(ruleServiceMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteRuleById_invalidFolder()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : folderValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteRuleById_invalidRuleSet()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : ruleSetValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
 | 
			
		||||
            given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
            then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testDeleteRuleById_invalidRule()
 | 
			
		||||
    {
 | 
			
		||||
        for (Exception exception : ruleValidationExceptions())
 | 
			
		||||
        {
 | 
			
		||||
            Mockito.reset(nodeValidatorMock);
 | 
			
		||||
            given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
 | 
			
		||||
            given(nodeValidatorMock.validateRuleSetNode(any(), any())).willReturn(RULE_SET_NODE_REF);
 | 
			
		||||
            given(nodeValidatorMock.validateRuleNode(any(), any())).willThrow(exception);
 | 
			
		||||
 | 
			
		||||
            // when
 | 
			
		||||
            assertThatExceptionOfType(exception.getClass()).isThrownBy(
 | 
			
		||||
                    () -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
 | 
			
		||||
 | 
			
		||||
            then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
 | 
			
		||||
            then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
 | 
			
		||||
            then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
 | 
			
		||||
            then(nodeValidatorMock).shouldHaveNoMoreInteractions();
 | 
			
		||||
            then(ruleServiceMock).shouldHaveNoInteractions();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static org.alfresco.service.cmr.rule.Rule createRule(final String id)
 | 
			
		||||
    {
 | 
			
		||||
        final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id);
 | 
			
		||||
        final org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule();
 | 
			
		||||
        rule.setNodeRef(nodeRef);
 | 
			
		||||
        rule.setRuleType("ruleType");
 | 
			
		||||
 | 
			
		||||
        return rule;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static List<Exception> folderValidationExceptions()
 | 
			
		||||
    {
 | 
			
		||||
        return List.of(
 | 
			
		||||
                new EntityNotFoundException(FOLDER_NODE_ID),
 | 
			
		||||
                new InvalidArgumentException(),
 | 
			
		||||
                new PermissionDeniedException()
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static List<Exception> ruleSetValidationExceptions()
 | 
			
		||||
    {
 | 
			
		||||
        return List.of(
 | 
			
		||||
                new EntityNotFoundException(RULE_SET_ID),
 | 
			
		||||
                new InvalidArgumentException(),
 | 
			
		||||
                new RelationshipResourceNotFoundException(RULE_SET_ID, "fake-relationship-id")
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static List<Exception> ruleValidationExceptions()
 | 
			
		||||
    {
 | 
			
		||||
        return List.of(
 | 
			
		||||
                new EntityNotFoundException(RULE_ID),
 | 
			
		||||
                new InvalidArgumentException(),
 | 
			
		||||
                new RelationshipResourceNotFoundException(RULE_ID, "fake-relationship-id")
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,79 @@
 | 
			
		||||
/*
 | 
			
		||||
 * #%L
 | 
			
		||||
 * Alfresco Remote API
 | 
			
		||||
 * %%
 | 
			
		||||
 * Copyright (C) 2005 - 2022 Alfresco Software Limited
 | 
			
		||||
 * %%
 | 
			
		||||
 * This file is part of the Alfresco software.
 | 
			
		||||
 * If the software was purchased under a paid Alfresco license, the terms of
 | 
			
		||||
 * the paid license agreement will prevail.  Otherwise, the software is
 | 
			
		||||
 * provided under the following open source license terms:
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Lesser General Public License as published by
 | 
			
		||||
 * the Free Software Foundation, either version 3 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * Alfresco is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 *  GNU Lesser General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Lesser General Public License
 | 
			
		||||
 * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 * #L%
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.alfresco.rest.api.model.rules;
 | 
			
		||||
 | 
			
		||||
import static org.alfresco.repo.action.executer.SetPropertyValueActionExecuter.PARAM_PROPERTY;
 | 
			
		||||
import static org.alfresco.repo.action.executer.SetPropertyValueActionExecuter.PARAM_VALUE;
 | 
			
		||||
import static org.assertj.core.api.Assertions.assertThat;
 | 
			
		||||
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import org.alfresco.repo.action.ActionImpl;
 | 
			
		||||
import org.alfresco.service.Experimental;
 | 
			
		||||
import org.alfresco.service.cmr.repository.NodeRef;
 | 
			
		||||
import org.alfresco.service.cmr.repository.StoreRef;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
@Experimental
 | 
			
		||||
public class ActionTest
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    private static final String ACTION_DEFINITION_NAME = "actionDefName";
 | 
			
		||||
    private static final Map<String, Serializable> parameters = new HashMap<>();
 | 
			
		||||
 | 
			
		||||
    static
 | 
			
		||||
    {
 | 
			
		||||
        parameters.put(PARAM_PROPERTY, "propertyName");
 | 
			
		||||
        parameters.put(PARAM_VALUE, "propertyValue");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFrom()
 | 
			
		||||
    {
 | 
			
		||||
        final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "ruleId");
 | 
			
		||||
        final org.alfresco.service.cmr.action.Action actionModel = new ActionImpl(nodeRef, "actionId", ACTION_DEFINITION_NAME, parameters);
 | 
			
		||||
        final Action expectedAction = Action.builder().actionDefinitionId(ACTION_DEFINITION_NAME).params(parameters).create();
 | 
			
		||||
 | 
			
		||||
        final Action actualAction = Action.from(actionModel);
 | 
			
		||||
 | 
			
		||||
        assertThat(actualAction).isNotNull().usingRecursiveComparison().isEqualTo(expectedAction);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testFromActionModelWithNullValues()
 | 
			
		||||
    {
 | 
			
		||||
        final org.alfresco.service.cmr.action.Action actionModel = new ActionImpl(null, null, null);
 | 
			
		||||
        final Action expectedAction = Action.builder().params(Collections.emptyMap()).create();
 | 
			
		||||
 | 
			
		||||
        final Action actualAction = Action.from(actionModel);
 | 
			
		||||
 | 
			
		||||
        assertThat(actualAction).isNotNull().usingRecursiveComparison().isEqualTo(expectedAction);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user