Rules v1 REST API - Get rule definition - mapping of "other fields" (#1244)

ACS-3229: Rules v1 REST API - Get rule definition
- adding mapping of so-called "other fields"
This commit is contained in:
krdabrowski
2022-07-27 14:02:08 +02:00
committed by GitHub
parent 71080c9c7d
commit ac9151ed86
11 changed files with 587 additions and 77 deletions

View File

@@ -65,10 +65,11 @@ public class RulesImpl implements Rules
public CollectionWithPagingInfo<Rule> getRules(final String folderNodeId, final String ruleSetId, final Paging paging) public CollectionWithPagingInfo<Rule> getRules(final String folderNodeId, final String ruleSetId, final Paging paging)
{ {
final NodeRef folderNodeRef = validateFolderNode(folderNodeId, false); final NodeRef folderNodeRef = validateFolderNode(folderNodeId, false);
validateRuleSetNode(ruleSetId, folderNodeRef); final NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef);
final boolean isShared = isRuleSetNotNullAndShared(ruleSetNodeRef);
final List<Rule> rules = ruleService.getRules(folderNodeRef).stream() final List<Rule> rules = ruleService.getRules(folderNodeRef).stream()
.map(Rule::from) .map(ruleModel -> Rule.from(ruleModel, isShared))
.collect(Collectors.toList()); .collect(Collectors.toList());
return ListPage.of(rules, paging); return ListPage.of(rules, paging);
@@ -81,7 +82,7 @@ public class RulesImpl implements Rules
final NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef); final NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef);
final NodeRef ruleNodeRef = validateRuleNode(ruleId, ruleSetNodeRef); final NodeRef ruleNodeRef = validateRuleNode(ruleId, ruleSetNodeRef);
return Rule.from(ruleService.getRule(ruleNodeRef)); return Rule.from(ruleService.getRule(ruleNodeRef), isRuleSetNotNullAndShared(ruleSetNodeRef));
} }
@Override @Override
@@ -89,15 +90,12 @@ public class RulesImpl implements Rules
{ {
final NodeRef folderNodeRef = validateFolderNode(folderNodeId, true); final NodeRef folderNodeRef = validateFolderNode(folderNodeId, true);
// Don't validate the ruleset node if -default- is passed since we may need to create it. // Don't validate the ruleset node if -default- is passed since we may need to create it.
if (RuleSet.isNotDefaultId(ruleSetId)) final NodeRef ruleSetNodeRef = (RuleSet.isNotDefaultId(ruleSetId)) ? validateRuleSetNode(ruleSetId, folderNodeRef) : null;
{
validateRuleSetNode(ruleSetId, folderNodeRef);
}
return rules.stream() return rules.stream()
.map(rule -> rule.toServiceModel(nodes)) .map(rule -> rule.toServiceModel(nodes))
.map(rule -> ruleService.saveRule(folderNodeRef, rule)) .map(rule -> ruleService.saveRule(folderNodeRef, rule))
.map(Rule::from) .map(rule -> Rule.from(rule, isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef)))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@@ -207,11 +205,30 @@ public class RulesImpl implements Rules
return nodeRef; return nodeRef;
} }
private void verifyNodeType(final NodeRef nodeRef, final QName expectedType, final String expectedTypeName) { private void verifyNodeType(final NodeRef nodeRef, final QName expectedType, final String expectedTypeName)
{
final Set<QName> expectedTypes = Set.of(expectedType); final Set<QName> expectedTypes = Set.of(expectedType);
if (!nodes.nodeMatches(nodeRef, expectedTypes, null)) { if (!nodes.nodeMatches(nodeRef, expectedTypes, null)) {
final String expectedTypeLocalName = (expectedTypeName != null)? expectedTypeName : expectedType.getLocalName(); final String expectedTypeLocalName = (expectedTypeName != null)? expectedTypeName : expectedType.getLocalName();
throw new InvalidArgumentException(String.format("NodeId of a %s is expected!", expectedTypeLocalName)); throw new InvalidArgumentException(String.format("NodeId of a %s is expected!", expectedTypeLocalName));
} }
} }
private boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef)
{
if (ruleSetNodeRef == null && folderNodeRef != null)
{
final NodeRef ruleSetNode = ruleService.getRuleSetNode(folderNodeRef);
return ruleSetNode != null && ruleService.isRuleSetShared(ruleSetNode);
}
else
{
return isRuleSetNotNullAndShared(ruleSetNodeRef);
}
}
private boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef)
{
return ruleSetNodeRef != null && ruleService.isRuleSetShared(ruleSetNodeRef);
}
} }

