ACS-3198: Folder rules v1 REST API - List rules for node (#1193)

ACS-3198: Rules v1 REST API - List rules for a folder node
This commit is contained in:
krdabrowski
2022-07-07 19:40:47 +02:00
committed by GitHub
parent 9e7b8fcdce
commit 101eb1843d
20 changed files with 1226 additions and 74 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2011 Alfresco Software Limited.
* Copyright (C) 2005-2022 Alfresco Software Limited.
*
* This file is part of Alfresco
*
@@ -16,6 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.query;
import java.util.Collections;
@@ -55,7 +56,7 @@ public class ListBackedPagingResults<R> implements PagingResults<R>
}
this.results = Collections.unmodifiableList(
list.subList(start, end));
list.subList(Math.min(start, end), end));
this.size = list.size();
this.hasMore = ! (list.size() == end);
}

View File

@@ -65,6 +65,7 @@
<dependency.webscripts.version>8.31</dependency.webscripts.version>
<dependency.bouncycastle.version>1.70</dependency.bouncycastle.version>
<dependency.mockito-core.version>4.6.1</dependency.mockito-core.version>
<dependency.assertj.version>3.23.1</dependency.assertj.version>
<dependency.org-json.version>20220320</dependency.org-json.version>
<dependency.commons-dbcp.version>2.9.0</dependency.commons-dbcp.version>
<dependency.commons-io.version>2.11.0</dependency.commons-io.version>
@@ -755,6 +756,11 @@
<artifactId>mockito-core</artifactId>
<version>${dependency.mockito-core.version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${dependency.assertj.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>

View File

@@ -87,6 +87,11 @@
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>

View File

@@ -0,0 +1,50 @@
/*
* #%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.model.Rule;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.service.Experimental;
/**
* Folder node rules API.
*
*/
@Experimental
public interface Rules
{
/**
* Get rules for node's and rule set's IDs
*
* @param folderNodeId node ID
* @param ruleSetId rule set ID
* @param paging {@link Paging} information
* @return {@link CollectionWithPagingInfo} containing a list page of folder rules
*/
CollectionWithPagingInfo<Rule> getRules(String folderNodeId, String ruleSetId, Paging paging);
}

View File

@@ -0,0 +1,129 @@
/*
* #%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.impl;
import org.alfresco.model.ContentModel;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.Rules;
import org.alfresco.rest.api.model.Rule;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.ListPage;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Experimental
public class RulesImpl implements Rules
{
private static final String DEFAULT_RULE_SET_ID = "-default-";
private Nodes nodes;
private PermissionService permissionService;
private RuleService ruleService;
@Override
public CollectionWithPagingInfo<Rule> getRules(final String folderNodeId, final String ruleSetId, final Paging paging)
{
final NodeRef folderNodeRef = validateNode(folderNodeId, ContentModel.TYPE_FOLDER);
if (isNotDefaultId(ruleSetId)) {
final NodeRef ruleSetNodeRef = validateNode(ruleSetId, ContentModel.TYPE_SYSTEM_FOLDER, "rule set");
if (!ruleService.isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef)) {
throw new InvalidArgumentException("Rule set is not associated with folder node!");
}
}
final List<Rule> rules = ruleService.getRules(folderNodeRef).stream()
.map(Rule::from)
.collect(Collectors.toList());
return ListPage.of(rules, paging);
}
public void setNodes(Nodes nodes)
{
this.nodes = nodes;
}
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
public void setRuleService(RuleService ruleService)
{
this.ruleService = ruleService;
}
private NodeRef validateNode(final String nodeId, final QName namespaceType)
{
return validateNode(nodeId, namespaceType, null);
}
/**
* Validates if node exists, user have permission to read from it and is of a given type.
*
* @param nodeId - node ID
* @param expectedType - expected type
* @param expectedTypeName - expected type local name
* @return node reference
*/
private NodeRef validateNode(final String nodeId, final QName expectedType, final String expectedTypeName)
{
final NodeRef nodeRef = nodes.validateNode(nodeId);
if (permissionService.hasReadPermission(nodeRef) != AccessStatus.ALLOWED) {
throw new PermissionDeniedException("Cannot read from this node!");
}
final Set<QName> expectedTypes = Set.of(expectedType);
if (!nodes.nodeMatches(nodeRef, expectedTypes, null)) {
final String expectedTypeLocalName = (expectedTypeName != null)? expectedTypeName : expectedType.getLocalName();
throw new InvalidArgumentException(String.format("NodeId of a %s is expected!", expectedTypeLocalName));
}
return nodeRef;
}
private static boolean isNotDefaultId(final String ruleSetId) {
return !DEFAULT_RULE_SET_ID.equals(ruleSetId);
}
}

View File

@@ -0,0 +1,70 @@
/*
* #%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;
import org.alfresco.rest.framework.resource.UniqueId;
import org.alfresco.service.Experimental;
@Experimental
public class Rule
{
private String id;
private String name;
public static Rule from(final org.alfresco.service.cmr.rule.Rule ruleModel) {
if (ruleModel == null) {
return null;
}
final Rule rule = new Rule();
rule.id = ruleModel.getNodeRef().getId();
rule.name = ruleModel.getTitle();
return rule;
}
@UniqueId
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}

View File

@@ -0,0 +1,40 @@
/*
* #%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.nodes;
import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.service.Experimental;
/**
* Folder node rule sets.
*
*/
@Experimental
@RelationshipResource(name = "rule-sets", entityResource = NodesEntityResource.class, title = "Folder node rule sets")
public class NodeRuleSetsRelation
{
}

View File

@@ -0,0 +1,85 @@
/*
* #%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.nodes;
import org.alfresco.rest.api.Rules;
import org.alfresco.rest.api.model.Rule;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.Experimental;
import org.alfresco.util.PropertyCheck;
import org.springframework.beans.factory.InitializingBean;
import javax.servlet.http.HttpServletResponse;
/**
* Folder node's rules.
*
*/
@Experimental
@RelationshipResource(name = "rules", entityResource = NodeRuleSetsRelation.class, title = "Folder node rules")
public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>, InitializingBean
{
private Rules rules;
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "rules", this.rules);
}
/**
* List folder node rules for given node's and rule set's IDs as a page.
*
* - GET /nodes/{folderNodeId}/rulesets/{ruleSetId}/rules
*
* @param folderNodeId - entity resource context for this relationship
* @param parameters - will never be null. Contains i.a. paging information and ruleSetId (relationshipId)
* @return a paged list of folder rules
*/
@WebApiDescription(
title = "Get folder node rules",
description = "Returns a paged list of folder rules for given node's and rule set's ID",
successStatus = HttpServletResponse.SC_OK
)
@Override
public CollectionWithPagingInfo<Rule> readAll(String folderNodeId, Parameters parameters)
{
final String ruleSetId = parameters.getRelationshipId();
return rules.getRules(folderNodeId, ruleSetId, parameters.getPaging());
}
public void setRules(Rules rules)
{
this.rules = rules;
}
}

