diff --git a/amps/ags/pom.xml b/amps/ags/pom.xml index 5168c28c3f..b784b0d898 100644 --- a/amps/ags/pom.xml +++ b/amps/ags/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo-amps - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/amps/ags/rm-automation/pom.xml b/amps/ags/rm-automation/pom.xml index 323b1bee17..b4a9688e68 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 - 17.126-SNAPSHOT + 17.128-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 4f55228fae..24b2a195a3 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 - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/amps/ags/rm-community/pom.xml b/amps/ags/rm-community/pom.xml index 5ff4ae7aeb..02b483c857 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 - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/amps/ags/rm-community/rm-community-repo/pom.xml b/amps/ags/rm-community/rm-community-repo/pom.xml index 184413c5d6..1de1207000 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 - 17.126-SNAPSHOT + 17.128-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 a848222f51..76b0e16822 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 - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/amps/pom.xml b/amps/pom.xml index 87cc763432..d304fc383e 100644 --- a/amps/pom.xml +++ b/amps/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/amps/share-services/pom.xml b/amps/share-services/pom.xml index 6aeac13f69..12017f8b7d 100644 --- a/amps/share-services/pom.xml +++ b/amps/share-services/pom.xml @@ -8,7 +8,7 @@ org.alfresco alfresco-community-repo-amps - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/core/pom.xml b/core/pom.xml index 6b874d5d52..2c9490a4e4 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/data-model/pom.xml b/data-model/pom.xml index 213ca9f379..87f6a7b3d9 100644 --- a/data-model/pom.xml +++ b/data-model/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/mmt/pom.xml b/mmt/pom.xml index 47333dbf93..a3507d15ed 100644 --- a/mmt/pom.xml +++ b/mmt/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/packaging/distribution/pom.xml b/packaging/distribution/pom.xml index 07d492a8aa..3e489cf39c 100644 --- a/packaging/distribution/pom.xml +++ b/packaging/distribution/pom.xml @@ -9,6 +9,6 @@ org.alfresco alfresco-community-repo-packaging - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/packaging/docker-alfresco/pom.xml b/packaging/docker-alfresco/pom.xml index 420d34f757..689803136b 100644 --- a/packaging/docker-alfresco/pom.xml +++ b/packaging/docker-alfresco/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo-packaging - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/packaging/pom.xml b/packaging/pom.xml index 282659ec1c..1a0c640449 100644 --- a/packaging/pom.xml +++ b/packaging/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/packaging/tests/pom.xml b/packaging/tests/pom.xml index 80e229c2e6..5d618b7685 100644 --- a/packaging/tests/pom.xml +++ b/packaging/tests/pom.xml @@ -6,7 +6,7 @@ org.alfresco alfresco-community-repo-packaging - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/packaging/tests/tas-cmis/pom.xml b/packaging/tests/tas-cmis/pom.xml index 3ca199682a..a9bf9007ff 100644 --- a/packaging/tests/tas-cmis/pom.xml +++ b/packaging/tests/tas-cmis/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-community-repo-tests - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/packaging/tests/tas-email/pom.xml b/packaging/tests/tas-email/pom.xml index c7ec6b0514..2d352ffab6 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 - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/packaging/tests/tas-integration/pom.xml b/packaging/tests/tas-integration/pom.xml index 06776a24be..a977f5ea37 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 - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/packaging/tests/tas-restapi/pom.xml b/packaging/tests/tas-restapi/pom.xml index 7a176aa344..31e9ae8e1e 100644 --- a/packaging/tests/tas-restapi/pom.xml +++ b/packaging/tests/tas-restapi/pom.xml @@ -9,7 +9,7 @@ org.alfresco alfresco-community-repo-tests - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/GetRuleSetsTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/GetRuleSetsTests.java index 020951f8db..4feaa7586e 100644 --- a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/GetRuleSetsTests.java +++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/GetRuleSetsTests.java @@ -354,7 +354,7 @@ public class GetRuleSetsTests extends RestTest RestRuleSetLinkModel ruleSetLink = new RestRuleSetLinkModel(); ruleSetLink.setId(ruleFolder.getNodeRef()); coreAPIForUser().usingNode(publicFolder).createRuleLink(ruleSetLink); - coreAPIForUser().usingNode(privateFolder).createRuleLink(ruleSetLink); + coreAPIForAdmin().usingNode(privateFolder).createRuleLink(ruleSetLink); STEP("Get the rule set and linkedToBy field"); RestRuleSetModel ruleSet = coreAPIForUser().usingNode(ruleFolder) @@ -447,6 +447,62 @@ public class GetRuleSetsTests extends RestTest ruleSet.assertThat().field("isInherited").is(false); } + + /** Check that a user can see that a rule set is linked to even if they don't have permission to view the linking folder. */ + @Test + public void getRuleSetAndIsLinkedToWithoutPermission() + { + STEP("Create a site owned by admin and add user as a contributor"); + SiteModel siteModel = dataSite.usingAdmin().createPrivateRandomSite(); + dataUser.addUserToSite(user, siteModel, UserRole.SiteContributor); + + STEP("Create a folder with a rule set"); + FolderModel ruleFolder = dataContent.usingUser(user).usingSite(siteModel).createFolder(); + RestRuleModel ruleModel = createRuleModelWithDefaultValues(); + coreAPIForUser().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel); + + STEP("Create a private folder linking to the rule set"); + FolderModel linkingFolder = dataContent.usingAdmin().usingSite(siteModel).createFolder(); + RestRuleSetLinkModel linkModel = new RestRuleSetLinkModel(); + linkModel.setId(ruleFolder.getNodeRef()); + coreAPIForAdmin().usingNode(linkingFolder).createRuleLink(linkModel); + + STEP("Remove the user from the site"); + dataUser.removeUserFromSite(user, siteModel); + + STEP("Get the rule set and isLinkedTo field"); + RestRuleSetModel ruleSet = coreAPIForUser().usingNode(ruleFolder) + .include("isLinkedTo", "linkedToBy", "owningFolder") + .getDefaultRuleSet(); + + restClient.assertStatusCodeIs(OK); + ruleSet.assertThat().field("isLinkedTo").is(true) + .assertThat().field("linkedToBy").isEmpty(); + + } + + /** + * Check that if a rule set is owned and inherited but not linked to then isLinkedTo returns false. + */ + @Test + public void getRuleSetAndIsLinkedToCanBeFalse() + { + STEP("Create a site, a folder with a rule and a child folder that inherits it"); + SiteModel siteModel = dataSite.usingUser(user).createPublicRandomSite(); + FolderModel ruleFolder = dataContent.usingUser(user).usingSite(siteModel).createFolder(); + RestRuleModel ruleModel = createRuleModelWithDefaultValues(); + coreAPIForUser().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel); + dataContent.usingUser(user).usingResource(ruleFolder).createFolder(); + + STEP("Get the rule set and isLinkedTo field"); + RestRuleSetModel ruleSet = coreAPIForUser().usingNode(ruleFolder) + .include("isLinkedTo") + .getDefaultRuleSet(); + + restClient.assertStatusCodeIs(OK); + ruleSet.assertThat().field("isLinkedTo").is(false); + } + private RestCoreAPI coreAPIForUser() { return restClient.authenticateUser(user).withCoreAPI(); diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/UpdateRulesTests.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/UpdateRulesTests.java index be4ea977db..c841ca0966 100644 --- a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/UpdateRulesTests.java +++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/UpdateRulesTests.java @@ -27,17 +27,22 @@ package org.alfresco.rest.rules; import static org.alfresco.rest.rules.RulesTestsUtils.ID; import static org.alfresco.rest.rules.RulesTestsUtils.INBOUND; +import static org.alfresco.rest.rules.RulesTestsUtils.INVERTED; import static org.alfresco.rest.rules.RulesTestsUtils.IS_SHARED; import static org.alfresco.rest.rules.RulesTestsUtils.RULE_ASYNC_DEFAULT; import static org.alfresco.rest.rules.RulesTestsUtils.RULE_CASCADE_DEFAULT; import static org.alfresco.rest.rules.RulesTestsUtils.RULE_ENABLED_DEFAULT; +import static org.alfresco.rest.rules.RulesTestsUtils.createCompositeCondition; import static org.alfresco.rest.rules.RulesTestsUtils.createDefaultActionModel; import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel; import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModelWithModifiedValues; +import static org.alfresco.rest.rules.RulesTestsUtils.createSimpleCondition; +import static org.alfresco.rest.rules.RulesTestsUtils.createVariousConditions; import static org.alfresco.utility.constants.UserRole.SiteCollaborator; import static org.alfresco.utility.report.log.Step.STEP; import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR; import static org.springframework.http.HttpStatus.NOT_FOUND; import static org.springframework.http.HttpStatus.OK; @@ -47,6 +52,7 @@ import java.util.Map; import com.google.common.collect.ImmutableMap; import org.alfresco.rest.RestTest; import org.alfresco.rest.model.RestActionBodyExecTemplateModel; +import org.alfresco.rest.model.RestCompositeConditionDefinitionModel; import org.alfresco.rest.model.RestRuleModel; import org.alfresco.utility.model.FolderModel; import org.alfresco.utility.model.SiteModel; @@ -287,14 +293,173 @@ public class UpdateRulesTests extends RestTest final String updatedErrorScript = "updated-error-script"; rule.setErrorScript(updatedErrorScript); final RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() - .include(IS_SHARED) .updateRule(rule.getId(), rule); restClient.assertStatusCodeIs(OK); - updatedRule.assertThat().isEqualTo(rule, ID, IS_SHARED) + updatedRule.assertThat().isEqualTo(rule, ID) .assertThat().field(ID).isNotNull(); } + /** Check we can use the POST response and update rule by adding conditions. */ + @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY }) + public void updateRuleAddConditions() + { + final RestRuleModel rule = createAndSaveRule(createRuleModelWithModifiedValues()); + + STEP("Try to update the rule and add conditions."); + rule.setConditions(createVariousConditions()); + + final RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .updateRule(rule.getId(), rule); + + restClient.assertStatusCodeIs(OK); + updatedRule.assertThat().isEqualTo(rule, ID) + .assertThat().field(ID).isNotNull(); + } + + /** Check we can use the POST response and update a rule rule without any conditions by adding null conditions. */ + @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY }) + public void updateRuleAddNullConditions() + { + final RestRuleModel rule = createAndSaveRule(createRuleModelWithModifiedValues()); + + STEP("Try to update the rule and add null conditions."); + rule.setConditions(createCompositeCondition(null)); + + final RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .updateRule(rule.getId(), rule); + + restClient.assertStatusCodeIs(OK); + updatedRule.assertThat().isEqualTo(rule, ID) + .assertThat().field(ID).isNotNull(); + } + + /** Check we can use the POST response and update rule by modifying conditions. */ + @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY }) + public void updateRuleModifyConditions() + { + final RestRuleModel ruleModelWithInitialValues = createRuleModelWithModifiedValues(); + ruleModelWithInitialValues.setConditions(createVariousConditions()); + final RestRuleModel rule = createAndSaveRule(ruleModelWithInitialValues); + + STEP("Try to update the rule and modify conditions."); + final RestCompositeConditionDefinitionModel compositeCondition = createCompositeCondition( + List.of(createCompositeCondition(false, List.of(createSimpleCondition("tag", "equals", "sample_tag"))))); + rule.setConditions(compositeCondition); + + final RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .updateRule(rule.getId(), rule); + + restClient.assertStatusCodeIs(OK); + updatedRule.assertThat().isEqualTo(rule, ID) + .assertThat().field(ID).isNotNull(); + } + + /** Check we can use the POST response and update rule by removing all conditions. */ + @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY }) + public void updateRuleRemoveAllConditions() + { + final RestRuleModel ruleModelWithInitialValues = createRuleModelWithModifiedValues(); + ruleModelWithInitialValues.setConditions(createVariousConditions()); + final RestRuleModel rule = createAndSaveRule(ruleModelWithInitialValues); + + STEP("Try to update the rule and remove all conditions."); + rule.setConditions(null); + + final RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .updateRule(rule.getId(), rule); + + //set expected object + rule.setConditions(createCompositeCondition(null)); + restClient.assertStatusCodeIs(OK); + updatedRule.assertThat().isEqualTo(rule, ID) + .assertThat().field(ID).isNotNull(); + } + + /** Check we get a 400 error when using the POST response and update rule by adding condition with invalid category. */ + @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY }) + public void updateRuleWithInvalidCategoryInConditionAndFail() + { + final RestRuleModel ruleModelWithInitialValues = createRuleModelWithModifiedValues(); + ruleModelWithInitialValues.setConditions(createVariousConditions()); + final RestRuleModel rule = createAndSaveRule(ruleModelWithInitialValues); + + STEP("Try to update the rule with invalid condition."); + final RestCompositeConditionDefinitionModel conditions = createCompositeCondition( + List.of(createCompositeCondition(!INVERTED, List.of(createSimpleCondition("category", "equals", "fake-category-id"))))); + rule.setConditions(conditions); + + restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .include(IS_SHARED) + .updateRule(rule.getId(), rule); + + restClient.assertStatusCodeIs(BAD_REQUEST); + restClient.assertLastError().containsSummary("Category in condition is invalid"); + } + + /** Check we get a 500 error when using the POST response and update rule by adding condition without comparator. */ + @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY }) + public void updateRuleWithConditionWithoutComparatorAndFail() + { + final RestRuleModel ruleModelWithInitialValues = createRuleModelWithModifiedValues(); + ruleModelWithInitialValues.setConditions(createVariousConditions()); + final RestRuleModel rule = createAndSaveRule(ruleModelWithInitialValues); + + STEP("Try to update the rule with invalid condition."); + final RestCompositeConditionDefinitionModel conditions = createCompositeCondition( + List.of(createCompositeCondition(!INVERTED, List.of(createSimpleCondition("size", null, "65500"))))); + rule.setConditions(conditions); + + restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .include(IS_SHARED) + .updateRule(rule.getId(), rule); + + //TODO: in next iteration of mapper refactoring this error code will change to 400 + restClient.assertStatusCodeIs(INTERNAL_SERVER_ERROR); + } + + /** Check we get a 500 error when using the POST response and update rule by adding condition without field. */ + @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY }) + public void updateRuleWithConditionWithoutFieldAndFail() + { + final RestRuleModel ruleModelWithInitialValues = createRuleModelWithModifiedValues(); + ruleModelWithInitialValues.setConditions(createVariousConditions()); + final RestRuleModel rule = createAndSaveRule(ruleModelWithInitialValues); + + STEP("Try to update the rule with invalid condition."); + final RestCompositeConditionDefinitionModel conditions = createCompositeCondition( + List.of(createCompositeCondition(!INVERTED, List.of(createSimpleCondition(null, "greater_than", "65500"))))); + rule.setConditions(conditions); + + restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .include(IS_SHARED) + .updateRule(rule.getId(), rule); + + //TODO: in next iteration of mapper refactoring this error code will change to 400 + restClient.assertStatusCodeIs(INTERNAL_SERVER_ERROR); + } + + /** Check we get a 500 error when using the POST response and update rule by adding condition without parameter value. */ + @Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY }) + public void updateRuleWithConditionWithoutParamValueAndFail() + { + final RestRuleModel ruleModelWithInitialValues = createRuleModelWithModifiedValues(); + ruleModelWithInitialValues.setConditions(createVariousConditions()); + final RestRuleModel rule = createAndSaveRule(ruleModelWithInitialValues); + + STEP("Try to update the rule with invalid condition."); + final RestCompositeConditionDefinitionModel conditions = createCompositeCondition( + List.of(createCompositeCondition(!INVERTED, List.of(createSimpleCondition("size", "greater_than", null))))); + rule.setConditions(conditions); + + restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .include(IS_SHARED) + .updateRule(rule.getId(), rule); + + //TODO: in next iteration of mapper refactoring this error code will change to 400 + restClient.assertStatusCodeIs(INTERNAL_SERVER_ERROR); + } + private RestRuleModel createAndSaveRule(String name) { return createAndSaveRule(name, List.of(createDefaultActionModel())); diff --git a/packaging/tests/tas-webdav/pom.xml b/packaging/tests/tas-webdav/pom.xml index 7897fe32ad..c920edf41b 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 - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/packaging/war/pom.xml b/packaging/war/pom.xml index 15e1799a7e..48c2ed0ff2 100644 --- a/packaging/war/pom.xml +++ b/packaging/war/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo-packaging - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/pom.xml b/pom.xml index 298e2b8714..384ee23024 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 alfresco-community-repo - 17.126-SNAPSHOT + 17.128-SNAPSHOT pom Alfresco Community Repo Parent diff --git a/remote-api/pom.xml b/remote-api/pom.xml index 05647bd606..6d5bd36615 100644 --- a/remote-api/pom.xml +++ b/remote-api/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 17.126-SNAPSHOT + 17.128-SNAPSHOT diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleSetLoader.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleSetLoader.java index 6fd9e8f338..bda45c9c15 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleSetLoader.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleSetLoader.java @@ -30,7 +30,6 @@ import static org.alfresco.rest.api.model.rules.InclusionType.LINKED; import static org.alfresco.rest.api.model.rules.InclusionType.OWNED; import java.util.List; -import java.util.stream.Collectors; import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.rest.api.model.rules.RuleSet; @@ -49,6 +48,7 @@ public class RuleSetLoader protected static final String INHERITED_BY = "inheritedBy"; protected static final String LINKED_TO_BY = "linkedToBy"; protected static final String IS_INHERITED = "isInherited"; + protected static final String IS_LINKED_TO = "isLinkedTo"; private static final int MAX_INHERITED_BY_SIZE = 100; private NodeService nodeService; private RuleService ruleService; @@ -93,17 +93,16 @@ public class RuleSetLoader } if (includes.contains(LINKED_TO_BY)) { - List linkedToBy = nodeService.getParentAssocs(ruleSetNodeRef) - .stream() - .map(ChildAssociationRef::getParentRef) - .filter(folder -> !folder.equals(parentRef)) - .collect(Collectors.toList()); - ruleSet.setLinkedToBy(linkedToBy); + ruleSet.setLinkedToBy(loadLinkedToBy(ruleSetNodeRef)); } if (includes.contains(IS_INHERITED)) { ruleSet.setIsInherited(loadIsInherited(ruleSetNodeRef)); } + if (includes.contains(IS_LINKED_TO)) + { + ruleSet.setIsLinkedTo(loadIsLinkedTo(ruleSetNodeRef, parentRef)); + } } return ruleSet; } @@ -113,11 +112,33 @@ public class RuleSetLoader return ruleService.getFoldersInheritingRuleSet(ruleSetNodeRef, MAX_INHERITED_BY_SIZE); } + private List loadLinkedToBy(NodeRef ruleSetNodeRef) + { + return ruleService.getFoldersLinkingToRuleSet(ruleSetNodeRef); + } + private boolean loadIsInherited(NodeRef ruleSetNodeRef) { return AuthenticationUtil.runAsSystem(() -> !ruleService.getFoldersInheritingRuleSet(ruleSetNodeRef, 1).isEmpty()); } + /** + * Check if any parents of the rule set node are not the owning folder. + * + * @param ruleSetNodeRef The rule set node. + * @param parentRef The owning folder. + * @return True if another folder links to the rule set. + */ + private Boolean loadIsLinkedTo(NodeRef ruleSetNodeRef, NodeRef parentRef) + { + return AuthenticationUtil.runAsSystem(() -> + nodeService.getParentAssocs(ruleSetNodeRef) + .stream() + .map(ChildAssociationRef::getParentRef) + .anyMatch(folder -> !folder.equals(parentRef)) + ); + } + public void setNodeService(NodeService nodeService) { this.nodeService = nodeService; diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/RuleSet.java b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/RuleSet.java index 379228ce66..4a3713936d 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/RuleSet.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/RuleSet.java @@ -44,6 +44,7 @@ public class RuleSet private List inheritedBy; private List linkedToBy; private Boolean isInherited; + private Boolean isLinkedTo; public static RuleSet of(String id) { @@ -130,6 +131,26 @@ public class RuleSet return isInherited; } + /** + * Set a flag indicating that the rule set is linked to by a folder. + * + * @param isLinkedTo The flag. + */ + public void setIsLinkedTo(Boolean isLinkedTo) + { + this.isLinkedTo = isLinkedTo; + } + + /** + * Find if the rule set is linked to by a folder. + * + * @return The value of the flag. + */ + public Boolean getIsLinkedTo() + { + return isLinkedTo; + } + @Override public String toString() { @@ -141,6 +162,7 @@ public class RuleSet .add("inheritedBy='" + inheritedBy + "'") .add("linkedToBy='" + linkedToBy + "'") .add("isInherited='" + isInherited + "'") + .add("isLinkedTo='" + isLinkedTo + "'") .toString() + '}'; } @@ -158,13 +180,14 @@ public class RuleSet && inclusionType == ruleSet.inclusionType && Objects.equals(inheritedBy, ruleSet.inheritedBy) && Objects.equals(linkedToBy, ruleSet.linkedToBy) - && Objects.equals(isInherited, ruleSet.isInherited); + && Objects.equals(isInherited, ruleSet.isInherited) + && Objects.equals(isLinkedTo, ruleSet.isLinkedTo); } @Override public int hashCode() { - return Objects.hash(id, owningFolder, inclusionType, inheritedBy, linkedToBy, isInherited); + return Objects.hash(id, owningFolder, inclusionType, inheritedBy, linkedToBy, isInherited, isLinkedTo); } public static Builder builder() @@ -180,6 +203,7 @@ public class RuleSet private List inheritedBy; private List linkedToBy; private Boolean isInherited; + private Boolean isLinkedTo; public Builder id(String id) { @@ -217,6 +241,12 @@ public class RuleSet return this; } + public Builder isLinkedTo(Boolean isLinkedTo) + { + this.isLinkedTo = isLinkedTo; + return this; + } + public RuleSet create() { final RuleSet ruleSet = new RuleSet(); @@ -226,6 +256,7 @@ public class RuleSet ruleSet.setInheritedBy(inheritedBy); ruleSet.setLinkedToBy(linkedToBy); ruleSet.setIsInherited(isInherited); + ruleSet.setIsLinkedTo(isLinkedTo); return ruleSet; } } diff --git a/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RuleSetLoaderTest.java b/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RuleSetLoaderTest.java index afa3a710e1..bf4f001e99 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RuleSetLoaderTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RuleSetLoaderTest.java @@ -28,6 +28,7 @@ package org.alfresco.rest.api.impl.rules; import static org.alfresco.rest.api.impl.rules.RuleSetLoader.INCLUSION_TYPE; import static org.alfresco.rest.api.impl.rules.RuleSetLoader.INHERITED_BY; import static org.alfresco.rest.api.impl.rules.RuleSetLoader.IS_INHERITED; +import static org.alfresco.rest.api.impl.rules.RuleSetLoader.IS_LINKED_TO; import static org.alfresco.rest.api.impl.rules.RuleSetLoader.LINKED_TO_BY; import static org.alfresco.rest.api.impl.rules.RuleSetLoader.OWNING_FOLDER; import static org.alfresco.rest.api.model.rules.InclusionType.INHERITED; @@ -170,4 +171,14 @@ public class RuleSetLoaderTest extends TestCase RuleSet expected = RuleSet.builder().id(RULE_SET_ID).isInherited(true).create(); assertEquals(expected, actual); } + + @Test + public void testLoadRuleSet_isLinkedTo() + { + // Call the method under test. + RuleSet actual = ruleSetLoader.loadRuleSet(RULE_SET_NODE, FOLDER_NODE, List.of(IS_LINKED_TO)); + + RuleSet expected = RuleSet.builder().id(RULE_SET_ID).isLinkedTo(true).create(); + assertEquals(expected, actual); + } } diff --git a/repository/pom.xml b/repository/pom.xml index 681875e1e2..d585b088ae 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -7,7 +7,7 @@ org.alfresco alfresco-community-repo - 17.126-SNAPSHOT + 17.128-SNAPSHOT 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 db591fbbf7..b833e426c8 100644 --- a/repository/src/main/java/org/alfresco/repo/rule/RuleServiceImpl.java +++ b/repository/src/main/java/org/alfresco/repo/rule/RuleServiceImpl.java @@ -689,6 +689,20 @@ public class RuleServiceImpl return inheritors; } + /** {@inheritDoc} */ + @Override + @Experimental + public List getFoldersLinkingToRuleSet(NodeRef ruleSet) + { + NodeRef parentRef = nodeService.getPrimaryParent(ruleSet).getParentRef(); + return nodeService.getParentAssocs(ruleSet) + .stream() + .map(ChildAssociationRef::getParentRef) + .filter(folder -> !folder.equals(parentRef)) + .filter(folder -> permissionService.hasReadPermission(folder) == ALLOWED) + .collect(Collectors.toList()); + } + /** * Gets the inherited rules for a given node reference * 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 3b03eb329b..330e731f03 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 @@ -232,13 +232,23 @@ public interface RuleService * * @param ruleSet The rule set node. * @param maxFoldersToReturn A limit on the number of folders to return (since otherwise this could traverse a very large proportion of - * the repository. - * @return The list of the specified + * the repository). + * @return The list of the inheriting folders. */ @Auditable (parameters = { "ruleSet", "maxFoldersToReturn" }) @Experimental List getFoldersInheritingRuleSet(NodeRef ruleSet, int maxFoldersToReturn); + /** + * Get a list of folders linking to the specified rule set. + * + * @param ruleSet The rule set node. + * @return The list linking folders. + */ + @Auditable (parameters = { "ruleSet" }) + @Experimental + List getFoldersLinkingToRuleSet(NodeRef ruleSet); + /** * Get the rule given its node reference * diff --git a/repository/src/test/java/org/alfresco/repo/rule/RuleServiceImplUnitTest.java b/repository/src/test/java/org/alfresco/repo/rule/RuleServiceImplUnitTest.java index 8c085abaea..939743efc1 100644 --- a/repository/src/test/java/org/alfresco/repo/rule/RuleServiceImplUnitTest.java +++ b/repository/src/test/java/org/alfresco/repo/rule/RuleServiceImplUnitTest.java @@ -714,4 +714,46 @@ public class RuleServiceImplUnitTest assertEquals("Unexpected list of inheriting folders.", List.of(child), actual); } + + /** Check that a linked folder can be retrieved from a rule set node. */ + @Test + public void testGetFoldersLinkingToRuleSet() + { + NodeRef ruleSetNode = new NodeRef("rule://set/"); + NodeRef owningFolder = new NodeRef("owning://folder/"); + ChildAssociationRef owningAssocMock = mock(ChildAssociationRef.class); + given(owningAssocMock.getParentRef()).willReturn(owningFolder); + given(nodeService.getPrimaryParent(ruleSetNode)).willReturn(owningAssocMock); + // Simulate a folder linking to the rule set. + NodeRef linkingFolder = new NodeRef("linking://folder/"); + ChildAssociationRef linkingAssocMock = mock(ChildAssociationRef.class); + given(linkingAssocMock.getParentRef()).willReturn(linkingFolder); + given(nodeService.getParentAssocs(ruleSetNode)).willReturn(List.of(owningAssocMock, linkingAssocMock)); + + List linkingFolders = ruleService.getFoldersLinkingToRuleSet(ruleSetNode); + + assertEquals("Unexpected list of linking folders.", List.of(linkingFolder), linkingFolders); + } + + /** Check that permissions affect which linked folders are returned to the user. */ + @Test + public void testGetFoldersLinkingToRuleSet_respectsPermissions() + { + NodeRef ruleSetNode = new NodeRef("rule://set/"); + NodeRef owningFolder = new NodeRef("owning://folder/"); + ChildAssociationRef owningAssocMock = mock(ChildAssociationRef.class); + given(owningAssocMock.getParentRef()).willReturn(owningFolder); + given(nodeService.getPrimaryParent(ruleSetNode)).willReturn(owningAssocMock); + // Simulate a folder linking to the rule set. + NodeRef linkingFolder = new NodeRef("linking://folder/"); + ChildAssociationRef linkingAssocMock = mock(ChildAssociationRef.class); + given(linkingAssocMock.getParentRef()).willReturn(linkingFolder); + given(nodeService.getParentAssocs(ruleSetNode)).willReturn(List.of(owningAssocMock, linkingAssocMock)); + // The currect user does not have permission to view the folder. + given(permissionService.hasReadPermission(linkingFolder)).willReturn(DENIED); + + List linkingFolders = ruleService.getFoldersLinkingToRuleSet(ruleSetNode); + + assertEquals("Unexpected list of linking folders.", emptyList(), linkingFolders); + } }