From 4692d471a3e94d2e150e03379433cff8da63a69f Mon Sep 17 00:00:00 2001 From: krdabrowski <98942253+krdabrowski@users.noreply.github.com> Date: Tue, 13 Sep 2022 12:32:29 +0200 Subject: [PATCH] ACS-3430: POST support for conditions (#1356) --- .../alfresco/rest/rules/CreateRulesTests.java | 63 +++++ .../alfresco/rest/rules/RulesTestsUtils.java | 58 +++- .../rest/api/impl/rules/NodeValidator.java | 6 + .../rest/api/impl/rules/RuleLoader.java | 9 +- .../rest/api/impl/rules/RulesImpl.java | 10 +- .../api/model/rules/CompositeCondition.java | 33 ++- .../alfresco/rest/api/model/rules/Rule.java | 11 +- .../rest/api/model/rules/SimpleCondition.java | 161 +++++++---- .../rest/api/nodes/NodeRulesRelation.java | 6 +- .../alfresco/public-rest-context.xml | 2 + .../rest/api/impl/rules/RulesImplTest.java | 19 +- .../model/rules/CompositeConditionTest.java | 15 +- .../rest/api/model/rules/RuleTest.java | 39 +-- .../api/model/rules/SimpleConditionTest.java | 260 +++++++++++++++--- .../repo/action/ParameterizedItemImpl.java | 85 +++--- .../service/cmr/rule/RuleService.java | 2 +- 16 files changed, 607 insertions(+), 172 deletions(-) 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 7594ee8ca3..7e9f980d6d 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 @@ -49,6 +49,7 @@ import java.util.stream.IntStream; 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.rest.model.RestRuleModelsCollection; import org.alfresco.utility.constants.UserRole; @@ -392,4 +393,66 @@ public class CreateRulesTests extends RestTest rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED) .assertThat().field("isShared").isNull(); } + + /** + * Check we can create a rule with multiple conditions + */ + @Test(groups = {TestGroup.REST_API, TestGroup.RULES}) + public void createRuleWithConditions() + { + RestRuleModel ruleModel = createRuleModelWithDefaultValues(); + ruleModel.setConditions(createVariousConditions()); + + RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .createSingleRule(ruleModel); + + RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues(); + expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions())); + expectedRuleModel.setConditions(createVariousConditions()); + expectedRuleModel.setTriggers(List.of("inbound")); + restClient.assertStatusCodeIs(CREATED); + rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED); + } + + /** + * Check we can create a rule with empty list as conditions + */ + @Test(groups = {TestGroup.REST_API, TestGroup.RULES}) + public void createRuleWithConditions_emptyConditionList() + { + RestRuleModel ruleModel = createRuleModelWithDefaultValues(); + ruleModel.setConditions(createCompositeCondition(null)); + + RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet() + .createSingleRule(ruleModel); + + RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues(); + expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions())); + expectedRuleModel.setConditions(createCompositeCondition(null)); + expectedRuleModel.setTriggers(List.of("inbound")); + restClient.assertStatusCodeIs(CREATED); + rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED); + } + + /** + * Check we can NOT create a rule when category ID in condition is invalid, HTTP status code 400 is expected + */ + @Test(groups = {TestGroup.REST_API, TestGroup.RULES}) + public void createRuleWithConditions_invalidCategory() + { + STEP("Try to create a rule with non existing category in conditions."); + String fakeCategoryId = "bdba5f9f-fake-id22-803b-349bcfd06fd1"; + RestCompositeConditionDefinitionModel conditions = createCompositeCondition(List.of( + createCompositeCondition(!INVERTED, List.of( + createSimpleCondition("category", "equals", fakeCategoryId) + )) + )); + RestRuleModel ruleModel = createRuleModelWithDefaultValues(); + ruleModel.setConditions(conditions); + + restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel); + + restClient.assertStatusCodeIs(BAD_REQUEST); + restClient.assertLastError().containsSummary("Category in condition is invalid"); + } } diff --git a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/RulesTestsUtils.java b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/RulesTestsUtils.java index 2c4fec1657..89e9775693 100644 --- a/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/RulesTestsUtils.java +++ b/packaging/tests/tas-restapi/src/test/java/org/alfresco/rest/rules/RulesTestsUtils.java @@ -33,6 +33,7 @@ import java.util.Map; import org.alfresco.rest.model.RestActionBodyExecTemplateModel; import org.alfresco.rest.model.RestCompositeConditionDefinitionModel; import org.alfresco.rest.model.RestRuleModel; +import org.alfresco.rest.model.RestSimpleConditionDefinitionModel; public class RulesTestsUtils { @@ -44,6 +45,8 @@ public class RulesTestsUtils static final boolean RULE_SHARED_DEFAULT = false; static final String RULE_ERROR_SCRIPT_DEFAULT = "error-script"; static final List ruleTriggersDefault = List.of("inbound", "update", "outbound"); + static final boolean INVERTED = true; + static final String AND = "and"; /** * Create a rule model filled with default values. @@ -123,8 +126,59 @@ public class RulesTestsUtils public static RestCompositeConditionDefinitionModel createEmptyConditionModel() { RestCompositeConditionDefinitionModel conditions = new RestCompositeConditionDefinitionModel(); - conditions.setInverted(false); - conditions.setBooleanMode("and"); + conditions.setInverted(!INVERTED); + conditions.setBooleanMode(AND); return conditions; } + + public static RestCompositeConditionDefinitionModel createVariousConditions() + { + return createCompositeCondition(List.of( + createCompositeCondition(!INVERTED, List.of( + createSimpleCondition("cm:created", "less_than", "2022-09-01T12:59:00.000+02:00"), + createSimpleCondition("cm:creator", "ends", "ski"), + createSimpleCondition("size", "greater_than", "90000000"), + createSimpleCondition("mimetype", "equals", "video/3gpp"), + createSimpleCondition("encoding", "equals", "utf-8"), + createSimpleCondition("type", "equals", "cm:folder"), + createSimpleCondition("tag", "equals", "uat") + )), + createCompositeCondition(INVERTED, List.of( + createSimpleCondition("aspect", "equals", "audio:audio"), + createSimpleCondition("cm:modelVersion", "begins", "1.") + )) + )); + } + + public static RestSimpleConditionDefinitionModel createSimpleCondition(String field, String comparator, String parameter) + { + RestSimpleConditionDefinitionModel simpleCondition = new RestSimpleConditionDefinitionModel(); + simpleCondition.setField(field); + simpleCondition.setComparator(comparator); + simpleCondition.setParameter(parameter); + return simpleCondition; + } + + public static RestCompositeConditionDefinitionModel createCompositeCondition(List compositeConditions) + { + return createCompositeCondition(AND, !INVERTED, compositeConditions, null); + } + + public static RestCompositeConditionDefinitionModel createCompositeCondition(boolean inverted, + List simpleConditions) + { + return createCompositeCondition(AND, inverted, null, simpleConditions); + } + + private static RestCompositeConditionDefinitionModel createCompositeCondition(String booleanMode, boolean inverted, + List compositeConditions, List simpleConditions) + { + RestCompositeConditionDefinitionModel compositeCondition = new RestCompositeConditionDefinitionModel(); + compositeCondition.setBooleanMode(booleanMode); + compositeCondition.setInverted(inverted); + compositeCondition.setCompositeConditions(compositeConditions); + compositeCondition.setSimpleConditions(simpleConditions); + + return compositeCondition; + } } diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/NodeValidator.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/NodeValidator.java index c012f231ee..7b8cc25c73 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/NodeValidator.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/NodeValidator.java @@ -180,6 +180,12 @@ public class NodeValidator } } + /** + * Verifies if rule set node or folder node's default rule set is shared + * @param ruleSetNodeRef + * @param folderNodeRef + * @return + */ public boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef) { if (ruleSetNodeRef == null && folderNodeRef != null) diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleLoader.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleLoader.java index 38a4e557ba..80b416ab5f 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleLoader.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RuleLoader.java @@ -31,6 +31,7 @@ import org.alfresco.rest.api.model.rules.Rule; import org.alfresco.service.Experimental; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.rule.RuleService; +import org.alfresco.service.namespace.NamespaceService; /** Responsible for creating {@link Rule} objects. */ @Experimental @@ -39,10 +40,11 @@ public class RuleLoader public static final String IS_SHARED = "isShared"; private RuleService ruleService; private NodeValidator nodeValidator; + private NamespaceService namespaceService; public Rule loadRule(org.alfresco.service.cmr.rule.Rule ruleModel, List includes) { - Rule rule = Rule.from(ruleModel); + Rule rule = Rule.from(ruleModel, namespaceService); if (includes != null && includes.contains(IS_SHARED)) { NodeRef ruleSet = ruleService.getRuleSetNode(ruleModel.getNodeRef()); @@ -61,4 +63,9 @@ public class RuleLoader { this.nodeValidator = nodeValidator; } + + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } } diff --git a/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RulesImpl.java b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RulesImpl.java index 81efa535e8..2b791981fc 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RulesImpl.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/impl/rules/RulesImpl.java @@ -41,6 +41,7 @@ import org.alfresco.service.Experimental; import org.alfresco.service.cmr.action.CompositeAction; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.rule.RuleService; +import org.alfresco.service.namespace.NamespaceService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -55,6 +56,7 @@ public class RulesImpl implements Rules private RuleLoader ruleLoader; private ActionParameterConverter actionParameterConverter; private ActionPermissionValidator actionPermissionValidator; + private NamespaceService namespaceService; @Override public CollectionWithPagingInfo getRules(final String folderNodeId, @@ -124,7 +126,7 @@ public class RulesImpl implements Rules private org.alfresco.service.cmr.rule.Rule mapToServiceModelAndValidateActions(Rule rule) { - final org.alfresco.service.cmr.rule.Rule serviceModelRule = rule.toServiceModel(nodes); + final org.alfresco.service.cmr.rule.Rule serviceModelRule = rule.toServiceModel(nodes, namespaceService); final CompositeAction compositeAction = (CompositeAction) serviceModelRule.getAction(); compositeAction.getActions().forEach(action -> action.setParameterValues( actionParameterConverter.getConvertedParams(action.getParameterValues(), action.getActionDefinitionName()))); @@ -134,7 +136,6 @@ public class RulesImpl implements Rules private Rule loadRuleAndConvertActionParams(org.alfresco.service.cmr.rule.Rule ruleModel, List includes) { - final Rule rule = ruleLoader.loadRule(ruleModel, includes); rule.getActions() .forEach(a -> a.setParams(a.getParams().entrySet() @@ -175,4 +176,9 @@ public class RulesImpl implements Rules { this.actionPermissionValidator = actionPermissionValidator; } + + public void setNamespaceService(NamespaceService namespaceService) + { + this.namespaceService = namespaceService; + } } diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/CompositeCondition.java b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/CompositeCondition.java index f33b862aa7..fc0c64dbf9 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/CompositeCondition.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/CompositeCondition.java @@ -32,8 +32,10 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; +import org.alfresco.rest.api.Nodes; import org.alfresco.service.Experimental; import org.alfresco.service.cmr.action.ActionCondition; +import org.alfresco.service.namespace.NamespaceService; import org.apache.commons.collections.CollectionUtils; @Experimental @@ -50,7 +52,7 @@ public class CompositeCondition * @param actionConditions - list of {@link ActionCondition} service POJOs * @return {@link CompositeCondition} REST model */ - public static CompositeCondition from(final List actionConditions) + public static CompositeCondition from(final List actionConditions, final NamespaceService namespaceService) { if (actionConditions == null) { @@ -62,7 +64,7 @@ public class CompositeCondition // group action conditions by inversion flag actionConditions.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(ActionCondition::getInvertCondition)) // map action condition sub lists - .forEach((inverted, actionConditionsPart) -> Optional.ofNullable(CompositeCondition.ofActionConditions(actionConditionsPart, inverted, ConditionOperator.AND)) + .forEach((inverted, actionConditionsPart) -> Optional.ofNullable(CompositeCondition.ofActionConditions(actionConditionsPart, namespaceService, inverted, ConditionOperator.AND)) // if composite condition present add to final list .ifPresent(compositeCondition -> conditions.compositeConditions.add(compositeCondition))); @@ -73,14 +75,14 @@ public class CompositeCondition return conditions; } - private static CompositeCondition ofActionConditions(final List actionConditions, final boolean inverted, final ConditionOperator conditionOperator) + private static CompositeCondition ofActionConditions(final List actionConditions, final NamespaceService namespaceService, final boolean inverted, final ConditionOperator conditionOperator) { if (actionConditions == null) { return null; } - return ofSimpleConditions(SimpleCondition.listOf(actionConditions), inverted, conditionOperator); + return ofSimpleConditions(SimpleCondition.listOf(actionConditions, namespaceService), inverted, conditionOperator); } /** @@ -112,6 +114,21 @@ public class CompositeCondition .create(); } + public List toServiceModels(final Nodes nodes, final NamespaceService namespaceService) + { + final List actionConditions = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(simpleConditions)) + { + simpleConditions.forEach(simpleCondition -> actionConditions.add(simpleCondition.toServiceModel(inverted, nodes, namespaceService))); + } + if (CollectionUtils.isNotEmpty(compositeConditions)) + { + compositeConditions.forEach(compositeCondition -> actionConditions.addAll(compositeCondition.toServiceModels(nodes, namespaceService))); + } + + return actionConditions; + } + public boolean isInverted() { return inverted; @@ -131,6 +148,14 @@ public class CompositeCondition return booleanMode.name().toLowerCase(); } + public void setBooleanMode(String booleanMode) + { + if (booleanMode != null) + { + this.booleanMode = ConditionOperator.valueOf(booleanMode.toUpperCase()); + } + } + public void setBooleanMode(ConditionOperator booleanMode) { this.booleanMode = booleanMode; diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/Rule.java b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/Rule.java index 5e55c6d9b3..4cad8386cc 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/Rule.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/Rule.java @@ -37,6 +37,7 @@ import org.alfresco.rest.framework.resource.UniqueId; import org.alfresco.service.Experimental; import org.alfresco.service.cmr.action.CompositeAction; import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.NamespaceService; import org.alfresco.util.GUID; @Experimental @@ -60,7 +61,7 @@ public class Rule * @param ruleModel - {@link org.alfresco.service.cmr.rule.Rule} service POJO * @return {@link Rule} REST model */ - public static Rule from(final org.alfresco.service.cmr.rule.Rule ruleModel) + public static Rule from(final org.alfresco.service.cmr.rule.Rule ruleModel, final NamespaceService namespaceService) { if (ruleModel == null) { @@ -83,7 +84,7 @@ public class Rule } if (ruleModel.getAction() != null) { - builder.conditions(CompositeCondition.from(ruleModel.getAction().getActionConditions())); + builder.conditions(CompositeCondition.from(ruleModel.getAction().getActionConditions(), namespaceService)); if (ruleModel.getAction().getCompensatingAction() != null && ruleModel.getAction().getCompensatingAction().getParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF) != null) { builder.errorScript(ruleModel.getAction().getCompensatingAction().getParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF).toString()); @@ -103,7 +104,7 @@ public class Rule * @param nodes The nodes API. * @return The rule service POJO. */ - public org.alfresco.service.cmr.rule.Rule toServiceModel(Nodes nodes) + public org.alfresco.service.cmr.rule.Rule toServiceModel(final Nodes nodes, final NamespaceService namespaceService) { final org.alfresco.service.cmr.rule.Rule ruleModel = new org.alfresco.service.cmr.rule.Rule(); final NodeRef nodeRef = (id != null) ? nodes.validateOrLookupNode(id, null) : null; @@ -124,6 +125,10 @@ public class Rule compensatingAction.setParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF, errorScript); ruleModel.getAction().setCompensatingAction(compensatingAction); } + if (conditions != null) + { + conditions.toServiceModels(nodes, namespaceService).forEach(condition -> ruleModel.getAction().addActionCondition(condition)); + } return ruleModel; } diff --git a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/SimpleCondition.java b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/SimpleCondition.java index cdd26ddc2b..54e0b566a0 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/model/rules/SimpleCondition.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/model/rules/SimpleCondition.java @@ -26,27 +26,41 @@ package org.alfresco.rest.api.model.rules; +import java.io.Serializable; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.UUID; import java.util.stream.Collectors; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.action.ActionConditionImpl; import org.alfresco.repo.action.evaluator.CompareMimeTypeEvaluator; import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator; import org.alfresco.repo.action.evaluator.HasAspectEvaluator; -import org.alfresco.repo.action.evaluator.HasChildEvaluator; import org.alfresco.repo.action.evaluator.HasTagEvaluator; -import org.alfresco.repo.action.evaluator.HasVersionHistoryEvaluator; import org.alfresco.repo.action.evaluator.InCategoryEvaluator; import org.alfresco.repo.action.evaluator.IsSubTypeEvaluator; import org.alfresco.repo.action.evaluator.NoConditionEvaluator; +import org.alfresco.repo.action.evaluator.compare.ComparePropertyValueOperation; +import org.alfresco.repo.action.evaluator.compare.ContentPropertyName; +import org.alfresco.rest.api.Nodes; +import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; +import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.service.Experimental; import org.alfresco.service.cmr.action.ActionCondition; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; import org.apache.commons.collections.CollectionUtils; @Experimental public class SimpleCondition { - private static final String COMPARATOR_EQUALS = "equals"; + private static final String CATEGORY_INVALID_MSG = "Category in condition is invalid"; + public static final String PARAM_CATEGORY = "category"; + public static final String PARAM_MIMETYPE = "mimetype"; private String field; private String comparator; @@ -58,7 +72,7 @@ public class SimpleCondition * @param actionConditions - list of {@link ActionCondition} service POJOs * @return list of {@link SimpleCondition} REST models */ - public static List listOf(final List actionConditions) + public static List listOf(final List actionConditions, final NamespaceService namespaceService) { if (CollectionUtils.isEmpty(actionConditions)) { @@ -66,7 +80,7 @@ public class SimpleCondition } return actionConditions.stream() - .map(SimpleCondition::from) + .map(actionCondition -> from(actionCondition, namespaceService)) .filter(Objects::nonNull) .collect(Collectors.toList()); } @@ -77,7 +91,7 @@ public class SimpleCondition * @param actionCondition - {@link ActionCondition} service POJO * @return {@link SimpleCondition} REST model */ - public static SimpleCondition from(final ActionCondition actionCondition) + public static SimpleCondition from(final ActionCondition actionCondition, final NamespaceService namespaceService) { if (actionCondition == null || actionCondition.getActionConditionDefinitionName() == null || actionCondition.getParameterValues() == null) { @@ -87,27 +101,86 @@ public class SimpleCondition switch (actionCondition.getActionConditionDefinitionName()) { case ComparePropertyValueEvaluator.NAME: - return createComparePropertyValueCondition(actionCondition); + return createComparePropertyValueCondition(actionCondition, namespaceService); case CompareMimeTypeEvaluator.NAME: return createCompareMimeTypeCondition(actionCondition); case HasAspectEvaluator.NAME: - return createHasAspectCondition(actionCondition); - case HasChildEvaluator.NAME: - return createHasChildCondition(actionCondition); + return createHasAspectCondition(actionCondition, namespaceService); case HasTagEvaluator.NAME: return createHasTagCondition(actionCondition); - case HasVersionHistoryEvaluator.NAME: - return createHasVersionHistoryCondition(actionCondition); case InCategoryEvaluator.NAME: return createInCategoryCondition(actionCondition); case IsSubTypeEvaluator.NAME: - return createIsSubtypeCondition(actionCondition); + return createIsSubtypeCondition(actionCondition, namespaceService); case NoConditionEvaluator.NAME: default: return null; } } + public ActionCondition toServiceModel(final boolean inverted, final Nodes nodes, final NamespaceService namespaceService) + { + if (field == null) + { + return null; + } + + Map parameterValues = new HashMap<>(); + String conditionDefinitionId; + + switch (field) + { + case HasAspectEvaluator.PARAM_ASPECT: + conditionDefinitionId = HasAspectEvaluator.NAME; + parameterValues.put(HasAspectEvaluator.PARAM_ASPECT, QName.createQName(parameter, namespaceService)); + break; + case HasTagEvaluator.PARAM_TAG: + conditionDefinitionId = HasTagEvaluator.NAME; + parameterValues.put(HasTagEvaluator.PARAM_TAG, parameter); + break; + case PARAM_CATEGORY: + conditionDefinitionId = InCategoryEvaluator.NAME; + parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_ASPECT, ContentModel.ASPECT_GEN_CLASSIFIABLE); + try + { + parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_VALUE, nodes.validateOrLookupNode(parameter, null)); + } catch (EntityNotFoundException e) { + throw new InvalidArgumentException(CATEGORY_INVALID_MSG); + } + break; + case IsSubTypeEvaluator.PARAM_TYPE: + conditionDefinitionId = IsSubTypeEvaluator.NAME; + parameterValues.put(IsSubTypeEvaluator.PARAM_TYPE, QName.createQName(parameter, namespaceService)); + break; + case PARAM_MIMETYPE: + conditionDefinitionId = CompareMimeTypeEvaluator.NAME; + parameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.TYPE_CONTENT); + parameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, parameter); + break; + default: + conditionDefinitionId = ComparePropertyValueEvaluator.NAME; + try + { + // if size or encoding create content property evaluator + ContentPropertyName.valueOf(field.toUpperCase()); + parameterValues.put(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY, field.toUpperCase()); + parameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.TYPE_CONTENT); + } + catch (IllegalArgumentException ignore) + { + // else create common property evaluator + parameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, QName.createQName(field, namespaceService)); + } + parameterValues.put(ComparePropertyValueEvaluator.PARAM_OPERATION, comparator.toUpperCase()); + parameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, parameter); + break; + } + + final ActionCondition actionCondition = new ActionConditionImpl(UUID.randomUUID().toString(), conditionDefinitionId, parameterValues); + actionCondition.setInvertCondition(inverted); + return actionCondition; + } + public String getField() { return field; @@ -161,13 +234,14 @@ public class SimpleCondition return Objects.hash(field, comparator, parameter); } - private static SimpleCondition createComparePropertyValueCondition(final ActionCondition actionCondition) { + private static SimpleCondition createComparePropertyValueCondition(final ActionCondition actionCondition, final NamespaceService namespaceService) + { final SimpleCondition.Builder builder = builder(); if (actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY) != null) { builder.field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY).toString().toLowerCase()); } else { - builder.field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY).toString().toLowerCase()); + builder.field(((QName) actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY)).toPrefixString(namespaceService)); } return builder .comparator(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_OPERATION).toString().toLowerCase()) @@ -175,65 +249,48 @@ public class SimpleCondition .create(); } - private static SimpleCondition createCompareMimeTypeCondition(final ActionCondition actionCondition) { + private static SimpleCondition createCompareMimeTypeCondition(final ActionCondition actionCondition) + { return builder() - .field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY).toString().toLowerCase()) - .comparator(COMPARATOR_EQUALS) + .field(PARAM_MIMETYPE) + .comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase()) .parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString()) .create(); } - private static SimpleCondition createHasAspectCondition(final ActionCondition actionCondition) { + private static SimpleCondition createHasAspectCondition(final ActionCondition actionCondition, final NamespaceService namespaceService) + { return builder() .field(HasAspectEvaluator.PARAM_ASPECT) - .comparator(COMPARATOR_EQUALS) - .parameter(actionCondition.getParameterValues().get(HasAspectEvaluator.PARAM_ASPECT).toString()) + .comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase()) + .parameter(((QName) actionCondition.getParameterValues().get(HasAspectEvaluator.PARAM_ASPECT)).toPrefixString(namespaceService)) .create(); } - private static SimpleCondition createHasChildCondition(final ActionCondition actionCondition) { - final SimpleCondition.Builder builder = builder(); - if (actionCondition.getParameterValues().get(HasChildEvaluator.PARAM_ASSOC_TYPE) != null) - { - builder.field(actionCondition.getParameterValues().get(HasChildEvaluator.PARAM_ASSOC_TYPE).toString().toLowerCase()); - } else { - builder.field(actionCondition.getParameterValues().get(HasChildEvaluator.PARAM_ASSOC_NAME).toString().toLowerCase()); - } - return builder - .comparator(COMPARATOR_EQUALS) - .parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString()) - .create(); - } - - private static SimpleCondition createHasTagCondition(final ActionCondition actionCondition) { + private static SimpleCondition createHasTagCondition(final ActionCondition actionCondition) + { return builder() .field(HasTagEvaluator.PARAM_TAG) - .comparator(COMPARATOR_EQUALS) + .comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase()) .parameter(actionCondition.getParameterValues().get(HasTagEvaluator.PARAM_TAG).toString()) .create(); } - private static SimpleCondition createHasVersionHistoryCondition(final ActionCondition actionCondition) { + private static SimpleCondition createInCategoryCondition(final ActionCondition actionCondition) + { return builder() - .field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY).toString().toLowerCase()) - .comparator(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_OPERATION).toString().toLowerCase()) - .parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString()) + .field(PARAM_CATEGORY) + .comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase()) + .parameter(((NodeRef) actionCondition.getParameterValues().get(InCategoryEvaluator.PARAM_CATEGORY_VALUE)).getId()) .create(); } - private static SimpleCondition createInCategoryCondition(final ActionCondition actionCondition) { - return builder() - .field(actionCondition.getParameterValues().get(InCategoryEvaluator.PARAM_CATEGORY_ASPECT).toString().toLowerCase()) - .comparator(COMPARATOR_EQUALS) - .parameter(actionCondition.getParameterValues().get(InCategoryEvaluator.PARAM_CATEGORY_VALUE).toString()) - .create(); - } - - private static SimpleCondition createIsSubtypeCondition(final ActionCondition actionCondition) { + private static SimpleCondition createIsSubtypeCondition(final ActionCondition actionCondition, final NamespaceService namespaceService) + { return builder() .field(IsSubTypeEvaluator.PARAM_TYPE) - .comparator(COMPARATOR_EQUALS) - .parameter(actionCondition.getParameterValues().get(IsSubTypeEvaluator.PARAM_TYPE).toString()) + .comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase()) + .parameter(((QName) actionCondition.getParameterValues().get(IsSubTypeEvaluator.PARAM_TYPE)).toPrefixString(namespaceService)) .create(); } diff --git a/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeRulesRelation.java b/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeRulesRelation.java index fba6fee787..d540ecdab9 100644 --- a/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeRulesRelation.java +++ b/remote-api/src/main/java/org/alfresco/rest/api/nodes/NodeRulesRelation.java @@ -65,7 +65,7 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read, /** * List folder rules for given folder node's and rule set's IDs as a page. - * + *

* - GET /nodes/{folderNodeId}/rule-sets/{ruleSetId}/rules * * @param folderNodeId - entity resource context for this relationship @@ -87,7 +87,7 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read, /** * Get single folder rule for given node's, rule set's and rule's IDs. - * + *

* - GET /nodes/{folderNodeId}/rule-sets/{ruleSetId}/rules/{ruleId} * * @param folderNodeId - entity resource context for this relationship @@ -158,7 +158,7 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read, /** * Delete single folder rule for given node's, rule set's and rule's IDs. - * + *

* - DELETE /nodes/{folderNodeId}/rule-sets/{ruleSetId}/rules/{ruleId} * * @param folderNodeId - entity resource context for this relationship diff --git a/remote-api/src/main/resources/alfresco/public-rest-context.xml b/remote-api/src/main/resources/alfresco/public-rest-context.xml index 59fc8c936b..a4436bc7c0 100644 --- a/remote-api/src/main/resources/alfresco/public-rest-context.xml +++ b/remote-api/src/main/resources/alfresco/public-rest-context.xml @@ -886,6 +886,7 @@ + @@ -909,6 +910,7 @@ + diff --git a/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RulesImplTest.java b/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RulesImplTest.java index cd6c8b67f4..e6797baa3b 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RulesImplTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/impl/rules/RulesImplTest.java @@ -61,6 +61,7 @@ import org.alfresco.service.cmr.action.CompositeAction; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.rule.RuleService; +import org.alfresco.service.namespace.NamespaceService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -87,6 +88,8 @@ public class RulesImplTest extends TestCase @Mock private Nodes nodesMock; @Mock + private NamespaceService namespaceService; + @Mock private NodeValidator nodeValidatorMock; @Mock private RuleService ruleServiceMock; @@ -288,7 +291,7 @@ public class RulesImplTest extends TestCase public void testCreateRules() { List ruleList = List.of(ruleMock); - given(ruleMock.toServiceModel(nodesMock)).willReturn(serviceRuleMock); + given(ruleMock.toServiceModel(nodesMock, namespaceService)).willReturn(serviceRuleMock); given(serviceRuleMock.getAction()).willReturn(compositeAction); given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMock)).willAnswer(arg -> arg.getArguments()[1]); given(ruleLoaderMock.loadRule(serviceRuleMock, INCLUDE)).willReturn(ruleMock); @@ -304,7 +307,7 @@ public class RulesImplTest extends TestCase then(actionParameterConverterMock).shouldHaveNoMoreInteractions(); then(actionPermissionValidatorMock).should().validateRulePermissions(serviceRuleMock); then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions(); - then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleMock.toServiceModel(nodesMock)); + then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleMock.toServiceModel(nodesMock, namespaceService)); then(ruleServiceMock).shouldHaveNoMoreInteractions(); List expected = List.of(ruleMock); assertThat(actual).isEqualTo(expected); @@ -317,7 +320,7 @@ public class RulesImplTest extends TestCase public void testCreateRules_defaultRuleSet() { List ruleList = List.of(ruleMock); - given(ruleMock.toServiceModel(nodesMock)).willReturn(serviceRuleMock); + given(ruleMock.toServiceModel(nodesMock, namespaceService)).willReturn(serviceRuleMock); given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMock)).willAnswer(arg -> arg.getArguments()[1]); given(ruleLoaderMock.loadRule(serviceRuleMock, INCLUDE)).willReturn(ruleMock); given(serviceRuleMock.getAction()).willReturn(compositeAction); @@ -332,7 +335,7 @@ public class RulesImplTest extends TestCase then(actionParameterConverterMock).shouldHaveNoMoreInteractions(); then(actionPermissionValidatorMock).should().validateRulePermissions(serviceRuleMock); then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions(); - then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleMock.toServiceModel(nodesMock)); + then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleMock.toServiceModel(nodesMock, namespaceService)); then(ruleServiceMock).shouldHaveNoMoreInteractions(); List expected = List.of(ruleMock); assertThat(actual).isEqualTo(expected); @@ -362,7 +365,7 @@ public class RulesImplTest extends TestCase Rule ruleBodyMock = mock(Rule.class); ruleBodyList.add(ruleBodyMock); org.alfresco.service.cmr.rule.Rule serviceRuleMockInner = mock(org.alfresco.service.cmr.rule.Rule.class); - given(ruleBodyMock.toServiceModel(nodesMock)).willReturn(serviceRuleMockInner); + given(ruleBodyMock.toServiceModel(nodesMock, namespaceService)).willReturn(serviceRuleMockInner); final CompositeAction compositeActionInner = new CompositeActionImpl(RULE_NODE_REF, "compositeActionInnerId"); compositeActionInner.addAction(new ActionImpl(FOLDER_NODE_REF, "actionInnerId", ACTION_DEFINITION_NAME, DUMMY_PARAMS)); given(serviceRuleMockInner.getAction()).willReturn(compositeActionInner); @@ -381,8 +384,8 @@ public class RulesImplTest extends TestCase then(nodeValidatorMock).shouldHaveNoMoreInteractions(); for (Rule ruleBody : ruleBodyList) { - then(actionPermissionValidatorMock).should().validateRulePermissions(ruleBody.toServiceModel(nodesMock)); - then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleBody.toServiceModel(nodesMock)); + then(actionPermissionValidatorMock).should().validateRulePermissions(ruleBody.toServiceModel(nodesMock, namespaceService)); + then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleBody.toServiceModel(nodesMock, namespaceService)); } then(actionParameterConverterMock).should(times(3)).getConvertedParams(DUMMY_PARAMS, ACTION_DEFINITION_NAME); then(actionParameterConverterMock).shouldHaveNoMoreInteractions(); @@ -435,7 +438,7 @@ public class RulesImplTest extends TestCase @Test public void testUpdateRuleById() { - given(ruleMock.toServiceModel(nodesMock)).willReturn(serviceRuleMock); + given(ruleMock.toServiceModel(nodesMock, namespaceService)).willReturn(serviceRuleMock); given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMock)).willAnswer(a -> a.getArguments()[1]); given(serviceRuleMock.getAction()).willReturn(compositeAction); given(ruleLoaderMock.loadRule(serviceRuleMock, INCLUDE)).willReturn(ruleMock); diff --git a/remote-api/src/test/java/org/alfresco/rest/api/model/rules/CompositeConditionTest.java b/remote-api/src/test/java/org/alfresco/rest/api/model/rules/CompositeConditionTest.java index 427c208848..80b225cfc4 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/model/rules/CompositeConditionTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/model/rules/CompositeConditionTest.java @@ -27,6 +27,7 @@ package org.alfresco.rest.api.model.rules; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; import java.io.Serializable; import java.util.ArrayList; @@ -39,12 +40,18 @@ import org.alfresco.repo.action.ActionConditionImpl; import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator; import org.alfresco.service.Experimental; import org.alfresco.service.cmr.action.ActionCondition; +import org.alfresco.service.namespace.NamespaceService; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; @Experimental +@RunWith(MockitoJUnitRunner.class) public class CompositeConditionTest { + private final NamespaceService namespaceService = mock(NamespaceService.class); + @Test public void testFrom() { @@ -64,7 +71,7 @@ public class CompositeConditionTest )); // when - final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions); + final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions, namespaceService); assertThat(actualCompositeCondition).isNotNull().usingRecursiveComparison().isEqualTo(expectedCompositeCondition); } @@ -76,7 +83,7 @@ public class CompositeConditionTest final CompositeCondition expectedCompositeCondition = CompositeCondition.builder().create(); // when - final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions); + final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions, namespaceService); assertThat(actualCompositeCondition).isNotNull().usingRecursiveComparison().isEqualTo(expectedCompositeCondition); } @@ -85,7 +92,7 @@ public class CompositeConditionTest public void testFromNullValue() { // when - final CompositeCondition actualCompositeCondition = CompositeCondition.from(null); + final CompositeCondition actualCompositeCondition = CompositeCondition.from(null, namespaceService); assertThat(actualCompositeCondition).isNull(); } @@ -98,7 +105,7 @@ public class CompositeConditionTest final CompositeCondition expectedCompositeCondition = CompositeCondition.builder().create(); // when - final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions); + final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions, namespaceService); assertThat(actualCompositeCondition).isNotNull().usingRecursiveComparison().isEqualTo(expectedCompositeCondition); } diff --git a/remote-api/src/test/java/org/alfresco/rest/api/model/rules/RuleTest.java b/remote-api/src/test/java/org/alfresco/rest/api/model/rules/RuleTest.java index 771e576f26..72a4d9b1ce 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/model/rules/RuleTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/model/rules/RuleTest.java @@ -42,6 +42,7 @@ import org.alfresco.service.cmr.action.ActionCondition; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.rule.RuleType; +import org.alfresco.service.namespace.NamespaceService; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; @@ -60,6 +61,8 @@ public class RuleTest private static final String ACTION_DEFINITION_NAME = "action-def-name"; private static final String ERROR_SCRIPT = "error-script-ref"; + private final NamespaceService namespaceService = mock(NamespaceService.class); + @Test public void testFrom() { @@ -67,7 +70,7 @@ public class RuleTest final Rule expectedRule = createRuleWithDefaultValues(); // when - final Rule actualRule = Rule.from(ruleModel); + final Rule actualRule = Rule.from(ruleModel, namespaceService); assertThat(actualRule).isNotNull().usingRecursiveComparison().isEqualTo(expectedRule); @@ -80,7 +83,7 @@ public class RuleTest final Rule expectedRule = Rule.builder().enabled(true).create(); // when - final Rule actualRule = Rule.from(ruleModel); + final Rule actualRule = Rule.from(ruleModel, namespaceService); assertThat(actualRule).isNotNull().usingRecursiveComparison().isEqualTo(expectedRule); @@ -96,7 +99,7 @@ public class RuleTest final org.alfresco.service.cmr.action.Action expectedCompensatingActionModel = createCompensatingActionModel(); // when - final org.alfresco.service.cmr.rule.Rule actualRuleModel = rule.toServiceModel(nodesMock); + final org.alfresco.service.cmr.rule.Rule actualRuleModel = rule.toServiceModel(nodesMock, namespaceService); then(nodesMock).should().validateOrLookupNode(RULE_ID, null); then(nodesMock).shouldHaveNoMoreInteractions(); @@ -121,7 +124,7 @@ public class RuleTest expectedRuleModel.setRuleDisabled(true); // when - final org.alfresco.service.cmr.rule.Rule actualRuleModel = rule.toServiceModel(nodesMock); + final org.alfresco.service.cmr.rule.Rule actualRuleModel = rule.toServiceModel(nodesMock, namespaceService); then(nodesMock).shouldHaveNoInteractions(); assertThat(actualRuleModel) @@ -131,6 +134,20 @@ public class RuleTest .isEqualTo(expectedRuleModel); } + private Rule createRuleWithDefaultValues() { + return Rule.builder() + .id(RULE_ID) + .name(RULE_NAME) + .description(RULE_DESCRIPTION) + .enabled(RULE_ENABLED) + .cascade(RULE_CASCADE) + .asynchronous(RULE_ASYNC) + .triggers(List.of(RuleTrigger.INBOUND, RuleTrigger.UPDATE)) + .errorScript(ERROR_SCRIPT) + .conditions(CompositeCondition.from(Collections.emptyList(), namespaceService)) + .create(); + } + private static org.alfresco.service.cmr.rule.Rule createRuleModel() { final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID); final org.alfresco.service.cmr.rule.Rule ruleModel = new org.alfresco.service.cmr.rule.Rule(nodeRef); @@ -160,18 +177,4 @@ public class RuleTest return compensatingActionModel; } - - private static Rule createRuleWithDefaultValues() { - return Rule.builder() - .id(RULE_ID) - .name(RULE_NAME) - .description(RULE_DESCRIPTION) - .enabled(RULE_ENABLED) - .cascade(RULE_CASCADE) - .asynchronous(RULE_ASYNC) - .triggers(List.of(RuleTrigger.INBOUND, RuleTrigger.UPDATE)) - .errorScript(ERROR_SCRIPT) - .conditions(CompositeCondition.from(Collections.emptyList())) - .create(); - } } \ No newline at end of file diff --git a/remote-api/src/test/java/org/alfresco/rest/api/model/rules/SimpleConditionTest.java b/remote-api/src/test/java/org/alfresco/rest/api/model/rules/SimpleConditionTest.java index 9c0de39112..6520a57fe2 100644 --- a/remote-api/src/test/java/org/alfresco/rest/api/model/rules/SimpleConditionTest.java +++ b/remote-api/src/test/java/org/alfresco/rest/api/model/rules/SimpleConditionTest.java @@ -27,6 +27,8 @@ package org.alfresco.rest.api.model.rules; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; import java.io.Serializable; import java.util.ArrayList; @@ -36,6 +38,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import org.alfresco.model.ContentModel; import org.alfresco.repo.action.ActionConditionImpl; import org.alfresco.repo.action.evaluator.CompareMimeTypeEvaluator; import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator; @@ -46,28 +49,54 @@ import org.alfresco.repo.action.evaluator.HasVersionHistoryEvaluator; import org.alfresco.repo.action.evaluator.InCategoryEvaluator; import org.alfresco.repo.action.evaluator.IsSubTypeEvaluator; import org.alfresco.repo.action.evaluator.NoConditionEvaluator; +import org.alfresco.repo.action.evaluator.compare.ComparePropertyValueOperation; +import org.alfresco.repo.action.evaluator.compare.ContentPropertyName; +import org.alfresco.rest.api.Nodes; import org.alfresco.service.Experimental; import org.alfresco.service.cmr.action.ActionCondition; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.service.namespace.QName; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnitRunner; @Experimental +@RunWith(MockitoJUnitRunner.class) public class SimpleConditionTest { + private static final boolean NULL_RESULT = true; + private static final boolean NOT_INVERTED = false; + private static final String PARAMETER_DEFAULT = "value"; + + private final Nodes nodes = mock(Nodes.class); + private final NamespaceService namespaceService = mock(NamespaceService.class); + + @Before + public void setUp() throws Exception + { + given(namespaceService.getPrefixes(NamespaceService.CONTENT_MODEL_1_0_URI)).willReturn(List.of(NamespaceService.CONTENT_MODEL_PREFIX)); + given(namespaceService.getNamespaceURI(NamespaceService.CONTENT_MODEL_PREFIX)).willReturn(NamespaceService.CONTENT_MODEL_1_0_URI); + given(namespaceService.getPrefixes(NamespaceService.AUDIO_MODEL_1_0_URI)).willReturn(List.of(NamespaceService.AUDIO_MODEL_PREFIX)); + given(namespaceService.getNamespaceURI(NamespaceService.AUDIO_MODEL_PREFIX)).willReturn(NamespaceService.AUDIO_MODEL_1_0_URI); + } private static List getTestData() { return List.of( TestData.of(ComparePropertyValueEvaluator.NAME), TestData.of(CompareMimeTypeEvaluator.NAME), TestData.of(HasAspectEvaluator.NAME), - TestData.of(HasChildEvaluator.NAME), + TestData.of(HasChildEvaluator.NAME, NULL_RESULT), TestData.of(HasTagEvaluator.NAME), - TestData.of(HasVersionHistoryEvaluator.NAME), + TestData.of(HasVersionHistoryEvaluator.NAME, NULL_RESULT), TestData.of(InCategoryEvaluator.NAME), TestData.of(IsSubTypeEvaluator.NAME), - TestData.of(NoConditionEvaluator.NAME, true), - TestData.of("fake-definition-name", true), - TestData.of("", true), - TestData.of(null, true) + TestData.of(NoConditionEvaluator.NAME, NULL_RESULT), + TestData.of("fake-definition-name", NULL_RESULT), + TestData.of("", NULL_RESULT), + TestData.of(null, NULL_RESULT) ); } @@ -76,10 +105,10 @@ public class SimpleConditionTest { for (TestData testData : getTestData()) { - final ActionCondition actionCondition = createActionCondition(testData.actionDefinitionName); + final ActionCondition actionCondition = createActionCondition(testData.conditionDefinitionName); // when - final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition); + final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition, namespaceService); assertThat(Objects.isNull(actualSimpleCondition)).isEqualTo(testData.isNullResult); if (!testData.isNullResult) @@ -95,7 +124,7 @@ public class SimpleConditionTest public void testFromNullValue() { // when - final SimpleCondition actualSimpleCondition = SimpleCondition.from(null); + final SimpleCondition actualSimpleCondition = SimpleCondition.from(null, namespaceService); assertThat(actualSimpleCondition).isNull(); } @@ -106,7 +135,7 @@ public class SimpleConditionTest final ActionCondition actionCondition = new ActionConditionImpl("fake-id", null, createParameterValues()); // when - final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition); + final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition, namespaceService); assertThat(actualSimpleCondition).isNull(); } @@ -117,7 +146,7 @@ public class SimpleConditionTest final ActionCondition actionCondition = new ActionConditionImpl("fake-id", "fake-def-name", null); // when - final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition); + final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition, namespaceService); assertThat(actualSimpleCondition).isNull(); } @@ -129,14 +158,22 @@ public class SimpleConditionTest createActionCondition(ComparePropertyValueEvaluator.NAME), createActionCondition(CompareMimeTypeEvaluator.NAME) ); - final List expectedSimpleConditions = List.of( - SimpleCondition.builder().field("content-property").comparator("operation").parameter("value").create(), - SimpleCondition.builder().field("property").comparator("equals").parameter("value").create() - ); // when - final List actualSimpleConditions = SimpleCondition.listOf(actionConditions); + final List actualSimpleConditions = SimpleCondition.listOf(actionConditions, namespaceService); + final List expectedSimpleConditions = List.of( + SimpleCondition.builder() + .field("content-property") + .comparator("operation") + .parameter("value") + .create(), + SimpleCondition.builder() + .field(SimpleCondition.PARAM_MIMETYPE) + .comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase()) + .parameter("value") + .create() + ); assertThat(actualSimpleConditions) .isNotNull() .containsExactlyElementsOf(expectedSimpleConditions); @@ -145,7 +182,8 @@ public class SimpleConditionTest @Test public void testListOfEmptyActionConditions() { - final List actualSimpleConditions = SimpleCondition.listOf(Collections.emptyList()); + // when + final List actualSimpleConditions = SimpleCondition.listOf(Collections.emptyList(), namespaceService); assertThat(actualSimpleConditions).isNull(); } @@ -153,7 +191,8 @@ public class SimpleConditionTest @Test public void testListOfNullActionConditions() { - final List actualSimpleConditions = SimpleCondition.listOf(null); + // when + final List actualSimpleConditions = SimpleCondition.listOf(null, namespaceService); assertThat(actualSimpleConditions).isNull(); } @@ -164,50 +203,207 @@ public class SimpleConditionTest final List actionConditions = new ArrayList<>(); actionConditions.add(null); - final List actualSimpleConditions = SimpleCondition.listOf(actionConditions); + // when + final List actualSimpleConditions = SimpleCondition.listOf(actionConditions, namespaceService); assertThat(actualSimpleConditions).isNotNull().isEmpty(); } + @Test + public void testToServiceModel_withSizeContentProperty() + { + final SimpleCondition simpleCondition = createSimpleCondition(ContentPropertyName.SIZE.toString().toLowerCase()); + + // when + final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService); + + final Map expectedParameterValues = new HashMap<>(); + expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY, ContentPropertyName.SIZE.toString()); + expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.TYPE_CONTENT); + expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.EQUALS.toString()); + expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, PARAMETER_DEFAULT); + ActionCondition expectedActionCondition = new ActionConditionImpl(null, ComparePropertyValueEvaluator.NAME, expectedParameterValues); + assertThat(actualActionCondition) + .isNotNull().usingRecursiveComparison().ignoringFields("id") + .isEqualTo(expectedActionCondition); + } + + @Test + public void testToServiceModel_withoutContentProperty() + { + final SimpleCondition simpleCondition = createSimpleCondition(ContentModel.PROP_DESCRIPTION.toPrefixString(namespaceService)); + + // when + final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService); + + final Map expectedParameterValues = new HashMap<>(); + expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.PROP_DESCRIPTION); + expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.EQUALS.toString()); + expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, PARAMETER_DEFAULT); + final ActionCondition expectedActionCondition = new ActionConditionImpl(null, ComparePropertyValueEvaluator.NAME, expectedParameterValues); + assertThat(actualActionCondition) + .isNotNull().usingRecursiveComparison().ignoringFields("id", "parameterValues.property.prefix") + .isEqualTo(expectedActionCondition); + } + + @Test + public void testToServiceModel_compareMimetype() + { + final SimpleCondition simpleCondition = createSimpleCondition(SimpleCondition.PARAM_MIMETYPE); + + // when + final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService); + + final Map expectedParameterValues = new HashMap<>(); + expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.TYPE_CONTENT); + expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, PARAMETER_DEFAULT); + final ActionCondition expectedActionCondition = new ActionConditionImpl(null, CompareMimeTypeEvaluator.NAME, expectedParameterValues); + assertThat(actualActionCondition) + .isNotNull().usingRecursiveComparison().ignoringFields("id") + .isEqualTo(expectedActionCondition); + } + + @Test + public void testToServiceModel_hasAspect() + { + final QName audioAspect = QName.createQName(NamespaceService.AUDIO_MODEL_1_0_URI, NamespaceService.AUDIO_MODEL_PREFIX); + final SimpleCondition simpleCondition = createSimpleCondition(HasAspectEvaluator.PARAM_ASPECT, audioAspect.toPrefixString(namespaceService)); + + // when + final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService); + + final Map expectedParameterValues = new HashMap<>(); + expectedParameterValues.put(HasAspectEvaluator.PARAM_ASPECT, audioAspect); + final ActionCondition expectedActionCondition = new ActionConditionImpl(null, HasAspectEvaluator.NAME, expectedParameterValues); + assertThat(actualActionCondition) + .isNotNull().usingRecursiveComparison().ignoringFields("id", "parameterValues.aspect.prefix") + .isEqualTo(expectedActionCondition); + } + + @Test + public void testToServiceModel_hasTag() + { + final String tag = "some tag"; + final SimpleCondition simpleCondition = createSimpleCondition(HasTagEvaluator.PARAM_TAG, tag); + + // when + final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService); + + final Map expectedParameterValues = new HashMap<>(); + expectedParameterValues.put(HasTagEvaluator.PARAM_TAG, tag); + final ActionCondition expectedActionCondition = new ActionConditionImpl(null, HasTagEvaluator.NAME, expectedParameterValues); + assertThat(actualActionCondition) + .isNotNull().usingRecursiveComparison().ignoringFields("id") + .isEqualTo(expectedActionCondition); + } + + @Test + public void testToServiceModel_inCategory() + { + final SimpleCondition simpleCondition = createSimpleCondition(SimpleCondition.PARAM_CATEGORY); + final NodeRef defaultNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARAMETER_DEFAULT); + given(nodes.validateOrLookupNode(PARAMETER_DEFAULT, null)).willReturn(defaultNodeRef); + + // when + final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService); + + final Map expectedParameterValues = new HashMap<>(); + expectedParameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_ASPECT, ContentModel.ASPECT_GEN_CLASSIFIABLE); + expectedParameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_VALUE, defaultNodeRef); + final ActionCondition expectedActionCondition = new ActionConditionImpl(null, InCategoryEvaluator.NAME, expectedParameterValues); + assertThat(actualActionCondition) + .isNotNull().usingRecursiveComparison().ignoringFields("id") + .isEqualTo(expectedActionCondition); + } + + @Test + public void testToServiceModel_isSubType() + { + final SimpleCondition simpleCondition = createSimpleCondition(IsSubTypeEvaluator.PARAM_TYPE, ContentModel.TYPE_FOLDER.toPrefixString(namespaceService)); + + // when + final ActionCondition actualActionCondition = simpleCondition.toServiceModel(NOT_INVERTED, nodes, namespaceService); + + final Map expectedParameterValues = new HashMap<>(); + expectedParameterValues.put(IsSubTypeEvaluator.PARAM_TYPE, ContentModel.TYPE_FOLDER); + final ActionCondition expectedActionCondition = new ActionConditionImpl(null, IsSubTypeEvaluator.NAME, expectedParameterValues); + assertThat(actualActionCondition) + .isNotNull().usingRecursiveComparison().ignoringFields("id", "parameterValues.type.prefix") + .isEqualTo(expectedActionCondition); + } + + @Test + public void testToServiceModel_inverted() + { + final SimpleCondition simpleCondition = createSimpleCondition(ContentModel.PROP_DESCRIPTION.toPrefixString(namespaceService)); + + // when + final ActionCondition actualActionCondition = simpleCondition.toServiceModel(!NOT_INVERTED, nodes, namespaceService); + + final Map expectedParameterValues = new HashMap<>(); + expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.PROP_DESCRIPTION); + expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_OPERATION, ComparePropertyValueOperation.EQUALS.toString()); + expectedParameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, PARAMETER_DEFAULT); + final ActionCondition expectedActionCondition = new ActionConditionImpl(null, ComparePropertyValueEvaluator.NAME, expectedParameterValues); + expectedActionCondition.setInvertCondition(!NOT_INVERTED); + assertThat(actualActionCondition) + .isNotNull().usingRecursiveComparison().ignoringFields("id", "parameterValues.property.prefix") + .isEqualTo(expectedActionCondition); + } + + private static SimpleCondition createSimpleCondition(final String field) + { + return createSimpleCondition(field, PARAMETER_DEFAULT); + } + + private static SimpleCondition createSimpleCondition(final String field, final String parameter) + { + return SimpleCondition.builder() + .field(field) + .comparator(ComparePropertyValueOperation.EQUALS.toString().toLowerCase()) + .parameter(parameter) + .create(); + } + private static ActionCondition createActionCondition(final String actionDefinitionName) { return new ActionConditionImpl("fake-id", actionDefinitionName, createParameterValues()); } private static Map createParameterValues() { + final QName audioAspect = QName.createQName(NamespaceService.AUDIO_MODEL_1_0_URI, NamespaceService.AUDIO_MODEL_PREFIX); + final NodeRef defaultNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARAMETER_DEFAULT); final Map parameterValues = new HashMap<>(); parameterValues.put(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY, "content-property"); - parameterValues.put(HasChildEvaluator.PARAM_ASSOC_TYPE, "assoc-type"); - parameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, "property"); + parameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, ContentModel.TYPE_CONTENT); parameterValues.put(ComparePropertyValueEvaluator.PARAM_OPERATION, "operation"); parameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, "value"); - parameterValues.put(HasAspectEvaluator.PARAM_ASPECT, "aspect"); - parameterValues.put(HasChildEvaluator.PARAM_ASSOC_NAME, "assoc-name"); + parameterValues.put(HasAspectEvaluator.PARAM_ASPECT, audioAspect); parameterValues.put(HasTagEvaluator.PARAM_TAG, "tag"); parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_ASPECT, "category-aspect"); - parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_VALUE, "category-value"); - parameterValues.put(IsSubTypeEvaluator.PARAM_TYPE, "type"); + parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_VALUE, defaultNodeRef); + parameterValues.put(IsSubTypeEvaluator.PARAM_TYPE, ContentModel.TYPE_FOLDER); return parameterValues; } private static class TestData { - String actionDefinitionName; + String conditionDefinitionName; boolean isNullResult; - public TestData(String actionDefinitionName, boolean isNullResult) + public TestData(String conditionDefinitionName, boolean isNullResult) { - this.actionDefinitionName = actionDefinitionName; + this.conditionDefinitionName = conditionDefinitionName; this.isNullResult = isNullResult; } - public static TestData of(String actionDefinitionName) { - return new TestData(actionDefinitionName, false); + public static TestData of(String conditionDefinitionName) { + return new TestData(conditionDefinitionName, false); } - public static TestData of(String actionDefinitionName, boolean isNullResult) { - return new TestData(actionDefinitionName, isNullResult); + public static TestData of(String conditionDefinitionName, boolean isNullResult) { + return new TestData(conditionDefinitionName, isNullResult); } } } \ No newline at end of file diff --git a/repository/src/main/java/org/alfresco/repo/action/ParameterizedItemImpl.java b/repository/src/main/java/org/alfresco/repo/action/ParameterizedItemImpl.java index f5a8d165ee..1783785308 100644 --- a/repository/src/main/java/org/alfresco/repo/action/ParameterizedItemImpl.java +++ b/repository/src/main/java/org/alfresco/repo/action/ParameterizedItemImpl.java @@ -1,33 +1,34 @@ -/* - * #%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 - 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% + */ package org.alfresco.repo.action; import java.io.Serializable; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import org.alfresco.service.cmr.action.ParameterizedItem; @@ -38,8 +39,8 @@ import org.alfresco.service.cmr.action.ParameterizedItem; */ public abstract class ParameterizedItemImpl implements ParameterizedItem, Serializable { - private static final long serialVersionUID = 3578052215076397741L; - + private static final long serialVersionUID = 3578052215076397741L; + /** * The id */ @@ -50,23 +51,23 @@ public abstract class ParameterizedItemImpl implements ParameterizedItem, Serial */ private Map parameterValues = new HashMap(); - /** - * Constructor - * - * @param id the id - */ - public ParameterizedItemImpl(String id) - { + /** + * Constructor + * + * @param id the id + */ + public ParameterizedItemImpl(String id) + { this(id, null); } - /** - * Constructor - * - * @param id the rule item - * @param parameterValues the parameter values - */ - public ParameterizedItemImpl(String id, Map parameterValues) + /** + * Constructor + * + * @param id the rule item + * @param parameterValues the parameter values + */ + public ParameterizedItemImpl(String id, Map parameterValues) { // Set the action id this.id = id; @@ -135,7 +136,7 @@ public abstract class ParameterizedItemImpl implements ParameterizedItem, Serial @Override public int hashCode() { - return this.id.hashCode(); + return Objects.hashCode(this.id); } /** 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 03a82e80df..ed42df7e25 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 @@ -385,7 +385,7 @@ public interface RuleService boolean isRuleAssociatedWithRuleSet(final NodeRef ruleNodeRef, final NodeRef ruleSetNodeRef); /** - * Check if others folders are linked to rule set. + * Check if other folders are linked to rule set. * * @param ruleSetNodeRef - node reference of a rule set * @return true if others folders are linked to rule set