View File

@@ -0,0 +1,123 @@
/*
* #%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.framework.resource.parameters;
import org.alfresco.rest.api.search.context.SearchContext;
import org.alfresco.service.Experimental;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Experimental
public class ArrayListPage<E> extends ArrayList<E> implements ListPage<E>
{
private final Paging paging;
private final int totalItems;
private final boolean hasMore;
public ArrayListPage(final List<? extends E> list)
{
super(list != null ? list : Collections.emptyList());
this.paging = null;
this.totalItems = this.size();
this.hasMore = false;
}
public ArrayListPage(final List<? extends E> list, final Paging paging)
{
super(sublistFrom(list, paging));
this.paging = paging;
if (list != null)
{
this.totalItems = list.size();
if (paging != null)
{
final int start = paging.getSkipCount();
final int end = (paging.getMaxItems() == 0) ? list.size() : Math.min(list.size(), start + paging.getMaxItems());
this.hasMore = !(list.size() == end);
} else {
this.hasMore = false;
}
} else {
this.totalItems = 0;
this.hasMore = false;
}
}
@Override
public Paging getPaging()
{
return paging;
}
@Override
public Integer getTotalItems()
{
return totalItems;
}
@Override
public boolean hasMoreItems()
{
return hasMore;
}
@Override
public String getQueryExecutionId()
{
return null;
}
@Override
public Object getSourceEntity()
{
return null;
}
@Override
public SearchContext getContext()
{
return null;
}
private static <E> List<? extends E> sublistFrom(final List<? extends E> list, final Paging paging)
{
if (list == null)
{
return Collections.emptyList();
}
if (paging == null)
{
return list;
}
final int start = paging.getSkipCount();
final int end = (paging.getMaxItems() == 0)? list.size() : Math.min(list.size(), start + paging.getMaxItems());
return list.subList(Math.min(start, end), end);
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -43,7 +43,7 @@ import java.util.Collections;
*
* @author Gethin James.
*/
public class CollectionWithPagingInfo<T> implements SerializablePagedCollection
public class CollectionWithPagingInfo<T> implements SerializablePagedCollection<T>
{
private final Collection<T> collection;
@@ -80,6 +80,18 @@ public class CollectionWithPagingInfo<T> implements SerializablePagedCollection
this.context = context;
}
/**
* Constructs a new CollectionWithPagingInfo from a {@link SerializablePagedCollection} instance.
*
* @param pagedCollection - a collection with paging information
* @return CollectionWithPagingInfo
*/
public static <T> CollectionWithPagingInfo<T> from(SerializablePagedCollection<T> pagedCollection)
{
return new CollectionWithPagingInfo<>(pagedCollection.getCollection(), pagedCollection.getPaging(), pagedCollection.hasMoreItems(), pagedCollection.getTotalItems(),
pagedCollection.getSourceEntity(), pagedCollection.getContext());
}
/**
* Constructs a new CollectionWithPagingInfo.
* It automatically sets the total items based on the collection size and

View File

@@ -0,0 +1,80 @@
/*
* #%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.framework.resource.parameters;
import org.alfresco.query.PagingResults;
import org.alfresco.rest.framework.resource.SerializablePagedCollection;
import org.alfresco.service.Experimental;
import org.alfresco.util.Pair;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* List page with paging information.
*
*
* @param <E> - list element type
*/
@Experimental
public interface ListPage<E> extends List<E>, PagingResults<E>, SerializablePagedCollection<E>
{
default List<E> getPage()
{
return this;
}
default Pair<Integer, Integer> getTotalResultCount()
{
return new Pair<>(this.getTotalItems(), this.getTotalItems());
}
default Collection<E> getCollection()
{
return this;
}
/**
* Builds a collection with paging information.
*
* @param list - the list that needs to be paged
* @param paging - paging request info
* @return list page in {@link CollectionWithPagingInfo}
* @param <E> - list element type
*/
static <E> CollectionWithPagingInfo<E> of(final List<? extends E> list, final Paging paging)
{
if (list == null)
{
return CollectionWithPagingInfo.asPaged(paging, Collections.emptyList());
}
return CollectionWithPagingInfo.from(new ArrayListPage<>(list, paging));
}
}