View File

@@ -31,14 +31,15 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.ActionImpl; import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.executer.ScriptActionExecuter;
import org.alfresco.repo.action.executer.SetPropertyValueActionExecuter; import org.alfresco.repo.action.executer.SetPropertyValueActionExecuter;
import org.alfresco.rest.api.Nodes; import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.framework.resource.UniqueId; import org.alfresco.rest.framework.resource.UniqueId;
import org.alfresco.service.Experimental; import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.GUID; import org.alfresco.util.GUID;
@@ -47,16 +48,48 @@ public class Rule
{ {
private String id; private String id;
private String name; private String name;
private String description;
private boolean enabled;
private boolean cascade;
private boolean asynchronous;
private boolean shared;
private String errorScript;
private List<RuleTrigger> triggers;
public static Rule from(final org.alfresco.service.cmr.rule.Rule ruleModel) { /**
if (ruleModel == null) { * Converts service POJO rule to REST model rule.
*
* @param ruleModel - {@link org.alfresco.service.cmr.rule.Rule} service POJO
* @return {@link Rule} REST model
*/
public static Rule from(final org.alfresco.service.cmr.rule.Rule ruleModel, final boolean shared)
{
if (ruleModel == null)
{
return null; return null;
} }
return builder() final Rule.Builder builder = builder()
.setId(ruleModel.getNodeRef().getId()) .name(ruleModel.getTitle())
.setName(ruleModel.getTitle()) .description(ruleModel.getDescription())
.createRule(); .enabled(!ruleModel.getRuleDisabled())
.cascade(ruleModel.isAppliedToChildren())
.asynchronous(ruleModel.getExecuteAsynchronously())
.shared(shared);
if (ruleModel.getNodeRef() != null) {
builder.id(ruleModel.getNodeRef().getId());
}
if (ruleModel.getRuleTypes() != null)
{
builder.triggers(ruleModel.getRuleTypes().stream().map(RuleTrigger::of).collect(Collectors.toList()));
}
if (ruleModel.getAction() != null && ruleModel.getAction().getCompensatingAction() != null && ruleModel.getAction().getCompensatingAction().getParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF) != null)
{
builder.errorScript(ruleModel.getAction().getCompensatingAction().getParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF).toString());
}
return builder.create();
} }
/** /**
@@ -79,7 +112,7 @@ public class Rule
Map<String, Serializable> parameters = Map.of( Map<String, Serializable> parameters = Map.of(
SetPropertyValueActionExecuter.PARAM_PROPERTY, ContentModel.PROP_TITLE, SetPropertyValueActionExecuter.PARAM_PROPERTY, ContentModel.PROP_TITLE,
SetPropertyValueActionExecuter.PARAM_VALUE, "UPDATED:" + GUID.generate()); SetPropertyValueActionExecuter.PARAM_VALUE, "UPDATED:" + GUID.generate());
Action action = new ActionImpl(null, GUID.generate(), SetPropertyValueActionExecuter.NAME, parameters); org.alfresco.service.cmr.action.Action action = new ActionImpl(null, GUID.generate(), SetPropertyValueActionExecuter.NAME, parameters);
ruleModel.setAction(action); ruleModel.setAction(action);
return ruleModel; return ruleModel;
@@ -106,68 +139,190 @@ public class Rule
this.name = name; this.name = name;
} }
// TODO: Added stub for actions as it's a required field. Replace this implementation when we implement support for actions. public String getDescription()
{
return description;
}
public void setDescription(String description)
{
this.description = description;
}
public boolean isEnabled()
{
return enabled;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
public boolean isCascade()
{
return cascade;
}
public void setCascade(boolean cascade)
{
this.cascade = cascade;
}
public boolean isAsynchronous()
{
return asynchronous;
}
public void setAsynchronous(boolean asynchronous)
{
this.asynchronous = asynchronous;
}
public String getErrorScript()
{
return errorScript;
}
public void setErrorScript(String errorScript)
{
this.errorScript = errorScript;
}
public boolean isShared()
{
return shared;
}
public void setShared(boolean shared)
{
this.shared = shared;
}
public List<RuleTrigger> getTriggers()
{
return triggers;
}
public void setTriggers(List<RuleTrigger> triggers)
{
this.triggers = triggers;
}
public List<Void> getActions() public List<Void> getActions()
{ {
return Collections.emptyList(); return Collections.emptyList();
} }
@Override
public String toString()
{
return "Rule{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", description='" + description + '\'' + ", enabled=" + enabled + ", cascade=" + cascade
+ ", asynchronous=" + asynchronous + ", shared=" + shared + ", errorScript='" + errorScript + '\'' + ", triggers=" + triggers + '}';
}
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {
if (this == o) if (this == o)
{
return true; return true;
} if (o == null || getClass() != o.getClass())
if (!(o instanceof Rule))
{
return false; return false;
}
Rule rule = (Rule) o; Rule rule = (Rule) o;
return Objects.equals(id, rule.id) && return enabled == rule.enabled && cascade == rule.cascade && asynchronous == rule.asynchronous && shared == rule.shared && Objects.equals(id, rule.id) && Objects.equals(
Objects.equals(name, rule.name); name, rule.name) && Objects.equals(description, rule.description) && Objects.equals(errorScript, rule.errorScript) && Objects.equals(triggers, rule.triggers);
} }
@Override @Override
public int hashCode() public int hashCode()
{ {
return Objects.hash(id, name); return Objects.hash(id, name, description, enabled, cascade, asynchronous, shared, errorScript, triggers);
} }
@Override public static Builder builder()
public String toString()
{ {
return "Rule{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; return new Builder();
}
public static RuleBuilder builder()
{
return new RuleBuilder();
} }
/** Builder class. */ /** Builder class. */
public static class RuleBuilder public static class Builder
{ {
private String id; private String id;
private String name; private String name;
private String description;
private boolean enabled;
private boolean cascade;
private boolean asynchronous;
private boolean shared;
private String errorScript;
private List<RuleTrigger> triggers;
public RuleBuilder setId(String id) public Builder id(String id)
{ {
this.id = id; this.id = id;
return this; return this;
} }
public RuleBuilder setName(String name) public Builder name(String name)
{ {
this.name = name; this.name = name;
return this; return this;
} }
public Rule createRule() public Builder description(String description)
{
this.description = description;
return this;
}
public Builder enabled(boolean enabled)
{
this.enabled = enabled;
return this;
}
public Builder cascade(boolean cascade)
{
this.cascade = cascade;
return this;
}
public Builder asynchronous(boolean asynchronous)
{
this.asynchronous = asynchronous;
return this;
}
public Builder shared(boolean shared)
{
this.shared = shared;
return this;
}
public Builder errorScript(String errorScript)
{
this.errorScript = errorScript;
return this;
}
public Builder triggers(List<RuleTrigger> triggers)
{
this.triggers = triggers;
return this;
}
public Rule create()
{ {
Rule rule = new Rule(); Rule rule = new Rule();
rule.setId(id); rule.setId(id);
rule.setName(name); rule.setName(name);
rule.setDescription(description);
rule.setEnabled(enabled);
rule.setCascade(cascade);
rule.setAsynchronous(asynchronous);
rule.setShared(shared);
rule.setErrorScript(errorScript);
rule.setTriggers(triggers);
return rule; return rule;
} }
} }

