Merge branch 'feature/RM-6796_DeclareAndFileTests' into 'master'

RM-6796 Automated tests for Declare and file to a record folder functionality

See merge request records-management/records-management!1164
This commit is contained in:
Claudia Agache
2019-05-22 13:51:08 +01:00
35 changed files with 1072 additions and 183 deletions

View File

@@ -85,5 +85,10 @@
<artifactId>commons-collections4</artifactId> <artifactId>commons-collections4</artifactId>
<version>4.1</version> <version>4.1</version>
</dependency> </dependency>
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java</artifactId>
<version>3.0.14</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -56,4 +56,7 @@ public class RMRestProperties extends RestProperties
@Value ("${rest.rmPath}") @Value ("${rest.rmPath}")
private String restRmPath; private String restRmPath;
@Value ("${docker.host}")
private String dockerHost;
} }

View File

@@ -34,6 +34,7 @@ import org.alfresco.rest.requests.Node;
import org.alfresco.rest.requests.coreAPI.RestCoreAPI; import org.alfresco.rest.requests.coreAPI.RestCoreAPI;
import org.alfresco.rest.requests.search.SearchAPI; import org.alfresco.rest.requests.search.SearchAPI;
import org.alfresco.rest.rm.community.requests.gscore.GSCoreAPI; import org.alfresco.rest.rm.community.requests.gscore.GSCoreAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.ActionsExecutionAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI; import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.FilesAPI; import org.alfresco.rest.rm.community.requests.gscore.api.FilesAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI;
@@ -225,4 +226,14 @@ public class RestAPIFactory
{ {
return getGSCoreAPI(userModel).usingUnfiledRecordFolder(); return getGSCoreAPI(userModel).usingUnfiledRecordFolder();
} }
public ActionsExecutionAPI getActionsAPI(UserModel userModel)
{
return getGSCoreAPI(userModel).usingActionsExecutionsAPI();
}
public ActionsExecutionAPI getActionsAPI()
{
return getGSCoreAPI(null).usingActionsExecutionsAPI();
}
} }

View File

@@ -89,7 +89,7 @@ public abstract class BaseAPI
private AlfrescoHttpClientFactory alfrescoHttpClientFactory; private AlfrescoHttpClientFactory alfrescoHttpClientFactory;
@Autowired @Autowired
private ContentService contentService; protected ContentService contentService;
public static final String NODE_REF_WORKSPACE_SPACES_STORE = "workspace://SpacesStore/"; public static final String NODE_REF_WORKSPACE_SPACES_STORE = "workspace://SpacesStore/";
private static final String FILE_PLAN_PATH = "/Sites/rm/documentLibrary"; private static final String FILE_PLAN_PATH = "/Sites/rm/documentLibrary";

View File

@@ -32,9 +32,16 @@ package org.alfresco.rest.rm.community.model.user;
* @author Kristijan Conkas * @author Kristijan Conkas
* @since 2.6 * @since 2.6
*/ */
public class UserPermissions public enum UserPermissions
{ {
public static final String PERMISSION_FILING = "Filing"; PERMISSION_FILING("Filing"),
public static final String PERMISSION_READ_RECORDS = "ReadRecords"; PERMISSION_READ_RECORDS("ReadRecords"),
public static final String PERMISSION_FILE_RECORDS = "FileRecords"; PERMISSION_FILE_RECORDS("FileRecords");
public final String permissionId;
UserPermissions(String permissionId)
{
this.permissionId = permissionId;
}
} }

View File