View File

@@ -850,6 +850,26 @@
</property>
</bean>
<bean id="rules" class="org.alfresco.rest.api.impl.RulesImpl">
<property name="nodes" ref="Nodes" />
<property name="permissionService" ref="PermissionService"/>
<property name="ruleService" ref="RuleService" />
</bean>
<bean id="Rules" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="org.alfresco.rest.api.Rules"/>
<property name="target" ref="rules"/>
<property name="interceptorNames">
<list>
<idref bean="legacyExceptionInterceptor" />
</list>
</property>
</bean>
<bean class="org.alfresco.rest.api.nodes.NodeRulesRelation">
<property name="rules" ref="Rules" />
</bean>
<bean id="publicapi.mimeTypePropertyLookup" class="org.alfresco.rest.api.lookups.MimeTypePropertyLookup">
<property name="serviceRegistry" ref="ServiceRegistry"/>
<property name="supported">

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -49,6 +49,8 @@ import org.junit.runners.Suite;
org.alfresco.repo.webdav.WebDAVHelperTest.class,
org.alfresco.repo.webdav.WebDAVLockServiceImplTest.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.search.ResultMapperTests.class,
org.alfresco.rest.api.search.SearchApiWebscriptTests.class,
@@ -56,6 +58,7 @@ import org.junit.runners.Suite;
org.alfresco.rest.api.search.SearchQuerySerializerTests.class,
org.alfresco.rest.api.search.StoreMapperTests.class,
org.alfresco.rest.api.tests.ModulePackageTest.class,
org.alfresco.rest.framework.resource.parameters.ArrayListPageTest.class,
org.alfresco.rest.framework.tests.core.InspectorTests.class,
org.alfresco.rest.framework.tests.core.JsonJacksonTests.class,
org.alfresco.rest.framework.tests.core.ParamsExtractorTests.class,

View File