View File

@@ -26,6 +26,8 @@
package org.alfresco.rest.api.model.rules; package org.alfresco.rest.api.model.rules;
import java.util.Objects;
import org.alfresco.service.Experimental; import org.alfresco.service.Experimental;
@Experimental @Experimental
@@ -37,10 +39,9 @@ public class RuleSet
public static RuleSet of(String id) public static RuleSet of(String id)
{ {
final RuleSet ruleSet = new RuleSet(); return builder()
ruleSet.id = id; .id(id)
.create();
return ruleSet;
} }
public boolean isNotDefaultId() { public boolean isNotDefaultId() {
@@ -74,4 +75,44 @@ public class RuleSet
{ {
return "RuleSet{" + "id='" + id + '\'' + '}'; return "RuleSet{" + "id='" + id + '\'' + '}';
} }
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
RuleSet ruleSet = (RuleSet) o;
return Objects.equals(id, ruleSet.id);
}
@Override
public int hashCode()
{
return Objects.hash(id);
}
public static Builder builder()
{
return new Builder();
}
public static class Builder
{
private String id;
public Builder id(String id)
{
this.id = id;
return this;
}
public RuleSet create()
{
final RuleSet ruleSet = new RuleSet();
ruleSet.setId(id);
return ruleSet;
}
}
} }