@@ -41,14 +41,14 @@ import lombok.Setter;
* @author Tuna Aksoy * @author Tuna Aksoy
* @since 2.6 * @since 2.6
*/ */
public abstract class RMModelRequest extends ModelRequest<RMModelRequest> public abstract class RMModelRequest<Request> extends ModelRequest<Request>
{ {
@Getter (value = PROTECTED) @Getter (value = PROTECTED)
@Setter (value = PRIVATE) @Setter (value = PRIVATE)
private RMRestWrapper rmRestWrapper; private RMRestWrapper rmRestWrapper;
/** /**
* @param restWrapper * @param rmRestWrapper
*/ */
public RMModelRequest(RMRestWrapper rmRestWrapper) public RMModelRequest(RMRestWrapper rmRestWrapper)
{ {

View File

@@ -33,6 +33,7 @@ import com.jayway.restassured.RestAssured;
import org.alfresco.rest.core.RMRestProperties; import org.alfresco.rest.core.RMRestProperties;
import org.alfresco.rest.core.RMRestWrapper; import org.alfresco.rest.core.RMRestWrapper;
import org.alfresco.rest.rm.community.requests.gscore.api.ActionsExecutionAPI;
import org.alfresco.rest.rm.community.requests.RMModelRequest; import org.alfresco.rest.rm.community.requests.RMModelRequest;
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI; import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.FilesAPI; import org.alfresco.rest.rm.community.requests.gscore.api.FilesAPI;
@@ -113,7 +114,7 @@ public class GSCoreAPI extends RMModelRequest
/** /**
* Provides DSL on all REST calls under <code>records/...</code> API path * Provides DSL on all REST calls under <code>records/...</code> API path
* *
* @return {@link FilePlanComponentAPI} * @return {@link RecordsAPI}
*/ */
public RecordsAPI usingRecords() public RecordsAPI usingRecords()
{ {
@@ -179,4 +180,14 @@ public class GSCoreAPI extends RMModelRequest
{ {
return new RMUserAPI(getRmRestWrapper()); return new RMUserAPI(getRmRestWrapper());
} }
/**
* Provides DSL for ActionExecution API
*
* @return {@link ActionsExecutionAPI}
*/
public ActionsExecutionAPI usingActionsExecutionsAPI()
{
return new ActionsExecutionAPI(getRmRestWrapper());
}
} }

View File

@@ -0,0 +1,78 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 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.rm.community.requests.gscore.api;
import com.google.common.collect.ImmutableMap;
import org.alfresco.rest.core.RMRestWrapper;
import org.alfresco.rest.rm.community.model.rules.ActionsOnRule;
import org.alfresco.rest.rm.community.requests.RMModelRequest;
import org.alfresco.utility.model.RepoTestModel;
import org.json.JSONObject;
/**
* Produces processed results from Core Actions API calls
*
* @author Claudia Agache
* @since 3.1
*/
public class ActionsExecutionAPI extends RMModelRequest
{
/**
* @param rmRestWrapper RM REST Wrapper
*/
public ActionsExecutionAPI(RMRestWrapper rmRestWrapper)
{
super(rmRestWrapper);
}
/**
* Declares and files a document as record to a record folder using v1 actions api
*
* @param targetNode the node on which the action is executed
* @param destinationPath the path to the record folder
* @throws Exception
*/
public JSONObject declareAndFile(RepoTestModel targetNode, String destinationPath) throws Exception
{
return getRmRestWrapper().withCoreAPI().usingActions()
.executeAction(ActionsOnRule.DECLARE_AS_RECORD.getActionValue(), targetNode,
ImmutableMap.of("path", destinationPath));
}
/**
* Declares a document as record using v1 actions api
*
* @param targetNode the node on which the action is executed
* @throws Exception
*/
public JSONObject declareAsRecord(RepoTestModel targetNode) throws Exception
{
return getRmRestWrapper().withCoreAPI().usingActions()
.executeAction(ActionsOnRule.DECLARE_AS_RECORD.getActionValue(), targetNode);
}
}

View File

@@ -54,7 +54,7 @@ public class FilePlanAPI extends RMModelRequest
/** /**
* Constructor. * Constructor.
* *
* @param restWrapper * @param rmRestWrapper RM REST Wrapper
*/ */
public FilePlanAPI(RMRestWrapper rmRestWrapper) public FilePlanAPI(RMRestWrapper rmRestWrapper)
{ {

View File

@@ -41,10 +41,12 @@ import org.alfresco.rest.rm.community.requests.RMModelRequest;
* @author Kristijan Conkas * @author Kristijan Conkas
* @since 2.6 * @since 2.6
*/ */
public class FilesAPI extends RMModelRequest public class FilesAPI extends RMModelRequest<FilesAPI>
{ {
public static final String PARENT_ID_PARAM = "parentId";
/** /**
* @param rmRestWrapper * @param rmRestWrapper RM REST Wrapper
*/ */
public FilesAPI(RMRestWrapper rmRestWrapper) public FilesAPI(RMRestWrapper rmRestWrapper)
{ {
@@ -55,26 +57,6 @@ public class FilesAPI extends RMModelRequest
* Declare file as record * Declare file as record
* *
* @param fileId The Id of a file to declare as record * @param fileId The Id of a file to declare as record
* @param parameters Request parameters, refer to API documentation for more details
* @return The {@link Record} for created record
* @throws Exception for malformed JSON responses
*/
public Record declareAsRecord(String fileId, String parameters) throws Exception
{
mandatoryString("fileId", fileId);
return getRmRestWrapper().processModel(Record.class, simpleRequest(
POST,
"/files/{fileId}/declare?{parameters}",
fileId,
parameters
));
}
/**
* A no-parameter version of {@link FilesAPI#declareAsRecord}
*
* @param fileId The Id of a file to declare as record
* @return The {@link Record} for created record * @return The {@link Record} for created record
* @throws Exception for malformed JSON responses * @throws Exception for malformed JSON responses
*/ */
@@ -82,7 +64,12 @@ public class FilesAPI extends RMModelRequest
{ {
mandatoryString("fileId", fileId); mandatoryString("fileId", fileId);
return declareAsRecord(fileId, EMPTY); return getRmRestWrapper().processModel(Record.class, simpleRequest(
POST,
"/files/{fileId}/declare?{parameters}",
fileId,
getRmRestWrapper().getParameters()
));
} }
} }

View File

@@ -59,7 +59,7 @@ import org.alfresco.utility.model.UserModel;
public class RMUserAPI extends RMModelRequest public class RMUserAPI extends RMModelRequest
{ {
/** /**
* @param rmRestWrapper * @param rmRestWrapper RM REST Wrapper
*/ */
public RMUserAPI(RMRestWrapper rmRestWrapper) public RMUserAPI(RMRestWrapper rmRestWrapper)
{ {
@@ -86,9 +86,8 @@ public class RMUserAPI extends RMModelRequest
* Assign RM role to user * Assign RM role to user
* @param userName User's username * @param userName User's username
* @param userRole User's RM role, one of {@link UserRoles} roles * @param userRole User's RM role, one of {@link UserRoles} roles
* @throws Exception for failed requests
*/ */
public void assignRoleToUser(String userName, String userRole) throws Exception public void assignRoleToUser(String userName, String userRole)
{ {
UserModel adminUser = getRmRestWrapper().getTestUser(); UserModel adminUser = getRmRestWrapper().getTestUser();
@@ -117,11 +116,11 @@ public class RMUserAPI extends RMModelRequest
/** /**
* Helper method to add permission on a component to user * Helper method to add permission on a component to user
* @param component The id of the file plan component on which permission should be given * @param filePlanComponentId The id of the file plan component on which permission should be given
* @param user {@link UserModel} for a user to be granted permission * @param user {@link UserModel} for a user to be granted permission
* @param permission {@link UserPermissions} to be granted * @param permission {@link UserPermissions} to be granted
*/ */
public void addUserPermission(String filePlanComponentId, UserModel user, String permission) public void addUserPermission(String filePlanComponentId, UserModel user, UserPermissions permission)
{ {
UserModel adminUser = getRmRestWrapper().getTestUser(); UserModel adminUser = getRmRestWrapper().getTestUser();
@@ -132,7 +131,7 @@ public class RMUserAPI extends RMModelRequest
.addArray("permissions") .addArray("permissions")
.addObject() .addObject()
.add("authority", user.getUsername()) .add("authority", user.getUsername())
.add("role", permission) .add("role", permission.permissionId)
.end() .end()
.getJson(); .getJson();

View File

@@ -54,7 +54,7 @@ public class RecordCategoryAPI extends RMModelRequest
/** /**
* Constructor. * Constructor.
* *
* @param restWrapper * @param rmRestWrapper RM REST Wrapper
*/ */
public RecordCategoryAPI(RMRestWrapper rmRestWrapper) public RecordCategoryAPI(RMRestWrapper rmRestWrapper)
{ {

View File

@@ -66,7 +66,7 @@ public class RecordFolderAPI extends RMModelRequest
/** /**
* Constructor. * Constructor.
* *
* @param restWrapper * @param rmRestWrapper RM REST Wrapper
*/ */
public RecordFolderAPI(RMRestWrapper rmRestWrapper) public RecordFolderAPI(RMRestWrapper rmRestWrapper)
{ {

View File

@@ -53,7 +53,7 @@ import org.alfresco.rest.rm.community.requests.RMModelRequest;
public class RecordsAPI extends RMModelRequest public class RecordsAPI extends RMModelRequest
{ {
/** /**
* @param rmRestWrapper * @param rmRestWrapper RM REST Wrapper
*/ */
public RecordsAPI(RMRestWrapper rmRestWrapper) public RecordsAPI(RMRestWrapper rmRestWrapper)
{ {

View File

@@ -46,7 +46,7 @@ import org.alfresco.rest.rm.community.requests.RMModelRequest;
public class TransferAPI extends RMModelRequest public class TransferAPI extends RMModelRequest
{ {
/** /**
* @param rmRestWrapper * @param rmRestWrapper RM REST Wrapper
*/ */
public TransferAPI(RMRestWrapper rmRestWrapper) public TransferAPI(RMRestWrapper rmRestWrapper)
{ {

View File

@@ -50,7 +50,7 @@ import org.alfresco.rest.rm.community.requests.RMModelRequest;
public class TransferContainerAPI extends RMModelRequest public class TransferContainerAPI extends RMModelRequest
{ {
/** /**
* @param rmRestWrapper * @param rmRestWrapper RM REST Wrapper
*/ */
public TransferContainerAPI(RMRestWrapper rmRestWrapper) public TransferContainerAPI(RMRestWrapper rmRestWrapper)
{ {

View File

@@ -63,7 +63,7 @@ import org.alfresco.rest.rm.community.util.UnfiledContainerChildMixin;
public class UnfiledContainerAPI extends RMModelRequest public class UnfiledContainerAPI extends RMModelRequest
{ {
/** /**
* @param rmRestWrapper * @param rmRestWrapper RM REST Wrapper
*/ */
public UnfiledContainerAPI(RMRestWrapper rmRestWrapper) public UnfiledContainerAPI(RMRestWrapper rmRestWrapper)
{ {

View File

@@ -63,7 +63,7 @@ import org.alfresco.rest.rm.community.util.UnfiledContainerChildMixin;
public class UnfiledRecordFolderAPI extends RMModelRequest public class UnfiledRecordFolderAPI extends RMModelRequest
{ {
/** /**
* @param rmRestWrapper * @param rmRestWrapper RM REST Wrapper
*/ */
public UnfiledRecordFolderAPI(RMRestWrapper rmRestWrapper) public UnfiledRecordFolderAPI(RMRestWrapper rmRestWrapper)
{ {

View File

@@ -0,0 +1,142 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 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.rm.community.util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.LogContainerCmd;
import com.github.dockerjava.api.model.Container;
import com.github.dockerjava.api.model.Frame;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.command.LogContainerResultCallback;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang.SystemUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* Helper class for interaction with docker containers
*
* @author Claudia Agache
* @since 3.1
*/
@Service
public class DockerHelper
{
private static final Logger LOGGER = LoggerFactory.getLogger(DockerHelper.class);
private static final String REPO_IMAGE_NAME = "repository";
@Getter
@Setter
private DockerClient dockerClient;
@Autowired
public DockerHelper(@Value ("${docker.host}") String dockerHost)
{
if (SystemUtils.IS_OS_WINDOWS)
{
this.dockerClient = DockerClientBuilder.getInstance(dockerHost).build();
}
else
{
this.dockerClient = DockerClientBuilder.getInstance().build();
}
}
/**
* Method for returning logs of docker container
*
* @param containerId - ID of the container
* @return list of strings, where every string is log line
*/
private List<String> getDockerLogs(String containerId)
{
final List<String> logs = new ArrayList<>();
// get the logs since current time - 10 seconds
final int timeStamp = (int) (System.currentTimeMillis() / 1000) - 10;
final LogContainerCmd logContainerCmd = getDockerClient().logContainerCmd(containerId);
logContainerCmd.withStdOut(true)
.withStdErr(true)
.withSince(timeStamp) // UNIX timestamp to filter logs. Output log-entries since that timestamp.
.withTimestamps(true); //print timestamps for every log line
try
{
logContainerCmd.exec(new LogContainerResultCallback()
{
@Override
public void onNext(Frame item)
{
logs.add(item.toString());
}
}).awaitCompletion();
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt(); // set interrupt flag
LOGGER.error("Failed to retrieve logs of container " + containerId, e);
}
return logs;
}
/**
* Get the alfresco container logs
*
* @return list of strings, where every string is log line
*/
public List<String> getAlfrescoLogs()
{
final Optional<Container> alfrescoContainer = findContainerByImageName(REPO_IMAGE_NAME);
return (alfrescoContainer.isPresent()) ? getDockerLogs(alfrescoContainer.get().getId()) : Collections.emptyList();
}
/**
* Method for finding a docker container after the image name
*
* @param imageName - the name of the image used by container
* @return the container
*/
private Optional<Container> findContainerByImageName(String imageName)
{
final List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).exec();
return containers.stream()
.filter(container -> container.getImage().contains(imageName))
.findFirst();
}
}

View File

@@ -30,6 +30,7 @@ import static org.alfresco.dataprep.AlfrescoHttpClient.MIME_TYPE_JSON;
import static org.alfresco.rest.core.v0.APIUtils.ISO_INSTANT_FORMATTER; import static org.alfresco.rest.core.v0.APIUtils.ISO_INSTANT_FORMATTER;
import static org.apache.http.HttpStatus.SC_OK; import static org.apache.http.HttpStatus.SC_OK;
import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertNotNull;
import static org.testng.AssertJUnit.assertTrue; import static org.testng.AssertJUnit.assertTrue;
import static org.testng.AssertJUnit.fail; import static org.testng.AssertJUnit.fail;
@@ -44,10 +45,10 @@ import java.util.Set;
import org.alfresco.dataprep.AlfrescoHttpClient; import org.alfresco.dataprep.AlfrescoHttpClient;
import org.alfresco.dataprep.AlfrescoHttpClientFactory; import org.alfresco.dataprep.AlfrescoHttpClientFactory;
import org.alfresco.dataprep.ContentService;
import org.alfresco.dataprep.UserService; import org.alfresco.dataprep.UserService;
import org.alfresco.rest.core.v0.BaseAPI; import org.alfresco.rest.core.v0.BaseAPI;
import org.alfresco.rest.core.v0.RMEvents; import org.alfresco.rest.core.v0.RMEvents;
import org.alfresco.utility.Utility;
import org.apache.chemistry.opencmis.client.api.CmisObject; import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
@@ -73,6 +74,8 @@ import org.springframework.stereotype.Component;
@Component @Component
public class RMRolesAndActionsAPI extends BaseAPI public class RMRolesAndActionsAPI extends BaseAPI
{ {
public static final String HOLDS_CONTAINER = "Holds";
/** The URI to view the configured roles and capabilities. */ /** The URI to view the configured roles and capabilities. */
private static final String RM_ROLES = "{0}rma/admin/rmroles"; private static final String RM_ROLES = "{0}rma/admin/rmroles";
/** The URI for REST requests about a particular configured role. */ /** The URI for REST requests about a particular configured role. */
@@ -83,6 +86,8 @@ public class RMRolesAndActionsAPI extends BaseAPI
private static final Logger LOGGER = LoggerFactory.getLogger(RMRolesAndActionsAPI.class); private static final Logger LOGGER = LoggerFactory.getLogger(RMRolesAndActionsAPI.class);
private static final String MOVE_ACTIONS_API = "action/rm-move-to/site/rm/documentLibrary/{0}"; private static final String MOVE_ACTIONS_API = "action/rm-move-to/site/rm/documentLibrary/{0}";
private static final String CREATE_HOLDS_API = "{0}type/rma:hold/formprocessor"; private static final String CREATE_HOLDS_API = "{0}type/rma:hold/formprocessor";
/** The URI to view the configured roles and capabilities. */
private static final String RM_HOLDS_API = "{0}rma/holds";
/** http client factory */ /** http client factory */
@Autowired @Autowired
@@ -92,9 +97,6 @@ public class RMRolesAndActionsAPI extends BaseAPI
@Autowired @Autowired
private UserService userService; private UserService userService;
@Autowired
private ContentService contentService;
/** /**
* Get all the configured RM roles. * Get all the configured RM roles.
* *
@@ -105,7 +107,8 @@ public class RMRolesAndActionsAPI extends BaseAPI
public Set<String> getConfiguredRoles(String adminUser, String adminPassword) public Set<String> getConfiguredRoles(String adminUser, String adminPassword)
{ {
// Using "is=true" includes the in-place readers and writers. // Using "is=true" includes the in-place readers and writers.
JSONObject jsonObject = doGetRequest(adminUser, adminPassword, RM_ROLES + "?is=true").getJSONObject("data"); final JSONObject jsonObject = doGetRequest(adminUser, adminPassword, RM_ROLES + "?is=true").getJSONObject(
"data");
return jsonObject.toMap().keySet(); return jsonObject.toMap().keySet();
} }
@@ -119,11 +122,31 @@ public class RMRolesAndActionsAPI extends BaseAPI
*/ */
public Set<String> getCapabilitiesForRole(String adminUser, String adminPassword, String role) public Set<String> getCapabilitiesForRole(String adminUser, String adminPassword, String role)
{ {
JSONObject jsonObject = doGetRequest(adminUser, adminPassword, RM_ROLES + "?is=true").getJSONObject("data"); final JSONObject jsonObject = doGetRequest(adminUser, adminPassword, RM_ROLES + "?is=true").getJSONObject(
"data");
assertTrue("Could not find role '" + role + "' in " + jsonObject.keySet(), jsonObject.has(role)); assertTrue("Could not find role '" + role + "' in " + jsonObject.keySet(), jsonObject.has(role));
return jsonObject.getJSONObject(role).getJSONObject("capabilities").keySet(); return jsonObject.getJSONObject(role).getJSONObject("capabilities").keySet();
} }
/**
* Creates the body for PUT/POST Roles API requests
*
* @param roleName the role name
* @param roleDisplayLabel a human-readable label for the role
* @param capabilities a list of capabilities for the role
* @return
*/
private JSONObject roleRequestBody(String roleName, String roleDisplayLabel, Set<String> capabilities)
{
final JSONObject requestBody = new JSONObject();
requestBody.put("name", roleName);
requestBody.put("displayLabel", roleDisplayLabel);
final JSONArray capabilitiesArray = new JSONArray();
capabilities.forEach(capabilitiesArray::put);
requestBody.put("capabilities", capabilitiesArray);
return requestBody;
}
/** /**
* Create a new RM role. * Create a new RM role.
* *
@@ -135,13 +158,8 @@ public class RMRolesAndActionsAPI extends BaseAPI
*/ */
public void createRole(String adminUser, String adminPassword, String roleName, String roleDisplayLabel, Set<String> capabilities) public void createRole(String adminUser, String adminPassword, String roleName, String roleDisplayLabel, Set<String> capabilities)
{ {
JSONObject requestBody = new JSONObject(); doPostJsonRequest(adminUser, adminPassword, HttpStatus.SC_OK, roleRequestBody(roleName, roleDisplayLabel, capabilities),
requestBody.put("name", roleName); RM_ROLES);
requestBody.put("displayLabel", roleDisplayLabel);
JSONArray capabilitiesArray = new JSONArray();
capabilities.forEach(capabilitiesArray::put);
requestBody.put("capabilities", capabilitiesArray);
doPostJsonRequest(adminUser, adminPassword, HttpStatus.SC_OK, requestBody, RM_ROLES);
} }
/** /**
@@ -155,13 +173,8 @@ public class RMRolesAndActionsAPI extends BaseAPI
*/ */
public void updateRole(String adminUser, String adminPassword, String roleName, String roleDisplayLabel, Set<String> capabilities) public void updateRole(String adminUser, String adminPassword, String roleName, String roleDisplayLabel, Set<String> capabilities)
{ {
JSONObject requestBody = new JSONObject(); doPutJsonRequest(adminUser, adminPassword, HttpStatus.SC_OK, roleRequestBody(roleName, roleDisplayLabel, capabilities),
requestBody.put("name", roleName); RM_ROLES_ROLE, roleName);
requestBody.put("displayLabel", roleDisplayLabel);
JSONArray capabilitiesArray = new JSONArray();
capabilities.forEach(capabilitiesArray::put);
requestBody.put("capabilities", capabilitiesArray);
doPutJsonRequest(adminUser, adminPassword, HttpStatus.SC_OK, requestBody, RM_ROLES_ROLE, roleName);
} }
/** /**
@@ -174,8 +187,8 @@ public class RMRolesAndActionsAPI extends BaseAPI
public void deleteRole(String adminUser, String adminPassword, String roleName) public void deleteRole(String adminUser, String adminPassword, String roleName)
{ {
doDeleteRequest(adminUser, adminPassword, MessageFormat.format(RM_ROLES_ROLE, "{0}", roleName)); doDeleteRequest(adminUser, adminPassword, MessageFormat.format(RM_ROLES_ROLE, "{0}", roleName));
boolean success = !getConfiguredRoles(adminUser, adminPassword).contains(roleName); assertFalse("Failed to delete role " + roleName + " with " + adminUser,
assertTrue("Failed to delete role " + roleName + " with " + adminUser, success); getConfiguredRoles(adminUser, adminPassword).contains(roleName));
} }
/** /**
@@ -274,7 +287,7 @@ public class RMRolesAndActionsAPI extends BaseAPI
} }
catch (JSONException | IOException e) catch (JSONException | IOException e)
{ {
e.printStackTrace(); LOGGER.error(e.toString());
} }
finally finally
{ {
@@ -312,16 +325,40 @@ public class RMRolesAndActionsAPI extends BaseAPI
} }
/** /**
* Perform an action on the record folder * Perform an action on the given content
* *
* @param user the user executing the action * @param user the user executing the action
* @param password the user's password * @param password the user's password
* @param contentName the content name * @param contentName the content name
* @return The HTTP response. * @return The HTTP response.
*/ */
public HttpResponse executeAction(String user, String password, String contentName, RM_ACTIONS rm_action) public HttpResponse executeAction(String user, String password, String contentName, RM_ACTIONS action)
{ {
return executeAction(user, password, contentName, rm_action, null); return executeAction(user, password, contentName, action, null);
}
/**
* Creates the body for Actions API requests
*
* @param user the user executing the action
* @param password the user's password
* @param contentName the content on which the action is executed
* @param action the action executed
* @param actionsParams the request parameters
* @return the JSONObject created
*/
private JSONObject actionsRequestBody(String user, String password, String contentName, RM_ACTIONS action,
JSONObject actionsParams)
{
final String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, contentName);
final JSONObject requestParams = new JSONObject();
requestParams.put("name", action.getAction());
requestParams.put("nodeRef", recNodeRef);
if (actionsParams != null)
{
requestParams.put("params", actionsParams);
}
return requestParams;
} }
/** /**
@@ -335,19 +372,12 @@ public class RMRolesAndActionsAPI extends BaseAPI
*/ */
public HttpResponse executeAction(String user, String password, String contentName, RM_ACTIONS action, ZonedDateTime date) public HttpResponse executeAction(String user, String password, String contentName, RM_ACTIONS action, ZonedDateTime date)
{ {
String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, contentName); final JSONObject actionParams = new JSONObject();
JSONObject requestParams = new JSONObject();
requestParams.put("name", action.getAction());
requestParams.put("nodeRef", recNodeRef);
if (date != null) if (date != null)
{ {
String thisMoment = date.format(ISO_INSTANT_FORMATTER); actionParams.put("asOfDate", new JSONObject().put("iso8601", ISO_INSTANT_FORMATTER.format(date)));
requestParams.put("params", new JSONObject()
.put("asOfDate", new JSONObject()
.put("iso8601", thisMoment)
)
);
} }
final JSONObject requestParams = actionsRequestBody(user, password, contentName, action, actionParams);
return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API); return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API);
} }
@@ -363,20 +393,14 @@ public class RMRolesAndActionsAPI extends BaseAPI
*/ */
public HttpResponse completeEvent(String user, String password, String nodeName, RMEvents event, Instant date) public HttpResponse completeEvent(String user, String password, String nodeName, RMEvents event, Instant date)
{ {
String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, nodeName);
JSONObject requestParams = new JSONObject();
requestParams.put("name", RM_ACTIONS.COMPLETE_EVENT.getAction());
requestParams.put("nodeRef", recNodeRef);
date = (date != null) ? date : Instant.now(); date = (date != null) ? date : Instant.now();
String formattedDate = ISO_INSTANT_FORMATTER.format(date); final JSONObject actionParams = new JSONObject().put("eventName", event.getEventName())
requestParams.put("params", new JSONObject() .put("eventCompletedBy", user)
.put("eventName", event.getEventName()) .put("eventCompletedAt", new JSONObject()
.put("eventCompletedBy", user) .put("iso8601", ISO_INSTANT_FORMATTER.format(date))
.put("eventCompletedAt", new JSONObject() );
.put("iso8601", formattedDate) final JSONObject requestParams = actionsRequestBody(user, password, nodeName, RM_ACTIONS.COMPLETE_EVENT,
) actionParams);
);
return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API); return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API);
} }
@@ -391,13 +415,8 @@ public class RMRolesAndActionsAPI extends BaseAPI
*/ */
public HttpResponse undoEvent(String user, String password, String contentName, RMEvents event) public HttpResponse undoEvent(String user, String password, String contentName, RMEvents event)
{ {
String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, contentName); final JSONObject requestParams = actionsRequestBody(user, password, contentName, RM_ACTIONS.UNDO_EVENT,
JSONObject requestParams = new JSONObject(); new JSONObject().put("eventName", event.getEventName()));
requestParams.put("name", RM_ACTIONS.UNDO_EVENT.getAction());
requestParams.put("nodeRef", recNodeRef);
requestParams.put("params", new JSONObject()
.put("eventName", event.getEventName()));
return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API); return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API);
} }
@@ -416,8 +435,8 @@ public class RMRolesAndActionsAPI extends BaseAPI
{ {
item.delete(); item.delete();
} }
boolean success = !(contentService.getFolderObject(contentService.getCMISSession(username, password), siteId, containerName).getChildren().getHasMoreItems()); assertFalse("Not all items were deleted from " + containerName,
assertTrue("Not all items were deleted from " + containerName, success); contentService.getFolderObject(contentService.getCMISSession(username, password), siteId, containerName).getChildren().getHasMoreItems());
} }
/** /**
@@ -430,10 +449,9 @@ public class RMRolesAndActionsAPI extends BaseAPI
*/ */
public void deleteHold(String username, String password, String holdName) public void deleteHold(String username, String password, String holdName)
{ {
deleteItem(username, password, "/Holds/" + holdName); deleteItem(username, password, String.format("/%s/%s", HOLDS_CONTAINER, holdName));
} }
/** /**
* Util method to create a hold * Util method to create a hold
* *
@@ -447,29 +465,49 @@ public class RMRolesAndActionsAPI extends BaseAPI
public HttpResponse createHold(String user, String password, String holdName, String reason, String description) public HttpResponse createHold(String user, String password, String holdName, String reason, String description)
{ {
// if the hold already exists don't try to create it again // if the hold already exists don't try to create it again
String holdsContainerPath = getFilePlanPath() + "/Holds"; final String fullHoldPath = Utility.buildPath(getFilePlanPath(), HOLDS_CONTAINER) + holdName;
String fullHoldPath = holdsContainerPath + "/" + holdName; final CmisObject hold = getObjectByPath(user, password, fullHoldPath);
CmisObject hold = getObjectByPath(user, password, fullHoldPath);
if (hold != null) if (hold != null)
{ {
return null; return null;
} }
// retrieve the Holds container nodeRef // retrieve the Holds container nodeRef
String parentNodeRef = getItemNodeRef(user, password, "/Holds"); final String parentNodeRef = getItemNodeRef(user, password, "/" + HOLDS_CONTAINER);
JSONObject requestParams = new JSONObject(); final JSONObject requestParams = new JSONObject();
requestParams.put("alf_destination", getNodeRefSpacesStore() + parentNodeRef); requestParams.put("alf_destination", getNodeRefSpacesStore() + parentNodeRef);
requestParams.put("prop_cm_name", holdName); requestParams.put("prop_cm_name", holdName);
requestParams.put("prop_cm_description", description); requestParams.put("prop_cm_description", description);
requestParams.put("prop_rma_holdReason", reason); requestParams.put("prop_rma_holdReason", reason);
// Make the POST request and throw an assertion error if it fails. // Make the POST request and throw an assertion error if it fails.
HttpResponse httpResponse = doPostJsonRequest(user, password, SC_OK, requestParams, CREATE_HOLDS_API); final HttpResponse httpResponse = doPostJsonRequest(user, password, SC_OK, requestParams, CREATE_HOLDS_API);
assertNotNull("Expected object to have been created at " + fullHoldPath, assertNotNull("Expected object to have been created at " + fullHoldPath,
getObjectByPath(user, password, fullHoldPath)); getObjectByPath(user, password, fullHoldPath));
return httpResponse; return httpResponse;
} }
/**
* Adds item (record/ record folder) to the hold
*
* @param user the user who adds the item to the hold
* @param password the user's password
* @param itemNodeRef the nodeRef of the item to be added to hold
* @param holdName the hold name
* @return The HTTP response
*/
public HttpResponse addItemToHold(String user, String password, String itemNodeRef, String holdName)
{
final JSONArray nodeRefs = new JSONArray().put(getNodeRefSpacesStore() + itemNodeRef);
final String holdNodeRef = getItemNodeRef(user, password, String.format("/%s/%s", HOLDS_CONTAINER, holdName));
final JSONArray holds = new JSONArray().put(getNodeRefSpacesStore() + holdNodeRef);
final JSONObject requestParams = new JSONObject();
requestParams.put("nodeRefs", nodeRefs);
requestParams.put("holds", holds);
return doPostJsonRequest(user, password, SC_OK, requestParams, RM_HOLDS_API);
}
/** /**
* Updates metadata, can be used on records, folders and categories * Updates metadata, can be used on records, folders and categories
* *

View File

@@ -28,14 +28,12 @@ package org.alfresco.rest.v0;
import static org.apache.http.HttpStatus.SC_OK; import static org.apache.http.HttpStatus.SC_OK;
import org.alfresco.dataprep.ContentService;
import org.alfresco.rest.core.v0.BaseAPI; import org.alfresco.rest.core.v0.BaseAPI;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
@@ -49,9 +47,6 @@ public class RecordFoldersAPI extends BaseAPI
{ {
private static final Logger LOGGER = LoggerFactory.getLogger(RecordFoldersAPI.class); private static final Logger LOGGER = LoggerFactory.getLogger(RecordFoldersAPI.class);
@Autowired
private ContentService contentService;
/** /**
* Close the record folder * Close the record folder
* *

View File

@@ -33,7 +33,6 @@ import java.text.MessageFormat;
import java.util.Map; import java.util.Map;
import org.alfresco.dataprep.CMISUtil.DocumentType; import org.alfresco.dataprep.CMISUtil.DocumentType;
import org.alfresco.dataprep.ContentService;
import org.alfresco.rest.core.v0.BaseAPI; import org.alfresco.rest.core.v0.BaseAPI;
import org.apache.chemistry.opencmis.client.api.CmisObject; import org.apache.chemistry.opencmis.client.api.CmisObject;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
@@ -42,7 +41,6 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
/** /**
@@ -59,9 +57,6 @@ public class RecordsAPI extends BaseAPI
private static final String CREATE_NON_ELECTRONIC_RECORD_API = "{0}type/rma:nonElectronicDocument/formprocessor"; private static final String CREATE_NON_ELECTRONIC_RECORD_API = "{0}type/rma:nonElectronicDocument/formprocessor";
@Autowired
private ContentService contentService;
/** /**
* Declare documents as records * Declare documents as records
* *

View File

@@ -26,12 +26,22 @@
*/ */
package org.alfresco.rest.v0.service; package org.alfresco.rest.v0.service;
import static lombok.AccessLevel.PROTECTED;
import static org.springframework.http.HttpStatus.OK;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import lombok.Getter;
import org.alfresco.rest.core.RestAPIFactory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.user.UserPermissions;
import org.alfresco.rest.rm.community.model.user.UserRoles; import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.v0.RMRolesAndActionsAPI; import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.data.DataUser; import org.alfresco.utility.data.DataUser;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -45,11 +55,29 @@ import org.springframework.stereotype.Service;
public class RoleService public class RoleService
{ {
@Autowired @Autowired
@Getter (value = PROTECTED)
private RMRolesAndActionsAPI rmRolesAndActionsAPI; private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@Autowired @Autowired
@Getter (value = PROTECTED)
private DataUser dataUser; private DataUser dataUser;
@Autowired
@Getter (value = PROTECTED)
private RestAPIFactory restAPIFactory;
/**
* Get the capabilities for a role
*
* @param roleName the role name
* @return the list of capabilities
*/
public Set<String> getRoleCapabilities(String roleName)
{
return getRmRolesAndActionsAPI().getCapabilitiesForRole(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(), roleName);
}
/** /**
* Add capabilities to a role * Add capabilities to a role
* *
@@ -58,12 +86,10 @@ public class RoleService
*/ */
public void addCapabilitiesToRole(UserRoles role, Set<String> capabilities) public void addCapabilitiesToRole(UserRoles role, Set<String> capabilities)
{ {
Set<String> roleCapabilities = new HashSet<>(); Set<String> roleCapabilities = new HashSet<>(getRoleCapabilities(role.roleId));
roleCapabilities.addAll(rmRolesAndActionsAPI.getCapabilitiesForRole(dataUser.getAdminUser().getUsername(), roleCapabilities.addAll(capabilities);
dataUser.getAdminUser().getPassword(), role.roleId));
capabilities.stream().forEach(cap -> roleCapabilities.add(cap));
rmRolesAndActionsAPI.updateRole(dataUser.getAdminUser().getUsername(), dataUser.getAdminUser().getPassword(), getRmRolesAndActionsAPI().updateRole(getDataUser().getAdminUser().getUsername(), getDataUser().getAdminUser().getPassword(),
role.roleId, role.displayName, roleCapabilities); role.roleId, role.displayName, roleCapabilities);
} }
@@ -75,10 +101,75 @@ public class RoleService
*/ */
public void removeCapabilitiesFromRole(UserRoles role, Set<String> capabilities) public void removeCapabilitiesFromRole(UserRoles role, Set<String> capabilities)
{ {
Set<String> roleCapabilities = rmRolesAndActionsAPI.getCapabilitiesForRole(dataUser.getAdminUser().getUsername(), Set<String> roleCapabilities = getRoleCapabilities(role.roleId);
dataUser.getAdminUser().getPassword(), role.roleId);
roleCapabilities.removeAll(capabilities); roleCapabilities.removeAll(capabilities);
rmRolesAndActionsAPI.updateRole(dataUser.getAdminUser().getUsername(), dataUser.getAdminUser().getPassword(), getRmRolesAndActionsAPI().updateRole(getDataUser().getAdminUser().getUsername(), getDataUser().getAdminUser().getPassword(),
role.roleId, role.displayName, roleCapabilities); role.roleId, role.displayName, roleCapabilities);
} }
/**
* Assign permission on a record category and give the user RM role
*
* @param user the user to assign rm role and permissions
* @param categoryId the id of the category to assign permissions for
* @param userPermission the permissions to be assigned to the user
* @param userRole the rm role to be assigned to the user
*/
public void assignUserPermissionsOnCategoryAndRMRole(UserModel user, String categoryId, UserPermissions userPermission,
String userRole)
{
getRestAPIFactory().getRMUserAPI().addUserPermission(categoryId, user, userPermission);
getRmRolesAndActionsAPI().assignRoleToUser(getDataUser().getAdminUser().getUsername(), getDataUser().getAdminUser().getPassword(),
user.getUsername(), userRole);
}
/**
* Helper method to create a test user with rm role
*
* @param userRole the rm role
* @return the created user model
*/
public UserModel createUserWithRMRole(String userRole)
{
final UserModel rmUser = getDataUser().createRandomTestUser();
getRestAPIFactory().getRMUserAPI().assignRoleToUser(rmUser.getUsername(), userRole);
getRestAPIFactory().getRmRestWrapper().assertStatusCodeIs(OK);
return rmUser;
}
/**
* Helper method to create a test user with rm role and permissions over the record category
*
* @param userRole the rm role
* @param userPermission the permissions over the record category
* @param recordCategory the category on which user has permissions
* @return the created user model
*/
public UserModel createUserWithRMRoleAndCategoryPermission(String userRole, RecordCategory recordCategory,
UserPermissions userPermission)
{
final UserModel rmUser = createUserWithRMRole(userRole);
getRestAPIFactory().getRMUserAPI().addUserPermission(recordCategory.getId(), rmUser, userPermission);
getRestAPIFactory().getRmRestWrapper().assertStatusCodeIs(OK);
return rmUser;
}
/**
* Helper method to create a test user with rm role and permissions over the recordCategory and collaborator role
* in collaboration site
*
* @param siteModel collaboration site
* @param recordCategory the category on which permission should be given
* @param userRole the rm role
* @param userPermission the permissions over the recordCategory
* @return the created user model
*/
public UserModel createCollaboratorWithRMRoleAndPermission(SiteModel siteModel, RecordCategory recordCategory,
UserRoles userRole, UserPermissions userPermission)
{
final UserModel rmUser = createUserWithRMRoleAndCategoryPermission(userRole.roleId, recordCategory,
userPermission);
getDataUser().addUserToSite(rmUser, siteModel, UserRole.SiteCollaborator);
return rmUser;
}
} }

View File

@@ -1,3 +1,6 @@
alfresco.server=localhost alfresco.server=localhost
alfresco.port=8080 alfresco.port=8080
rest.rmPath=alfresco/api/-default-/public/gs/versions/1 rest.rmPath=alfresco/api/-default-/public/gs/versions/1
# Docker properties values
docker.host=tcp://127.0.0.1:2375

View File

@@ -52,8 +52,10 @@ import static org.testng.Assert.assertTrue;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.Getter;
import org.alfresco.dataprep.ContentService; import org.alfresco.dataprep.ContentService;
import org.alfresco.rest.RestTest; import org.alfresco.rest.RestTest;
import org.alfresco.rest.core.RestAPIFactory; import org.alfresco.rest.core.RestAPIFactory;
@@ -64,11 +66,13 @@ import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory; import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild; import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolder; import org.alfresco.rest.rm.community.model.recordfolder.RecordFolder;
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolderEntry;
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolderProperties; import org.alfresco.rest.rm.community.model.recordfolder.RecordFolderProperties;
import org.alfresco.rest.rm.community.model.site.RMSite; import org.alfresco.rest.rm.community.model.site.RMSite;
import org.alfresco.rest.rm.community.model.transfercontainer.TransferContainer; import org.alfresco.rest.rm.community.model.transfercontainer.TransferContainer;
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainer; import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainer;
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChild; import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChild;
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChildEntry;
import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordCategoryAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RecordCategoryAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI;
@@ -76,10 +80,11 @@ import org.alfresco.rest.rm.community.requests.gscore.api.RecordsAPI;
import org.alfresco.rest.search.RestRequestQueryModel; import org.alfresco.rest.search.RestRequestQueryModel;
import org.alfresco.rest.search.SearchNodeModel; import org.alfresco.rest.search.SearchNodeModel;
import org.alfresco.rest.search.SearchRequest; import org.alfresco.rest.search.SearchRequest;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.SearchAPI; import org.alfresco.rest.v0.SearchAPI;
import org.alfresco.utility.Utility;
import org.alfresco.utility.data.DataUser; import org.alfresco.utility.data.DataUser;
import org.alfresco.utility.model.ContentModel; import org.alfresco.utility.model.ContentModel;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel; import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel; import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel; import org.alfresco.utility.model.UserModel;
@@ -88,8 +93,6 @@ import org.springframework.http.HttpStatus;
import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import lombok.Getter;
/** /**
* Base class for all GS REST API Tests * Base class for all GS REST API Tests
* *
@@ -111,10 +114,6 @@ public class BaseRMRestTest extends RestTest
@Getter(value = PROTECTED) @Getter(value = PROTECTED)
private ContentService contentService; private ContentService contentService;
@Autowired
@Getter(value = PROTECTED)
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@Autowired @Autowired
@Getter(value = PROTECTED) @Getter(value = PROTECTED)
private SearchAPI searchApi; private SearchAPI searchApi;
@@ -481,32 +480,32 @@ public class BaseRMRestTest extends RestTest
return createCategoryFolderInFilePlan(getAdminUser()); return createCategoryFolderInFilePlan(getAdminUser());
} }
public UnfiledContainer getUnfiledContainerAsUser(UserModel user, String componentId) throws Exception public UnfiledContainer getUnfiledContainerAsUser(UserModel user, String componentId)
{ {
return getRestAPIFactory().getUnfiledContainersAPI(user).getUnfiledContainer(componentId); return getRestAPIFactory().getUnfiledContainersAPI(user).getUnfiledContainer(componentId);
} }
public UnfiledContainer getUnfiledContainer(String componentId) throws Exception public UnfiledContainer getUnfiledContainer(String componentId)
{ {
return getUnfiledContainerAsUser(getAdminUser(), componentId); return getUnfiledContainerAsUser(getAdminUser(), componentId);
} }
public TransferContainer getTransferContainerAsUser(UserModel user, String componentId) throws Exception public TransferContainer getTransferContainerAsUser(UserModel user, String componentId)
{ {
return getRestAPIFactory().getTransferContainerAPI(user).getTransferContainer(componentId); return getRestAPIFactory().getTransferContainerAPI(user).getTransferContainer(componentId);
} }
public TransferContainer getTransferContainer(String componentId) throws Exception public TransferContainer getTransferContainer(String componentId)
{ {
return getTransferContainerAsUser(getAdminUser(), componentId); return getTransferContainerAsUser(getAdminUser(), componentId);
} }
public FilePlan getFilePlanAsUser(UserModel user, String componentId) throws Exception public FilePlan getFilePlanAsUser(UserModel user, String componentId)
{ {
return getRestAPIFactory().getFilePlansAPI(user).getFilePlan(componentId); return getRestAPIFactory().getFilePlansAPI(user).getFilePlan(componentId);
} }
public FilePlan getFilePlan(String componentId) throws Exception public FilePlan getFilePlan(String componentId)
{ {
return getFilePlanAsUser(getAdminUser(), componentId); return getFilePlanAsUser(getAdminUser(), componentId);
} }
@@ -614,21 +613,6 @@ public class BaseRMRestTest extends RestTest
recordCategoryAPI.deleteRecordCategory(recordCategoryId); recordCategoryAPI.deleteRecordCategory(recordCategoryId);
} }
/**
* Assign filling permission on a record category and give the user RM_USER role
*
* @param user the user to assign the permission to
* @param categoryId the id of the category to assign permissions for
* @throws Exception
*/
public void assignFillingPermissionsOnCategory(UserModel user, String categoryId,
String userPermission, String userRole) throws Exception
{
getRestAPIFactory().getRMUserAPI().addUserPermission(categoryId, user, userPermission);
rmRolesAndActionsAPI.assignRoleToUser(getAdminUser().getUsername(),
getAdminUser().getPassword(), user.getUsername(), userRole);
}
/** /**
* Returns search results for the given search term * Returns search results for the given search term
* *
@@ -658,6 +642,8 @@ public class BaseRMRestTest extends RestTest
} }
catch (InterruptedException e) catch (InterruptedException e)
{ {
// Restore interrupted state...
Thread.currentThread().interrupt();
} }
} }
@@ -706,6 +692,8 @@ public class BaseRMRestTest extends RestTest
} }
catch (InterruptedException e) catch (InterruptedException e)
{ {
// Restore interrupted state...
Thread.currentThread().interrupt();
} }
} }
@@ -755,6 +743,8 @@ public class BaseRMRestTest extends RestTest
} }
catch (InterruptedException e) catch (InterruptedException e)
{ {
// Restore interrupted state...
Thread.currentThread().interrupt();
} }
} }
result = searchApi.searchForNodePropertyAsUser(user.getUsername(), user.getPassword(), nodeRef, result = searchApi.searchForNodePropertyAsUser(user.getUsername(), user.getPassword(), nodeRef,
@@ -794,4 +784,86 @@ public class BaseRMRestTest extends RestTest
return documentLibrary; return documentLibrary;
} }
/**
* Checks if the given file has record aspect
*
* @param testFile the file to be checked
* @return true if the file has the aspect, false otherwise
*/
protected boolean hasRecordAspect(FileModel testFile) throws Exception
{
return hasAspect(testFile,RECORD_TYPE);
}
/**
* Checks if the given file has the given aspect
*
* @param testFile the file to be checked
* @param aspectName the matching aspect
* @return true if the file has the aspect, false otherwise
*/
private boolean hasAspect(FileModel testFile, String aspectName) throws Exception
{
return getRestAPIFactory().getNodeAPI(testFile).getNode()
.getAspectNames().contains(aspectName);
}
/**
* Helper method to verify if the declared record is in Unfiled Records location
*
* @param testFile the file declared as record
* @return true if the matching record is found in Unfiled Records, false otherwise
*/
protected boolean isMatchingRecordInUnfiledRecords(FileModel testFile)
{
try
{
Utility.sleep(5000, 15000,
() -> {
Optional<UnfiledContainerChildEntry> matchingRecord = getRestAPIFactory().getUnfiledContainersAPI()
.getUnfiledContainerChildren(UNFILED_RECORDS_CONTAINER_ALIAS)
.getEntries()
.stream()
.filter(e -> e.getEntry().getId()
.equals(testFile.getNodeRefWithoutVersion()))
.findAny();
assertTrue(matchingRecord.isPresent());
});
return true;
}
catch (AssertionError | Exception e)
{
return false;
}
}
/**
* Helper method to verify if the declared record is filed to the record folder location
*
* @param testFile the file declared as record
* @param recFolder the record folder where the declared record has been filed
* @return true if matching record is found in record folder, null otherwise
*/
protected boolean isMatchingRecordInRecordFolder(FileModel testFile, RecordCategoryChild recFolder)
{
try
{
Utility.sleep(5000, 15000,
() -> {
Optional<RecordFolderEntry> matchingRecord = getRestAPIFactory().getRecordFolderAPI()
.getRecordFolderChildren(recFolder.getId())
.getEntries()
.stream()
.filter(e -> e.getEntry().getId()
.equals(testFile.getNodeRefWithoutVersion()))
.findAny();
assertTrue(matchingRecord.isPresent());
});
return true;
}
catch (AssertionError | Exception e)
{
return false;
}
}
} }

View File

@@ -38,7 +38,6 @@ import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanCo
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.TRANSFER_TYPE; import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.TRANSFER_TYPE;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.UNFILED_CONTAINER_TYPE; import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.UNFILED_CONTAINER_TYPE;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.UNFILED_RECORD_FOLDER_TYPE; import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.UNFILED_RECORD_FOLDER_TYPE;
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
@@ -105,7 +104,7 @@ public class DataProviderClass
* @return file plan component alias * @return file plan component alias
*/ */
@DataProvider @DataProvider
public static String[][] categoryTypes() public static Object[][] categoryTypes()
{ {
return new String[][] { return new String[][] {
{ FOLDER_TYPE }, { FOLDER_TYPE },

View File

@@ -0,0 +1,449 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2019 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.rm.community.files;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.TRANSFERS_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.UNFILED_RECORD_FOLDER_TYPE;
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_READ_RECORDS;
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_POWER_USER;
import static org.alfresco.rest.rm.community.requests.gscore.api.FilesAPI.PARENT_ID_PARAM;
import static org.alfresco.rest.v0.RMRolesAndActionsAPI.HOLDS_CONTAINER;
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.ACCEPTED;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.util.List;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChild;
import org.alfresco.rest.rm.community.util.DockerHelper;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.service.RoleService;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.Utility;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* API tests for declaring document as record and filing it immediately to a record folder location within the file plan
*
* @author Claudia Agache
* @since 3.1
*/
@AlfrescoTest (jira = "RM-6779")
public class DeclareAndFileDocumentAsRecordTests extends BaseRMRestTest
{
private final static String DESTINATION_PATH_NOT_FOUND_EXC = "Unable to execute create-record action, because the destination path could not be found.";
private final static String INVALID_DESTINATION_PATH_EXC = "Unable to execute create-record action, because the destination path is invalid.";
private final static String DESTINATION_PATH_NOT_RECORD_FOLDER_EXC = "Unable to execute create-record action, because the destination path is not a record folder.";
private final static String CLOSED_RECORD_FOLDER_EXC = "Unable to create record, because container is closed";
private final static String HOLD_NAME = "holdName";
private UserModel userFillingPermission, userReadOnlyPermission;
private SiteModel publicSite;
private FolderModel testFolder;
private FileModel testFile;
private RecordCategory recordCategory;
private RecordCategoryChild recordFolder, subcategoryRecordFolder, subCategory, closedRecordFolder;
private UnfiledContainerChild unfiledContainerFolder;
@Autowired
private DockerHelper dockerHelper;
@Autowired
private RoleService roleService;
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
/**
* Invalid destination paths where in-place records can't be filed
*/
@DataProvider (name = "invalidDestinationPaths")
public Object[][] getInvalidDestinationPaths()
{
return new String[][]
{
{ "/", DESTINATION_PATH_NOT_FOUND_EXC },
{ "Unfiled Records", INVALID_DESTINATION_PATH_EXC },
{ "Transfers", INVALID_DESTINATION_PATH_EXC },
{ "Holds", INVALID_DESTINATION_PATH_EXC },
{ "rm/documentlibrary", DESTINATION_PATH_NOT_FOUND_EXC },
{ recordCategory.getName(), DESTINATION_PATH_NOT_RECORD_FOLDER_EXC },
// a closed record folder
{ Utility.buildPath(recordCategory.getName(), closedRecordFolder.getName()), CLOSED_RECORD_FOLDER_EXC},
// an arbitrary unfiled records folder
{ "Unfiled Records/" + unfiledContainerFolder.getName(), INVALID_DESTINATION_PATH_EXC },
// a collaboration site folder
{ testFolder.getCmisLocation(), DESTINATION_PATH_NOT_FOUND_EXC }
};
}
/**
* Invalid destination ids where in-place records can't be filed
*/
@DataProvider (name = "invalidDestinationIds")
public Object[][] getInvalidDestinationIds()
{
return new String[][]
{
{ getFilePlan(FILE_PLAN_ALIAS).getId() },
{ getUnfiledContainer(UNFILED_RECORDS_CONTAINER_ALIAS).getId() },
{ getTransferContainer(TRANSFERS_ALIAS).getId() },
{ rmRolesAndActionsAPI.getItemNodeRef(getAdminUser().getUsername(), getAdminUser().getPassword(),
"/" + HOLDS_CONTAINER) },
{ recordCategory.getId() },
{ unfiledContainerFolder.getId() },
{ testFolder.getNodeRef() }
};
}
@BeforeClass (alwaysRun = true)
public void declareAndFileDocumentAsRecordSetup() throws Exception
{
STEP("Create test collaboration site to store documents in.");
publicSite = dataSite.usingAdmin().createPublicRandomSite();
STEP("Create a test folder within the collaboration site");
testFolder = dataContent.usingAdmin().usingSite(publicSite).createFolder();
STEP("Create record categories and record folders");
recordCategory = createRootCategory(getRandomName("recordCategory"));
subCategory = createRecordCategory(recordCategory.getId(), getRandomName("subCategory"));
recordFolder = createFolder(recordCategory.getId(), getRandomName("recordFolder"));
subcategoryRecordFolder = createFolder(subCategory.getId(), getRandomName("recordFolder"));
unfiledContainerFolder = createUnfiledContainerChild(UNFILED_RECORDS_CONTAINER_ALIAS,
"Unfiled Folder " + getRandomAlphanumeric(), UNFILED_RECORD_FOLDER_TYPE);
closedRecordFolder = createFolder(recordCategory.getId(), getRandomName("closedRecordFolder"));
closeFolder(closedRecordFolder.getId());
STEP("Create rm users with different permissions on the record category");
userFillingPermission = roleService.createCollaboratorWithRMRoleAndPermission(publicSite, recordCategory, ROLE_RM_POWER_USER, PERMISSION_FILING);
userReadOnlyPermission = roleService.createCollaboratorWithRMRoleAndPermission(publicSite, recordCategory,
ROLE_RM_POWER_USER, PERMISSION_READ_RECORDS);
}
@BeforeMethod(alwaysRun = true)
public void createDocument() throws Exception
{
STEP("Create a document in the collaboration site");
testFile = dataContent.usingSite(publicSite)
.usingAdmin()
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
}
/**
* Given I am calling the "declare as record" action
* And I am not providing a location parameter value
* When I execute the action
* Then the document is declared as a record
* And is placed in the Unfiled Records location
*/
@Test
public void declareAndFileNoLocationUsingActionsAPI() throws Exception
{
STEP("Declare document as record without providing a location parameter value using v1 actions api");
getRestAPIFactory().getActionsAPI(userReadOnlyPermission).declareAsRecord(testFile);
STEP("Verify the declared record is placed in the Unfiled Records folder");
assertTrue(isMatchingRecordInUnfiledRecords(testFile), "Record should be filed to Unfiled Records folder");
STEP("Verify the document in collaboration site is now a record");
assertTrue(hasRecordAspect(testFile), "File should have record aspect");
}
/**
* Given I am calling the "declare as record" action
* And I provide a valid record folder in the location parameter
* When I execute the action
* Then the document is declared as a record
* And is filed to the record folder specified
*/
@Test
public void declareAndFileToValidLocationUsingActionsAPI() throws Exception
{
STEP("Declare document as record with a location parameter value");
getRestAPIFactory().getActionsAPI(userFillingPermission).declareAndFile(testFile,
Utility.buildPath(recordCategory.getName(), recordFolder.getName()));
STEP("Verify the declared record is placed in the record folder");
assertTrue(isMatchingRecordInRecordFolder(testFile, recordFolder), "Record should be filed to record folder");
STEP("Verify the document in collaboration site is now a record");
assertTrue(hasRecordAspect(testFile), "File should have record aspect");
}
/**
* Given I am calling the "declare as record" action
* And I provide an invalid record folder in the location parameter
* When I execute the action
* Then I receive an error indicating that I have attempted to declare and file a document into an invalid record folder
* And the document is not declared as a record
*/
@Test (dataProvider = "invalidDestinationPaths")
public void declareAndFileToInvalidLocationUsingActionsAPI(String containerPath, String expectedException) throws Exception
{
STEP("Declare document as record with an invalid location parameter value");
getRestAPIFactory().getActionsAPI().declareAndFile(testFile, containerPath);
assertStatusCode(ACCEPTED);
STEP("Check the exception thrown in alfresco logs");
//Retry the operation because sometimes it takes few seconds to throw the exception
Utility.sleep(6000, 30000, () ->
{
List<String> alfrescoLogs = dockerHelper.getAlfrescoLogs();
assertTrue(alfrescoLogs.stream().anyMatch(logLine -> logLine.contains(expectedException)));
});
STEP("Check that the file is not a record");
assertFalse(hasRecordAspect(testFile), "File should not have record aspect");
}
/**
* Given I declare a record using the v1 API
* When I provide a location parameter
* Then the record is declared in the correct location
*/
@Test
public void declareAndFileToValidLocationUsingFilesAPI() throws Exception
{
STEP("Declare document as record with a location parameter value");
Record record = getRestAPIFactory().getFilesAPI(userFillingPermission)
.usingParams(String.format("%s=%s", PARENT_ID_PARAM, recordFolder.getId()))
.declareAsRecord(testFile.getNodeRefWithoutVersion());
assertStatusCode(CREATED);
STEP("Verify the declared record is placed in the record folder");
assertEquals(record.getParentId(), recordFolder.getId(), "Record should be filed to record folder");
STEP("Verify the document in collaboration site is now a record");
assertTrue(hasRecordAspect(testFile), "File should have record aspect");
}
/**
* Given I declare a record using the v1 API
* When I provide an invalid record folder in the location parameter
* Then I receive an error indicating that I have attempted to declare and file a document into an invalid record folder
* And the document is not declared as a record
*/
@Test (dataProvider = "invalidDestinationIds")
public void declareAndFileToInvalidLocationUsingFilesAPI(String containerID) throws Exception
{
STEP("Declare document as record with an invalid location parameter value");
getRestAPIFactory().getFilesAPI()
.usingParams(String.format("%s=%s", PARENT_ID_PARAM, containerID))
.declareAsRecord(testFile.getNodeRefWithoutVersion());
assertStatusCode(BAD_REQUEST);
getRestAPIFactory().getRmRestWrapper()
.assertLastError()
.containsSummary("is not valid for this endpoint. Expected nodeType is:{http://www.alfresco.org/model/recordsmanagement/1.0}recordFolder");
STEP("Check that the file is not a record");
assertFalse(hasRecordAspect(testFile), "File should not have record aspect");
}
/**
* Given I am an user with read only permissions on a record folder
* When I declare and file a record to the record folder
* Then I receive an error indicating that the access is denied
* And the document is not declared as a record
*/
@Test
public void declareAndFileByUserWithReadOnlyPermission() throws Exception
{
STEP("Declare document as record with a record folder as location parameter");
getRestAPIFactory().getFilesAPI(userReadOnlyPermission)
.usingParams(String.format("%s=%s", PARENT_ID_PARAM, recordFolder.getId()))
.declareAsRecord(testFile.getNodeRefWithoutVersion());
assertStatusCode(FORBIDDEN);
STEP("Check that the file is not a record");
assertFalse(hasRecordAspect(testFile), "File should not have record aspect");
}
/**
* Given I am a non RM user
* When I declare and file a record to the record folder
* Then I receive an error indicating that the access is denied
* And the document is not declared as a record
*/
@Test
public void declareAndFileByNonRMUser() throws Exception
{
STEP("Create an user with no rm rights");
UserModel nonRMUser = getDataUser().createRandomTestUser();
getDataUser().addUserToSite(nonRMUser, publicSite, UserRole.SiteCollaborator);
STEP("Declare document as record with a record folder as location parameter");
getRestAPIFactory().getFilesAPI(nonRMUser)
.usingParams(String.format("%s=%s", PARENT_ID_PARAM, recordFolder.getId()))
.declareAsRecord(testFile.getNodeRefWithoutVersion());
assertStatusCode(FORBIDDEN);
STEP("Check that the file is not a record");
assertFalse(hasRecordAspect(testFile), "File should not have record aspect");
}
/**
* Given I declare a record using the v1 API
* When I provide a nonexistent record folder in the location parameter
* Then I receive an error indicating that the record folder does not exist
* And the document is not declared as a record
*/
@Test
public void declareAndFileToNonexistentRecordFolderUsingFilesAPI() throws Exception
{
STEP("Declare document as record with a nonexistent location parameter value");
getRestAPIFactory().getFilesAPI()
.usingParams(String.format("%s=%s", PARENT_ID_PARAM, "nonexistent"))
.declareAsRecord(testFile.getNodeRefWithoutVersion());
assertStatusCode(NOT_FOUND);
STEP("Check that the file is not a record");
assertFalse(hasRecordAspect(testFile), "File should not have record aspect");
}
/**
* Given I declare a record using the v1 API
* When I provide a closed record folder in the location parameter
* Then I receive an error indicating that the record folder is closed
* And the document is not declared as a record
*/
@Test
public void declareAndFileToClosedRecordFolderUsingFilesAPI() throws Exception
{
STEP("Declare document as record with a closed location parameter value");
getRestAPIFactory().getFilesAPI()
.usingParams(String.format("%s=%s", PARENT_ID_PARAM, closedRecordFolder.getId()))
.declareAsRecord(testFile.getNodeRefWithoutVersion());
assertStatusCode(UNPROCESSABLE_ENTITY);
getRestAPIFactory().getRmRestWrapper()
.assertLastError()
.containsSummary(CLOSED_RECORD_FOLDER_EXC);
STEP("Check that the file is not a record");
assertFalse(hasRecordAspect(testFile), "File should not have record aspect");
}
/**
* Given I declare a record using the v1 API
* When I provide a held record folder in the location parameter
* Then I receive an error indicating that the record folder is held
* And the document is not declared as a record
*/
@Test
public void declareAndFileToHeldRecordFolderUsingFilesAPI() throws Exception
{
RecordCategoryChild heldRecordFolder = createFolder(recordCategory.getId(), getRandomName("heldRecordFolder"));
rmRolesAndActionsAPI.createHold(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD_NAME,
"hold reason", "hold description");
rmRolesAndActionsAPI.addItemToHold(getAdminUser().getUsername(), getAdminUser().getPassword(),
heldRecordFolder.getId(), HOLD_NAME);
STEP("Declare document as record with a frozen location parameter value");
getRestAPIFactory().getFilesAPI()
.usingParams(String.format("%s=%s", PARENT_ID_PARAM, heldRecordFolder.getId()))
.declareAsRecord(testFile.getNodeRefWithoutVersion());
assertStatusCode(UNPROCESSABLE_ENTITY);
STEP("Check that the file is not a record");
assertFalse(hasRecordAspect(testFile), "File should not have record aspect");
}
/**
* Given I declare a record using the v1 API
* When I provide a location parameter
* Then the record is declared in the correct location
* And when I declare it again using a different location
* Then I get an invalid operation exception
*/
@Test
public void declareAndFileTwiceDifferentLocations() throws Exception
{
STEP("Create a document in the collaboration site");
FileModel testFile = dataContent.usingSite(publicSite).usingAdmin()
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
STEP("Declare document as record with a record folder as location parameter");
getRestAPIFactory().getFilesAPI(userFillingPermission)
.usingParams(String.format("%s=%s", PARENT_ID_PARAM, subcategoryRecordFolder.getId()))
.declareAsRecord(testFile.getNodeRefWithoutVersion());
assertStatusCode(CREATED);
STEP("Declare it again using a different record folder as location parameter");
getRestAPIFactory().getFilesAPI(userFillingPermission)
.usingParams(String.format("%s=%s", PARENT_ID_PARAM, recordFolder.getId()))
.declareAsRecord(testFile.getNodeRefWithoutVersion());
assertStatusCode(UNPROCESSABLE_ENTITY);
STEP("Verify the declared record is placed in the first record folder");
assertTrue(isMatchingRecordInRecordFolder(testFile, subcategoryRecordFolder),
"Record should be filed to recordFolder");
assertFalse(isMatchingRecordInRecordFolder(testFile, recordFolder),
"Record should not be filed to subcategoryRecordFolder");
}
@AfterClass(alwaysRun = true)
public void declareAndFileDocumentAsRecordCleanup()
{
//delete rm items
deleteRecordCategory(recordCategory.getId());
getRestAPIFactory().getUnfiledRecordFoldersAPI().deleteUnfiledRecordFolder(unfiledContainerFolder.getId());
//delete created collaboration site
dataSite.deleteSite(publicSite);
//delete users
getDataUser().deleteUser(userFillingPermission);
getDataUser().deleteUser(userReadOnlyPermission);
}
}

View File

@@ -100,10 +100,16 @@ public class DeclareDocumentAsRecordTests extends BaseRMRestTest
* And it is now a record * And it is now a record
* And it remains a secondary child of the starting location where I can still view it * And it remains a secondary child of the starting location where I can still view it
* <pre> * <pre>
*
* RM-6779
* Given I declare a record using the v1 API
* When I do not provide a location parameter
* Then the record is declared in the unfiled folder
*
* @throws Exception for malformed JSON API response * @throws Exception for malformed JSON API response
*/ */
@Test(description = "User with correct permissions can declare document as a record") @Test(description = "User with correct permissions can declare document as a record")
@AlfrescoTest(jira = "RM-4429") @AlfrescoTest(jira = "RM-4429, RM-6779")
public void userWithPrivilegesCanDeclareDocumentAsRecord() throws Exception public void userWithPrivilegesCanDeclareDocumentAsRecord() throws Exception
{ {
// create document in a folder in a collaboration site // create document in a folder in a collaboration site
@@ -156,8 +162,8 @@ public class DeclareDocumentAsRecordTests extends BaseRMRestTest
try try
( (
InputStream recordInputStream = getRestAPIFactory().getRecordsAPI().getRecordContent(record.getId()).asInputStream(); InputStream recordInputStream = getRestAPIFactory().getRecordsAPI().getRecordContent(record.getId()).asInputStream();
InputStream documentInputStream = documentPostFiling.getContentStream().getStream(); InputStream documentInputStream = documentPostFiling.getContentStream().getStream()
) )
{ {
assertEquals(DigestUtils.sha1(recordInputStream), DigestUtils.sha1(documentInputStream)); assertEquals(DigestUtils.sha1(recordInputStream), DigestUtils.sha1(documentInputStream));
} }

View File

@@ -775,7 +775,6 @@ public class RecordCategoryTests extends BaseRMRestTest
{ {
//is unfiled container //is unfiled container
containerId = getRestAPIFactory().getUnfiledContainersAPI().getUnfiledContainer(containerAlias).getId(); containerId = getRestAPIFactory().getUnfiledContainersAPI().getUnfiledContainer(containerAlias).getId();
;
} }
// Create a record folder // Create a record folder

View File

@@ -42,8 +42,6 @@ import java.util.List;
import org.alfresco.rest.rm.community.base.BaseRMRestTest; import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.record.Record; import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.site.RMSite;
import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordsAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RecordsAPI;
import org.alfresco.test.AlfrescoTest; import org.alfresco.test.AlfrescoTest;

View File

@@ -49,7 +49,6 @@ import static org.springframework.http.HttpStatus.NO_CONTENT;
import static org.springframework.http.HttpStatus.OK; import static org.springframework.http.HttpStatus.OK;
import org.alfresco.dataprep.CMISUtil; import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.core.JsonBodyGenerator;
import org.alfresco.rest.core.RestResponse; import org.alfresco.rest.core.RestResponse;
import org.alfresco.rest.core.v0.BaseAPI.RM_ACTIONS; import org.alfresco.rest.core.v0.BaseAPI.RM_ACTIONS;
import org.alfresco.rest.model.RestNodeBodyMoveCopyModel; import org.alfresco.rest.model.RestNodeBodyMoveCopyModel;
@@ -66,6 +65,7 @@ import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordsAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RecordsAPI;
import org.alfresco.rest.v0.RMRolesAndActionsAPI; import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.service.DispositionScheduleService; import org.alfresco.rest.v0.service.DispositionScheduleService;
import org.alfresco.rest.v0.service.RoleService;
import org.alfresco.test.AlfrescoTest; import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.data.RandomData; import org.alfresco.utility.data.RandomData;
import org.alfresco.utility.model.FileModel; import org.alfresco.utility.model.FileModel;
@@ -90,6 +90,8 @@ public class DeleteRecordTests extends BaseRMRestTest
private RMRolesAndActionsAPI rmRolesAndActionsAPI; private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@Autowired @Autowired
private org.alfresco.rest.v0.RecordsAPI recordsAPI; private org.alfresco.rest.v0.RecordsAPI recordsAPI;
@Autowired
private RoleService roleService;
/** /**
* <pre> * <pre>
@@ -236,15 +238,12 @@ public class DeleteRecordTests extends BaseRMRestTest
public void userWithoutDeleteRecordsCapabilityCantDeleteRecord() throws Exception public void userWithoutDeleteRecordsCapabilityCantDeleteRecord() throws Exception
{ {
// Create test user and add it with collaboration privileges // Create test user and add it with collaboration privileges
UserModel deleteUser = getDataUser().createRandomTestUser("delnoperm"); // Add RM role to user, RM Power User doesn't have the "Delete Record" capabilities
UserModel deleteUser = roleService.createUserWithRMRole(ROLE_RM_POWER_USER.roleId);
getDataUser().addUserToSite(deleteUser, new SiteModel(getRestAPIFactory().getRMSiteAPI().getSite().getId()), SiteCollaborator); getDataUser().addUserToSite(deleteUser, new SiteModel(getRestAPIFactory().getRMSiteAPI().getSite().getId()), SiteCollaborator);
String username = deleteUser.getUsername(); String username = deleteUser.getUsername();
logger.info("Test user: " + username); logger.info("Test user: " + username);
// Add RM role to user, RM Power User doesn't have the "Delete Record" capabilities
getRestAPIFactory().getRMUserAPI().assignRoleToUser(username, ROLE_RM_POWER_USER.roleId);
assertStatusCode(OK);
// Create random folder // Create random folder
RecordCategoryChild recordFolder = createCategoryFolderInFilePlan(); RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
logger.info("Random folder:" + recordFolder.getName()); logger.info("Random folder:" + recordFolder.getName());

View File

@@ -68,7 +68,7 @@ public class FileRecordsTests extends BaseRMRestTest
{ {
private UnfiledContainerChild electronicRecord = UnfiledContainerChild.builder() private UnfiledContainerChild electronicRecord = UnfiledContainerChild.builder()
.name(ELECTRONIC_RECORD_NAME) .name(ELECTRONIC_RECORD_NAME)
.nodeType(CONTENT_TYPE.toString()) .nodeType(CONTENT_TYPE)
.content(RecordContent.builder().mimeType("text/plain").build()) .content(RecordContent.builder().mimeType("text/plain").build())
.build(); .build();
@@ -78,14 +78,14 @@ public class FileRecordsTests extends BaseRMRestTest
.title("Title") .title("Title")
.build()) .build())
.name(NONELECTRONIC_RECORD_NAME) .name(NONELECTRONIC_RECORD_NAME)
.nodeType(NON_ELECTRONIC_RECORD_TYPE.toString()) .nodeType(NON_ELECTRONIC_RECORD_TYPE)
.build(); .build();
/** /**
* Invalid containers where electronic and non-electronic records can be filed * Invalid containers where electronic and non-electronic records can be filed
*/ */
@DataProvider (name = "invalidContainersToFile") @DataProvider (name = "invalidContainersToFile")
public String[][] getFolderContainers() throws Exception public Object[][] getFolderContainers() throws Exception
{ {
return new String[][] { return new String[][] {
{ FILE_PLAN_ALIAS}, { FILE_PLAN_ALIAS},

View File

@@ -269,7 +269,7 @@ public class ReadRecordTests extends BaseRMRestTest
try try
( (
InputStream recordContentStream = recordsAPI.getRecordContent(binaryRecordId).asInputStream(); InputStream recordContentStream = recordsAPI.getRecordContent(binaryRecordId).asInputStream();
FileInputStream localFileStream = new FileInputStream(getFile(IMAGE_FILE)); FileInputStream localFileStream = new FileInputStream(getFile(IMAGE_FILE))
) )
{ {
assertEquals(DigestUtils.sha1(recordContentStream), DigestUtils.sha1(localFileStream)); assertEquals(DigestUtils.sha1(recordContentStream), DigestUtils.sha1(localFileStream));

View File

@@ -66,10 +66,12 @@ import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordsAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RecordsAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.UnfiledContainerAPI; import org.alfresco.rest.rm.community.requests.gscore.api.UnfiledContainerAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.UnfiledRecordFolderAPI; import org.alfresco.rest.rm.community.requests.gscore.api.UnfiledRecordFolderAPI;
import org.alfresco.rest.v0.service.RoleService;
import org.alfresco.test.AlfrescoTest; import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.constants.UserRole; import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.model.SiteModel; import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel; import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterClass; import org.testng.annotations.AfterClass;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@@ -87,6 +89,9 @@ public class UpdateRecordsTests extends BaseRMRestTest
/* to be used to append to modifications */ /* to be used to append to modifications */
private final String MODIFIED_PREFIX = "modified_"; private final String MODIFIED_PREFIX = "modified_";
@Autowired
private RoleService roleService;
/** Incomplete electronic and non electronic records created in one record folder, unfiled records container and one unfiled record folder */ /** Incomplete electronic and non electronic records created in one record folder, unfiled records container and one unfiled record folder */
@DataProvider(name = "incompleteRecords") @DataProvider(name = "incompleteRecords")
public Object[][] getIncompleteRecords() throws Exception public Object[][] getIncompleteRecords() throws Exception
@@ -234,15 +239,12 @@ public class UpdateRecordsTests extends BaseRMRestTest
public void userWithEditMetadataCapsCanUpdateMetadata() throws Exception public void userWithEditMetadataCapsCanUpdateMetadata() throws Exception
{ {
RMUserAPI rmUserAPI = getRestAPIFactory().getRMUserAPI(); RMUserAPI rmUserAPI = getRestAPIFactory().getRMUserAPI();
// Create test user and add it with collab. privileges // Create test user and add it with collab. privileges.
UserModel updateUser = getDataUser().createRandomTestUser("updateuser"); // RM Security Officer is the lowest role with Edit Record Metadata capabilities
UserModel updateUser = roleService.createUserWithRMRole(ROLE_RM_SECURITY_OFFICER.roleId);
updateUser.setUserRole(UserRole.SiteCollaborator); updateUser.setUserRole(UserRole.SiteCollaborator);
getDataUser().addUserToSite(updateUser, new SiteModel(getRestAPIFactory().getRMSiteAPI().getSite().getId()), UserRole.SiteCollaborator); getDataUser().addUserToSite(updateUser, new SiteModel(getRestAPIFactory().getRMSiteAPI().getSite().getId()), UserRole.SiteCollaborator);
// RM Security Officer is the lowest role with Edit Record Metadata capabilities
rmUserAPI.assignRoleToUser(updateUser.getUsername(), ROLE_RM_SECURITY_OFFICER.roleId);
assertStatusCode(OK);
// Create random folder // Create random folder
RecordCategoryChild recordFolder = createCategoryFolderInFilePlan(); RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
logger.info("random folder:" + recordFolder.getName()); logger.info("random folder:" + recordFolder.getName());

View File

@@ -66,7 +66,7 @@ public class RMSiteUtil
/** /**
* Creates an RM Site for the given compliance and default title and description * Creates an RM Site for the given compliance and default title and description
* *
* @param The RM site compliance * @param compliance The RM site compliance
* @return The {@link RMSite} with the given details * @return The {@link RMSite} with the given details
*/ */
private static RMSite createRMSiteModel(RMSiteCompliance compliance) private static RMSite createRMSiteModel(RMSiteCompliance compliance)