diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/RuleSetLinksTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/RuleSetLinksTests.java index 844dfda7ee..9dd4d54788 100644 --- a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/RuleSetLinksTests.java +++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/RuleSetLinksTests.java @@ -46,6 +46,7 @@ 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.springframework.http.HttpStatus; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -172,6 +173,56 @@ public class RuleSetLinksTests extends RestTest .get(0).onModel().assertThat().isEqualTo(expectedRuleSet); } + /** + * Check we can link to a rule set when linking from a folder which has inherited rules. + */ + @Test(groups = {TestGroup.REST_API, TestGroup.RULES}) + public void linkFromFolderWithInheritedRules() + { + STEP("Create folders"); + final FolderModel parentFolder = dataContent.usingUser(user).usingSite(site).createFolder(); + final FolderModel childFolder = dataContent.usingUser(user).usingResource(parentFolder).createFolder(); + final FolderModel linkedToFolder = dataContent.usingUser(user).usingSite(site).createFolder(); + + STEP("Create rules in the parent folder and the linking folder"); + RestRuleModel parentRule = rulesUtils.createInheritableRuleModel(); + parentRule = restClient.authenticateUser(user).withPrivateAPI().usingNode(parentFolder).usingDefaultRuleSet().createSingleRule(parentRule); + restClient.assertStatusCodeIs(CREATED); + + RestRuleModel linkingFolderRule = rulesUtils.createRuleModelWithDefaultValues(); + restClient.authenticateUser(user).withPrivateAPI().usingNode(linkedToFolder).usingDefaultRuleSet().createSingleRule(linkingFolderRule); + restClient.assertStatusCodeIs(CREATED); + + STEP("Get the rule sets for the linking folder and find the rule set id"); + final RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withPrivateAPI().usingNode(linkedToFolder).getListOfRuleSets(); + restClient.assertStatusCodeIs(OK); + ruleSets.assertThat().entriesListCountIs(1); + final String ruleSetId = ruleSets.getEntries().get(0).onModel().getId(); + + STEP("Link the child folder to the target folder"); + final RestRuleSetLinkModel request = new RestRuleSetLinkModel(); + request.setId(linkedToFolder.getNodeRef()); + final RestRuleSetLinkModel ruleLink = restClient.authenticateUser(user).withPrivateAPI().usingNode(childFolder).createRuleLink(request); + restClient.assertStatusCodeIs(CREATED); + + STEP("Assert link result"); + final RestRuleSetLinkModel expectedLink = new RestRuleSetLinkModel(); + expectedLink.setId(ruleSetId); + ruleLink.assertThat().isEqualTo(expectedLink); + + STEP("Assert that the child folder has also inherited the parent rule"); + RestRuleSetModelsCollection ruleSetsInh = restClient.authenticateUser(user).withPrivateAPI().usingNode(childFolder).include("inclusionType").getListOfRuleSets(); + restClient.assertStatusCodeIs(OK); + String inheritedRuleSetId = ruleSetsInh.getEntries().stream() + .filter(ruleSet -> ruleSet.onModel().getInclusionType().equals("inherited")) + .findFirst().get().onModel().getId(); + + RestRuleModelsCollection inheritedRules = restClient.authenticateUser(user).withPrivateAPI().usingNode(childFolder).usingRuleSet(inheritedRuleSetId).getListOfRules(); + restClient.assertStatusCodeIs(OK); + inheritedRules.assertThat().entriesListContains("id", parentRule.getId()) + .and().entriesListCountIs(1); + } + /** * Check we get 404 when linking to a non-existing rule set/folder. */ diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleSetsImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleSetsImpl.java index 4c99e81225..dbe1f84e76 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleSetsImpl.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleSetsImpl.java @@ -170,7 +170,7 @@ public class RuleSetsImpl implements RuleSets } //The folder shouldn't have any pre-existing rules - if (ruleService.hasRules(folderNodeRef)) { + if (ruleService.hasNonInheritedRules(folderNodeRef)) { throw new InvalidArgumentException("Unable to link to a rule set because the folder has pre-existing rules or is already linked to a rule set."); } diff --git a/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RuleSetsImplTest.java b/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RuleSetsImplTest.java index f0402b304c..0362c11815 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RuleSetsImplTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RuleSetsImplTest.java @@ -257,7 +257,7 @@ public class RuleSetsImplTest extends TestCase String actual = ruleSets.linkToRuleSet(FOLDER_ID,LINK_TO_NODE_ID).getId(); then(ruleServiceMock).should().hasRules(LINK_TO_NODE); - then(ruleServiceMock).should().hasRules(FOLDER_NODE); + then(ruleServiceMock).should().hasNonInheritedRules(FOLDER_NODE); then(runtimeRuleServiceMock).should().getSavedRuleFolderAssoc(LINK_TO_NODE); then(runtimeRuleServiceMock).shouldHaveNoMoreInteractions(); then(nodeServiceMock).should().addChild(FOLDER_NODE, childNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER); @@ -284,7 +284,7 @@ public class RuleSetsImplTest extends TestCase then(nodeValidatorMock).should().validateRuleSetNode(LINK_TO_NODE_ID,false); then(nodeValidatorMock).shouldHaveNoMoreInteractions(); then(ruleServiceMock).should().hasRules(LINK_TO_NODE); - then(ruleServiceMock).should().hasRules(FOLDER_NODE); + then(ruleServiceMock).should().hasNonInheritedRules(FOLDER_NODE); then(runtimeRuleServiceMock).should().getSavedRuleFolderAssoc(LINK_TO_NODE); then(runtimeRuleServiceMock).shouldHaveNoMoreInteractions(); then(nodeServiceMock).should().addChild(FOLDER_NODE, childNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER); @@ -312,7 +312,8 @@ public class RuleSetsImplTest extends TestCase @Test public void testLinkToRuleSet_folderShouldntHavePreExistingRules() { - given(ruleServiceMock.hasRules(any(NodeRef.class))).willReturn(true, true); + given(ruleServiceMock.hasRules(any(NodeRef.class))).willReturn(true); + given(ruleServiceMock.hasNonInheritedRules(any(NodeRef.class))).willReturn(true); //when assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy( @@ -320,7 +321,7 @@ public class RuleSetsImplTest extends TestCase then(nodeServiceMock).shouldHaveNoMoreInteractions(); then(ruleServiceMock).should().hasRules(LINK_TO_NODE); - then(ruleServiceMock).should().hasRules(FOLDER_NODE); + then(ruleServiceMock).should().hasNonInheritedRules(FOLDER_NODE); then(ruleServiceMock).shouldHaveNoMoreInteractions(); then(runtimeRuleServiceMock).shouldHaveNoInteractions(); } diff --git a/repository/src/main/java/org/alfresco/repo/rule/RuleServiceImpl.java b/repository/src/main/java/org/alfresco/repo/rule/RuleServiceImpl.java index 5340251328..36759d020e 100644 --- a/repository/src/main/java/org/alfresco/repo/rule/RuleServiceImpl.java +++ b/repository/src/main/java/org/alfresco/repo/rule/RuleServiceImpl.java @@ -459,7 +459,13 @@ public class RuleServiceImpl public boolean hasRules(NodeRef nodeRef) { return getRules(nodeRef).size() != 0; - } + } + + @Override + public boolean hasNonInheritedRules(NodeRef nodeRef) + { + return getRules(nodeRef, false).size() != 0; + } @Override public List getRules(NodeRef nodeRef) diff --git a/repository/src/main/java/org/alfresco/service/cmr/rule/RuleService.java b/repository/src/main/java/org/alfresco/service/cmr/rule/RuleService.java index 8b84ebc53d..b56e4c29b3 100644 --- a/repository/src/main/java/org/alfresco/service/cmr/rule/RuleService.java +++ b/repository/src/main/java/org/alfresco/service/cmr/rule/RuleService.java @@ -165,6 +165,15 @@ public interface RuleService @Auditable(parameters = {"nodeRef"}) public boolean hasRules(NodeRef nodeRef); + /** + * Indicates whether the node in question has any non-inherited rules associated with it. + * + * @param nodeRef the node reference + * @return true if the node has rules associated, false otherwise + */ + @Auditable(parameters = {"nodeRef"}) + public boolean hasNonInheritedRules(NodeRef nodeRef); + /** * Get all the rules associated with an actionable node, including those * inherited from parents.