View File

@@ -0,0 +1,61 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.api.model.rules;
import org.alfresco.service.Experimental;
@Experimental
public enum RuleTrigger
{
INBOUND("inbound"),
UPDATE("update"),
OUTBOUND("outbound");
RuleTrigger(String value)
{
this.value = value;
}
private final String value;
public String getValue()
{
return value;
}
public static RuleTrigger of(final String value)
{
for (RuleTrigger ruleTrigger : values())
{
if (ruleTrigger.value.equals(value)) {
return ruleTrigger;
}
}
return null;
}
}

View File

@@ -48,9 +48,8 @@ import org.junit.runners.Suite;
org.alfresco.repo.webdav.RenameShuffleDetectionTest.class, org.alfresco.repo.webdav.RenameShuffleDetectionTest.class,
org.alfresco.repo.webdav.WebDAVHelperTest.class, org.alfresco.repo.webdav.WebDAVHelperTest.class,
org.alfresco.repo.webdav.WebDAVLockServiceImplTest.class, org.alfresco.repo.webdav.WebDAVLockServiceImplTest.class,
org.alfresco.rest.api.RulesUnitTests.class,
org.alfresco.rest.api.impl.ContentStorageInformationImplTest.class, org.alfresco.rest.api.impl.ContentStorageInformationImplTest.class,
org.alfresco.rest.api.impl.RulesImplTest.class,
org.alfresco.rest.api.nodes.NodeRulesRelationTest.class,
org.alfresco.rest.api.nodes.NodeStorageInfoRelationTest.class, org.alfresco.rest.api.nodes.NodeStorageInfoRelationTest.class,
org.alfresco.rest.api.search.ResultMapperTests.class, org.alfresco.rest.api.search.ResultMapperTests.class,
org.alfresco.rest.api.search.SearchApiWebscriptTests.class, org.alfresco.rest.api.search.SearchApiWebscriptTests.class,

View File

@@ -0,0 +1,45 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.api;
import org.alfresco.rest.api.impl.RulesImplTest;
import org.alfresco.rest.api.model.rules.RuleTest;
import org.alfresco.rest.api.nodes.NodeRulesRelationTest;
import org.alfresco.service.Experimental;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@Experimental
@RunWith(Suite.class)
@Suite.SuiteClasses({
NodeRulesRelationTest.class,
RulesImplTest.class,
RuleTest.class
})
public class RulesUnitTests
{
}

View File