@@ -0,0 +1,193 @@
/*
* #%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.impl;
import junit.framework.TestCase;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.Rule;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.service.Experimental;
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.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
@Experimental
@RunWith(MockitoJUnitRunner.class)
public class RulesImplTest extends TestCase
{
private static final String FOLDER_NODE_ID = "dummy-node-id";
private static final String RULE_SET_ID = "dummy-rule-set-id";
private static final NodeRef folderNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_NODE_ID);
private static final NodeRef ruleSetNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
@Mock
private Nodes nodes;
@Mock
private PermissionService permissionService;
@Mock
private RuleService ruleService;
@InjectMocks
private RulesImpl rules;
@Before
@Override
public void setUp() throws Exception
{
MockitoAnnotations.openMocks(this);
given(nodes.validateNode(eq(FOLDER_NODE_ID))).willReturn(folderNodeRef);
given(nodes.validateNode(eq(RULE_SET_ID))).willReturn(ruleSetNodeRef);
given(nodes.nodeMatches(any(), any(), any())).willReturn(true);
given(permissionService.hasReadPermission(any())).willReturn(AccessStatus.ALLOWED);
}
@Test
public void testGetRules()
{
final Paging paging = Paging.DEFAULT;
given(ruleService.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
// when
final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging);
then(nodes).should().validateNode(eq(FOLDER_NODE_ID));
then(nodes).should().validateNode(eq(RULE_SET_ID));
then(nodes).should().nodeMatches(eq(folderNodeRef), any(), isNull());
then(nodes).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
then(nodes).shouldHaveNoMoreInteractions();
then(permissionService).should().hasReadPermission(eq(folderNodeRef));
then(permissionService).should().hasReadPermission(eq(ruleSetNodeRef));
then(permissionService).shouldHaveNoMoreInteractions();
then(ruleService).should().isRuleSetAssociatedWithFolder(eq(ruleSetNodeRef), eq(folderNodeRef));
then(ruleService).should().getRules(eq(folderNodeRef));
then(ruleService).shouldHaveNoMoreInteractions();
assertThat(rulesPage)
.isNotNull()
.extracting(CollectionWithPagingInfo::getCollection)
.isNotNull();
}
@Test
public void testGetRulesForDefaultRuleSet()
{
final String defaultRuleSetId = "-default-";
final Paging paging = Paging.DEFAULT;
// when
final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, defaultRuleSetId, paging);
then(nodes).should().validateNode(eq(FOLDER_NODE_ID));
then(nodes).should().nodeMatches(eq(folderNodeRef), any(), isNull());
then(nodes).shouldHaveNoMoreInteractions();
then(permissionService).should().hasReadPermission(eq(folderNodeRef));
then(permissionService).shouldHaveNoMoreInteractions();
then(ruleService).should().getRules(eq(folderNodeRef));
then(ruleService).shouldHaveNoMoreInteractions();
assertThat(rulesPage)
.isNotNull()
.extracting(CollectionWithPagingInfo::getCollection)
.isNotNull();
}
@Test
public void testGetRulesForNotExistingFolderNode()
{
final Paging paging = Paging.DEFAULT;
given(nodes.nodeMatches(eq(folderNodeRef), any(), any())).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging));
then(ruleService).shouldHaveNoInteractions();
}
@Test
public void testGetRulesForNotExistingRuleSetNode()
{
final Paging paging = Paging.DEFAULT;
given(nodes.nodeMatches(eq(folderNodeRef), any(), any())).willReturn(true);
given(nodes.nodeMatches(eq(ruleSetNodeRef), any(), any())).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging));
then(ruleService).shouldHaveNoInteractions();
}
@Test
public void testGetRulesForNotAssociatedRuleSetToFolder()
{
final Paging paging = Paging.DEFAULT;
given(ruleService.isRuleSetAssociatedWithFolder(any(), any())).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging));
then(ruleService).should().isRuleSetAssociatedWithFolder(eq(ruleSetNodeRef), eq(folderNodeRef));
then(ruleService).shouldHaveNoMoreInteractions();
}
@Test
public void testGetRulesWithoutReadPermission()
{
final Paging paging = Paging.DEFAULT;
given(permissionService.hasReadPermission(any())).willReturn(AccessStatus.DENIED);
// when
assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(
() -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging));
then(ruleService).shouldHaveNoInteractions();
}
}

View File

@@ -0,0 +1,80 @@
/*
* #%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.nodes;
import junit.framework.TestCase;
import org.alfresco.rest.api.Rules;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.framework.resource.parameters.Params;
import org.alfresco.service.Experimental;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.then;
@Experimental
@RunWith(MockitoJUnitRunner.class)
public class NodeRulesRelationTest extends TestCase
{
private static final String FOLDER_NODE_ID = "dummy-node-id";
private static final String RULE_SET_ID = "dummy-rule-set-id";
@Mock
private Rules rules;
@InjectMocks
private NodeRulesRelation nodeRulesRelation;
@Override
@Before
public void setUp() throws Exception
{
MockitoAnnotations.openMocks(this);
}
@Test
public void testReadAll()
{
final Paging paging = Paging.DEFAULT;
final Params.RecognizedParams params = new Params.RecognizedParams(null, paging, null, null, null, null, null, null, false);
final Parameters parameters = Params.valueOf(FOLDER_NODE_ID, RULE_SET_ID, params, null, null);
// when
nodeRulesRelation.readAll(FOLDER_NODE_ID, parameters);
then(rules).should().getRules(eq(FOLDER_NODE_ID), eq(RULE_SET_ID), eq(paging));
then(rules).shouldHaveNoMoreInteractions();
}
}

View File

@@ -0,0 +1,198 @@
/*
* #%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.framework.resource.parameters;
import junit.framework.TestCase;
import org.alfresco.rest.framework.resource.SerializablePagedCollection;
import org.alfresco.service.Experimental;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@Experimental
@RunWith(MockitoJUnitRunner.class)
public class ArrayListPageTest extends TestCase
{
private List<PageFormat> getPageFormats() {
return List.of(
new PageFormat(10, 0),
new PageFormat(10, 10),
new PageFormat(110, 20)
);
}
@Test
public void testCreatePage()
{
final List<PageFormat> pageFormats = getPageFormats();
for (PageFormat pageFormat : pageFormats)
{
final int pageSize = pageFormat.size;
final int offset = pageFormat.offset;
final List<Object> list = randomListOf(offset,100, Object.class);
final Paging paging = Paging.valueOf(offset, pageSize);
// when
final SerializablePagedCollection<Object> page = new ArrayListPage<>(list, paging);
assertThat(page)
.isNotNull()
.extracting(SerializablePagedCollection::getCollection)
.isNotNull()
.isEqualTo(list.subList(offset, Math.min(offset + pageSize, list.size())))
.extracting(Collection::size)
.isEqualTo(Math.min(pageSize, list.size() - offset));
assertThat(page.getTotalItems())
.isEqualTo(list.size());
assertThat(page.hasMoreItems())
.isEqualTo(list.size() - offset > pageSize);
assertThat(page.getPaging())
.isNotNull();
}
}
@Test
public void testCreatePageWithoutPaging()
{
final List<Object> list = randomListOf(0,100, Object.class);
// when
final SerializablePagedCollection<Object> page = new ArrayListPage<>(list);
assertThat(page)
.isNotNull()
.extracting(SerializablePagedCollection::getCollection)
.isNotNull()
.isEqualTo(list)
.extracting(Collection::size)
.isEqualTo(list.size());
assertThat(page.getTotalItems())
.isEqualTo(list.size());
assertThat(page.hasMoreItems())
.isFalse();
assertThat(page.getPaging())
.isNull();
}
@Test
public void testCreatePageForBiggerOffsetThanListSize()
{
final int offset = 10;
final List<Object> list = createListOf(8, Object.class);
final Paging paging = Paging.valueOf(offset, 5);
// when
final SerializablePagedCollection<Object> page = new ArrayListPage<>(list, paging);
assertThat(page)
.isNotNull()
.extracting(SerializablePagedCollection::getCollection)
.isNotNull()
.extracting(Collection::isEmpty)
.isEqualTo(true);
assertThat(page.getTotalItems())
.isEqualTo(list.size());
assertThat(page.hasMoreItems())
.isFalse();
}
@Test
public void testCreatePageForNullList()
{
// when
final SerializablePagedCollection<Object> page = new ArrayListPage<>(null, Paging.DEFAULT);
assertThat(page)
.isNotNull()
.extracting(SerializablePagedCollection::getCollection)
.isNotNull()
.extracting(Collection::isEmpty)
.isEqualTo(true);
assertThat(page.getTotalItems())
.isEqualTo(0);
assertThat(page.hasMoreItems())
.isFalse();
}
@Test
public void testCreatePageForNullPaging()
{
final List<Object> list = createListOf(18, Object.class);
// when
final SerializablePagedCollection<Object> page = new ArrayListPage<>(list, null);
assertThat(page)
.isNotNull()
.extracting(SerializablePagedCollection::getCollection)
.isNotNull()
.extracting(Collection::size)
.isEqualTo(list.size());
assertThat(page.getTotalItems())
.isEqualTo(list.size());
assertThat(page.hasMoreItems())
.isFalse();
assertThat(page.getPaging())
.isNull();
}
private static <T> List<T> randomListOf(final int minSize, final int maxSize, final Class<T> clazz) {
return createListOf(new Random().nextInt((maxSize - minSize) + 1) + minSize, clazz);
}
private static <T> List<T> createListOf(final int size, final Class<T> clazz) {
final List<T> list = new ArrayList<>();
for (int i = 0; i < size; i++) {
list.add(mock(clazz));
}
Collections.shuffle(list);
return list;
}
private static final class PageFormat
{
private final int size;
private final int offset;
public PageFormat(int size, int offset)
{
this.size = size;
this.offset = offset;
}
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -25,15 +25,6 @@
*/
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.repo.action.ActionImpl;
import org.alfresco.repo.action.ActionModel;
@@ -66,12 +57,22 @@ import org.alfresco.service.cmr.rule.RuleType;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.QNamePattern;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.
* <p>
@@ -1611,4 +1612,15 @@ public class RuleServiceImpl
}
return result;
}
@Override
public boolean isRuleSetAssociatedWithFolder(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef) {
return findAssociatedParents(ruleSetNodeRef, RuleModel.ASSOC_RULE_FOLDER).stream()
.map(ChildAssociationRef::getParentRef)
.anyMatch(folderNodeRef::equals);
}
private List<ChildAssociationRef> findAssociatedParents(final NodeRef nodeRef, final QNamePattern pattern) {
return runtimeNodeService.getParentAssocs(nodeRef, pattern, pattern);
}
}

