diff --git a/amps/ags/pom.xml b/amps/ags/pom.xml
index cf4a3386a4..237a98066c 100644
--- a/amps/ags/pom.xml
+++ b/amps/ags/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-community-repo-amps
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/amps/ags/rm-automation/pom.xml b/amps/ags/rm-automation/pom.xml
index 7318a2532d..2466106d64 100644
--- a/amps/ags/rm-automation/pom.xml
+++ b/amps/ags/rm-automation/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-governance-services-community-parent
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/amps/ags/rm-automation/rm-automation-community-rest-api/pom.xml b/amps/ags/rm-automation/rm-automation-community-rest-api/pom.xml
index 609655602e..7f93589e86 100644
--- a/amps/ags/rm-automation/rm-automation-community-rest-api/pom.xml
+++ b/amps/ags/rm-automation/rm-automation-community-rest-api/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-governance-services-automation-community-repo
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
@@ -42,18 +42,6 @@
-
- org.apache.logging.log4j
- log4j-slf4j2-impl
- ${dependency.log4j.version}
- test
-
-
- org.apache.logging.log4j
- log4j-core
- ${dependency.log4j.version}
- test
-
org.alfresco.tas
restapi
@@ -69,17 +57,6 @@
org.alfresco.tas
utility
${dependency.tas-utility.version}
-
-
-
- ch.qos.reload4j
- reload4j
-
-
- org.slf4j
- slf4j-reload4j
-
-
org.projectlombok
diff --git a/amps/ags/rm-community/pom.xml b/amps/ags/rm-community/pom.xml
index e9192e384f..9e977acdb1 100644
--- a/amps/ags/rm-community/pom.xml
+++ b/amps/ags/rm-community/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-governance-services-community-parent
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/amps/ags/rm-community/rm-community-repo/.env b/amps/ags/rm-community/rm-community-repo/.env
index fc37bc79cc..9c612ce1fb 100644
--- a/amps/ags/rm-community/rm-community-repo/.env
+++ b/amps/ags/rm-community/rm-community-repo/.env
@@ -1,3 +1,3 @@
-SOLR6_TAG=2.0.6-A4
+SOLR6_TAG=2.0.6
POSTGRES_TAG=14.4
ACTIVEMQ_TAG=5.17.1-jre11-rockylinux8
diff --git a/amps/ags/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/security/rm-method-security.properties b/amps/ags/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/security/rm-method-security.properties
index 8c9bd9a7e8..60fe652775 100644
--- a/amps/ags/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/security/rm-method-security.properties
+++ b/amps/ags/rm-community/rm-community-repo/config/alfresco/module/org_alfresco_module_rm/security/rm-method-security.properties
@@ -47,6 +47,7 @@ rm.methodsecurity.org.alfresco.service.cmr.repository.NodeService.getPaths=RM.Re
rm.methodsecurity.org.alfresco.service.cmr.repository.NodeService.getStoreArchiveNode=RM_ABSTAIN
rm.methodsecurity.org.alfresco.service.cmr.repository.NodeService.restoreNode=RM_ABSTAIN
rm.methodsecurity.org.alfresco.service.cmr.repository.NodeService.getChildAssocsWithoutParentAssocsOfType=RM_ABSTAIN
+rm.methodsecurity.org.alfresco.service.cmr.repository.NodeService.findAssocsNotLinkedByTwoOtherAssocs=RM_ABSTAIN
rm.methodsecurity.org.alfresco.service.cmr.repository.NodeService.getNodeRef=RM.Read.0
rm.methodsecurity.org.alfresco.service.cmr.repository.NodeService.getChildAssocsByPropertyValue=RM.Read.0,AFTER_RM.FilterNode
rm.methodsecurity.org.alfresco.service.cmr.repository.NodeService.countChildAssocs=RM.Read.0
diff --git a/amps/ags/rm-community/rm-community-repo/pom.xml b/amps/ags/rm-community/rm-community-repo/pom.xml
index ebf65c7b3f..526e69f26c 100644
--- a/amps/ags/rm-community/rm-community-repo/pom.xml
+++ b/amps/ags/rm-community/rm-community-repo/pom.xml
@@ -8,7 +8,7 @@
org.alfresco
alfresco-governance-services-community-repo-parent
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/amps/ags/rm-community/rm-community-rest-api-explorer/pom.xml b/amps/ags/rm-community/rm-community-rest-api-explorer/pom.xml
index d70eac8adc..75f33cfa4d 100644
--- a/amps/ags/rm-community/rm-community-rest-api-explorer/pom.xml
+++ b/amps/ags/rm-community/rm-community-rest-api-explorer/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-governance-services-community-repo-parent
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/amps/pom.xml b/amps/pom.xml
index 8a04186766..ecddb5031a 100644
--- a/amps/pom.xml
+++ b/amps/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-community-repo
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/amps/share-services/pom.xml b/amps/share-services/pom.xml
index 9af36da4ba..102b74653a 100644
--- a/amps/share-services/pom.xml
+++ b/amps/share-services/pom.xml
@@ -8,7 +8,7 @@
org.alfresco
alfresco-community-repo-amps
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/core/pom.xml b/core/pom.xml
index c3f86f82be..bfb5beb7d2 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-community-repo
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/data-model/pom.xml b/data-model/pom.xml
index d1ab881e19..6021f15d93 100644
--- a/data-model/pom.xml
+++ b/data-model/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-community-repo
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/data-model/src/main/java/org/alfresco/service/cmr/repository/NodeService.java b/data-model/src/main/java/org/alfresco/service/cmr/repository/NodeService.java
index 449b4dad9c..b2d59e4935 100644
--- a/data-model/src/main/java/org/alfresco/service/cmr/repository/NodeService.java
+++ b/data-model/src/main/java/org/alfresco/service/cmr/repository/NodeService.java
@@ -2,7 +2,7 @@
* #%L
* Alfresco Data model classes
* %%
- * 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
@@ -714,6 +714,18 @@ public interface NodeService
final NodeRef parent,
final QName assocTypeQName);
+ /**
+ * Gets the list of the localnames of the child associations without parent node
+ *
+ * @param parent
+ * the parent node reference
+ * @return a list of the local names of the child associations
+ */
+ @Auditable(parameters = {"parent"})
+ public List findAssocsNotLinkedByTwoOtherAssocs(
+ final NodeRef parent);
+
+
/**
* Create a peer association between two nodes.
*
diff --git a/mmt/pom.xml b/mmt/pom.xml
index 2db4e39189..0729623636 100644
--- a/mmt/pom.xml
+++ b/mmt/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-community-repo
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/packaging/distribution/pom.xml b/packaging/distribution/pom.xml
index 2ff114b42c..f6feafbdd2 100644
--- a/packaging/distribution/pom.xml
+++ b/packaging/distribution/pom.xml
@@ -9,6 +9,6 @@
org.alfresco
alfresco-community-repo-packaging
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/packaging/docker-alfresco/pom.xml b/packaging/docker-alfresco/pom.xml
index 3b738c9057..6a12975b46 100644
--- a/packaging/docker-alfresco/pom.xml
+++ b/packaging/docker-alfresco/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-community-repo-packaging
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/packaging/pom.xml b/packaging/pom.xml
index 6bc332b0fd..f154ed8aea 100644
--- a/packaging/pom.xml
+++ b/packaging/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-community-repo
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/packaging/tests/environment/.env b/packaging/tests/environment/.env
index fc37bc79cc..9c612ce1fb 100644
--- a/packaging/tests/environment/.env
+++ b/packaging/tests/environment/.env
@@ -1,3 +1,3 @@
-SOLR6_TAG=2.0.6-A4
+SOLR6_TAG=2.0.6
POSTGRES_TAG=14.4
ACTIVEMQ_TAG=5.17.1-jre11-rockylinux8
diff --git a/packaging/tests/pom.xml b/packaging/tests/pom.xml
index 4069327bff..72108b5fd4 100644
--- a/packaging/tests/pom.xml
+++ b/packaging/tests/pom.xml
@@ -6,7 +6,7 @@
org.alfresco
alfresco-community-repo-packaging
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/packaging/tests/scripts/output_tests_run.sh b/packaging/tests/scripts/output_tests_run.sh
index ca1c9355c4..cd7c630cbf 100755
--- a/packaging/tests/scripts/output_tests_run.sh
+++ b/packaging/tests/scripts/output_tests_run.sh
@@ -4,4 +4,4 @@ TAS_DIRECTORY=$1
cd ${TAS_DIRECTORY}
-cat target/reports/alfresco-tas.log | grep "*** STARTING"
+cat target/reports/alfresco-tas.log | grep -a "*** STARTING"
diff --git a/packaging/tests/tas-cmis/pom.xml b/packaging/tests/tas-cmis/pom.xml
index 113072ab83..e649f22bca 100644
--- a/packaging/tests/tas-cmis/pom.xml
+++ b/packaging/tests/tas-cmis/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-community-repo-tests
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/packaging/tests/tas-cmis/src/main/resources/log4j.properties b/packaging/tests/tas-cmis/src/main/resources/log4j.properties
deleted file mode 100644
index 00e9b5a114..0000000000
--- a/packaging/tests/tas-cmis/src/main/resources/log4j.properties
+++ /dev/null
@@ -1,26 +0,0 @@
-# Root logger option
-log4j.rootLogger=INFO, file, stdout
-
-# Direct log messages to a log file
-log4j.appender.file=org.apache.log4j.RollingFileAppender
-log4j.appender.file.File=./target/reports/alfresco-tas.log
-log4j.appender.file.MaxBackupIndex=10
-log4j.appender.file.layout=org.apache.log4j.PatternLayout
-log4j.appender.file.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# Direct log messages to stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.Target=System.out
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# TestRail particular log file
-# Direct log messages to a log file
-log4j.appender.testrailLog=org.apache.log4j.RollingFileAppender
-log4j.appender.testrailLog.File=./target/reports/alfresco-testrail.log
-log4j.appender.testrailLog.MaxBackupIndex=10
-log4j.appender.testrailLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.testrailLog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-log4j.category.testrail=INFO, testrailLog
-log4j.additivity.testrail=false
\ No newline at end of file
diff --git a/packaging/tests/tas-cmis/src/main/resources/log4j2.properties b/packaging/tests/tas-cmis/src/main/resources/log4j2.properties
new file mode 100644
index 0000000000..5e34814028
--- /dev/null
+++ b/packaging/tests/tas-cmis/src/main/resources/log4j2.properties
@@ -0,0 +1,42 @@
+# Root logger option
+rootLogger.level=info
+rootLogger.appenderRef.stdout.ref=ConsoleAppender
+rootLogger.appenderRef.rolling.ref=RollingAppender
+
+###### File appender definition #######
+appender.rolling.type=RollingFile
+appender.rolling.name=RollingAppender
+appender.rolling.fileName=./target/reports/alfresco-tas.log
+appender.rolling.filePattern=./target/reports/alfresco-tas.log.%i
+appender.rolling.layout.type=PatternLayout
+appender.rolling.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.rolling.policies.type = Policies
+appender.rolling.policies.size.type=SizeBasedTriggeringPolicy
+appender.rolling.policies.size.size=10MB
+appender.rolling.strategy.type=DefaultRolloverStrategy
+appender.rolling.strategy.max=10
+
+###### Console appender definition #######
+appender.console.type=Console
+appender.console.name=ConsoleAppender
+appender.console.layout.type=PatternLayout
+appender.console.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+
+# TestRail particular log file
+# Direct log messages to a log file
+logger.testrail.name=testrail
+logger.testrail.level=info
+logger.testrail.additivity=false
+logger.testrail.appenderRef.testrail.ref=TestrailAppender
+
+appender.testrail.name=TestrailAppender
+appender.testrail.type=RollingFile
+appender.testrail.fileName=./target/reports/alfresco-testrail.log
+appender.testrail.filePattern=./target/reports/alfresco-testrail.log.%i
+appender.testrail.layout.type=PatternLayout
+appender.testrail.layout.pattern=%d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.testrail.policies.type=Policies
+appender.testrail.policies.size.type=SizeBasedTriggeringPolicy
+appender.testrail.policies.size.size=10MB
+appender.testrail.strategy.type=DefaultRolloverStrategy
+appender.testrail.strategy.max=10
\ No newline at end of file
diff --git a/packaging/tests/tas-cmis/src/test/resources/log4j.properties b/packaging/tests/tas-cmis/src/test/resources/log4j.properties
deleted file mode 100644
index 00e9b5a114..0000000000
--- a/packaging/tests/tas-cmis/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,26 +0,0 @@
-# Root logger option
-log4j.rootLogger=INFO, file, stdout
-
-# Direct log messages to a log file
-log4j.appender.file=org.apache.log4j.RollingFileAppender
-log4j.appender.file.File=./target/reports/alfresco-tas.log
-log4j.appender.file.MaxBackupIndex=10
-log4j.appender.file.layout=org.apache.log4j.PatternLayout
-log4j.appender.file.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# Direct log messages to stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.Target=System.out
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# TestRail particular log file
-# Direct log messages to a log file
-log4j.appender.testrailLog=org.apache.log4j.RollingFileAppender
-log4j.appender.testrailLog.File=./target/reports/alfresco-testrail.log
-log4j.appender.testrailLog.MaxBackupIndex=10
-log4j.appender.testrailLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.testrailLog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-log4j.category.testrail=INFO, testrailLog
-log4j.additivity.testrail=false
\ No newline at end of file
diff --git a/packaging/tests/tas-cmis/src/test/resources/log4j2.properties b/packaging/tests/tas-cmis/src/test/resources/log4j2.properties
new file mode 100644
index 0000000000..5e34814028
--- /dev/null
+++ b/packaging/tests/tas-cmis/src/test/resources/log4j2.properties
@@ -0,0 +1,42 @@
+# Root logger option
+rootLogger.level=info
+rootLogger.appenderRef.stdout.ref=ConsoleAppender
+rootLogger.appenderRef.rolling.ref=RollingAppender
+
+###### File appender definition #######
+appender.rolling.type=RollingFile
+appender.rolling.name=RollingAppender
+appender.rolling.fileName=./target/reports/alfresco-tas.log
+appender.rolling.filePattern=./target/reports/alfresco-tas.log.%i
+appender.rolling.layout.type=PatternLayout
+appender.rolling.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.rolling.policies.type = Policies
+appender.rolling.policies.size.type=SizeBasedTriggeringPolicy
+appender.rolling.policies.size.size=10MB
+appender.rolling.strategy.type=DefaultRolloverStrategy
+appender.rolling.strategy.max=10
+
+###### Console appender definition #######
+appender.console.type=Console
+appender.console.name=ConsoleAppender
+appender.console.layout.type=PatternLayout
+appender.console.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+
+# TestRail particular log file
+# Direct log messages to a log file
+logger.testrail.name=testrail
+logger.testrail.level=info
+logger.testrail.additivity=false
+logger.testrail.appenderRef.testrail.ref=TestrailAppender
+
+appender.testrail.name=TestrailAppender
+appender.testrail.type=RollingFile
+appender.testrail.fileName=./target/reports/alfresco-testrail.log
+appender.testrail.filePattern=./target/reports/alfresco-testrail.log.%i
+appender.testrail.layout.type=PatternLayout
+appender.testrail.layout.pattern=%d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.testrail.policies.type=Policies
+appender.testrail.policies.size.type=SizeBasedTriggeringPolicy
+appender.testrail.policies.size.size=10MB
+appender.testrail.strategy.type=DefaultRolloverStrategy
+appender.testrail.strategy.max=10
\ No newline at end of file
diff --git a/packaging/tests/tas-email/pom.xml b/packaging/tests/tas-email/pom.xml
index c0a373d1c6..b12506d2db 100644
--- a/packaging/tests/tas-email/pom.xml
+++ b/packaging/tests/tas-email/pom.xml
@@ -9,7 +9,7 @@
org.alfresco
alfresco-community-repo-tests
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/packaging/tests/tas-email/src/test/resources/log4j.properties b/packaging/tests/tas-email/src/test/resources/log4j.properties
deleted file mode 100644
index 00e9b5a114..0000000000
--- a/packaging/tests/tas-email/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,26 +0,0 @@
-# Root logger option
-log4j.rootLogger=INFO, file, stdout
-
-# Direct log messages to a log file
-log4j.appender.file=org.apache.log4j.RollingFileAppender
-log4j.appender.file.File=./target/reports/alfresco-tas.log
-log4j.appender.file.MaxBackupIndex=10
-log4j.appender.file.layout=org.apache.log4j.PatternLayout
-log4j.appender.file.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# Direct log messages to stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.Target=System.out
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# TestRail particular log file
-# Direct log messages to a log file
-log4j.appender.testrailLog=org.apache.log4j.RollingFileAppender
-log4j.appender.testrailLog.File=./target/reports/alfresco-testrail.log
-log4j.appender.testrailLog.MaxBackupIndex=10
-log4j.appender.testrailLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.testrailLog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-log4j.category.testrail=INFO, testrailLog
-log4j.additivity.testrail=false
\ No newline at end of file
diff --git a/packaging/tests/tas-email/src/test/resources/log4j2.properties b/packaging/tests/tas-email/src/test/resources/log4j2.properties
new file mode 100644
index 0000000000..5e34814028
--- /dev/null
+++ b/packaging/tests/tas-email/src/test/resources/log4j2.properties
@@ -0,0 +1,42 @@
+# Root logger option
+rootLogger.level=info
+rootLogger.appenderRef.stdout.ref=ConsoleAppender
+rootLogger.appenderRef.rolling.ref=RollingAppender
+
+###### File appender definition #######
+appender.rolling.type=RollingFile
+appender.rolling.name=RollingAppender
+appender.rolling.fileName=./target/reports/alfresco-tas.log
+appender.rolling.filePattern=./target/reports/alfresco-tas.log.%i
+appender.rolling.layout.type=PatternLayout
+appender.rolling.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.rolling.policies.type = Policies
+appender.rolling.policies.size.type=SizeBasedTriggeringPolicy
+appender.rolling.policies.size.size=10MB
+appender.rolling.strategy.type=DefaultRolloverStrategy
+appender.rolling.strategy.max=10
+
+###### Console appender definition #######
+appender.console.type=Console
+appender.console.name=ConsoleAppender
+appender.console.layout.type=PatternLayout
+appender.console.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+
+# TestRail particular log file
+# Direct log messages to a log file
+logger.testrail.name=testrail
+logger.testrail.level=info
+logger.testrail.additivity=false
+logger.testrail.appenderRef.testrail.ref=TestrailAppender
+
+appender.testrail.name=TestrailAppender
+appender.testrail.type=RollingFile
+appender.testrail.fileName=./target/reports/alfresco-testrail.log
+appender.testrail.filePattern=./target/reports/alfresco-testrail.log.%i
+appender.testrail.layout.type=PatternLayout
+appender.testrail.layout.pattern=%d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.testrail.policies.type=Policies
+appender.testrail.policies.size.type=SizeBasedTriggeringPolicy
+appender.testrail.policies.size.size=10MB
+appender.testrail.strategy.type=DefaultRolloverStrategy
+appender.testrail.strategy.max=10
\ No newline at end of file
diff --git a/packaging/tests/tas-integration/pom.xml b/packaging/tests/tas-integration/pom.xml
index d6620f0da1..f4e05be8b2 100644
--- a/packaging/tests/tas-integration/pom.xml
+++ b/packaging/tests/tas-integration/pom.xml
@@ -9,7 +9,7 @@
org.alfresco
alfresco-community-repo-tests
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/packaging/tests/tas-integration/src/test/resources/log4j.properties b/packaging/tests/tas-integration/src/test/resources/log4j.properties
deleted file mode 100644
index 00e9b5a114..0000000000
--- a/packaging/tests/tas-integration/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,26 +0,0 @@
-# Root logger option
-log4j.rootLogger=INFO, file, stdout
-
-# Direct log messages to a log file
-log4j.appender.file=org.apache.log4j.RollingFileAppender
-log4j.appender.file.File=./target/reports/alfresco-tas.log
-log4j.appender.file.MaxBackupIndex=10
-log4j.appender.file.layout=org.apache.log4j.PatternLayout
-log4j.appender.file.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# Direct log messages to stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.Target=System.out
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# TestRail particular log file
-# Direct log messages to a log file
-log4j.appender.testrailLog=org.apache.log4j.RollingFileAppender
-log4j.appender.testrailLog.File=./target/reports/alfresco-testrail.log
-log4j.appender.testrailLog.MaxBackupIndex=10
-log4j.appender.testrailLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.testrailLog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-log4j.category.testrail=INFO, testrailLog
-log4j.additivity.testrail=false
\ No newline at end of file
diff --git a/packaging/tests/tas-integration/src/test/resources/log4j2.properties b/packaging/tests/tas-integration/src/test/resources/log4j2.properties
new file mode 100644
index 0000000000..5e34814028
--- /dev/null
+++ b/packaging/tests/tas-integration/src/test/resources/log4j2.properties
@@ -0,0 +1,42 @@
+# Root logger option
+rootLogger.level=info
+rootLogger.appenderRef.stdout.ref=ConsoleAppender
+rootLogger.appenderRef.rolling.ref=RollingAppender
+
+###### File appender definition #######
+appender.rolling.type=RollingFile
+appender.rolling.name=RollingAppender
+appender.rolling.fileName=./target/reports/alfresco-tas.log
+appender.rolling.filePattern=./target/reports/alfresco-tas.log.%i
+appender.rolling.layout.type=PatternLayout
+appender.rolling.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.rolling.policies.type = Policies
+appender.rolling.policies.size.type=SizeBasedTriggeringPolicy
+appender.rolling.policies.size.size=10MB
+appender.rolling.strategy.type=DefaultRolloverStrategy
+appender.rolling.strategy.max=10
+
+###### Console appender definition #######
+appender.console.type=Console
+appender.console.name=ConsoleAppender
+appender.console.layout.type=PatternLayout
+appender.console.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+
+# TestRail particular log file
+# Direct log messages to a log file
+logger.testrail.name=testrail
+logger.testrail.level=info
+logger.testrail.additivity=false
+logger.testrail.appenderRef.testrail.ref=TestrailAppender
+
+appender.testrail.name=TestrailAppender
+appender.testrail.type=RollingFile
+appender.testrail.fileName=./target/reports/alfresco-testrail.log
+appender.testrail.filePattern=./target/reports/alfresco-testrail.log.%i
+appender.testrail.layout.type=PatternLayout
+appender.testrail.layout.pattern=%d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.testrail.policies.type=Policies
+appender.testrail.policies.size.type=SizeBasedTriggeringPolicy
+appender.testrail.policies.size.size=10MB
+appender.testrail.strategy.type=DefaultRolloverStrategy
+appender.testrail.strategy.max=10
\ No newline at end of file
diff --git a/packaging/tests/tas-restapi/pom.xml b/packaging/tests/tas-restapi/pom.xml
index 701ab667dc..c44c0ce6fd 100644
--- a/packaging/tests/tas-restapi/pom.xml
+++ b/packaging/tests/tas-restapi/pom.xml
@@ -8,7 +8,7 @@
org.alfresco
alfresco-community-repo-tests
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestCategoryModel.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestCategoryModel.java
index 5c94132075..e25c56e22a 100644
--- a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestCategoryModel.java
+++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/model/RestCategoryModel.java
@@ -128,5 +128,52 @@ This must be unique within the parent category.
", count=" + count +
'}';
}
+
+ public static Builder builder()
+ {
+ return new Builder();
+ }
+
+ public static class Builder
+ {
+ private String id;
+ private String name;
+ private String parentId;
+ private boolean hasChildren;
+
+ public Builder id(String id)
+ {
+ this.id = id;
+ return this;
+ }
+
+ public Builder name(String name)
+ {
+ this.name = name;
+ return this;
+ }
+
+ public Builder parentId(String parentId)
+ {
+ this.parentId = parentId;
+ return this;
+ }
+
+ public Builder hasChildren(boolean hasChildren)
+ {
+ this.hasChildren = hasChildren;
+ return this;
+ }
+
+ public RestCategoryModel create()
+ {
+ final RestCategoryModel category = new RestCategoryModel();
+ category.setId(id);
+ category.setName(name);
+ category.setParentId(parentId);
+ category.setHasChildren(hasChildren);
+ return category;
+ }
+ }
}
diff --git a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/requests/Categories.java b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/requests/Categories.java
index 460ae87a3f..9dbdb38ab1 100644
--- a/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/requests/Categories.java
+++ b/packaging/tests/tas-restapi/src/main/java/org/alfresco/rest/requests/Categories.java
@@ -33,7 +33,6 @@ import org.alfresco.rest.core.RestRequest;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.model.RestCategoryModelsCollection;
-import org.alfresco.rest.model.RestRuleModelsCollection;
import org.springframework.http.HttpMethod;
public class Categories extends ModelRequest
@@ -47,7 +46,7 @@ public class Categories extends ModelRequest
}
/**
- * Retrieves a category with ID using GET call on using GET call on "/tags/{tagId}"
+ * Retrieves a category with ID using GET call on "/categories/{categoryId}"
*
* @return RestCategoryModel
*/
@@ -72,12 +71,48 @@ public class Categories extends ModelRequest
/**
* Create single category.
*
- * @param restCategoryModel The categories to create.
+ * @param restCategoryModel The category to create.
* @return Created category with additional data populated by the repository.
*/
- public RestCategoryModel createSingleCategory(RestCategoryModel restCategoryModel) {
- RestRequest request = RestRequest.requestWithBody(HttpMethod.POST, restCategoryModel.toJson(), "categories/{categoryId}/subcategories", category.getId());
+ public RestCategoryModel createSingleCategory(RestCategoryModel restCategoryModel)
+ {
+ RestRequest request = RestRequest
+ .requestWithBody(HttpMethod.POST, restCategoryModel.toJson(), "categories/{categoryId}/subcategories", category.getId());
return restWrapper.processModel(RestCategoryModel.class, request);
}
+ /**
+ * Get parent category children.
+ *
+ * @return The list of child categories.
+ */
+ public RestCategoryModelsCollection getCategoryChildren()
+ {
+ RestRequest request = RestRequest.simpleRequest(HttpMethod.GET, "categories/{categoryId}/subcategories", category.getId());
+ return restWrapper.processModels(RestCategoryModelsCollection.class, request);
+ }
+
+ /**
+ * Update single category.
+ * - PUT /categories/{categoryId}
+ *
+ * @param restCategoryModel The categories to update.
+ * @return Created category with additional data populated by the repository.
+ */
+ public RestCategoryModel updateCategory(RestCategoryModel restCategoryModel)
+ {
+ RestRequest request = RestRequest.requestWithBody(HttpMethod.PUT, restCategoryModel.toJson(), "categories/{categoryId}", category.getId());
+ return restWrapper.processModel(RestCategoryModel.class, request);
+ }
+ /**
+ * Delete category.
+ * - DELETE /categories/{categoryId}
+ */
+ public void deleteCategory()
+ {
+ RestRequest request = RestRequest.
+ simpleRequest(HttpMethod.DELETE, "/categories/{categoryId}", category.getId());
+ restWrapper.processEmptyModel(request);
+ }
+
}
diff --git a/packaging/tests/tas-restapi/src/main/resources/log4j.properties b/packaging/tests/tas-restapi/src/main/resources/log4j.properties
deleted file mode 100644
index 00e9b5a114..0000000000
--- a/packaging/tests/tas-restapi/src/main/resources/log4j.properties
+++ /dev/null
@@ -1,26 +0,0 @@
-# Root logger option
-log4j.rootLogger=INFO, file, stdout
-
-# Direct log messages to a log file
-log4j.appender.file=org.apache.log4j.RollingFileAppender
-log4j.appender.file.File=./target/reports/alfresco-tas.log
-log4j.appender.file.MaxBackupIndex=10
-log4j.appender.file.layout=org.apache.log4j.PatternLayout
-log4j.appender.file.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# Direct log messages to stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.Target=System.out
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# TestRail particular log file
-# Direct log messages to a log file
-log4j.appender.testrailLog=org.apache.log4j.RollingFileAppender
-log4j.appender.testrailLog.File=./target/reports/alfresco-testrail.log
-log4j.appender.testrailLog.MaxBackupIndex=10
-log4j.appender.testrailLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.testrailLog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-log4j.category.testrail=INFO, testrailLog
-log4j.additivity.testrail=false
\ No newline at end of file
diff --git a/packaging/tests/tas-restapi/src/main/resources/log4j2.properties b/packaging/tests/tas-restapi/src/main/resources/log4j2.properties
new file mode 100644
index 0000000000..5e34814028
--- /dev/null
+++ b/packaging/tests/tas-restapi/src/main/resources/log4j2.properties
@@ -0,0 +1,42 @@
+# Root logger option
+rootLogger.level=info
+rootLogger.appenderRef.stdout.ref=ConsoleAppender
+rootLogger.appenderRef.rolling.ref=RollingAppender
+
+###### File appender definition #######
+appender.rolling.type=RollingFile
+appender.rolling.name=RollingAppender
+appender.rolling.fileName=./target/reports/alfresco-tas.log
+appender.rolling.filePattern=./target/reports/alfresco-tas.log.%i
+appender.rolling.layout.type=PatternLayout
+appender.rolling.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.rolling.policies.type = Policies
+appender.rolling.policies.size.type=SizeBasedTriggeringPolicy
+appender.rolling.policies.size.size=10MB
+appender.rolling.strategy.type=DefaultRolloverStrategy
+appender.rolling.strategy.max=10
+
+###### Console appender definition #######
+appender.console.type=Console
+appender.console.name=ConsoleAppender
+appender.console.layout.type=PatternLayout
+appender.console.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+
+# TestRail particular log file
+# Direct log messages to a log file
+logger.testrail.name=testrail
+logger.testrail.level=info
+logger.testrail.additivity=false
+logger.testrail.appenderRef.testrail.ref=TestrailAppender
+
+appender.testrail.name=TestrailAppender
+appender.testrail.type=RollingFile
+appender.testrail.fileName=./target/reports/alfresco-testrail.log
+appender.testrail.filePattern=./target/reports/alfresco-testrail.log.%i
+appender.testrail.layout.type=PatternLayout
+appender.testrail.layout.pattern=%d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.testrail.policies.type=Policies
+appender.testrail.policies.size.type=SizeBasedTriggeringPolicy
+appender.testrail.policies.size.size=10MB
+appender.testrail.strategy.type=DefaultRolloverStrategy
+appender.testrail.strategy.max=10
\ No newline at end of file
diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/CategoriesRestTest.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/CategoriesRestTest.java
new file mode 100644
index 0000000000..660729bfb6
--- /dev/null
+++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/CategoriesRestTest.java
@@ -0,0 +1,91 @@
+/*
+ * #%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 .
+ * #L%
+ */
+
+package org.alfresco.rest.categories;
+
+import static org.alfresco.utility.data.RandomData.getRandomName;
+import static org.alfresco.utility.report.log.Step.STEP;
+import static org.springframework.http.HttpStatus.CREATED;
+
+import org.alfresco.rest.RestTest;
+import org.alfresco.rest.model.RestCategoryModel;
+import org.alfresco.utility.model.UserModel;
+import org.testng.annotations.BeforeClass;
+
+abstract class CategoriesRestTest extends RestTest
+{
+ protected static final String ROOT_CATEGORY_ID = "-root-";
+ protected static final String CATEGORY_NAME_PREFIX = "CategoryName";
+ protected static final String FIELD_NAME = "name";
+ protected static final String FIELD_ID = "id";
+ protected static final String FIELD_PARENT_ID = "parentId";
+ protected static final String FIELD_HAS_CHILDREN = "hasChildren";
+
+ protected UserModel user;
+
+ @BeforeClass(alwaysRun = true)
+ public void dataPreparation() throws Exception
+ {
+ STEP("Create a user");
+ user = dataUser.createRandomTestUser();
+ }
+
+ protected RestCategoryModel prepareCategoryUnderRoot()
+ {
+ return prepareCategoryUnder(ROOT_CATEGORY_ID);
+ }
+
+ protected RestCategoryModel prepareCategoryUnder(final String parentId)
+ {
+ final RestCategoryModel parentCategory = createCategoryModelWithId(parentId);
+ final RestCategoryModel categoryModel = createCategoryModelWithName(getRandomName(CATEGORY_NAME_PREFIX));
+ final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(parentCategory)
+ .createSingleCategory(categoryModel);
+ restClient.assertStatusCodeIs(CREATED);
+
+ return createdCategory;
+ }
+
+ protected RestCategoryModel createCategoryModelWithId(final String id)
+ {
+ return createCategoryModelWithIdAndName(id, null);
+ }
+
+ protected RestCategoryModel createCategoryModelWithName(final String name)
+ {
+ return createCategoryModelWithIdAndName(null, name);
+ }
+
+ protected RestCategoryModel createCategoryModelWithIdAndName(final String id, final String name)
+ {
+ return RestCategoryModel.builder()
+ .id(id)
+ .name(name)
+ .create();
+ }
+}
diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/CreateCategoriesTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/CreateCategoriesTests.java
index edfc95d36f..92ccb56d44 100644
--- a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/CreateCategoriesTests.java
+++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/CreateCategoriesTests.java
@@ -36,31 +36,17 @@ import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
-import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.model.RestCategoryModelsCollection;
import org.alfresco.utility.data.RandomData;
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.apache.commons.lang3.StringUtils;
import org.testng.annotations.Test;
-public class CreateCategoriesTests extends RestTest
+public class CreateCategoriesTests extends CategoriesRestTest
{
- private static final String FIELD_NAME = "name";
- private static final String FIELD_PARENT_ID = "parentId";
- private static final String FIELD_HAS_CHILDREN = "hasChildren";
- private static final String FIELD_ID = "id";
- private UserModel user;
-
- @BeforeClass(alwaysRun = true)
- public void dataPreparation() throws Exception
- {
- STEP("Create a user");
- user = dataUser.createRandomTestUser();
- }
/**
* Check we can create a category as direct child of root category
@@ -69,10 +55,8 @@ public class CreateCategoriesTests extends RestTest
public void testCreateCategoryUnderRoot()
{
STEP("Create a category under root category (as admin)");
- final RestCategoryModel rootCategory = new RestCategoryModel();
- rootCategory.setId("-root-");
- final RestCategoryModel aCategory = new RestCategoryModel();
- aCategory.setName(RandomData.getRandomName("Category"));
+ final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
+ final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(rootCategory)
@@ -84,6 +68,22 @@ public class CreateCategoriesTests extends RestTest
createdCategory.assertThat().field(FIELD_HAS_CHILDREN).is(false);
}
+ /**
+ * Check we get 400 error when attempting to create a category with empty name
+ */
+ @Test(groups = {TestGroup.REST_API})
+ public void testCreateCategoryWithoutName_andFail()
+ {
+ STEP("Create a category under root category (as admin)");
+ final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
+ final RestCategoryModel aCategory = createCategoryModelWithName(StringUtils.EMPTY);
+ restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(rootCategory)
+ .createSingleCategory(aCategory);
+ restClient.assertStatusCodeIs(BAD_REQUEST).assertLastError().containsSummary("Category name must not be null or empty");
+ }
+
/**
* Check we can create several categories as children of a created category
*/
@@ -91,10 +91,8 @@ public class CreateCategoriesTests extends RestTest
public void testCreateSeveralSubCategories()
{
STEP("Create a category under root category (as admin)");
- final RestCategoryModel rootCategory = new RestCategoryModel();
- rootCategory.setId("-root-");
- final RestCategoryModel aCategory = new RestCategoryModel();
- aCategory.setName(RandomData.getRandomName("Category"));
+ final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
+ final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(rootCategory)
@@ -134,6 +132,52 @@ public class CreateCategoriesTests extends RestTest
parentCategoryFromGet.assertThat().field(FIELD_HAS_CHILDREN).is(true);
}
+ /**
+ * Check we can create over 100 categories as children of a created category and pagination information is proper.
+ */
+ @Test(groups = {TestGroup.REST_API})
+ public void testCreateOver100SubCategories()
+ {
+ STEP("Create a category under root category (as admin)");
+ final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
+ final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
+ final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(rootCategory)
+ .createSingleCategory(aCategory);
+ restClient.assertStatusCodeIs(CREATED);
+
+ createdCategory.assertThat().field(FIELD_NAME).is(aCategory.getName())
+ .assertThat().field(FIELD_PARENT_ID).is(rootCategory.getId())
+ .assertThat().field(FIELD_HAS_CHILDREN).is(false)
+ .assertThat().field(FIELD_ID).isNotEmpty();
+
+ STEP("Create more than a hundred categories under the previously created (as admin)");
+ final int categoriesNumber = 120;
+ final List categoriesToCreate = getCategoriesToCreate(categoriesNumber);
+ final RestCategoryModelsCollection createdSubCategories = restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(createdCategory)
+ .createCategoriesList(categoriesToCreate);
+ restClient.assertStatusCodeIs(CREATED);
+
+ createdSubCategories.assertThat()
+ .entriesListCountIs(categoriesToCreate.size());
+ IntStream.range(0, categoriesNumber)
+ .forEach(i -> createdSubCategories.getEntries().get(i).onModel()
+ .assertThat().field(FIELD_NAME).is(categoriesToCreate.get(i).getName())
+ .assertThat().field(FIELD_PARENT_ID).is(createdCategory.getId())
+ .assertThat().field(FIELD_HAS_CHILDREN).is(false)
+ .assertThat().field(FIELD_ID).isNotEmpty()
+ );
+ createdSubCategories.getPagination().assertThat().field("count").is(categoriesNumber)
+ .assertThat().field("totalItems").is(categoriesNumber)
+ .assertThat().field("maxItems").is(categoriesNumber)
+ .assertThat().field("skipCount").is(0)
+ .assertThat().field("hasMoreItems").is(false);
+
+ }
+
/**
* Check we cannot create a category as direct child of root category as non-admin user
*/
@@ -141,15 +185,13 @@ public class CreateCategoriesTests extends RestTest
public void testCreateCategoryUnderRootAsRegularUser_andFail()
{
STEP("Create a category under root category (as user)");
- final RestCategoryModel rootCategory = new RestCategoryModel();
- rootCategory.setId("-root-");
- final RestCategoryModel aCategory = new RestCategoryModel();
- aCategory.setName(RandomData.getRandomName("Category"));
+ final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
+ final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
restClient.authenticateUser(user)
.withCoreAPI()
.usingCategory(rootCategory)
.createSingleCategory(aCategory);
- restClient.assertStatusCodeIs(FORBIDDEN).assertLastError().containsSummary("Current user does not have permission to create a category");
+ restClient.assertStatusCodeIs(FORBIDDEN).assertLastError().containsSummary("Current user does not have permission to manage a category");
}
/**
@@ -159,11 +201,9 @@ public class CreateCategoriesTests extends RestTest
public void testCreateCategoryUnderNonExistingParent_andFail()
{
STEP("Create a category under non existing category node (as admin)");
- final RestCategoryModel rootCategory = new RestCategoryModel();
final String id = "non-existing-node-id";
- rootCategory.setId(id);
- final RestCategoryModel aCategory = new RestCategoryModel();
- aCategory.setName(RandomData.getRandomName("Category"));
+ final RestCategoryModel rootCategory = createCategoryModelWithId(id);
+ final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(rootCategory)
@@ -182,10 +222,8 @@ public class CreateCategoriesTests extends RestTest
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Create a category under folder node (as admin)");
- final RestCategoryModel rootCategory = new RestCategoryModel();
- rootCategory.setId(folder.getNodeRef());
- final RestCategoryModel aCategory = new RestCategoryModel();
- aCategory.setName(RandomData.getRandomName("Category"));
+ final RestCategoryModel rootCategory = createCategoryModelWithId(folder.getNodeRef());
+ final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(rootCategory)
@@ -193,14 +231,10 @@ public class CreateCategoriesTests extends RestTest
restClient.assertStatusCodeIs(BAD_REQUEST).assertLastError().containsSummary("Node id does not refer to a valid category");
}
- private List getCategoriesToCreate(final int count)
+ static List getCategoriesToCreate(final int count)
{
return IntStream.range(0, count)
- .mapToObj(i -> {
- final RestCategoryModel aSubCategory = new RestCategoryModel();
- aSubCategory.setName((RandomData.getRandomName("SubCategory")));
- return aSubCategory;
- })
- .collect(Collectors.toList());
+ .mapToObj(i -> RestCategoryModel.builder().name(RandomData.getRandomName("SubCategory")).create())
+ .collect(Collectors.toList());
}
}
diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/DeleteCategoriesTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/DeleteCategoriesTests.java
new file mode 100644
index 0000000000..779876017b
--- /dev/null
+++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/DeleteCategoriesTests.java
@@ -0,0 +1,102 @@
+/*
+ * #%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 .
+ * #L%
+ */
+
+package org.alfresco.rest.categories;
+
+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.NO_CONTENT;
+
+import org.alfresco.rest.model.RestCategoryModel;
+import org.alfresco.utility.model.FolderModel;
+import org.alfresco.utility.model.SiteModel;
+import org.alfresco.utility.model.TestGroup;
+import org.testng.annotations.Test;
+
+public class DeleteCategoriesTests extends CategoriesRestTest
+{
+
+ /**
+ * Check we can delete a category.
+ */
+ @Test(groups = {TestGroup.REST_API})
+ public void testDeleteCategory()
+ {
+ STEP("Create a category and send a request to delete it.");
+ RestCategoryModel aCategory = prepareCategoryUnderRoot();
+ restClient.authenticateUser(dataUser.getAdminUser()).withCoreAPI().usingCategory(aCategory).deleteCategory();
+ restClient.assertStatusCodeIs(NO_CONTENT);
+
+ STEP("Ensure that the category has been deleted by sending a GET request and receiving 404.");
+ restClient.authenticateUser(user).withCoreAPI().usingCategory(aCategory).getCategory();
+ restClient.assertStatusCodeIs(NOT_FOUND);
+ }
+
+ /**
+ * Check we get an error when trying to delete a category as a non-admin user.
+ */
+ @Test(groups = {TestGroup.REST_API})
+ public void testDeleteCategoryAsRegularUser_andFail()
+ {
+ RestCategoryModel aCategory = prepareCategoryUnderRoot();
+ restClient.authenticateUser(user).withCoreAPI().usingCategory(aCategory).deleteCategory();
+ restClient.assertStatusCodeIs(FORBIDDEN).assertLastError().containsSummary("Current user does not have permission to manage a category");
+ }
+
+ /**
+ * Check we receive 404 error when trying to delete a category with a non-existent node id.
+ */
+ @Test(groups = {TestGroup.REST_API})
+ public void testDeleteNonExistentCategory()
+ {
+ STEP("Get category with non-existent id");
+ final String id = "non-existing-dummy-id";
+ final RestCategoryModel rootCategory = createCategoryModelWithId(id);
+
+ STEP("Attempt to delete category with non-existent id and receive 404");
+ restClient.authenticateUser(dataUser.getAdminUser()).withCoreAPI().usingCategory(rootCategory).deleteCategory();
+ restClient.assertStatusCodeIs(NOT_FOUND);
+ }
+
+ /**
+ * Attempt to delete a category when providing a node id that doesn't belong to a category
+ */
+ @Test(groups = {TestGroup.REST_API})
+ public void testDeleteCategory_givenNonCategoryNodeId()
+ {
+ STEP("Create a site and a folder inside it");
+ final SiteModel site = dataSite.usingUser(user).createPublicRandomSite();
+ final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
+ String id = folder.getNodeRef();
+
+ STEP("Create a category, set its id to the folder id and attempt to delete it");
+ final RestCategoryModel aCategory = createCategoryModelWithId(id);
+ restClient.authenticateUser(dataUser.getAdminUser()).withCoreAPI().usingCategory(aCategory).deleteCategory();
+ restClient.assertStatusCodeIs(BAD_REQUEST).assertLastError().containsSummary("Node id does not refer to a valid category");
+ }
+}
diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/GetCategoriesTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/GetCategoriesTests.java
index d02312442b..ac1e7c666e 100644
--- a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/GetCategoriesTests.java
+++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/GetCategoriesTests.java
@@ -28,28 +28,26 @@ package org.alfresco.rest.categories;
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 static org.springframework.http.HttpStatus.OK;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+import java.util.stream.Collectors;
-import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestCategoryModel;
+import org.alfresco.rest.model.RestCategoryModelsCollection;
+import org.alfresco.utility.data.RandomData;
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;
-public class GetCategoriesTests extends RestTest
+public class GetCategoriesTests extends CategoriesRestTest
{
- private UserModel user;
-
- @BeforeClass(alwaysRun = true)
- public void dataPreparation() throws Exception
- {
- STEP("Create a user");
- user = dataUser.createRandomTestUser();
- }
+ private static final List DEFAULT_ROOT_CATEGORIES = List.of("Software Document Classification", "Languages", "Regions", "Tags");
+ private static final String NON_EXISTING_CATEGORY_ID = "non-existing-category-id";
/**
* Check we can get a category which we just created in as direct child of root category
@@ -57,11 +55,24 @@ public class GetCategoriesTests extends RestTest
@Test(groups = {TestGroup.REST_API})
public void testGetCategoryById()
{
- STEP("Get category with -root- as id (which does not exist)");
- final RestCategoryModel rootCategory = new RestCategoryModel();
- rootCategory.setId("-root-");
- restClient.authenticateUser(user).withCoreAPI().usingCategory(rootCategory).getCategory();
- restClient.assertStatusCodeIs(NOT_FOUND);
+ STEP("Create a category under root category (as admin)");
+ final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
+ final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
+ final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(rootCategory)
+ .createSingleCategory(aCategory);
+ restClient.assertStatusCodeIs(CREATED);
+
+ createdCategory.assertThat().field("name").is(aCategory.getName());
+ createdCategory.assertThat().field("parentId").is(rootCategory.getId());
+ createdCategory.assertThat().field("hasChildren").is(false);
+
+ STEP("Get the created category (as regular user)");
+ final RestCategoryModel categoryFromGet =
+ restClient.authenticateUser(user).withCoreAPI().usingCategory(createdCategory).getCategory();
+ restClient.assertStatusCodeIs(OK);
+ categoryFromGet.assertThat().isEqualTo(createdCategory);
}
/**
@@ -70,15 +81,14 @@ public class GetCategoriesTests extends RestTest
@Test(groups = {TestGroup.REST_API})
public void testGetCategoryByIdProvidingRootAsId()
{
- STEP("Get category with -root- as id (which does not exist)");
- final RestCategoryModel rootCategory = new RestCategoryModel();
- rootCategory.setId("-root-");
+ STEP("Get category with -root- as id");
+ final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
restClient.authenticateUser(user).withCoreAPI().usingCategory(rootCategory).getCategory();
- restClient.assertStatusCodeIs(NOT_FOUND);
+ restClient.assertStatusCodeIs(BAD_REQUEST).assertLastError().containsSummary("Node id does not refer to a valid category");
}
/**
- * Check we get an error when passing as category id
+ * Check we get an error when passing folder node id as category id
*/
@Test(groups = {TestGroup.REST_API})
public void testGetCategoryByIdProvidingFolderAsId()
@@ -88,10 +98,98 @@ public class GetCategoriesTests extends RestTest
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Get category with folder id passed as id");
- final RestCategoryModel rootCategory = new RestCategoryModel();
- rootCategory.setId(folder.getNodeRef());
+ final RestCategoryModel rootCategory = createCategoryModelWithId(folder.getNodeRef());
restClient.authenticateUser(user).withCoreAPI().usingCategory(rootCategory).getCategory();
- restClient.assertStatusCodeIs(BAD_REQUEST);
+ restClient.assertStatusCodeIs(BAD_REQUEST).assertLastError().containsSummary("Node id does not refer to a valid category");
}
+ /**
+ * Check we get an error when passing non existing as category id
+ */
+ @Test(groups = {TestGroup.REST_API})
+ public void testGetCategoryByIdProvidingNonExistingId()
+ {
+ STEP("Get category with id which does not exist");
+ final String id = NON_EXISTING_CATEGORY_ID;
+ final RestCategoryModel rootCategory = createCategoryModelWithId(id);
+ restClient.authenticateUser(user).withCoreAPI().usingCategory(rootCategory).getCategory();
+ restClient.assertStatusCodeIs(NOT_FOUND).assertLastError().containsSummary(id);
+ }
+
+ /**
+ * Check we can get children category of a root category
+ */
+ @Test(groups = {TestGroup.REST_API})
+ public void testGetCategoryChildren()
+ {
+ STEP("Get category children with -root- as parent id");
+ final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
+ RestCategoryModelsCollection childCategoriesList =
+ restClient.authenticateUser(user).withCoreAPI().usingCategory(rootCategory).getCategoryChildren();
+ restClient.assertStatusCodeIs(OK);
+
+ childCategoriesList.assertThat().entriesListIsNotEmpty();
+ assertTrue(childCategoriesList.getEntries().stream()
+ .map(RestCategoryModel::onModel)
+ .map(RestCategoryModel::getName)
+ .collect(Collectors.toList())
+ .containsAll(DEFAULT_ROOT_CATEGORIES));
+ STEP("Create a new category under root and make sure it is returned as one of root's children");
+ final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("newCategoryUnderRoot"));
+ final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(rootCategory)
+ .createSingleCategory(aCategory);
+ restClient.assertStatusCodeIs(CREATED);
+
+ childCategoriesList = restClient.authenticateUser(user).withCoreAPI().usingCategory(rootCategory).getCategoryChildren();
+ restClient.assertStatusCodeIs(OK);
+ assertTrue(childCategoriesList.getEntries().stream()
+ .map(RestCategoryModel::onModel)
+ .map(RestCategoryModel::getId)
+ .collect(Collectors.toList())
+ .contains(createdCategory.getId()));
+
+ STEP("Create 2 more categories under newCategoryUnderRoot and make sure they are returned as children");
+ final int categoriesCount = 2;
+ final List categoriesToCreate = CreateCategoriesTests.getCategoriesToCreate(categoriesCount);
+ final RestCategoryModelsCollection createdSubCategories = restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(createdCategory)
+ .createCategoriesList(categoriesToCreate);
+ restClient.assertStatusCodeIs(CREATED);
+ childCategoriesList = restClient.authenticateUser(user).withCoreAPI().usingCategory(rootCategory).getCategoryChildren();
+ restClient.assertStatusCodeIs(OK);
+ childCategoriesList.getEntries().containsAll(createdSubCategories.getEntries());
+ }
+
+ /**
+ * Check we get an error when passing folder node id as parent category id when getting children.
+ */
+ @Test(groups = {TestGroup.REST_API})
+ public void testGetCategoryChildrenProvidingFolderAsId()
+ {
+ STEP("Create a site and a folder inside it");
+ final SiteModel site = dataSite.usingUser(user).createPublicRandomSite();
+ final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
+
+ STEP("Get category children with folder id passed as parent id");
+ final RestCategoryModel parentCategory = createCategoryModelWithId(folder.getNodeRef());
+ restClient.authenticateUser(user).withCoreAPI().usingCategory(parentCategory).getCategoryChildren();
+ restClient.assertStatusCodeIs(BAD_REQUEST).assertLastError().containsSummary("Node id does not refer to a valid category");
+ }
+
+ /**
+ * Check we get an error when passing a non-existent node id as parent category id when getting children.
+ */
+ @Test(groups = {TestGroup.REST_API})
+ public void testGetCategoryChildrenProvidingNonExistingParent()
+ {
+
+ STEP("Get category with folder id passed as id");
+ final String parentId = NON_EXISTING_CATEGORY_ID;
+ final RestCategoryModel parentCategory = createCategoryModelWithId(parentId);
+ restClient.authenticateUser(user).withCoreAPI().usingCategory(parentCategory).getCategoryChildren();
+ restClient.assertStatusCodeIs(NOT_FOUND).assertLastError().containsSummary(parentId);
+ }
}
diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/UpdateCategoriesTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/UpdateCategoriesTests.java
new file mode 100644
index 0000000000..f439c07b6a
--- /dev/null
+++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/categories/UpdateCategoriesTests.java
@@ -0,0 +1,214 @@
+/*
+ * #%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 .
+ * #L%
+ */
+
+package org.alfresco.rest.categories;
+
+import static org.alfresco.utility.data.RandomData.getRandomName;
+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.model.RestCategoryModel;
+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.Test;
+
+public class UpdateCategoriesTests extends CategoriesRestTest
+{
+ private static final String CATEGORY_NEW_NAME_PREFIX = "NewCategoryName";
+ private static final String IGNORE_FIELD_NAME = FIELD_NAME;
+
+ /**
+ * Update a category (direct child of root category)
+ */
+ @Test(groups = { TestGroup.REST_API})
+ public void testUpdateCategory_asAdmin()
+ {
+ STEP("Prepare as admin a category under root category");
+ final RestCategoryModel createdCategory = prepareCategoryUnderRoot();
+
+ STEP("Update as admin newly created category");
+ final String categoryNewName = getRandomName(CATEGORY_NEW_NAME_PREFIX);
+ final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(categoryNewName);
+ final RestCategoryModel updatedCategory = restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(createdCategory)
+ .updateCategory(fixedCategoryModel);
+
+ restClient.assertStatusCodeIs(OK);
+ updatedCategory.assertThat().isEqualTo(createdCategory, IGNORE_FIELD_NAME);
+ updatedCategory.assertThat().field(FIELD_NAME).isNot(createdCategory.getName());
+ updatedCategory.assertThat().field(FIELD_NAME).is(categoryNewName);
+ }
+
+ /**
+ * Update a subcategory of root's child category
+ */
+ @Test(groups = { TestGroup.REST_API})
+ public void testUpdateSubcategory_asAdmin()
+ {
+ STEP("Prepare as admin a category under root category");
+ final RestCategoryModel createdCategory = prepareCategoryUnderRoot();
+
+ STEP("Prepare as admin a subcategory of root's child category");
+ final RestCategoryModel createdSubcategory = prepareCategoryUnder(createdCategory.getId());
+
+ STEP("Update as admin newly created subcategory");
+ final String categoryNewName = getRandomName(CATEGORY_NEW_NAME_PREFIX);
+ final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(categoryNewName);
+ final RestCategoryModel updatedCategory = restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(createdSubcategory)
+ .updateCategory(fixedCategoryModel);
+
+ restClient.assertStatusCodeIs(OK);
+ updatedCategory.assertThat().isEqualTo(createdSubcategory, IGNORE_FIELD_NAME);
+ updatedCategory.assertThat().field(FIELD_NAME).is(categoryNewName);
+ }
+
+ /**
+ * Try to update a category as a user and expect 403 (Forbidden) in response
+ */
+ @Test(groups = { TestGroup.REST_API})
+ public void testUpdateCategory_asUserAndExpect403()
+ {
+ STEP("Prepare as admin a category under root category");
+ final RestCategoryModel createdCategory = prepareCategoryUnderRoot();
+
+ STEP("Try to update as user newly created category");
+ final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(getRandomName(CATEGORY_NEW_NAME_PREFIX));
+ restClient.authenticateUser(user)
+ .withCoreAPI()
+ .usingCategory(createdCategory)
+ .updateCategory(fixedCategoryModel);
+
+ restClient.assertStatusCodeIs(FORBIDDEN);
+ }
+
+ /**
+ * Try to update a non-existing category and receive 404 (Not Found)
+ */
+ @Test(groups = { TestGroup.REST_API})
+ public void testUpdateCategory_usingNonExistingCategoryAndExpect404()
+ {
+ STEP("Create a fake parent category");
+ final RestCategoryModel nonExistingCategory = createCategoryModelWithIdAndName("non-existing-dummy-id", getRandomName(CATEGORY_NAME_PREFIX));
+
+ STEP("Try to update as admin fake category");
+ final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(getRandomName(CATEGORY_NEW_NAME_PREFIX));
+ restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(nonExistingCategory)
+ .updateCategory(fixedCategoryModel);
+
+ restClient.assertStatusCodeIs(NOT_FOUND);
+ }
+
+ /**
+ * Try to update a non-category (folder) node and receive 400 (Bad Request)
+ */
+ @Test(groups = { TestGroup.REST_API})
+ public void testUpdateCategory_usingFolderNodeAndExpect400()
+ {
+ STEP("Prepare a site and a folder inside it");
+ final UserModel user = dataUser.createRandomTestUser();
+ final SiteModel site = dataSite.usingUser(user).createPublicRandomSite();
+ final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
+ final RestCategoryModel categoryWithFolderId = createCategoryModelWithIdAndName(folder.getNodeRef(), getRandomName(CATEGORY_NAME_PREFIX));
+
+ STEP("Try to update as admin folder node as category");
+ final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(getRandomName(CATEGORY_NEW_NAME_PREFIX));
+ restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(categoryWithFolderId)
+ .updateCategory(fixedCategoryModel);
+
+ restClient.assertStatusCodeIs(BAD_REQUEST);
+ }
+
+ /**
+ * Try to update a root category and receive 400 (Bad Request)
+ */
+ @Test(groups = { TestGroup.REST_API})
+ public void testUpdateCategory_usingRootCategoryAndExpect400()
+ {
+ STEP("Create root category model");
+ final RestCategoryModel rootCategoryModel = createCategoryModelWithId(ROOT_CATEGORY_ID);
+
+ STEP("Try to update as admin root category");
+ final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(getRandomName(CATEGORY_NEW_NAME_PREFIX));
+ restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(rootCategoryModel)
+ .updateCategory(fixedCategoryModel);
+
+ restClient.assertStatusCodeIs(BAD_REQUEST);
+ }
+
+ /**
+ * Try to update a category with an empty name and receive 400 (Bad Request)
+ */
+ @Test(groups = { TestGroup.REST_API})
+ public void testUpdateCategory_withEmptyNameAndExpect400()
+ {
+ STEP("Prepare as admin a category under root category");
+ final RestCategoryModel createdCategory = prepareCategoryUnderRoot();
+
+ STEP("Try to update as admin newly created category with a category without name");
+ final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(null);
+ restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(createdCategory)
+ .updateCategory(fixedCategoryModel);
+
+ restClient.assertStatusCodeIs(BAD_REQUEST);
+ }
+
+ /**
+ * Try to update a category with an invalid, but not important ID in body and receive 200 (OK)
+ */
+ @Test(groups = { TestGroup.REST_API})
+ public void testUpdateCategory_withIgnoredInvalidIdInBodyAndExpect200()
+ {
+ STEP("Prepare as admin a category under root category");
+ final RestCategoryModel createdCategory = prepareCategoryUnderRoot();
+
+ STEP("Try to update as admin newly created category with a category with invalid ID and receive 200");
+ final String categoryNewName = getRandomName(CATEGORY_NEW_NAME_PREFIX);
+ final RestCategoryModel fixedCategoryModel = createCategoryModelWithIdAndName("non-existing-dummy-id", categoryNewName);
+ final RestCategoryModel updatedCategory = restClient.authenticateUser(dataUser.getAdminUser())
+ .withCoreAPI()
+ .usingCategory(createdCategory)
+ .updateCategory(fixedCategoryModel);
+
+ restClient.assertStatusCodeIs(OK);
+ updatedCategory.assertThat().field(FIELD_NAME).is(categoryNewName);
+ }
+}
diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/CreateRulesTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/CreateRulesTests.java
index cf4888952b..8b195e3ebd 100644
--- a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/CreateRulesTests.java
+++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/CreateRulesTests.java
@@ -56,6 +56,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javax.json.Json;
import javax.json.JsonObject;
@@ -63,6 +64,7 @@ import javax.json.JsonObject;
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
import org.alfresco.rest.model.RestActionConstraintModel;
import org.alfresco.rest.model.RestCompositeConditionDefinitionModel;
+import org.alfresco.rest.model.RestPaginationModel;
import org.alfresco.rest.model.RestRuleModel;
import org.alfresco.rest.model.RestRuleModelsCollection;
import org.alfresco.utility.constants.UserRole;
@@ -267,6 +269,38 @@ public class CreateRulesTests extends RulesRestTest
.assertThat().field("name").is(ruleNames.get(i)));
}
+ /** Check we can create over 100 rules and get them all back in response. */
+ @Test (groups = { TestGroup.REST_API, TestGroup.RULES })
+ public void createOver100Rules()
+ {
+ STEP("Create a list of 120 rules in one POST request");
+ final int ruleCount = 120;
+ final String ruleNamePrefix = "multiRule";
+ final List ruleModels = IntStream.rangeClosed(1, ruleCount)
+ .mapToObj(i -> rulesUtils.createRuleModel(ruleNamePrefix + i))
+ .collect(Collectors.toList());
+
+ final FolderModel aFolder = dataContent.usingUser(user).usingSite(site).createFolder();
+ final RestRuleModelsCollection rules = restClient.authenticateUser(user).withPrivateAPI().usingNode(aFolder).usingDefaultRuleSet()
+ .createListOfRules(ruleModels);
+
+ restClient.assertStatusCodeIs(CREATED);
+
+ assertEquals("Unexpected number of rules received in response.", ruleCount, rules.getEntries().size());
+ IntStream.range(0, ruleModels.size()).forEach(i ->
+ rules.getEntries().get(i).onModel()
+ .assertThat().field("id").isNotNull()
+ .assertThat().field("name").is(ruleNamePrefix + (i + 1)));
+
+ rules.getPagination()
+ .assertThat().field("count").is(ruleCount)
+ .assertThat().field("totalItems").is(ruleCount)
+ .assertThat().field("maxItems").is(ruleCount)
+ .assertThat().field("skipCount").is(0)
+ .assertThat().field("hasMoreItems").is(false);
+
+ }
+
/** Try to create several rules with an error in one of them. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRulesWithOneError()
diff --git a/packaging/tests/tas-restapi/src/test/resources/log4j.properties b/packaging/tests/tas-restapi/src/test/resources/log4j.properties
deleted file mode 100644
index 00e9b5a114..0000000000
--- a/packaging/tests/tas-restapi/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,26 +0,0 @@
-# Root logger option
-log4j.rootLogger=INFO, file, stdout
-
-# Direct log messages to a log file
-log4j.appender.file=org.apache.log4j.RollingFileAppender
-log4j.appender.file.File=./target/reports/alfresco-tas.log
-log4j.appender.file.MaxBackupIndex=10
-log4j.appender.file.layout=org.apache.log4j.PatternLayout
-log4j.appender.file.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# Direct log messages to stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.Target=System.out
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# TestRail particular log file
-# Direct log messages to a log file
-log4j.appender.testrailLog=org.apache.log4j.RollingFileAppender
-log4j.appender.testrailLog.File=./target/reports/alfresco-testrail.log
-log4j.appender.testrailLog.MaxBackupIndex=10
-log4j.appender.testrailLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.testrailLog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-log4j.category.testrail=INFO, testrailLog
-log4j.additivity.testrail=false
\ No newline at end of file
diff --git a/packaging/tests/tas-restapi/src/test/resources/log4j2.properties b/packaging/tests/tas-restapi/src/test/resources/log4j2.properties
new file mode 100644
index 0000000000..5e34814028
--- /dev/null
+++ b/packaging/tests/tas-restapi/src/test/resources/log4j2.properties
@@ -0,0 +1,42 @@
+# Root logger option
+rootLogger.level=info
+rootLogger.appenderRef.stdout.ref=ConsoleAppender
+rootLogger.appenderRef.rolling.ref=RollingAppender
+
+###### File appender definition #######
+appender.rolling.type=RollingFile
+appender.rolling.name=RollingAppender
+appender.rolling.fileName=./target/reports/alfresco-tas.log
+appender.rolling.filePattern=./target/reports/alfresco-tas.log.%i
+appender.rolling.layout.type=PatternLayout
+appender.rolling.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.rolling.policies.type = Policies
+appender.rolling.policies.size.type=SizeBasedTriggeringPolicy
+appender.rolling.policies.size.size=10MB
+appender.rolling.strategy.type=DefaultRolloverStrategy
+appender.rolling.strategy.max=10
+
+###### Console appender definition #######
+appender.console.type=Console
+appender.console.name=ConsoleAppender
+appender.console.layout.type=PatternLayout
+appender.console.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+
+# TestRail particular log file
+# Direct log messages to a log file
+logger.testrail.name=testrail
+logger.testrail.level=info
+logger.testrail.additivity=false
+logger.testrail.appenderRef.testrail.ref=TestrailAppender
+
+appender.testrail.name=TestrailAppender
+appender.testrail.type=RollingFile
+appender.testrail.fileName=./target/reports/alfresco-testrail.log
+appender.testrail.filePattern=./target/reports/alfresco-testrail.log.%i
+appender.testrail.layout.type=PatternLayout
+appender.testrail.layout.pattern=%d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.testrail.policies.type=Policies
+appender.testrail.policies.size.type=SizeBasedTriggeringPolicy
+appender.testrail.policies.size.size=10MB
+appender.testrail.strategy.type=DefaultRolloverStrategy
+appender.testrail.strategy.max=10
\ No newline at end of file
diff --git a/packaging/tests/tas-webdav/pom.xml b/packaging/tests/tas-webdav/pom.xml
index 6087a467c0..a3405e5827 100644
--- a/packaging/tests/tas-webdav/pom.xml
+++ b/packaging/tests/tas-webdav/pom.xml
@@ -9,7 +9,7 @@
org.alfresco
alfresco-community-repo-tests
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/packaging/tests/tas-webdav/src/test/java/org/alfresco/webdav/WebDavTest.java b/packaging/tests/tas-webdav/src/test/java/org/alfresco/webdav/WebDavTest.java
index f75eed0f92..ca71c0ab91 100644
--- a/packaging/tests/tas-webdav/src/test/java/org/alfresco/webdav/WebDavTest.java
+++ b/packaging/tests/tas-webdav/src/test/java/org/alfresco/webdav/WebDavTest.java
@@ -1,17 +1,25 @@
package org.alfresco.webdav;
+import java.lang.reflect.Method;
+
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.data.DataSite;
import org.alfresco.utility.data.DataUser;
+import org.alfresco.utility.LogFactory;
import org.alfresco.utility.network.ServerHealth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
+import org.slf4j.Logger;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
@ContextConfiguration("classpath:alfresco-webdav-context.xml")
public abstract class WebDavTest extends AbstractTestNGSpringContextTests
{
+ private static final Logger LOG = LogFactory.getLogger();
+
@Autowired
protected DataSite dataSite;
@@ -36,4 +44,16 @@ public abstract class WebDavTest extends AbstractTestNGSpringContextTests
// The webdav protocol is enabled by default.
//webDavProtocol.assertThat().protocolIsEnabled();
}
-}
+
+ @BeforeMethod(alwaysRun=true)
+ public void showStartTestInfo(Method method)
+ {
+ LOG.info(String.format("*** STARTING Test: [%s] ***", method.getName()));
+ }
+
+ @AfterMethod(alwaysRun=true)
+ public void showEndTestInfo(Method method)
+ {
+ LOG.info(String.format("*** ENDING Test: [%s] ***", method.getName()));
+ }
+}
\ No newline at end of file
diff --git a/packaging/tests/tas-webdav/src/test/resources/log4j.properties b/packaging/tests/tas-webdav/src/test/resources/log4j.properties
deleted file mode 100644
index 00e9b5a114..0000000000
--- a/packaging/tests/tas-webdav/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,26 +0,0 @@
-# Root logger option
-log4j.rootLogger=INFO, file, stdout
-
-# Direct log messages to a log file
-log4j.appender.file=org.apache.log4j.RollingFileAppender
-log4j.appender.file.File=./target/reports/alfresco-tas.log
-log4j.appender.file.MaxBackupIndex=10
-log4j.appender.file.layout=org.apache.log4j.PatternLayout
-log4j.appender.file.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# Direct log messages to stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.Target=System.out
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-# TestRail particular log file
-# Direct log messages to a log file
-log4j.appender.testrailLog=org.apache.log4j.RollingFileAppender
-log4j.appender.testrailLog.File=./target/reports/alfresco-testrail.log
-log4j.appender.testrailLog.MaxBackupIndex=10
-log4j.appender.testrailLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.testrailLog.layout.ConversionPattern=%d{HH:mm:ss} %-5p %c{1}:%L - %m%n
-
-log4j.category.testrail=INFO, testrailLog
-log4j.additivity.testrail=false
\ No newline at end of file
diff --git a/packaging/tests/tas-webdav/src/test/resources/log4j2.properties b/packaging/tests/tas-webdav/src/test/resources/log4j2.properties
new file mode 100644
index 0000000000..5e34814028
--- /dev/null
+++ b/packaging/tests/tas-webdav/src/test/resources/log4j2.properties
@@ -0,0 +1,42 @@
+# Root logger option
+rootLogger.level=info
+rootLogger.appenderRef.stdout.ref=ConsoleAppender
+rootLogger.appenderRef.rolling.ref=RollingAppender
+
+###### File appender definition #######
+appender.rolling.type=RollingFile
+appender.rolling.name=RollingAppender
+appender.rolling.fileName=./target/reports/alfresco-tas.log
+appender.rolling.filePattern=./target/reports/alfresco-tas.log.%i
+appender.rolling.layout.type=PatternLayout
+appender.rolling.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.rolling.policies.type = Policies
+appender.rolling.policies.size.type=SizeBasedTriggeringPolicy
+appender.rolling.policies.size.size=10MB
+appender.rolling.strategy.type=DefaultRolloverStrategy
+appender.rolling.strategy.max=10
+
+###### Console appender definition #######
+appender.console.type=Console
+appender.console.name=ConsoleAppender
+appender.console.layout.type=PatternLayout
+appender.console.layout.pattern=[%t] %d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+
+# TestRail particular log file
+# Direct log messages to a log file
+logger.testrail.name=testrail
+logger.testrail.level=info
+logger.testrail.additivity=false
+logger.testrail.appenderRef.testrail.ref=TestrailAppender
+
+appender.testrail.name=TestrailAppender
+appender.testrail.type=RollingFile
+appender.testrail.fileName=./target/reports/alfresco-testrail.log
+appender.testrail.filePattern=./target/reports/alfresco-testrail.log.%i
+appender.testrail.layout.type=PatternLayout
+appender.testrail.layout.pattern=%d{HH:mm:ss} %-5p %c{1}:%L - %replace{%m}{[\r\n]+}{}%n
+appender.testrail.policies.type=Policies
+appender.testrail.policies.size.type=SizeBasedTriggeringPolicy
+appender.testrail.policies.size.size=10MB
+appender.testrail.strategy.type=DefaultRolloverStrategy
+appender.testrail.strategy.max=10
\ No newline at end of file
diff --git a/packaging/war/pom.xml b/packaging/war/pom.xml
index 6c9ef0a9ce..f5d91b55b0 100644
--- a/packaging/war/pom.xml
+++ b/packaging/war/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-community-repo-packaging
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/packaging/war/src/main/resources/log4j2.properties b/packaging/war/src/main/resources/log4j2.properties
index bc37e2bd7c..39b84a34b7 100644
--- a/packaging/war/src/main/resources/log4j2.properties
+++ b/packaging/war/src/main/resources/log4j2.properties
@@ -29,7 +29,6 @@ appender.rolling.policies.time.interval = 1
# Log4j addLoggerMBean as long as the logger exists and has been loaded.
# Hibernate
-
logger.hibernate.name=org.hibernate
logger.hibernate.level=error
@@ -45,42 +44,29 @@ logger.hibernate-type.level=warn
logger.hibernate-cfg-SettingsFactory.name=org.hibernate.cfg.SettingsFactory
logger.hibernate-cfg-SettingsFactory.level=warn
-
-
# Spring
-
logger.springframework.name=org.springframework
logger.springframework.level=warn
# Turn off Spring remoting warnings that should really be info or debug.
-
logger.springframework-remoting-support.name=org.springframework.remoting.support
logger.springframework-remoting-support.level=error
logger.springframework-util.name=org.springframework.util
logger.springframework-util.level=error
-
-
# Axis/WSS4J
-
logger.apache-axis.name=org.apache.axis
logger.apache-axis.level=info
logger.apache-ws.name=org.apache.ws
logger.apache-ws.level=info
-
-
# CXF
-
logger.apache-cxf.name=org.apache.cxf
logger.apache-cxf.level=error
-
-
# MyFaces
-
logger.apache-myfaces-util-DebugUtils.name=org.apache.myfaces.util.DebugUtils
logger.apache-myfaces-util-DebugUtils.level=info
@@ -93,17 +79,11 @@ logger.apache-myfaces-application-jsp-JspViewHandlerImpl.level=error
logger.apache-myfaces-taglib.name=org.apache.myfaces.taglib
logger.apache-myfaces-taglib.level=error
-
-
# log prepared statement cache activity ###
-
logger.hibernate-ps-PreparedStatementCache.name=org.hibernate.ps.PreparedStatementCache
logger.hibernate-ps-PreparedStatementCache.level=info
-
-
# Alfresco
-
logger.alfresco.name=org.alfresco
logger.alfresco.level=error
@@ -146,8 +126,6 @@ logger.alfresco-repo-security-sync.level=info
logger.alfresco-repo-security-person.name=org.alfresco.repo.security.person
logger.alfresco-repo-security-person.level=info
-
-
logger.alfresco-sample.name=org.alfresco.sample
logger.alfresco-sample.level=info
@@ -172,34 +150,25 @@ logger.alfresco-service-descriptor-DescriptorService.level=info
#logger.alfresco-web-page.name=org.alfresco.web.page
#logger.alfresco-web-page.level=debug
-
-
logger.alfresco-repo-importer-ImporterBootstrap.name=org.alfresco.repo.importer.ImporterBootstrap
logger.alfresco-repo-importer-ImporterBootstrap.level=error
#logger.alfresco-repo-importer-ImporterBootstrap.name=org.alfresco.repo.importer.ImporterBootstrap
#logger.alfresco-repo-importer-ImporterBootstrap.level=info
-
-
logger.alfresco-repo-admin-patch-PatchExecuter.name=org.alfresco.repo.admin.patch.PatchExecuter
logger.alfresco-repo-admin-patch-PatchExecuter.level=info
logger.alfresco-repo-domain-patch-ibatis-PatchDAOImpl.name=org.alfresco.repo.domain.patch.ibatis.PatchDAOImpl
logger.alfresco-repo-domain-patch-ibatis-PatchDAOImpl.level=info
-
-
# Specific patches
-
logger.alfresco-repo-admin-patch-impl-DeploymentMigrationPatch.name=org.alfresco.repo.admin.patch.impl.DeploymentMigrationPatch
logger.alfresco-repo-admin-patch-impl-DeploymentMigrationPatch.level=info
logger.alfresco-repo-version-VersionMigrator.name=org.alfresco.repo.version.VersionMigrator
logger.alfresco-repo-version-VersionMigrator.level=info
-
-
logger.alfresco-repo-module-ModuleServiceImpl.name=org.alfresco.repo.module.ModuleServiceImpl
logger.alfresco-repo-module-ModuleServiceImpl.level=info
@@ -239,74 +208,49 @@ logger.alfresco-enterprise-repo-cluster.level=info
logger.alfresco-repo-version-Version2ServiceImpl.name=org.alfresco.repo.version.Version2ServiceImpl
logger.alfresco-repo-version-Version2ServiceImpl.level=warn
-
-
#logger.alfresco-web-app-DebugPhaseListener.name=org.alfresco.web.app.DebugPhaseListener
#logger.alfresco-web-app-DebugPhaseListener.level=debug
logger.alfresco-repo-node-db-NodeStringLengthWorker.name=org.alfresco.repo.node.db.NodeStringLengthWorker
logger.alfresco-repo-node-db-NodeStringLengthWorker.level=info
-
-
logger.alfresco-repo-workflow.name=org.alfresco.repo.workflow
logger.alfresco-repo-workflow.level=info
-
-
# FTP server debugging
-
logger.alfresco-ftp-protocol.name=org.alfresco.ftp.protocol
logger.alfresco-ftp-protocol.level=error
#logger.alfresco-ftp-server.name=org.alfresco.ftp.server
#logger.alfresco-ftp-server.level=debug
-
-
# WebDAV debugging
-
#logger.alfresco-webdav-protocol.name=org.alfresco.webdav.protocol
#logger.alfresco-webdav-protocol.level=debug
logger.alfresco-webdav-protocol.name=org.alfresco.webdav.protocol
logger.alfresco-webdav-protocol.level=info
-
-
# Kerberos servlet filters
-
#logger.alfresco-web-app-servlet-KerberosAuthenticationFilter.name=org.alfresco.web.app.servlet.KerberosAuthenticationFilter
#logger.alfresco-web-app-servlet-KerberosAuthenticationFilter.level=debug
#logger.alfresco-repo-webdav-auth-KerberosAuthenticationFilter.name=org.alfresco.repo.webdav.auth.KerberosAuthenticationFilter
#logger.alfresco-repo-webdav-auth-KerberosAuthenticationFilter.level=debug
-
-
# File servers
-
logger.alfresco-fileserver.name=org.alfresco.fileserver
logger.alfresco-fileserver.level=warn
-
-
# Repo filesystem debug logging
-
#logger.alfresco-filesys-repo-ContentDiskDriver.name=org.alfresco.filesys.repo.ContentDiskDriver
#logger.alfresco-filesys-repo-ContentDiskDriver.level=debug
-
-
# Integrity message threshold - if 'failOnViolation' is off, then WARNINGS are generated
-
logger.alfresco-repo-node-integrity.name=org.alfresco.repo.node.integrity
logger.alfresco-repo-node-integrity.level=error
-
-
# Authentication
-
logger.alfresco-filesys-auth-ftp.name=org.alfresco.filesys.auth.ftp
logger.alfresco-filesys-auth-ftp.level=warn
@@ -323,22 +267,16 @@ logger.alfresco-web-app-servlet.name=org.alfresco.web.app.servlet
logger.alfresco-web-app-servlet.level=warn
# Used also for brute force attack detection
-
logger.alfresco-repo-security-authentication.name=org.alfresco.repo.security.authentication
logger.alfresco-repo-security-authentication.level=warn
-
-
# Indexer debugging
-
logger.alfresco-repo-search-Indexer.name=org.alfresco.repo.search.Indexer
logger.alfresco-repo-search-Indexer.level=error
#logger.alfresco-repo-search-Indexer.name=org.alfresco.repo.search.Indexer
#logger.alfresco-repo-search-Indexer.level=debug
-
-
logger.alfresco-repo-search-impl-lucene-index.name=org.alfresco.repo.search.impl.lucene.index
logger.alfresco-repo-search-impl-lucene-index.level=error
@@ -348,97 +286,62 @@ logger.alfresco-repo-search-impl-lucene-fts-FullTextSearchIndexerImpl.level=warn
#logger.alfresco-repo-search-impl-lucene-index.name=org.alfresco.repo.search.impl.lucene.index
#logger.alfresco-repo-search-impl-lucene-index.level=debug
-
-
# Audit debugging
-
#logger.alfresco-repo-audit.name=org.alfresco.repo.audit
#logger.alfresco-repo-audit.level=debug
#logger.alfresco-repo-audit-model.name=org.alfresco.repo.audit.model
#logger.alfresco-repo-audit-model.level=debug
-
# Property sheet and modelling debugging
-
# change to error to hide the warnings about missing properties and associations
-
logger.missingProperties.name=alfresco.missingProperties
logger.missingProperties.level=warn
-
-
# Dictionary/Model debugging
-
logger.alfresco-repo-dictionary.name=org.alfresco.repo.dictionary
logger.alfresco-repo-dictionary.level=warn
logger.alfresco-repo-dictionary-types-period.name=org.alfresco.repo.dictionary.types.period
logger.alfresco-repo-dictionary-types-period.level=warn
-
-
# Virtualization Server Registry
-
logger.alfresco-mbeans-VirtServerRegistry.name=org.alfresco.mbeans.VirtServerRegistry
logger.alfresco-mbeans-VirtServerRegistry.level=error
-
-
# Spring context runtime property setter
-
logger.alfresco-util-RuntimeSystemPropertiesSetter.name=org.alfresco.util.RuntimeSystemPropertiesSetter
logger.alfresco-util-RuntimeSystemPropertiesSetter.level=info
-
-
# Debugging options for clustering
-
logger.alfresco-repo-content-ReplicatingContentStore.name=org.alfresco.repo.content.ReplicatingContentStore
logger.alfresco-repo-content-ReplicatingContentStore.level=error
logger.alfresco-repo-content-replication.name=org.alfresco.repo.content.replication
logger.alfresco-repo-content-replication.level=error
-
-
#logger.alfresco-repo-deploy-DeploymentServiceImpl.name=org.alfresco.repo.deploy.DeploymentServiceImpl
#logger.alfresco-repo-deploy-DeploymentServiceImpl.level=debug
-
-
# Activity service
-
logger.alfresco-repo-activities.name=org.alfresco.repo.activities
logger.alfresco-repo-activities.level=warn
-
-
# User usage tracking
-
logger.alfresco-repo-usage.name=org.alfresco.repo.usage
logger.alfresco-repo-usage.level=info
-
-
# Sharepoint
-
logger.alfresco-module-vti.name=org.alfresco.module.vti
logger.alfresco-module-vti.level=info
-
-
# Forms Engine
-
logger.alfresco-web-config-forms.name=org.alfresco.web.config.forms
logger.alfresco-web-config-forms.level=info
logger.alfresco-web-scripts-forms.name=org.alfresco.web.scripts.forms
logger.alfresco-web-scripts-forms.level=info
-
-
# CMIS
-
logger.alfresco-opencmis.name=org.alfresco.opencmis
logger.alfresco-opencmis.level=error
@@ -460,35 +363,20 @@ logger.apache-chemistry-opencmis-server-impl-browser-CmisBrowserBindingServlet.l
logger.apache-chemistry-opencmis-server-impl-atompub-CmisAtomPubServlet.name=org.apache.chemistry.opencmis.server.impl.atompub.CmisAtomPubServlet
logger.apache-chemistry-opencmis-server-impl-atompub-CmisAtomPubServlet.level=off
-
-
# IMAP
-
logger.alfresco-repo-imap.name=org.alfresco.repo.imap
logger.alfresco-repo-imap.level=info
-
-
# JBPM
-
# Note: non-fatal errors (eg. logged during job execution) should be handled by Alfresco's retrying transaction handler
-
logger.jbpm-graph-def-GraphElement.name=org.jbpm.graph.def.GraphElement
logger.jbpm-graph-def-GraphElement.level=fatal
-
-
#logger.alfresco-repo-googledocs.name=org.alfresco.repo.googledocs
#logger.alfresco-repo-googledocs.level=debug
-
-
###### Scripting #######
-
-
-
# Web Framework
-
logger.springframework-extensions-webscripts.name=org.springframework.extensions.webscripts
logger.springframework-extensions-webscripts.level=info
@@ -498,10 +386,7 @@ logger.springframework-extensions-webscripts-ScriptLogger.level=warn
logger.springframework-extensions-webscripts-ScriptDebugger.name=org.springframework.extensions.webscripts.ScriptDebugger
logger.springframework-extensions-webscripts-ScriptDebugger.level=off
-
-
# Repository
-
logger.alfresco-repo-web-scripts.name=org.alfresco.repo.web.scripts
logger.alfresco-repo-web-scripts.level=warn
@@ -520,8 +405,6 @@ logger.alfresco-repo-jscript-ScriptLogger.level=warn
logger.alfresco-repo-cmis-rest-CMISTest.name=org.alfresco.repo.cmis.rest.CMISTest
logger.alfresco-repo-cmis-rest-CMISTest.level=info
-
-
logger.alfresco-repo-domain-schema-script-ScriptBundleExecutorImpl.name=org.alfresco.repo.domain.schema.script.ScriptBundleExecutorImpl
logger.alfresco-repo-domain-schema-script-ScriptBundleExecutorImpl.level=off
@@ -531,103 +414,63 @@ logger.alfresco-repo-domain-schema-script-ScriptExecutorImpl.level=info
logger.alfresco-repo-domain-schema-script-DeleteNotExistsExecutor.name=org.alfresco.repo.domain.schema.script.DeleteNotExistsExecutor
logger.alfresco-repo-domain-schema-script-DeleteNotExistsExecutor.level=off
-
-
logger.alfresco-repo-search-impl-solr-facet-SolrFacetServiceImpl.name=org.alfresco.repo.search.impl.solr.facet.SolrFacetServiceImpl
logger.alfresco-repo-search-impl-solr-facet-SolrFacetServiceImpl.level=info
-
-
# Bulk Filesystem Import Tool
-
logger.alfresco-repo-bulkimport.name=org.alfresco.repo.bulkimport
logger.alfresco-repo-bulkimport.level=warn
-
-
# Freemarker
-
# Note the freemarker.runtime logger is used to log non-fatal errors that are handled by Alfresco's retrying transaction handler
-
logger.runtime.name=freemarker.runtime
logger.runtime.level=
-
-
# Metadata extraction
-
logger.alfresco-repo-content-metadata-AbstractMappingMetadataExtracter.name=org.alfresco.repo.content.metadata.AbstractMappingMetadataExtracter
logger.alfresco-repo-content-metadata-AbstractMappingMetadataExtracter.level=warn
-
-
# no index support
-
logger.alfresco-repo-search-impl-noindex-NoIndexIndexer.name=org.alfresco.repo.search.impl.noindex.NoIndexIndexer
logger.alfresco-repo-search-impl-noindex-NoIndexIndexer.level=fatal
logger.alfresco-repo-search-impl-noindex-NoIndexSearchService.name=org.alfresco.repo.search.impl.noindex.NoIndexSearchService
logger.alfresco-repo-search-impl-noindex-NoIndexSearchService.level=fatal
-
-
# lucene index warnings
-
logger.alfresco-repo-search-impl-lucene-index-IndexInfo.name=org.alfresco.repo.search.impl.lucene.index.IndexInfo
logger.alfresco-repo-search-impl-lucene-index-IndexInfo.level=warn
-
-
# Warn about RMI socket bind retries.
-
logger.alfresco-util-remote-server-socket-HostConfigurableSocketFactory.name=org.alfresco.util.remote.server.socket.HostConfigurableSocketFactory
logger.alfresco-util-remote-server-socket-HostConfigurableSocketFactory.level=warn
-
-
logger.alfresco-repo-usage-RepoUsageMonitor.name=org.alfresco.repo.usage.RepoUsageMonitor
logger.alfresco-repo-usage-RepoUsageMonitor.level=info
-
-
# Authorization
-
logger.alfresco-enterprise-repo-authorization-AuthorizationService.name=org.alfresco.enterprise.repo.authorization.AuthorizationService
logger.alfresco-enterprise-repo-authorization-AuthorizationService.level=info
logger.alfresco-enterprise-repo-authorization-AuthorizationsConsistencyMonitor.name=org.alfresco.enterprise.repo.authorization.AuthorizationsConsistencyMonitor
logger.alfresco-enterprise-repo-authorization-AuthorizationsConsistencyMonitor.level=warn
-
-
# HeartBeat
-
logger.alfresco-heartbeat.name=org.alfresco.heartbeat
logger.alfresco-heartbeat.level=info
-
-
# Transformations
-
#logger.alfresco-repo-content-transform-TransformerDebug.name=org.alfresco.repo.content.transform.TransformerDebug
#logger.alfresco-repo-content-transform-TransformerDebug.level=debug
-
-
logger.alfresco-repo-content-transform.name=org.alfresco.repo.content.transform
logger.alfresco-repo-content-transform.level=info
-
-
# Repository probes
-
logger.alfresco-rest-api-probes-ProbeEntityResource.name=org.alfresco.rest.api.probes.ProbeEntityResource
logger.alfresco-rest-api-probes-ProbeEntityResource.level=info
-
-
# ActiveMQ
logger.apache-activemq-transport-failover.name=org.apache.activemq.transport.failover
-logger.apache-activemq-transport-failover.level=warn
-
+logger.apache-activemq-transport-failover.level=warn
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index ec13bb64e9..bb6924343e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
alfresco-community-repo
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
pom
Alfresco Community Repo Parent
@@ -109,7 +109,7 @@
2.7.0
1.1.4
- 3.3.1-DEV-LOG4J2
+ 3.4.0-A1
1.6.0-A1
7.3.0
@@ -120,7 +120,7 @@
8.0.30
8
2.7.4
- 3.0.56
+ 3.0.57
5.2.0
1.11
1.7
diff --git a/remote-api/pom.xml b/remote-api/pom.xml
index 8dbe2825b2..49a4777626 100644
--- a/remote-api/pom.xml
+++ b/remote-api/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-community-repo
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/remote-api/src/main/java/org/alfresco/rest/api/Categories.java b/remote-api/src/main/java/org/alfresco/rest/api/Categories.java
index 6c18d06fd2..c5714f7acb 100644
--- a/remote-api/src/main/java/org/alfresco/rest/api/Categories.java
+++ b/remote-api/src/main/java/org/alfresco/rest/api/Categories.java
@@ -29,14 +29,28 @@ package org.alfresco.rest.api;
import java.util.List;
import org.alfresco.rest.api.model.Category;
+import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.Experimental;
-import org.alfresco.service.cmr.repository.NodeRef;
@Experimental
public interface Categories
{
- Category getCategoryById(String id, Parameters params);
+ Category getCategoryById(String id, Parameters parameters);
List createSubcategories(String parentCategoryId, List categories, Parameters parameters);
+
+ CollectionWithPagingInfo getCategoryChildren(String parentCategoryId, Parameters parameters);
+
+ /**
+ * Update category by ID. Currently, it's possible only to update the name of category.
+ *
+ * @param id Category ID.
+ * @param fixedCategoryModel Fixed category model.
+ * @return Updated category.
+ */
+ Category updateCategoryById(String id, Category fixedCategoryModel);
+
+ void deleteCategoryById(String id, Parameters parameters);
+
}
diff --git a/remote-api/src/main/java/org/alfresco/rest/api/categories/CategoriesEntityResource.java b/remote-api/src/main/java/org/alfresco/rest/api/categories/CategoriesEntityResource.java
index 3bde251ca0..23b79067ac 100644
--- a/remote-api/src/main/java/org/alfresco/rest/api/categories/CategoriesEntityResource.java
+++ b/remote-api/src/main/java/org/alfresco/rest/api/categories/CategoriesEntityResource.java
@@ -41,7 +41,9 @@ import org.alfresco.rest.framework.resource.parameters.Parameters;
* @author mpichura
*/
@EntityResource(name = "categories", title = "Categories")
-public class CategoriesEntityResource implements EntityResourceAction.ReadById
+public class CategoriesEntityResource implements EntityResourceAction.ReadById,
+ EntityResourceAction.Update,
+ EntityResourceAction.Delete
{
private final Categories categories;
@@ -50,12 +52,45 @@ public class CategoriesEntityResource implements EntityResourceAction.ReadById
+public class SubcategoriesRelation implements RelationshipResourceAction.Create,
+ RelationshipResourceAction.Read
{
private final Categories categories;
@@ -48,6 +50,9 @@ public class SubcategoriesRelation implements RelationshipResourceAction.Create<
this.categories = categories;
}
+ /**
+ * POST /categories/{categoryId}/subcategories
+ */
@WebApiDescription(title = "Create a category",
description = "Creates one or more categories under a parent category",
successStatus = HttpServletResponse.SC_CREATED)
@@ -56,4 +61,16 @@ public class SubcategoriesRelation implements RelationshipResourceAction.Create<
{
return categories.createSubcategories(parentCategoryId, categoryList, parameters);
}
+
+ /**
+ * GET /categories/{categoryId}/subcategories
+ */
+ @WebApiDescription(title = "List category direct children",
+ description = "Lists direct children of a parent category",
+ successStatus = HttpServletResponse.SC_OK)
+ @Override
+ public CollectionWithPagingInfo readAll(String parentCategoryId, Parameters params)
+ {
+ return categories.getCategoryChildren(parentCategoryId, params);
+ }
}
diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/CategoriesImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/CategoriesImpl.java
index 28f452ea31..515e2263e4 100644
--- a/remote-api/src/main/java/org/alfresco/rest/api/impl/CategoriesImpl.java
+++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/CategoriesImpl.java
@@ -39,6 +39,8 @@ 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.resource.parameters.CollectionWithPagingInfo;
+import org.alfresco.rest.framework.resource.parameters.ListPage;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
@@ -47,14 +49,18 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.CategoryService;
import org.alfresco.service.cmr.security.AuthorityService;
+import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
@Experimental
public class CategoriesImpl implements Categories
{
static final String NOT_A_VALID_CATEGORY = "Node id does not refer to a valid category";
- static final String NO_PERMISSION_TO_CREATE_A_CATEGORY = "Current user does not have permission to create a category";
+ static final String NO_PERMISSION_TO_MANAGE_A_CATEGORY = "Current user does not have permission to manage a category";
+ static final String NOT_NULL_OR_EMPTY = "Category name must not be null or empty";
+ static final String FIELD_NOT_MATCH = "Category field: %s does not match the original one";
private final AuthorityService authorityService;
private final CategoryService categoryService;
@@ -72,8 +78,8 @@ public class CategoriesImpl implements Categories
@Override
public Category getCategoryById(final String id, final Parameters params)
{
- final NodeRef nodeRef = nodes.validateNode(id);
- if (isNotACategory(nodeRef) || isRootCategory(nodeRef))
+ final NodeRef nodeRef = getCategoryNodeRef(id);
+ if (isRootCategory(nodeRef))
{
throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{id});
}
@@ -84,29 +90,99 @@ public class CategoriesImpl implements Categories
@Override
public List createSubcategories(String parentCategoryId, List categories, Parameters parameters)
{
- if (!authorityService.hasAdminAuthority())
- {
- throw new PermissionDeniedException(NO_PERMISSION_TO_CREATE_A_CATEGORY);
- }
- final NodeRef parentNodeRef = PATH_ROOT.equals(parentCategoryId) ?
- categoryService.getRootCategoryNodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE)
- .orElseThrow(() -> new EntityNotFoundException(parentCategoryId)) :
- nodes.validateNode(parentCategoryId);
- if (isNotACategory(parentNodeRef))
- {
- throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{parentCategoryId});
- }
+ verifyAdminAuthority();
+ final NodeRef parentNodeRef = getCategoryNodeRef(parentCategoryId);
final List categoryNodeRefs = categories.stream()
- .map(c -> categoryService.createCategory(parentNodeRef, c.getName()))
+ .map(c -> createCategoryNodeRef(parentNodeRef, c))
.collect(Collectors.toList());
return categoryNodeRefs.stream()
.map(this::mapToCategory)
.collect(Collectors.toList());
}
- private boolean isNotACategory(NodeRef nodeRef)
+ @Override
+ public CollectionWithPagingInfo getCategoryChildren(String parentCategoryId, Parameters params)
{
- return !nodes.isSubClass(nodeRef, ContentModel.TYPE_CATEGORY, false);
+ final NodeRef parentNodeRef = getCategoryNodeRef(parentCategoryId);
+ final List childCategoriesAssocs = nodeService.getChildAssocs(parentNodeRef).stream()
+ .filter(ca -> ContentModel.ASSOC_SUBCATEGORIES.equals(ca.getTypeQName()))
+ .collect(Collectors.toList());
+ final List categories = childCategoriesAssocs.stream()
+ .map(c -> mapToCategory(c.getChildRef()))
+ .collect(Collectors.toList());
+ return ListPage.of(categories, params.getPaging());
+ }
+
+ @Override
+ public Category updateCategoryById(final String id, final Category fixedCategoryModel)
+ {
+ verifyAdminAuthority();
+ final NodeRef categoryNodeRef = getCategoryNodeRef(id);
+ if (isRootCategory(categoryNodeRef))
+ {
+ throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{id});
+ }
+
+ verifyCategoryFields(fixedCategoryModel);
+
+ return mapToCategory(changeCategoryName(categoryNodeRef, fixedCategoryModel.getName()));
+ }
+
+ @Override
+ public void deleteCategoryById(String id, Parameters parameters)
+ {
+ verifyAdminAuthority();
+ final NodeRef nodeRef = getCategoryNodeRef(id);
+ if (isRootCategory(nodeRef))
+ {
+ throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{id});
+ }
+
+ nodeService.deleteNode(nodeRef);
+ }
+
+ private void verifyAdminAuthority()
+ {
+ if (!authorityService.hasAdminAuthority())
+ {
+ throw new PermissionDeniedException(NO_PERMISSION_TO_MANAGE_A_CATEGORY);
+ }
+ }
+
+ /**
+ * This method gets category NodeRef for a given category id.
+ * If '-root-' is passed as category id, then it's retrieved as a call to {@link org.alfresco.service.cmr.search.CategoryService#getRootCategoryNodeRef}
+ * In all other cases it's retrieved as a node of a category type {@link #validateCategoryNode(String)}
+ * @param nodeId category node id
+ * @return NodRef of category node
+ */
+ private NodeRef getCategoryNodeRef(String nodeId)
+ {
+ return PATH_ROOT.equals(nodeId) ?
+ categoryService.getRootCategoryNodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE)
+ .orElseThrow(() -> new EntityNotFoundException(nodeId)) :
+ validateCategoryNode(nodeId);
+ }
+
+ /**
+ * Validates if the node exists and is a category.
+ * @param nodeId (presumably) category node id
+ * @return category NodeRef
+ */
+ private NodeRef validateCategoryNode(String nodeId)
+ {
+ final NodeRef nodeRef = nodes.validateNode(nodeId);
+ if (isNotACategory(nodeRef))
+ {
+ throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{nodeId});
+ }
+ return nodeRef;
+ }
+
+ private NodeRef createCategoryNodeRef(NodeRef parentNodeRef, Category c)
+ {
+ verifyCategoryFields(c);
+ return categoryService.createCategory(parentNodeRef, c.getName());
}
private Category mapToCategory(NodeRef nodeRef)
@@ -122,6 +198,11 @@ public class CategoriesImpl implements Categories
.create();
}
+ private boolean isNotACategory(NodeRef nodeRef)
+ {
+ return !nodes.isSubClass(nodeRef, ContentModel.TYPE_CATEGORY, false);
+ }
+
private boolean isRootCategory(final NodeRef nodeRef)
{
final List parentAssocs = nodeService.getParentAssocs(nodeRef);
@@ -133,4 +214,37 @@ public class CategoriesImpl implements Categories
final NodeRef parentRef = nodeService.getPrimaryParent(nodeRef).getParentRef();
return isRootCategory(parentRef) ? PATH_ROOT : parentRef.getId();
}
+
+ /**
+ * Change category qualified name.
+ *
+ * @param categoryNodeRef Category node reference.
+ * @param newName New name.
+ * @return Updated category.
+ */
+ private NodeRef changeCategoryName(final NodeRef categoryNodeRef, final String newName)
+ {
+ final ChildAssociationRef parentAssociation = nodeService.getPrimaryParent(categoryNodeRef);
+ if (parentAssociation == null)
+ {
+ throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{categoryNodeRef.getId()});
+ }
+
+ nodeService.setProperty(categoryNodeRef, ContentModel.PROP_NAME, newName);
+ final QName newQName = QName.createQName(parentAssociation.getQName().getNamespaceURI(), QName.createValidLocalName(newName));
+ return nodeService.moveNode(parentAssociation.getChildRef(), parentAssociation.getParentRef(), parentAssociation.getTypeQName(), newQName).getChildRef();
+ }
+
+ /**
+ * Verify if fixed category name is not empty.
+ *
+ * @param fixedCategoryModel Fixed category model.
+ */
+ private void verifyCategoryFields(final Category fixedCategoryModel)
+ {
+ if (StringUtils.isEmpty(fixedCategoryModel.getName()))
+ {
+ throw new InvalidArgumentException(NOT_NULL_OR_EMPTY);
+ }
+ }
}
diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/Category.java b/remote-api/src/main/java/org/alfresco/rest/api/model/Category.java
index d9b3b6d959..b2f6eeb851 100644
--- a/remote-api/src/main/java/org/alfresco/rest/api/model/Category.java
+++ b/remote-api/src/main/java/org/alfresco/rest/api/model/Category.java
@@ -137,5 +137,4 @@ public class Category
return category;
}
}
-
}
diff --git a/remote-api/src/main/java/org/alfresco/rest/framework/webscripts/ResourceWebScriptPost.java b/remote-api/src/main/java/org/alfresco/rest/framework/webscripts/ResourceWebScriptPost.java
index 5fcd23b332..1d3500a596 100644
--- a/remote-api/src/main/java/org/alfresco/rest/framework/webscripts/ResourceWebScriptPost.java
+++ b/remote-api/src/main/java/org/alfresco/rest/framework/webscripts/ResourceWebScriptPost.java
@@ -44,6 +44,7 @@ import org.alfresco.rest.framework.resource.actions.interfaces.MultiPartResource
import org.alfresco.rest.framework.resource.actions.interfaces.MultiPartRelationshipResourceAction;
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.Params;
import org.alfresco.rest.framework.resource.parameters.Params.RecognizedParams;
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
@@ -377,7 +378,8 @@ public class ResourceWebScriptPost extends AbstractResourceWebScript implements
{
if (created !=null && created.size() > 1)
{
- return CollectionWithPagingInfo.asPagedCollection(created.toArray());
+ final Paging pagingAll = Paging.valueOf(0, created.size());
+ return CollectionWithPagingInfo.asPaged(pagingAll, created);
}
else
{
diff --git a/remote-api/src/test/java/org/alfresco/rest/api/categories/CategoriesEntityResourceTest.java b/remote-api/src/test/java/org/alfresco/rest/api/categories/CategoriesEntityResourceTest.java
index 4988ae4f32..56d2e72eca 100644
--- a/remote-api/src/test/java/org/alfresco/rest/api/categories/CategoriesEntityResourceTest.java
+++ b/remote-api/src/test/java/org/alfresco/rest/api/categories/CategoriesEntityResourceTest.java
@@ -26,7 +26,9 @@
package org.alfresco.rest.api.categories;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
@@ -65,4 +67,17 @@ public class CategoriesEntityResourceTest
then(categoriesMock).shouldHaveNoMoreInteractions();
assertEquals(categoryMock, category);
}
+
+ @Test
+ public void testUpdateCategoryById()
+ {
+ given(categoriesMock.updateCategoryById(any(), any())).willReturn(categoryMock);
+
+ // when
+ final Category actualCategory = objectUnderTest.update(CATEGORY_ID, categoryMock, parametersMock);
+
+ then(categoriesMock).should().updateCategoryById(CATEGORY_ID, categoryMock);
+ then(categoriesMock).shouldHaveNoMoreInteractions();
+ assertThat(actualCategory).isNotNull();
+ }
}
diff --git a/remote-api/src/test/java/org/alfresco/rest/api/categories/SubcategoriesRelationTest.java b/remote-api/src/test/java/org/alfresco/rest/api/categories/SubcategoriesRelationTest.java
new file mode 100644
index 0000000000..7b1948f7d2
--- /dev/null
+++ b/remote-api/src/test/java/org/alfresco/rest/api/categories/SubcategoriesRelationTest.java
@@ -0,0 +1,105 @@
+/*
+ * #%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 .
+ * #L%
+ */
+
+package org.alfresco.rest.api.categories;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.BDDMockito.then;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import org.alfresco.rest.api.Categories;
+import org.alfresco.rest.api.model.Category;
+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.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SubcategoriesRelationTest
+{
+ private static final String PARENT_CATEGORY_ID = "parent-category-node-id";
+ private static final String CATEGORY_ID = "category-node-id";
+ private static final String CATEGORY_NAME = "categoryName";
+ private static final String SUBCATEGORY_NAME_PREFIX = "childCategoryName";
+
+ @Mock
+ private Categories categoriesMock;
+ @Mock
+ private Parameters parametersMock;
+
+ @InjectMocks
+ private SubcategoriesRelation objectUnderTest;
+
+ @Test
+ public void testCreateSubcategory()
+ {
+ final Category categoryToCreate = Category.builder().name(CATEGORY_NAME).create();
+ final Category category = Category.builder().name(CATEGORY_NAME).parentId(PARENT_CATEGORY_ID).hasChildren(false).id(CATEGORY_ID).create();
+ final List categoriesToCreate = List.of(categoryToCreate);
+ given(categoriesMock.createSubcategories(PARENT_CATEGORY_ID, categoriesToCreate, parametersMock)).willReturn(List.of(category));
+
+ //when
+ List categories = objectUnderTest.create(PARENT_CATEGORY_ID, categoriesToCreate, parametersMock);
+
+ then(categoriesMock).should().createSubcategories(PARENT_CATEGORY_ID, categoriesToCreate, parametersMock);
+ then(categoriesMock).shouldHaveNoMoreInteractions();
+ assertEquals(List.of(category), categories);
+ }
+
+ @Test
+ public void testGetCategoryChildren() {
+ final CollectionWithPagingInfo categoryChildren = getCategories(3);
+ given(categoriesMock.getCategoryChildren(PARENT_CATEGORY_ID, parametersMock)).willReturn(categoryChildren);
+
+ //when
+ final CollectionWithPagingInfo returnedChildren = objectUnderTest.readAll(PARENT_CATEGORY_ID, parametersMock);
+
+ then(categoriesMock).should().getCategoryChildren(PARENT_CATEGORY_ID, parametersMock);
+ then(categoriesMock).shouldHaveNoMoreInteractions();
+ assertEquals(categoryChildren, returnedChildren);
+ }
+
+ private CollectionWithPagingInfo getCategories(final int count)
+ {
+ return CollectionWithPagingInfo.asPaged(Paging.DEFAULT,
+ IntStream.range(0, count)
+ .mapToObj(i -> Category.builder().name(SUBCATEGORY_NAME_PREFIX + "-" + i)
+ .parentId(PARENT_CATEGORY_ID)
+ .hasChildren(false)
+ .id(CATEGORY_ID + "-" + i)
+ .create())
+ .collect(Collectors.toList())
+ );
+ }
+}
diff --git a/remote-api/src/test/java/org/alfresco/rest/api/impl/CategoriesImplTest.java b/remote-api/src/test/java/org/alfresco/rest/api/impl/CategoriesImplTest.java
index 7787e19812..ccd35b5b17 100644
--- a/remote-api/src/test/java/org/alfresco/rest/api/impl/CategoriesImplTest.java
+++ b/remote-api/src/test/java/org/alfresco/rest/api/impl/CategoriesImplTest.java
@@ -27,14 +27,26 @@
package org.alfresco.rest.api.impl;
import static org.alfresco.rest.api.Nodes.PATH_ROOT;
+import static org.alfresco.rest.api.impl.CategoriesImpl.NOT_A_VALID_CATEGORY;
+import static org.alfresco.rest.api.impl.CategoriesImpl.NOT_NULL_OR_EMPTY;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
+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 static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
import org.alfresco.model.ContentModel;
import org.alfresco.rest.api.Nodes;
@@ -43,6 +55,7 @@ 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.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -50,7 +63,9 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.search.CategoryService;
import org.alfresco.service.cmr.security.AuthorityService;
+import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
@@ -64,6 +79,8 @@ public class CategoriesImplTest
private static final String CATEGORY_NAME = "categoryName";
private static final String PARENT_ID = "parent-node-id";
private static final String CAT_ROOT_NODE_ID = "cat-root-node-id";
+ private static final NodeRef CATEGORY_NODE_REF = createNodeRefWithId(CATEGORY_ID);
+ private static final Category CATEGORY = createDefaultCategoryWithName(CATEGORY_NAME);
@Mock
private Nodes nodesMock;
@@ -83,12 +100,19 @@ public class CategoriesImplTest
@InjectMocks
private CategoriesImpl objectUnderTest;
+ @Before
+ public void setUp() throws Exception
+ {
+ given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
+ given(nodesMock.validateNode(eq(CATEGORY_ID))).willReturn(CATEGORY_NODE_REF);
+ given(nodesMock.isSubClass(any(), any(), anyBoolean())).willReturn(true);
+ }
+
@Test
public void shouldNotGetRootCategoryById()
{
final NodeRef categoryRootNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CAT_ROOT_NODE_ID);
given(nodesMock.validateNode(CAT_ROOT_NODE_ID)).willReturn(categoryRootNodeRef);
- given(nodesMock.isSubClass(categoryRootNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
given(categoryChildAssociationRefMock.getQName()).willReturn(ContentModel.ASPECT_GEN_CLASSIFIABLE);
given(nodeServiceMock.getParentAssocs(categoryRootNodeRef)).willReturn(List.of(categoryChildAssociationRefMock));
@@ -101,7 +125,7 @@ public class CategoriesImplTest
then(nodeServiceMock).should().getParentAssocs(categoryRootNodeRef);
then(nodeServiceMock).shouldHaveNoMoreInteractions();
then(categoryServiceMock).shouldHaveNoInteractions();
- then(authorityServiceMock).shouldHaveNoMoreInteractions();
+ then(authorityServiceMock).shouldHaveNoInteractions();
}
@Test
@@ -109,7 +133,6 @@ public class CategoriesImplTest
{
final NodeRef categoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CATEGORY_ID);
given(nodesMock.validateNode(CATEGORY_ID)).willReturn(categoryNodeRef);
- given(nodesMock.isSubClass(categoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
final Node categoryNode = new Node();
categoryNode.setName(CATEGORY_NAME);
categoryNode.setNodeId(CATEGORY_ID);
@@ -152,7 +175,6 @@ public class CategoriesImplTest
{
final NodeRef categoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CATEGORY_ID);
given(nodesMock.validateNode(CATEGORY_ID)).willReturn(categoryNodeRef);
- given(nodesMock.isSubClass(categoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
final Node categoryNode = new Node();
categoryNode.setName(CATEGORY_NAME);
categoryNode.setNodeId(CATEGORY_ID);
@@ -225,14 +247,98 @@ public class CategoriesImplTest
}
@Test
- public void testCreateCategoryUnderRoot()
+ public void testDeleteCategoryById_asAdmin()
{
given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
+ final NodeRef categoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CATEGORY_ID);
+ given(nodesMock.validateNode(CATEGORY_ID)).willReturn(categoryNodeRef);
+ given(nodesMock.isSubClass(categoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
+ final Node categoryNode = new Node();
+ categoryNode.setName(CATEGORY_NAME);
+ categoryNode.setNodeId(CATEGORY_ID);
+ final NodeRef parentNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
+ categoryNode.setParentId(parentNodeRef);
+
+ //when
+ objectUnderTest.deleteCategoryById(CATEGORY_ID, parametersMock);
+
+ then(authorityServiceMock).should().hasAdminAuthority();
+ then(authorityServiceMock).shouldHaveNoMoreInteractions();
+ then(nodesMock).should().validateNode(CATEGORY_ID);
+
+ then(nodesMock).should().isSubClass(categoryNodeRef, ContentModel.TYPE_CATEGORY, false);
+ then(nodesMock).shouldHaveNoMoreInteractions();
+
+ then(nodeServiceMock).should().getParentAssocs(categoryNodeRef);
+ then(nodeServiceMock).should().deleteNode(categoryNodeRef);
+ then(nodeServiceMock).shouldHaveNoMoreInteractions();
+ }
+
+ @Test
+ public void testDeleteCategoryById_asNonAdminUser()
+ {
+ given(authorityServiceMock.hasAdminAuthority()).willReturn(false);
+
+ //when
+ assertThrows(PermissionDeniedException.class, () -> objectUnderTest.deleteCategoryById(CATEGORY_ID, parametersMock));
+
+ then(authorityServiceMock).should().hasAdminAuthority();
+ then(authorityServiceMock).shouldHaveNoMoreInteractions();
+
+ then(nodesMock).shouldHaveNoInteractions();
+ then(nodeServiceMock).shouldHaveNoInteractions();
+ }
+
+ @Test
+ public void testDeleteCategoryById_nonCategoryId()
+ {
+ given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
+ final NodeRef categoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CATEGORY_ID);
+ given(nodesMock.validateNode(CATEGORY_ID)).willReturn(categoryNodeRef);
+ given(nodesMock.isSubClass(categoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(false);
+
+ //when
+ assertThrows(InvalidArgumentException.class, () -> objectUnderTest.deleteCategoryById(CATEGORY_ID, parametersMock));
+
+ then(authorityServiceMock).should().hasAdminAuthority();
+ then(authorityServiceMock).shouldHaveNoMoreInteractions();
+
+ then(nodesMock).should().validateNode(CATEGORY_ID);
+ then(nodesMock).should().isSubClass(categoryNodeRef, ContentModel.TYPE_CATEGORY, false);
+ then(nodesMock).shouldHaveNoMoreInteractions();
+ }
+
+ @Test
+ public void testDeleteCategoryById_rootCategory()
+ {
+ given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
+ final NodeRef categoryRootNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CAT_ROOT_NODE_ID);
+ given(nodesMock.validateNode(CAT_ROOT_NODE_ID)).willReturn(categoryRootNodeRef);
+ given(nodesMock.isSubClass(categoryRootNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
+ given(categoryChildAssociationRefMock.getQName()).willReturn(ContentModel.ASPECT_GEN_CLASSIFIABLE);
+ given(nodeServiceMock.getParentAssocs(categoryRootNodeRef)).willReturn(List.of(categoryChildAssociationRefMock));
+
+ //when
+ assertThrows(InvalidArgumentException.class, () -> objectUnderTest.deleteCategoryById(CAT_ROOT_NODE_ID, parametersMock));
+
+ then(authorityServiceMock).should().hasAdminAuthority();
+ then(authorityServiceMock).shouldHaveNoMoreInteractions();
+
+ then(nodesMock).should().validateNode(CAT_ROOT_NODE_ID);
+ then(nodesMock).should().isSubClass(categoryRootNodeRef, ContentModel.TYPE_CATEGORY, false);
+ then(nodesMock).shouldHaveNoMoreInteractions();
+
+ then(nodeServiceMock).should().getParentAssocs(categoryRootNodeRef);
+ then(nodeServiceMock).shouldHaveNoMoreInteractions();
+ }
+
+ @Test
+ public void testCreateCategoryUnderRoot()
+ {
final NodeRef parentCategoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PATH_ROOT);
given(categoryServiceMock.getRootCategoryNodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE))
.willReturn(Optional.of(parentCategoryNodeRef));
- given(nodesMock.isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
- final NodeRef categoryNodeRef = prepareCategoryNodeRef();
+ final NodeRef categoryNodeRef = createNodeRefWithId(CATEGORY_ID);
given(categoryServiceMock.createCategory(parentCategoryNodeRef, CATEGORY_NAME)).willReturn(categoryNodeRef);
given(nodesMock.getNode(CATEGORY_ID)).willReturn(prepareCategoryNode());
final ChildAssociationRef parentAssoc = new ChildAssociationRef(null, parentCategoryNodeRef, null, categoryNodeRef);
@@ -246,7 +352,6 @@ public class CategoriesImplTest
then(authorityServiceMock).should().hasAdminAuthority();
then(authorityServiceMock).shouldHaveNoMoreInteractions();
- then(nodesMock).should().isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false);
then(nodesMock).should().getNode(CATEGORY_ID);
then(nodesMock).shouldHaveNoMoreInteractions();
then(nodeServiceMock).should().getPrimaryParent(categoryNodeRef);
@@ -271,11 +376,9 @@ public class CategoriesImplTest
@Test
public void testCreateCategory()
{
- given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
final NodeRef parentCategoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
given(nodesMock.validateNode(PARENT_ID)).willReturn(parentCategoryNodeRef);
- given(nodesMock.isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
- final NodeRef categoryNodeRef = prepareCategoryNodeRef();
+ final NodeRef categoryNodeRef = createNodeRefWithId(CATEGORY_ID);
given(categoryServiceMock.createCategory(parentCategoryNodeRef, CATEGORY_NAME)).willReturn(categoryNodeRef);
given(nodesMock.getNode(CATEGORY_ID)).willReturn(prepareCategoryNode());
final ChildAssociationRef parentAssoc = new ChildAssociationRef(null, parentCategoryNodeRef, null, categoryNodeRef);
@@ -330,7 +433,6 @@ public class CategoriesImplTest
@Test
public void testCreateCategories_wrongParentNodeType()
{
- given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
final NodeRef parentCategoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
given(nodesMock.validateNode(PARENT_ID)).willReturn(parentCategoryNodeRef);
given(nodesMock.isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(false);
@@ -351,7 +453,6 @@ public class CategoriesImplTest
@Test
public void testCreateCategories_nonExistingParentNode()
{
- given(authorityServiceMock.hasAdminAuthority()).willReturn(true);
given(nodesMock.validateNode(PARENT_ID)).willThrow(EntityNotFoundException.class);
//when
@@ -366,19 +467,331 @@ public class CategoriesImplTest
then(categoryServiceMock).shouldHaveNoInteractions();
}
- private Node prepareCategoryNode()
+ @Test
+ public void testGetRootCategoryChildren()
+ {
+ final NodeRef parentCategoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PATH_ROOT);
+ given(categoryServiceMock.getRootCategoryNodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE))
+ .willReturn(Optional.of(parentCategoryNodeRef));
+ final int childrenCount = 3;
+ final List childAssociationRefMocks = prepareChildAssocMocks(childrenCount, parentCategoryNodeRef);
+ given(nodeServiceMock.getChildAssocs(parentCategoryNodeRef)).willReturn(childAssociationRefMocks);
+ childAssociationRefMocks.forEach(this::prepareCategoryNodeMocks);
+
+ //when
+ final CollectionWithPagingInfo categoryChildren = objectUnderTest.getCategoryChildren(PATH_ROOT, parametersMock);
+
+ then(categoryServiceMock).should().getRootCategoryNodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
+ then(categoryServiceMock).shouldHaveNoMoreInteractions();
+ then(nodeServiceMock).should().getChildAssocs(parentCategoryNodeRef);
+ childAssociationRefMocks.forEach(ca -> {
+ then(nodesMock).should().getNode(ca.getChildRef().getId());
+ then(nodeServiceMock).should()
+ .getChildAssocs(ca.getChildRef(), RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL, false);
+ then(nodeServiceMock).should().getPrimaryParent(ca.getChildRef());
+ });
+ then(nodeServiceMock).should(times(childrenCount)).getParentAssocs(parentCategoryNodeRef);
+
+ then(nodesMock).shouldHaveNoMoreInteractions();
+ then(nodeServiceMock).shouldHaveNoMoreInteractions();
+
+ then(authorityServiceMock).shouldHaveNoInteractions();
+
+ assertEquals(childAssociationRefMocks.size(), categoryChildren.getTotalItems().intValue());
+ final List categoryChildrenList = new ArrayList<>(categoryChildren.getCollection());
+ assertEquals(childAssociationRefMocks.size(), categoryChildrenList.size());
+ IntStream.range(0, childrenCount).forEach(i -> doCategoryAssertions(categoryChildrenList.get(i), i, PATH_ROOT));
+ }
+
+ @Test
+ public void testGetCategoryChildren()
+ {
+ final NodeRef parentCategoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
+ given(nodesMock.validateNode(PARENT_ID)).willReturn(parentCategoryNodeRef);
+ given(nodesMock.isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
+ final int childrenCount = 3;
+ final List childAssociationRefMocks = prepareChildAssocMocks(childrenCount, parentCategoryNodeRef);
+ given(nodeServiceMock.getChildAssocs(parentCategoryNodeRef)).willReturn(childAssociationRefMocks);
+ childAssociationRefMocks.forEach(this::prepareCategoryNodeMocks);
+
+ //when
+ final CollectionWithPagingInfo categoryChildren = objectUnderTest.getCategoryChildren(PARENT_ID, parametersMock);
+
+ then(nodesMock).should().validateNode(PARENT_ID);
+ then(nodesMock).should().isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false);
+ then(nodeServiceMock).should().getChildAssocs(parentCategoryNodeRef);
+ childAssociationRefMocks.forEach(ca -> {
+ then(nodesMock).should().getNode(ca.getChildRef().getId());
+ then(nodeServiceMock).should()
+ .getChildAssocs(ca.getChildRef(), RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL, false);
+ then(nodeServiceMock).should().getPrimaryParent(ca.getChildRef());
+ });
+ then(nodeServiceMock).should(times(childrenCount)).getParentAssocs(parentCategoryNodeRef);
+
+ then(nodesMock).shouldHaveNoMoreInteractions();
+ then(nodeServiceMock).shouldHaveNoMoreInteractions();
+
+ then(authorityServiceMock).shouldHaveNoInteractions();
+ then(categoryServiceMock).shouldHaveNoInteractions();
+
+ assertEquals(childAssociationRefMocks.size(), categoryChildren.getTotalItems().intValue());
+ final List categoryChildrenList = new ArrayList<>(categoryChildren.getCollection());
+ assertEquals(childAssociationRefMocks.size(), categoryChildrenList.size());
+ IntStream.range(0, childrenCount).forEach(i -> doCategoryAssertions(categoryChildrenList.get(i), i, PARENT_ID));
+ }
+
+ @Test
+ public void testGetCategoryChildren_noChildren()
+ {
+ final NodeRef parentCategoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
+ given(nodesMock.validateNode(PARENT_ID)).willReturn(parentCategoryNodeRef);
+ given(nodesMock.isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
+
+ given(nodeServiceMock.getChildAssocs(parentCategoryNodeRef)).willReturn(Collections.emptyList());
+
+
+ //when
+ final CollectionWithPagingInfo categoryChildren = objectUnderTest.getCategoryChildren(PARENT_ID, parametersMock);
+
+ then(nodesMock).should().validateNode(PARENT_ID);
+ then(nodesMock).should().isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false);
+ then(nodesMock).shouldHaveNoMoreInteractions();
+ then(nodeServiceMock).should().getChildAssocs(parentCategoryNodeRef);
+ then(nodeServiceMock).shouldHaveNoMoreInteractions();
+
+ then(authorityServiceMock).shouldHaveNoInteractions();
+ then(categoryServiceMock).shouldHaveNoInteractions();
+
+ assertEquals(0, categoryChildren.getTotalItems().intValue());
+ }
+
+ @Test
+ public void testGetCategoryChildren_wrongParentNodeType()
+ {
+ final NodeRef parentCategoryNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
+ given(nodesMock.validateNode(PARENT_ID)).willReturn(parentCategoryNodeRef);
+ given(nodesMock.isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(false);
+
+ //when
+ assertThrows(InvalidArgumentException.class, () -> objectUnderTest.getCategoryChildren(PARENT_ID, parametersMock));
+
+ then(nodesMock).should().validateNode(PARENT_ID);
+ then(nodesMock).should().isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false);
+ then(nodesMock).shouldHaveNoMoreInteractions();
+
+ then(nodeServiceMock).shouldHaveNoInteractions();
+ then(categoryServiceMock).shouldHaveNoInteractions();
+ then(authorityServiceMock).shouldHaveNoInteractions();
+ }
+
+ @Test
+ public void testGetCategoryChildren_nonExistingParentNode()
+ {
+ given(nodesMock.validateNode(PARENT_ID)).willThrow(EntityNotFoundException.class);
+
+ //when
+ assertThrows(EntityNotFoundException.class, () -> objectUnderTest.getCategoryChildren(PARENT_ID, parametersMock));
+
+
+ then(nodesMock).should().validateNode(PARENT_ID);
+ then(nodesMock).shouldHaveNoMoreInteractions();
+
+ then(nodeServiceMock).shouldHaveNoInteractions();
+ then(categoryServiceMock).shouldHaveNoInteractions();
+ then(authorityServiceMock).shouldHaveNoInteractions();
+ }
+
+ @Test
+ public void testUpdateCategoryById()
+ {
+ final String categoryNewName = "categoryNewName";
+ final Category fixedCategory = createCategoryOnlyWithName(categoryNewName);
+ final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
+ final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
+ final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
+ given(nodesMock.getNode(any())).willReturn(prepareCategoryNode(categoryNewName));
+ given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
+ given(nodeServiceMock.moveNode(any(), any(), any(), any())).willReturn(createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, createCmQNameOf(categoryNewName)));
+
+ // when
+ final Category actualCategory = objectUnderTest.updateCategoryById(CATEGORY_ID, fixedCategory);
+
+ then(authorityServiceMock).should().hasAdminAuthority();
+ then(authorityServiceMock).shouldHaveNoMoreInteractions();
+ then(nodesMock).should().validateNode(CATEGORY_ID);
+ then(nodesMock).should().isSubClass(CATEGORY_NODE_REF, ContentModel.TYPE_CATEGORY, false);
+ then(nodesMock).should().getNode(CATEGORY_ID);
+ then(nodesMock).shouldHaveNoMoreInteractions();
+ then(nodeServiceMock).should().getParentAssocs(CATEGORY_NODE_REF);
+ then(nodeServiceMock).should().getChildAssocs(CATEGORY_NODE_REF, RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL, false);
+ then(nodeServiceMock).should().setProperty(CATEGORY_NODE_REF, ContentModel.PROP_NAME, categoryNewName);
+ then(nodeServiceMock).should(times(2)).getPrimaryParent(CATEGORY_NODE_REF);
+ final QName expectedNewQName = createCmQNameOf(categoryNewName);
+ then(nodeServiceMock).should().moveNode(CATEGORY_NODE_REF, parentCategoryNodeRef, ContentModel.ASSOC_SUBCATEGORIES, expectedNewQName);
+ then(nodeServiceMock).should().getParentAssocs(parentCategoryNodeRef);
+ then(nodeServiceMock).shouldHaveNoMoreInteractions();
+ then(categoryServiceMock).shouldHaveNoInteractions();
+ final Category expectedCategory = createDefaultCategoryWithName(categoryNewName);
+ assertThat(actualCategory)
+ .isNotNull().usingRecursiveComparison()
+ .isEqualTo(expectedCategory);
+ }
+
+ @Test
+ public void testUpdateCategoryById_noPermission()
+ {
+ given(authorityServiceMock.hasAdminAuthority()).willReturn(false);
+
+ // when
+ assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(() -> objectUnderTest.updateCategoryById(CATEGORY_ID, CATEGORY));
+
+ then(nodesMock).shouldHaveNoInteractions();
+ then(nodeServiceMock).shouldHaveNoInteractions();
+ }
+
+ @Test
+ public void testUpdateCategoryById_categoryNodeNotFound()
+ {
+ given(nodesMock.validateNode(any(String.class))).willThrow(EntityNotFoundException.class);
+
+ // when
+ assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(() -> objectUnderTest.updateCategoryById(CATEGORY_ID, CATEGORY));
+
+ then(nodeServiceMock).shouldHaveNoInteractions();
+ }
+
+ @Test
+ public void testUpdateCategoryById_notACategory()
+ {
+ given(nodesMock.isSubClass(any(), any(), eq(false))).willReturn(false);
+
+ // when
+ assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(() -> objectUnderTest.updateCategoryById(CATEGORY_ID, CATEGORY))
+ .withMessageContaining(NOT_A_VALID_CATEGORY);
+
+ then(nodeServiceMock).shouldHaveNoInteractions();
+ }
+
+ @Test
+ public void testUpdateCategoryById_isRootCategory()
+ {
+ given(categoryServiceMock.getRootCategoryNodeRef(any())).willReturn(Optional.of(createNodeRefWithId(PATH_ROOT)));
+ given(nodeServiceMock.getParentAssocs(any())).willReturn(List.of(categoryChildAssociationRefMock));
+ given(categoryChildAssociationRefMock.getQName()).willReturn(ContentModel.ASPECT_GEN_CLASSIFIABLE);
+
+ // when
+ assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(() -> objectUnderTest.updateCategoryById(PATH_ROOT, CATEGORY))
+ .withMessageContaining(NOT_A_VALID_CATEGORY);
+
+ then(categoryServiceMock).should().getRootCategoryNodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
+ then(categoryServiceMock).shouldHaveNoMoreInteractions();
+ }
+
+ private List getInvalidCategoryNames()
+ {
+ final List invalidNames = new ArrayList<>();
+ invalidNames.add(null);
+ invalidNames.add("");
+ return invalidNames;
+ }
+
+ @Test
+ public void testUpdateCategoryById_emptyName()
+ {
+ for (String invalidName : getInvalidCategoryNames())
+ {
+ final Category categoryWithoutName = createCategoryOnlyWithName(invalidName);
+
+ // when
+ assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(() -> objectUnderTest.updateCategoryById(CATEGORY_ID, categoryWithoutName))
+ .withMessageContaining(NOT_NULL_OR_EMPTY);
+ }
+ }
+
+ @Test
+ public void testUpdateCategoryById_notMatchingIdField()
+ {
+ final String categoryNewName = "categoryNewName";
+ final Category categoryWithInvalidId = createCategoryOnlyWithName(categoryNewName);
+ categoryWithInvalidId.setId("different-" + CATEGORY_ID);
+ final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
+ final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
+ final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
+ given(nodesMock.getNode(any())).willReturn(prepareCategoryNode(categoryNewName));
+ given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
+ given(nodeServiceMock.moveNode(any(), any(), any(), any())).willReturn(createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, createCmQNameOf(categoryNewName)));
+
+ // when
+ final Category actualCategory = objectUnderTest.updateCategoryById(CATEGORY_ID, categoryWithInvalidId);
+
+ final Category expectedCategory = createDefaultCategoryWithName(categoryNewName);
+ assertThat(actualCategory)
+ .isNotNull().usingRecursiveComparison()
+ .isEqualTo(expectedCategory);
+ }
+
+ @Test
+ public void testUpdateCategoryById_notMatchingParentIdField()
+ {
+ final String categoryNewName = "categoryNewName";
+ final Category categoryWithInvalidParentId = createCategoryOnlyWithName(categoryNewName);
+ categoryWithInvalidParentId.setParentId("different-" + PARENT_ID);
+ final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
+ final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
+ final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
+ given(nodesMock.getNode(any())).willReturn(prepareCategoryNode(categoryNewName));
+ given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
+ given(nodeServiceMock.moveNode(any(), any(), any(), any())).willReturn(createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, createCmQNameOf(categoryNewName)));
+
+ // when
+ final Category actualCategory = objectUnderTest.updateCategoryById(CATEGORY_ID, categoryWithInvalidParentId);
+
+ final Category expectedCategory = createDefaultCategoryWithName(categoryNewName);
+ assertThat(actualCategory)
+ .isNotNull().usingRecursiveComparison()
+ .isEqualTo(expectedCategory);
+ }
+
+ @Test
+ public void testUpdateCategoryById_notMatchingHasChildrenField()
+ {
+ final String categoryNewName = "categoryNewName";
+ final Category categoryWithInvalidHasChildren = createCategoryOnlyWithName(categoryNewName);
+ categoryWithInvalidHasChildren.setHasChildren(true);
+ final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
+ final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
+ final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
+ given(nodesMock.getNode(any())).willReturn(prepareCategoryNode(categoryNewName));
+ given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
+ given(nodeServiceMock.moveNode(any(), any(), any(), any())).willReturn(createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, createCmQNameOf(categoryNewName)));
+
+ // when
+ final Category actualCategory = objectUnderTest.updateCategoryById(CATEGORY_ID, categoryWithInvalidHasChildren);
+
+ final Category expectedCategory = createDefaultCategoryWithName(categoryNewName);
+ assertThat(actualCategory)
+ .isNotNull().usingRecursiveComparison()
+ .isEqualTo(expectedCategory);
+ }
+
+ private Node prepareCategoryNode(final String name, final String id, final NodeRef parentNodeRef)
{
final Node categoryNode = new Node();
- categoryNode.setName(CATEGORY_NAME);
- categoryNode.setNodeId(CATEGORY_ID);
- final NodeRef parentNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
+ categoryNode.setName(name);
+ categoryNode.setNodeId(id);
categoryNode.setParentId(parentNodeRef);
return categoryNode;
}
- private NodeRef prepareCategoryNodeRef()
+ private Node prepareCategoryNode(final String name)
{
- return new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CATEGORY_ID);
+ final NodeRef parentNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_ID);
+ return prepareCategoryNode(name, CATEGORY_ID, parentNodeRef);
+ }
+
+ private Node prepareCategoryNode()
+ {
+ return prepareCategoryNode(CATEGORY_NAME);
}
private List prepareCategories()
@@ -387,4 +800,69 @@ public class CategoriesImplTest
.name(CATEGORY_NAME)
.create());
}
+
+ private List prepareChildAssocMocks(final int count, NodeRef parentCategoryNodeRef)
+ {
+ return IntStream.range(0, count).mapToObj(i -> {
+ ChildAssociationRef dummyChildAssocMock = mock(ChildAssociationRef.class);
+ given(dummyChildAssocMock.getTypeQName()).willReturn(ContentModel.ASSOC_SUBCATEGORIES);
+ given(dummyChildAssocMock.getChildRef())
+ .willReturn(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, CATEGORY_ID + "-" + i));
+ given(dummyChildAssocMock.getParentRef()).willReturn(parentCategoryNodeRef);
+ return dummyChildAssocMock;
+ }).collect(Collectors.toList());
+ }
+
+ private void prepareCategoryNodeMocks(ChildAssociationRef childAssociationRef)
+ {
+ final NodeRef childRef = childAssociationRef.getChildRef();
+ final String id = childRef.getId();
+ final String name = id.replace(CATEGORY_ID, CATEGORY_NAME);
+ final NodeRef parentRef = childAssociationRef.getParentRef();
+ given(nodesMock.getNode(id)).willReturn(prepareCategoryNode(name, id, parentRef));
+ final ChildAssociationRef parentAssoc = new ChildAssociationRef(null, parentRef, null, childRef);
+ given(nodeServiceMock.getPrimaryParent(childRef)).willReturn(parentAssoc);
+ given(nodeServiceMock.getParentAssocs(parentRef)).willReturn(List.of(parentAssoc));
+ }
+
+ private void doCategoryAssertions(final Category category, final int index, final String parentId)
+ {
+ final Category expectedCategory = Category.builder()
+ .id(CATEGORY_ID + "-" + index)
+ .name(CATEGORY_NAME + "-" + index)
+ .parentId(parentId)
+ .hasChildren(false)
+ .create();
+ assertEquals(expectedCategory, category);
+ }
+
+ private static NodeRef createNodeRefWithId(final String id)
+ {
+ return new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id);
+ }
+
+ private static Category createCategoryOnlyWithName(final String name)
+ {
+ return Category.builder().name(name).create();
+ }
+
+ private static Category createDefaultCategoryWithName(final String name)
+ {
+ return Category.builder()
+ .id(CATEGORY_ID)
+ .name(name)
+ .parentId(PARENT_ID)
+ .hasChildren(false)
+ .create();
+ }
+
+ private static QName createCmQNameOf(final String name)
+ {
+ return QName.createQName(ContentModel.TYPE_CATEGORY.getNamespaceURI(), QName.createValidLocalName(name));
+ }
+
+ private static ChildAssociationRef createAssociationOf(final NodeRef parentNode, final NodeRef childNode, final QName childNodeName)
+ {
+ return new ChildAssociationRef(ContentModel.ASSOC_SUBCATEGORIES, parentNode, childNodeName, childNode);
+ }
}
diff --git a/remote-api/src/test/resources/log4j.properties b/remote-api/src/test/resources/log4j.properties
deleted file mode 100644
index e8b1b86823..0000000000
--- a/remote-api/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,25 +0,0 @@
-log4j.rootLogger=error, Console
-
-log4j.appender.Console=org.apache.log4j.ConsoleAppender
-log4j.appender.Console.layout=org.apache.log4j.PatternLayout
-log4j.appender.Console.layout.ConversionPattern=%d{ISO8601} %x %-5p [%c{3}] [%t] %m%n
-
-log4j.logger.org.alfresco=WARN
-log4j.logger.org.alfresco.rest.api=DEBUG
-log4j.logger.org.eclipse.jetty.util.log=INFO
-
-# Renditions and Transforms
-log4j.logger.org.alfresco.repo.content.transform.TransformerDebug=debug
-
-log4j.logger.org.alfresco.repo.rendition2=debug
-#log4j.logger.org.alfresco.repo.rendition2.LocalTransformClient=debug
-#log4j.logger.org.alfresco.repo.rendition.RenditionServiceImpl=debug
-#log4j.logger.org.alfresco.enterprise.repo.rendition2.RemoteTransformClient=debug
-log4j.logger.org.alfresco.repo.thumbnail.ThumbnailServiceImplTest=DEBUG
-log4j.logger.org.alfresco.repo.rendition2.RenditionService2Impl=DEBUG
-
-#log4j.logger.org.alfresco.repo.content.transform.LocalTransformServiceRegistry=debug
-#log4j.logger.org.alfresco.enterprise.repo.rendition2.RemoteTransformServiceRegistry=debug
-#log4j.logger.org.alfresco.repo.rendition2.RenditionDefinitionRegistry2Impl=debug
-#log4j.logger.org.alfresco.repo.content.MimetypeMap=debug
-#log4j.logger.org.alfresco.repo.content.transform.LocalTransform=trace
diff --git a/remote-api/src/test/resources/log4j2.properties b/remote-api/src/test/resources/log4j2.properties
new file mode 100644
index 0000000000..fc0d8a01c2
--- /dev/null
+++ b/remote-api/src/test/resources/log4j2.properties
@@ -0,0 +1,56 @@
+# Set root logger level to error
+rootLogger.level=error
+rootLogger.appenderRef.stdout.ref=ConsoleAppender
+
+###### Console appender definition #######
+# All outputs currently set to be a ConsoleAppender.
+appender.console.type=Console
+appender.console.name=ConsoleAppender
+appender.console.layout.type=PatternLayout
+appender.console.layout.pattern=%d{ISO8601} %x %-5p [%c{3}] [%t] %replace{%m}{[\r\n]+}{}%n
+
+logger.alfresco.name=org.alfresco
+logger.alfresco.level=warn
+
+logger.alfresco-rest-api.name=org.alfresco.rest.api
+logger.alfresco-rest-api.level=debug
+
+logger.eclipse-jetty-util-log.name=org.eclipse.jetty.util.log
+logger.eclipse-jetty-util-log.level=info
+
+# Renditions and Transforms
+logger.alfresco-repo-content-transform-TransformerDebug.name=org.alfresco.repo.content.transform.TransformerDebug
+logger.alfresco-repo-content-transform-TransformerDebug.level=debug
+
+logger.alfresco-repo-rendition2.name=org.alfresco.repo.rendition2
+logger.alfresco-repo-rendition2.level=debug
+
+#logger.alfresco-repo-rendition2-LocalTransformClient.name=org.alfresco.repo.rendition2.LocalTransformClient
+#logger.alfresco-repo-rendition2-LocalTransformClient.level=debug
+
+#logger.alfresco-repo-rendition-RenditionServiceImpl.name=org.alfresco.repo.rendition.RenditionServiceImpl
+#logger.alfresco-repo-rendition-RenditionServiceImpl.level=debug
+
+#logger.alfresco-enterprise-repo-rendition2-RemoteTransformClient.name=org.alfresco.enterprise.repo.rendition2.RemoteTransformClient
+#logger.alfresco-enterprise-repo-rendition2-RemoteTransformClient.level=debug
+
+logger.alfresco-repo-thumbnail-ThumbnailServiceImplTest.name=org.alfresco.repo.thumbnail.ThumbnailServiceImplTest
+logger.alfresco-repo-thumbnail-ThumbnailServiceImplTest.level=debug
+
+logger.alfresco-repo-rendition2-RenditionService2Impl.name=org.alfresco.repo.rendition2.RenditionService2Impl
+logger.alfresco-repo-rendition2-RenditionService2Impl.level=debug
+
+#logger.alfresco-repo-content-transform-LocalTransformServiceRegistry.name=org.alfresco.repo.content.transform.LocalTransformServiceRegistry
+#logger.alfresco-repo-content-transform-LocalTransformServiceRegistry.level=debug
+
+#logger.alfresco-enterprise-repo-rendition2-RemoteTransformServiceRegistry.name=org.alfresco.enterprise.repo.rendition2.RemoteTransformServiceRegistry
+#logger.alfresco-enterprise-repo-rendition2-RemoteTransformServiceRegistry.level=debug
+
+#logger.alfresco-repo-rendition2-RenditionDefinitionRegistry2Impl.name=org.alfresco.repo.rendition2.RenditionDefinitionRegistry2Impl
+#logger.alfresco-repo-rendition2-RenditionDefinitionRegistry2Impl.level=debug
+
+#logger.alfresco-repo-content-MimetypeMap.name=org.alfresco.repo.content.MimetypeMap
+#logger.alfresco-repo-content-MimetypeMap.level=debug
+
+#logger.alfresco-repo-content-transform-LocalTransform.name=org.alfresco.repo.content.transform.LocalTransform
+#logger.alfresco-repo-content-transform-LocalTransform.level=trace
\ No newline at end of file
diff --git a/repository/pom.xml b/repository/pom.xml
index 61c8d1f079..3f1dddf34f 100644
--- a/repository/pom.xml
+++ b/repository/pom.xml
@@ -7,7 +7,7 @@
org.alfresco
alfresco-community-repo
- 20.38-SNAPSHOT
+ 20.50-SNAPSHOT
diff --git a/repository/src/main/java/org/alfresco/repo/domain/node/NodeDAO.java b/repository/src/main/java/org/alfresco/repo/domain/node/NodeDAO.java
index 787587761e..3c1bb2675d 100644
--- a/repository/src/main/java/org/alfresco/repo/domain/node/NodeDAO.java
+++ b/repository/src/main/java/org/alfresco/repo/domain/node/NodeDAO.java
@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
- * 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
@@ -894,6 +894,8 @@ public interface NodeDAO extends NodeBulkLoader
Serializable nodeValue,
ChildAssocRefQueryCallback resultsCallback);
+ public abstract List selectAssocsNotLinkedByTwoOtherAssocs(
+ Long parentNodeId);
/**
* Used by the re-encryptor to re-encrypt encryptable properties with a new encryption key.
*/
diff --git a/repository/src/main/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java b/repository/src/main/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java
index e1e9e546f9..a387385de0 100644
--- a/repository/src/main/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java
+++ b/repository/src/main/java/org/alfresco/repo/domain/node/ibatis/NodeDAOImpl.java
@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
- * 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
@@ -139,6 +139,8 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
private static final String SELECT_CHILD_ASSOC_OF_PARENT_BY_NAME = "alfresco.node.select_ChildAssocOfParentByName";
private static final String SELECT_CHILD_ASSOCS_OF_PARENT_WITHOUT_PARENT_ASSOCS_OF_TYPE =
"alfresco.node.select_ChildAssocsOfParentWithoutParentAssocsOfType";
+
+ private static final String SELECT_ASSOCS_NOT_LINKED_BY_TWO_OTHER_ASSOCS = "alfresco.node.select_AssocsNotLinkedByTwoOtherAssocs";
private static final String SELECT_CHILD_ASSOCS_OF_PARENT_WITHOUT_NODE_ASSOCS_OF_TYPE =
"alfresco.node.select_ChildAssocsOfParentWithoutNodeAssocsOfType";
private static final String SELECT_PARENT_ASSOCS_OF_CHILD = "alfresco.node.select_ParentAssocsOfChild";
@@ -1415,11 +1417,23 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
assoc.setOrdered(resultsCallback.orderResults());
ChildAssocResultHandler resultHandler = new ChildAssocResultHandler(resultsCallback);
-
+
template.select(SELECT_CHILD_ASSOCS_OF_PARENT_WITHOUT_PARENT_ASSOCS_OF_TYPE, assoc, resultHandler);
resultsCallback.done();
}
+ public List selectAssocsNotLinkedByTwoOtherAssocs(
+ Long parentNodeId)
+ {
+ ChildAssocEntity assoc = new ChildAssocEntity();
+ // Parent
+ NodeEntity parentNode = new NodeEntity();
+ parentNode.setId(parentNodeId);
+ assoc.setParentNode(parentNode);
+ // Type QName
+ return template.selectList(SELECT_ASSOCS_NOT_LINKED_BY_TWO_OTHER_ASSOCS, assoc);
+ }
+
@Override
public List selectChildAssocsWithoutNodeAssocsOfTypes(Long parentNodeId, Long minNodeId, Long maxNodeId, Set assocTypeQNames)
{
diff --git a/repository/src/main/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java b/repository/src/main/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java
index cd6e33f032..e0c19856b9 100644
--- a/repository/src/main/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java
+++ b/repository/src/main/java/org/alfresco/repo/node/db/DbNodeServiceImpl.java
@@ -2133,7 +2133,16 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl implements Extens
// done
return results;
}
-
+
+ @Extend(traitAPI=NodeServiceTrait.class,extensionAPI=NodeServiceExtension.class)
+ public List findAssocsNotLinkedByTwoOtherAssocs(NodeRef parent)
+ {
+ // Get the parent node
+ Pair nodePair = getNodePairNotNull(parent);
+ Long parentNodeId = nodePair.getFirst();
+
+ return nodeDAO.selectAssocsNotLinkedByTwoOtherAssocs(parentNodeId);
+ }
/**
* Specific properties not supported by {@link #getChildAssocsByPropertyValue(NodeRef, QName, Serializable)}
*/
diff --git a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java
index 8e930b3497..f72f4b5177 100644
--- a/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java
+++ b/repository/src/main/java/org/alfresco/repo/security/authority/AuthorityDAOImpl.java
@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
- * 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
@@ -48,7 +48,6 @@ import org.alfresco.query.CannedQueryFactory;
import org.alfresco.query.CannedQueryResults;
import org.alfresco.query.PagingRequest;
import org.alfresco.query.PagingResults;
-import org.alfresco.repo.cache.AsynchronouslyRefreshedCache;
import org.alfresco.util.cache.RefreshableCacheEvent;
import org.alfresco.util.cache.RefreshableCacheListener;
import org.alfresco.repo.cache.SimpleCache;
@@ -1566,11 +1565,11 @@ public class AuthorityDAOImpl implements AuthorityDAO, NodeServicePolicies.Befor
{
return Collections. emptySet();
}
- Collection childRefs = nodeService.getChildAssocsWithoutParentAssocsOfType(container, ContentModel.ASSOC_MEMBER);
+ List rootGroupsNames = nodeService.findAssocsNotLinkedByTwoOtherAssocs(container);
Set authorities = new TreeSet();
- for (ChildAssociationRef childRef : childRefs)
+ for (String rootGroupName : rootGroupsNames)
{
- addAuthorityNameIfMatches(authorities, childRef.getQName().getLocalName(), type);
+ addAuthorityNameIfMatches(authorities, rootGroupName, type);
}
return authorities;
}
diff --git a/repository/src/main/java/org/alfresco/repo/version/NodeServiceImpl.java b/repository/src/main/java/org/alfresco/repo/version/NodeServiceImpl.java
index aa3d2514f8..b8c40cc21b 100644
--- a/repository/src/main/java/org/alfresco/repo/version/NodeServiceImpl.java
+++ b/repository/src/main/java/org/alfresco/repo/version/NodeServiceImpl.java
@@ -1,28 +1,28 @@
-/*
- * #%L
- * Alfresco Repository
- * %%
- * Copyright (C) 2005 - 2016 Alfresco Software Limited
- * %%
- * This file is part of the Alfresco software.
- * If the software was purchased under a paid Alfresco license, the terms of
- * the paid license agreement will prevail. Otherwise, the software is
- * provided under the following open source license terms:
- *
- * Alfresco is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Alfresco is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Alfresco. If not, see .
- * #L%
- */
+/*
+ * #%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 .
+ * #L%
+ */
package org.alfresco.repo.version;
import java.io.Serializable;
@@ -656,13 +656,13 @@ public class NodeServiceImpl implements NodeService, VersionModel
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
}
- /**
- * Gets an association by ID.
- *
- * @param id
- * the association id
- * @return the association, or null
if it does not exist
- */
+ /**
+ * Gets an association by ID.
+ *
+ * @param id
+ * the association id
+ * @return the association, or null
if it does not exist
+ */
public AssociationRef getAssoc(Long id)
{
return null;
@@ -762,7 +762,15 @@ public class NodeServiceImpl implements NodeService, VersionModel
public Collection getChildAssocsWithoutParentAssocsOfType(NodeRef parent, QName assocTypeQName)
{
throw new UnsupportedOperationException(MSG_UNSUPPORTED);
- }
+ }
+
+ /**
+ * @throws UnsupportedOperationException always
+ */
+ public List findAssocsNotLinkedByTwoOtherAssocs(NodeRef parent)
+ {
+ throw new UnsupportedOperationException(MSG_UNSUPPORTED);
+ }
/**
* Gets, converts and adds the intrinsic properties to the current node's properties
diff --git a/repository/src/main/java/org/alfresco/repo/virtual/bundle/VirtualNodeServiceExtension.java b/repository/src/main/java/org/alfresco/repo/virtual/bundle/VirtualNodeServiceExtension.java
index 7c752236e8..1cf368d1f1 100644
--- a/repository/src/main/java/org/alfresco/repo/virtual/bundle/VirtualNodeServiceExtension.java
+++ b/repository/src/main/java/org/alfresco/repo/virtual/bundle/VirtualNodeServiceExtension.java
@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
- * 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
@@ -1467,6 +1467,11 @@ public class VirtualNodeServiceExtension extends VirtualSpringBeanExtension findAssocsNotLinkedByTwoOtherAssocs(NodeRef nodeRef){
+ return getTrait().findAssocsNotLinkedByTwoOtherAssocs(nodeRef);
+ }
+
@Override
public void removeAssociation(NodeRef sourceRef, NodeRef targetRef, QName assocTypeQName)
throws InvalidNodeRefException
diff --git a/repository/src/main/resources/alfresco/extension/custom-log4j.properties.sample b/repository/src/main/resources/alfresco/extension/custom-log4j.properties.sample
deleted file mode 100644
index 7746d6f5dd..0000000000
--- a/repository/src/main/resources/alfresco/extension/custom-log4j.properties.sample
+++ /dev/null
@@ -1,3 +0,0 @@
-log4j.logger.org.alfresco.repo.content.transform.TransformerDebug=debug
-log4j.logger.org.alfresco.util.exec.RuntimeExecBootstrapBean=debug
-log4j.logger.org.alfresco.util.exec.RuntimeExec=debug
\ No newline at end of file
diff --git a/repository/src/main/resources/alfresco/extension/custom-log4j2.properties.sample b/repository/src/main/resources/alfresco/extension/custom-log4j2.properties.sample
new file mode 100644
index 0000000000..5e36cae2cd
--- /dev/null
+++ b/repository/src/main/resources/alfresco/extension/custom-log4j2.properties.sample
@@ -0,0 +1,8 @@
+logger.alfresco-repo-content-transform-TransformerDebug.name=org.alfresco.repo.content.transform.TransformerDebug
+logger.alfresco-repo-content-transform-TransformerDebug.level=debug
+
+logger.alfresco-util-exec-RuntimeExecBootstrapBean.name=org.alfresco.util.exec.RuntimeExecBootstrapBean
+logger.alfresco-util-exec-RuntimeExecBootstrapBean.level=debug
+
+logger.alfresco-util-exec-RuntimeExec.name=org.alfresco.util.exec.RuntimeExec
+logger.alfresco-util-exec-RuntimeExec.level=debug
\ No newline at end of file
diff --git a/repository/src/main/resources/alfresco/ibatis/org.alfresco.repo.domain.dialect.Dialect/node-common-SqlMap.xml b/repository/src/main/resources/alfresco/ibatis/org.alfresco.repo.domain.dialect.Dialect/node-common-SqlMap.xml
index 2c1ba5bf32..f208f3d222 100644
--- a/repository/src/main/resources/alfresco/ibatis/org.alfresco.repo.domain.dialect.Dialect/node-common-SqlMap.xml
+++ b/repository/src/main/resources/alfresco/ibatis/org.alfresco.repo.domain.dialect.Dialect/node-common-SqlMap.xml
@@ -1147,6 +1147,20 @@
parentNode.id = #{parentNode.id} and
a.child_node_id IS NULL
+
+