@@ -40,12 +40,14 @@ import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then; import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.rest.api.Nodes; import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.rules.Rule; import org.alfresco.rest.api.model.rules.Rule;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
@@ -54,6 +56,7 @@ import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo; import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging; import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.service.Experimental; import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef; import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.rule.RuleService; import org.alfresco.service.cmr.rule.RuleService;
@@ -77,6 +80,7 @@ public class RulesImplTest extends TestCase
private static final NodeRef ruleSetNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID); private static final NodeRef ruleSetNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
private static final NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID); private static final NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID);
private static final Paging paging = Paging.DEFAULT; private static final Paging paging = Paging.DEFAULT;
private static final Action action = new ActionImpl(folderNodeRef, "actionId", "actionDefinitionName");
private static final String RULE_NAME = "Rule name"; private static final String RULE_NAME = "Rule name";
@Mock @Mock
@@ -121,6 +125,7 @@ public class RulesImplTest extends TestCase
then(permissionServiceMock).should().hasReadPermission(folderNodeRef); then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
then(permissionServiceMock).shouldHaveNoMoreInteractions(); then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).should().getRules(folderNodeRef); then(ruleServiceMock).should().getRules(folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions(); then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(rulesPage) assertThat(rulesPage)
@@ -138,6 +143,7 @@ public class RulesImplTest extends TestCase
@Test @Test
public void testGetRulesForDefaultRuleSet() public void testGetRulesForDefaultRuleSet()
{ {
given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef);
given(ruleServiceMock.getRules(any())).willReturn(List.of(createRule(RULE_ID))); given(ruleServiceMock.getRules(any())).willReturn(List.of(createRule(RULE_ID)));
// when // when
@@ -149,6 +155,7 @@ public class RulesImplTest extends TestCase
then(permissionServiceMock).should().hasReadPermission(folderNodeRef); then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
then(permissionServiceMock).shouldHaveNoMoreInteractions(); then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().getRuleSetNode(folderNodeRef); then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).should().getRules(folderNodeRef); then(ruleServiceMock).should().getRules(folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions(); then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(rulesPage) assertThat(rulesPage)
@@ -235,6 +242,7 @@ public class RulesImplTest extends TestCase
then(permissionServiceMock).shouldHaveNoMoreInteractions(); then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef); then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).should().getRule(ruleNodeRef); then(ruleServiceMock).should().getRule(ruleNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions(); then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(rule) assertThat(rule)
@@ -264,7 +272,8 @@ public class RulesImplTest extends TestCase
then(permissionServiceMock).shouldHaveNoMoreInteractions(); then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().getRuleSetNode(folderNodeRef); then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef); then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
then(ruleServiceMock).should().getRule(eq(ruleNodeRef)); then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).should().getRule(ruleNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions(); then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(rule) assertThat(rule)
.isNotNull() .isNotNull()
@@ -301,14 +310,16 @@ public class RulesImplTest extends TestCase
org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class); org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class);
given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule); given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule);
given(serviceRule.getNodeRef()).willReturn(ruleNodeRef); given(serviceRule.getNodeRef()).willReturn(ruleNodeRef);
given(serviceRule.getAction()).willReturn(action);
// when // when
List<Rule> actual = rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList); List<Rule> actual = rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList);
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef); then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock)); then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock));
then(ruleServiceMock).shouldHaveNoMoreInteractions(); then(ruleServiceMock).shouldHaveNoMoreInteractions();
List<Rule> expected = List.of(Rule.from(serviceRule)); List<Rule> expected = List.of(Rule.from(serviceRule, false));
assertThat(actual).isEqualTo(expected); assertThat(actual).isEqualTo(expected);
} }
@@ -320,24 +331,27 @@ public class RulesImplTest extends TestCase
List<Rule> ruleList = List.of(ruleBody); List<Rule> ruleList = List.of(ruleBody);
org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class); org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class);
given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody); given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody);
given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef);
org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class); org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class);
given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule); given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule);
given(serviceRule.getNodeRef()).willReturn(ruleNodeRef); given(serviceRule.getNodeRef()).willReturn(ruleNodeRef);
given(serviceRule.getAction()).willReturn(action);
// when // when
List<Rule> actual = rules.createRules(folderNodeRef.getId(), DEFAULT_ID, ruleList); List<Rule> actual = rules.createRules(folderNodeRef.getId(), DEFAULT_ID, ruleList);
then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock)); then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock));
then(ruleServiceMock).shouldHaveNoMoreInteractions(); then(ruleServiceMock).shouldHaveNoMoreInteractions();
List<Rule> expected = List.of(Rule.from(serviceRule)); List<Rule> expected = List.of(Rule.from(serviceRule, false));
assertThat(actual).isEqualTo(expected); assertThat(actual).isEqualTo(expected);
} }
@Test @Test
public void testSaveRules_ruleSetNotAssociatedWithFolder() public void testSaveRules_ruleSetNotAssociatedWithFolder()
{ {
Rule rule = Rule.builder().setName(RULE_NAME) Rule rule = Rule.builder().name(RULE_NAME).create();
.createRule();
List<Rule> ruleList = List.of(rule); List<Rule> ruleList = List.of(rule);
given(ruleServiceMock.isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef)).willReturn(false); given(ruleServiceMock.isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef)).willReturn(false);
@@ -380,7 +394,8 @@ public class RulesImplTest extends TestCase
given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule); given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule);
NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, ruleId); NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, ruleId);
given(serviceRule.getNodeRef()).willReturn(ruleNodeRef); given(serviceRule.getNodeRef()).willReturn(ruleNodeRef);
expected.add(Rule.from(serviceRule)); given(serviceRule.getAction()).willReturn(action);
expected.add(Rule.from(serviceRule, false));
} }
// when // when
@@ -391,6 +406,7 @@ public class RulesImplTest extends TestCase
{ {
then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock)); then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock));
} }
then(ruleServiceMock).should(times(ruleBodyList.size())).isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions(); then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(actual).isEqualTo(expected); assertThat(actual).isEqualTo(expected);
} }
@@ -552,8 +568,11 @@ public class RulesImplTest extends TestCase
private static org.alfresco.service.cmr.rule.Rule createRule(final String id) { private static org.alfresco.service.cmr.rule.Rule createRule(final String id) {
final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id);
final org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule(); final org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule();
rule.setNodeRef(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id)); rule.setNodeRef(nodeRef);
rule.setRuleType("ruleType");
rule.setAction(action);
return rule; return rule;
} }