View File

@@ -1,28 +1,28 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.service.cmr.rule;
import java.io.Serializable;
@@ -70,7 +70,7 @@ public class Rule implements Serializable
/**
* The associated action
*/
private Action action;
private Action action;
/**
* Indicates whether the rule should execute the action asynchronously or not

View File

@@ -1,28 +1,28 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.service.cmr.rule;
import java.util.List;
@@ -329,4 +329,14 @@ public interface RuleService
*/
@Auditable(parameters = {"nodeRef"})
public List<NodeRef> getLinkedFromRuleNodes(NodeRef nodeRef);
/**
* Check if rule set's associated parent is equal to folder node.
*
* @param ruleSetNodeRef - node reference of a rule set
* @param folderNodeRef - node reference of a folder
* @return true if rule set is associated with folder
*/
@Auditable(parameters = {"nodeRef"})
boolean isRuleSetAssociatedWithFolder(NodeRef ruleSetNodeRef, NodeRef folderNodeRef);
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -25,12 +25,6 @@
*/
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.model.ContentModel;
import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator;
@@ -41,6 +35,7 @@ import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionCondition;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
@@ -56,6 +51,12 @@ import org.junit.Test;
import org.junit.experimental.categories.Category;
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.
*
@@ -350,7 +351,41 @@ public class RuleLinkTest extends BaseSpringTest
assertTrue(nodeService.hasAspect(folderThree, RuleModel.ASPECT_RULES));
assertEquals(rules1, rules3);
}
@Test
public void testIsRuleSetAssociatedWithFolder()
{
final Rule rule = createTestRule(false, "luke");
this.ruleService.saveRule(folderOne, rule);
final NodeRef ruleSetNodeRef = nodeService.getChildAssocs(folderOne, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER).stream()
.filter(ChildAssociationRef::isPrimary)
.map(ChildAssociationRef::getChildRef)
.findFirst()
.orElse(null);
// when
final boolean associated = ruleService.isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderOne);
assertTrue(associated);
}
@Test
public void testIsRuleSetNotAssociatedWithFolder()
{
final Rule rule = createTestRule(false, "luke");
this.ruleService.saveRule(folderTwo , rule);
final NodeRef ruleSetNodeRef = nodeService.getChildAssocs(folderTwo, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER).stream()
.filter(ChildAssociationRef::isPrimary)
.map(ChildAssociationRef::getChildRef)
.findFirst()
.orElse(null);
// when
final boolean associated = ruleService.isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderOne);
assertFalse(associated);
}
protected Rule createTestRule(boolean isAppliedToChildren, String title)
{
// Rule properties