View File

@@ -0,0 +1,116 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.api.model.rules;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import org.alfresco.repo.action.ActionConditionImpl;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.executer.ScriptActionExecuter;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.Action;
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.assertj.core.api.Condition;
import org.junit.Test;
@Experimental
public class RuleTest
{
private static final String RULE_ID = "fake-rule-id";
private static final String RULE_NAME = "rule name";
private static final String RULE_DESCRIPTION = "rule description";
private static final boolean RULE_ENABLED = true;
private static final boolean RULE_CASCADE = true;
private static final boolean RULE_ASYNC = false;
private static final boolean RULE_SHARED = true;
private static final String ERROR_SCRIPT = "error-script-ref";
@Test
public void testFrom()
{
final org.alfresco.service.cmr.rule.Rule ruleModel = createRuleModel();
final Rule expectedRule = createRuleWithDefaultValues();
// when
final Rule actualRule = Rule.from(ruleModel, RULE_SHARED);
assertThat(actualRule).isNotNull().usingRecursiveComparison().isEqualTo(expectedRule);
}
@Test
public void testFromRuleModelWithNullValues()
{
final org.alfresco.service.cmr.rule.Rule ruleModel = new org.alfresco.service.cmr.rule.Rule();
final Rule expectedRule = Rule.builder().enabled(true).create();
// when
final Rule actualRule = Rule.from(ruleModel, false);
assertThat(actualRule).isNotNull().usingRecursiveComparison().isEqualTo(expectedRule);
}
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);
ruleModel.setTitle(RULE_NAME);
ruleModel.setDescription(RULE_DESCRIPTION);
ruleModel.setRuleDisabled(!RULE_ENABLED);
ruleModel.applyToChildren(RULE_CASCADE);
ruleModel.setExecuteAsynchronously(RULE_ASYNC);
ruleModel.setRuleTypes(List.of(RuleType.INBOUND, RuleType.UPDATE));
final Action compensatingAction = new ActionImpl(nodeRef, "compensatingActionId", "compensatingActionDefName");
compensatingAction.setParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF, ERROR_SCRIPT);
final ActionCondition actionCondition = new ActionConditionImpl("actionConditionId", "actionConditionDefName");
final Action action = new ActionImpl(nodeRef, "actionId", "actionDefName");
action.setCompensatingAction(compensatingAction);
action.addActionCondition(actionCondition);
ruleModel.setAction(action);
return ruleModel;
}
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)
.shared(RULE_SHARED)
.triggers(List.of(RuleTrigger.INBOUND, RuleTrigger.UPDATE))
.errorScript(ERROR_SCRIPT)
.create();
}
}

View File

@@ -25,6 +25,15 @@
*/ */
package org.alfresco.repo.rule; package org.alfresco.repo.rule;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.ActionImpl; import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.ActionModel; import org.alfresco.repo.action.ActionModel;
@@ -65,15 +74,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.ParameterCheck; import org.springframework.extensions.surf.util.ParameterCheck;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** /**
* Rule service implementation. * Rule service implementation.
* <p> * <p>
@@ -1595,7 +1595,7 @@ public class RuleServiceImpl
public List<NodeRef> getLinkedFromRuleNodes(NodeRef nodeRef) public List<NodeRef> getLinkedFromRuleNodes(NodeRef nodeRef)
{ {
List<NodeRef> result = new ArrayList<NodeRef>(); List<NodeRef> result = new ArrayList<NodeRef>();
if (nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true) if (nodeService.hasAspect(nodeRef, RuleModel.ASPECT_RULES) == true)
{ {
ChildAssociationRef assoc = getSavedRuleFolderAssoc(nodeRef); ChildAssociationRef assoc = getSavedRuleFolderAssoc(nodeRef);
@@ -1616,13 +1616,9 @@ public class RuleServiceImpl
@Override @Override
@Experimental @Experimental
public NodeRef getRuleSetNode(final NodeRef folderNodeRef) { public NodeRef getRuleSetNode(final NodeRef folderNodeRef)
return getPrimaryChildNode(folderNodeRef, RuleModel.ASSOC_RULE_FOLDER); {
} return runtimeNodeService.getChildAssocs(folderNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER).stream()
private NodeRef getPrimaryChildNode(final NodeRef nodeRef, final QNamePattern associationType) {
return runtimeNodeService.getChildAssocs(nodeRef, associationType, associationType).stream()
.filter(ChildAssociationRef::isPrimary)
.map(ChildAssociationRef::getChildRef) .map(ChildAssociationRef::getChildRef)
.findFirst() .findFirst()
.orElse(null); .orElse(null);
@@ -1630,17 +1626,20 @@ public class RuleServiceImpl
@Override @Override
@Experimental @Experimental
public boolean isRuleSetAssociatedWithFolder(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef) { public boolean isRuleSetAssociatedWithFolder(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef)
{
return isChildOf(ruleSetNodeRef, RuleModel.ASSOC_RULE_FOLDER, folderNodeRef); return isChildOf(ruleSetNodeRef, RuleModel.ASSOC_RULE_FOLDER, folderNodeRef);
} }
@Override @Override
@Experimental @Experimental
public boolean isRuleAssociatedWithRuleSet(final NodeRef ruleNodeRef, final NodeRef ruleSetNodeRef) { public boolean isRuleAssociatedWithRuleSet(final NodeRef ruleNodeRef, final NodeRef ruleSetNodeRef)
{
return isChildOf(ruleNodeRef, null, ruleSetNodeRef); return isChildOf(ruleNodeRef, null, ruleSetNodeRef);
} }
private boolean isChildOf(final NodeRef childNodeRef, final QNamePattern associationType, final NodeRef parentNodeRef) { private boolean isChildOf(final NodeRef childNodeRef, final QNamePattern associationType, final NodeRef parentNodeRef)
{
final List<ChildAssociationRef> associations; final List<ChildAssociationRef> associations;
if (associationType == null) { if (associationType == null) {
associations = runtimeNodeService.getParentAssocs(childNodeRef); associations = runtimeNodeService.getParentAssocs(childNodeRef);
@@ -1652,4 +1651,12 @@ public class RuleServiceImpl
.map(ChildAssociationRef::getParentRef) .map(ChildAssociationRef::getParentRef)
.anyMatch(parentNodeRef::equals); .anyMatch(parentNodeRef::equals);
} }
@Override
@Experimental
public boolean isRuleSetShared(final NodeRef ruleSetNodeRef)
{
return runtimeNodeService.getParentAssocs(ruleSetNodeRef).stream()
.anyMatch(association -> !association.isPrimary());
}
} }

View File

@@ -362,4 +362,14 @@ public interface RuleService
@Auditable(parameters = {"ruleNodeRef", "ruleSetNodeRef"}) @Auditable(parameters = {"ruleNodeRef", "ruleSetNodeRef"})
@Experimental @Experimental
boolean isRuleAssociatedWithRuleSet(final NodeRef ruleNodeRef, final NodeRef ruleSetNodeRef); boolean isRuleAssociatedWithRuleSet(final NodeRef ruleNodeRef, final NodeRef ruleSetNodeRef);
/**
* Check if others folders are linked to rule set.
*
* @param ruleSetNodeRef - node reference of a rule set
* @return true if others folders are linked to rule set
*/
@Auditable(parameters = {"ruleSetNodeRef"})
@Experimental
boolean isRuleSetShared(final NodeRef ruleSetNodeRef);
} }

View File

@@ -25,6 +25,12 @@
*/ */
package org.alfresco.repo.rule; package org.alfresco.repo.rule;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator; import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator;
@@ -51,12 +57,6 @@ import org.junit.Test;
import org.junit.experimental.categories.Category; import org.junit.experimental.categories.Category;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* Parameter definition implementation unit test. * Parameter definition implementation unit test.
* *
@@ -364,6 +364,19 @@ public class RuleLinkTest extends BaseSpringTest
assertEquals(expectedRuleSetNodeRef, ruleSetNodeRef); assertEquals(expectedRuleSetNodeRef, ruleSetNodeRef);
} }
@Test
public void testGetRuleSetNodeForLinkedFolder() {
final Rule rule = createTestRule(false, "luke");
this.ruleService.saveRule(folderOne, rule);
link(folderOne, folderTwo);
final NodeRef expectedRuleSetNodeRef = getRuleSetNode(folderOne);
final NodeRef ruleSetNodeRef = ruleService.getRuleSetNode(folderTwo);
assertNotNull(ruleSetNodeRef);
assertEquals(expectedRuleSetNodeRef, ruleSetNodeRef);
}
@Test @Test
public void testIsRuleSetAssociatedWithFolder() public void testIsRuleSetAssociatedWithFolder()
{ {
@@ -425,6 +438,33 @@ public class RuleLinkTest extends BaseSpringTest
assertFalse(associated); assertFalse(associated);
} }
@Test
public void testIsRuleSetShared()
{
final Rule rule = createTestRule(false, "luke");
this.ruleService.saveRule(folderOne, rule);
link(folderOne, folderTwo);
final NodeRef ruleSetNodeRef = ruleService.getRuleSetNode(folderOne);
// when
final boolean shared = ruleService.isRuleSetShared(ruleSetNodeRef);
assertTrue(shared);
}
@Test
public void testIsRuleSetNotShared()
{
final Rule rule = createTestRule(false, "luke");
this.ruleService.saveRule(folderOne, rule);
final NodeRef ruleSetNodeRef = ruleService.getRuleSetNode(folderOne);
// when
final boolean shared = ruleService.isRuleSetShared(ruleSetNodeRef);
assertFalse(shared);
}
protected Rule createTestRule(boolean isAppliedToChildren, String title) protected Rule createTestRule(boolean isAppliedToChildren, String title)
{ {
// Rule properties // Rule properties