diff --git a/rm-automation/rm-automation-community-rest-api/pom.xml b/rm-automation/rm-automation-community-rest-api/pom.xml index 583d5b15e7..4662386d6c 100644 --- a/rm-automation/rm-automation-community-rest-api/pom.xml +++ b/rm-automation/rm-automation-community-rest-api/pom.xml @@ -85,5 +85,10 @@ commons-collections4 4.1 + + com.github.docker-java + docker-java + 3.0.14 + diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/RMRestProperties.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/RMRestProperties.java index 1d6e11f909..99991254a6 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/RMRestProperties.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/RMRestProperties.java @@ -56,4 +56,7 @@ public class RMRestProperties extends RestProperties @Value ("${rest.rmPath}") private String restRmPath; + + @Value ("${docker.host}") + private String dockerHost; } diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/RestAPIFactory.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/RestAPIFactory.java index 05e5c3db21..ac0a6025cc 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/RestAPIFactory.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/RestAPIFactory.java @@ -34,6 +34,7 @@ import org.alfresco.rest.requests.Node; import org.alfresco.rest.requests.coreAPI.RestCoreAPI; import org.alfresco.rest.requests.search.SearchAPI; 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.FilesAPI; import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI; @@ -225,4 +226,14 @@ public class RestAPIFactory { return getGSCoreAPI(userModel).usingUnfiledRecordFolder(); } + + public ActionsExecutionAPI getActionsAPI(UserModel userModel) + { + return getGSCoreAPI(userModel).usingActionsExecutionsAPI(); + } + + public ActionsExecutionAPI getActionsAPI() + { + return getGSCoreAPI(null).usingActionsExecutionsAPI(); + } } diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java index 20acd4cf57..7438ee5ed6 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/core/v0/BaseAPI.java @@ -89,7 +89,7 @@ public abstract class BaseAPI private AlfrescoHttpClientFactory alfrescoHttpClientFactory; @Autowired - private ContentService contentService; + protected ContentService contentService; public static final String NODE_REF_WORKSPACE_SPACES_STORE = "workspace://SpacesStore/"; private static final String FILE_PLAN_PATH = "/Sites/rm/documentLibrary"; diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/user/UserPermissions.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/user/UserPermissions.java index 1b9dfe5aba..7c237bd47c 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/user/UserPermissions.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/model/user/UserPermissions.java @@ -32,9 +32,16 @@ package org.alfresco.rest.rm.community.model.user; * @author Kristijan Conkas * @since 2.6 */ -public class UserPermissions +public enum UserPermissions { - public static final String PERMISSION_FILING = "Filing"; - public static final String PERMISSION_READ_RECORDS = "ReadRecords"; - public static final String PERMISSION_FILE_RECORDS = "FileRecords"; + PERMISSION_FILING("Filing"), + PERMISSION_READ_RECORDS("ReadRecords"), + PERMISSION_FILE_RECORDS("FileRecords"); + + public final String permissionId; + + UserPermissions(String permissionId) + { + this.permissionId = permissionId; + } } diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/RMModelRequest.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/RMModelRequest.java index c9eefdfa0d..7f1435142a 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/RMModelRequest.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/RMModelRequest.java @@ -41,14 +41,14 @@ import lombok.Setter; * @author Tuna Aksoy * @since 2.6 */ -public abstract class RMModelRequest extends ModelRequest +public abstract class RMModelRequest extends ModelRequest { @Getter (value = PROTECTED) @Setter (value = PRIVATE) private RMRestWrapper rmRestWrapper; /** - * @param restWrapper + * @param rmRestWrapper */ public RMModelRequest(RMRestWrapper rmRestWrapper) { diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/GSCoreAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/GSCoreAPI.java index 23f6655166..063eb03b43 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/GSCoreAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/GSCoreAPI.java @@ -33,6 +33,7 @@ import com.jayway.restassured.RestAssured; import org.alfresco.rest.core.RMRestProperties; 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.gscore.api.FilePlanAPI; 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 records/... API path * - * @return {@link FilePlanComponentAPI} + * @return {@link RecordsAPI} */ public RecordsAPI usingRecords() { @@ -179,4 +180,14 @@ public class GSCoreAPI extends RMModelRequest { return new RMUserAPI(getRmRestWrapper()); } + + /** + * Provides DSL for ActionExecution API + * + * @return {@link ActionsExecutionAPI} + */ + public ActionsExecutionAPI usingActionsExecutionsAPI() + { + return new ActionsExecutionAPI(getRmRestWrapper()); + } } diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/ActionsExecutionAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/ActionsExecutionAPI.java new file mode 100644 index 0000000000..a977db9ad6 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/ActionsExecutionAPI.java @@ -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 . + * #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); + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/FilePlanAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/FilePlanAPI.java index 2dc3978e1b..895ccd6d5e 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/FilePlanAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/FilePlanAPI.java @@ -54,7 +54,7 @@ public class FilePlanAPI extends RMModelRequest /** * Constructor. * - * @param restWrapper + * @param rmRestWrapper RM REST Wrapper */ public FilePlanAPI(RMRestWrapper rmRestWrapper) { diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/FilesAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/FilesAPI.java index 10da1e0570..8559459294 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/FilesAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/FilesAPI.java @@ -41,10 +41,12 @@ import org.alfresco.rest.rm.community.requests.RMModelRequest; * @author Kristijan Conkas * @since 2.6 */ -public class FilesAPI extends RMModelRequest +public class FilesAPI extends RMModelRequest { + public static final String PARENT_ID_PARAM = "parentId"; + /** - * @param rmRestWrapper + * @param rmRestWrapper RM REST Wrapper */ public FilesAPI(RMRestWrapper rmRestWrapper) { @@ -55,26 +57,6 @@ public class FilesAPI extends RMModelRequest * Declare file 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 * @throws Exception for malformed JSON responses */ @@ -82,7 +64,12 @@ public class FilesAPI extends RMModelRequest { mandatoryString("fileId", fileId); - return declareAsRecord(fileId, EMPTY); + return getRmRestWrapper().processModel(Record.class, simpleRequest( + POST, + "/files/{fileId}/declare?{parameters}", + fileId, + getRmRestWrapper().getParameters() + )); } } diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RMUserAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RMUserAPI.java index d24c53c614..7b53f855ea 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RMUserAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RMUserAPI.java @@ -59,7 +59,7 @@ import org.alfresco.utility.model.UserModel; public class RMUserAPI extends RMModelRequest { /** - * @param rmRestWrapper + * @param rmRestWrapper RM REST Wrapper */ public RMUserAPI(RMRestWrapper rmRestWrapper) { @@ -86,9 +86,8 @@ public class RMUserAPI extends RMModelRequest * Assign RM role to user * @param userName User's username * @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(); @@ -117,11 +116,11 @@ public class RMUserAPI extends RMModelRequest /** * 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 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(); @@ -132,7 +131,7 @@ public class RMUserAPI extends RMModelRequest .addArray("permissions") .addObject() .add("authority", user.getUsername()) - .add("role", permission) + .add("role", permission.permissionId) .end() .getJson(); diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordCategoryAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordCategoryAPI.java index 9158ce00e5..2d8121f36a 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordCategoryAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordCategoryAPI.java @@ -54,7 +54,7 @@ public class RecordCategoryAPI extends RMModelRequest /** * Constructor. * - * @param restWrapper + * @param rmRestWrapper RM REST Wrapper */ public RecordCategoryAPI(RMRestWrapper rmRestWrapper) { diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordFolderAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordFolderAPI.java index bc79c916e5..230517d571 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordFolderAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordFolderAPI.java @@ -66,7 +66,7 @@ public class RecordFolderAPI extends RMModelRequest /** * Constructor. * - * @param restWrapper + * @param rmRestWrapper RM REST Wrapper */ public RecordFolderAPI(RMRestWrapper rmRestWrapper) { diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java index 6057234ecb..f9958fc5bf 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/RecordsAPI.java @@ -53,7 +53,7 @@ import org.alfresco.rest.rm.community.requests.RMModelRequest; public class RecordsAPI extends RMModelRequest { /** - * @param rmRestWrapper + * @param rmRestWrapper RM REST Wrapper */ public RecordsAPI(RMRestWrapper rmRestWrapper) { diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/TransferAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/TransferAPI.java index 9ec19094e0..4bcf18813e 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/TransferAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/TransferAPI.java @@ -46,7 +46,7 @@ import org.alfresco.rest.rm.community.requests.RMModelRequest; public class TransferAPI extends RMModelRequest { /** - * @param rmRestWrapper + * @param rmRestWrapper RM REST Wrapper */ public TransferAPI(RMRestWrapper rmRestWrapper) { diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/TransferContainerAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/TransferContainerAPI.java index 22ae02b913..4613a65624 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/TransferContainerAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/TransferContainerAPI.java @@ -50,7 +50,7 @@ import org.alfresco.rest.rm.community.requests.RMModelRequest; public class TransferContainerAPI extends RMModelRequest { /** - * @param rmRestWrapper + * @param rmRestWrapper RM REST Wrapper */ public TransferContainerAPI(RMRestWrapper rmRestWrapper) { diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/UnfiledContainerAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/UnfiledContainerAPI.java index 05a1e6b846..b919f9ea93 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/UnfiledContainerAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/UnfiledContainerAPI.java @@ -63,7 +63,7 @@ import org.alfresco.rest.rm.community.util.UnfiledContainerChildMixin; public class UnfiledContainerAPI extends RMModelRequest { /** - * @param rmRestWrapper + * @param rmRestWrapper RM REST Wrapper */ public UnfiledContainerAPI(RMRestWrapper rmRestWrapper) { diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/UnfiledRecordFolderAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/UnfiledRecordFolderAPI.java index aa4328ccfd..d04576ed21 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/UnfiledRecordFolderAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/requests/gscore/api/UnfiledRecordFolderAPI.java @@ -63,7 +63,7 @@ import org.alfresco.rest.rm.community.util.UnfiledContainerChildMixin; public class UnfiledRecordFolderAPI extends RMModelRequest { /** - * @param rmRestWrapper + * @param rmRestWrapper RM REST Wrapper */ public UnfiledRecordFolderAPI(RMRestWrapper rmRestWrapper) { diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/util/DockerHelper.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/util/DockerHelper.java new file mode 100644 index 0000000000..ce17d71717 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/rm/community/util/DockerHelper.java @@ -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 . + * #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 getDockerLogs(String containerId) + { + final List 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 getAlfrescoLogs() + { + final Optional 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 findContainerByImageName(String imageName) + { + final List containers = getDockerClient().listContainersCmd().withShowAll(true).exec(); + + return containers.stream() + .filter(container -> container.getImage().contains(imageName)) + .findFirst(); + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java index 96025d88b3..2a98261c7e 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RMRolesAndActionsAPI.java @@ -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.apache.http.HttpStatus.SC_OK; import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertTrue; import static org.testng.AssertJUnit.fail; @@ -44,10 +45,10 @@ import java.util.Set; import org.alfresco.dataprep.AlfrescoHttpClient; import org.alfresco.dataprep.AlfrescoHttpClientFactory; -import org.alfresco.dataprep.ContentService; import org.alfresco.dataprep.UserService; import org.alfresco.rest.core.v0.BaseAPI; import org.alfresco.rest.core.v0.RMEvents; +import org.alfresco.utility.Utility; import org.apache.chemistry.opencmis.client.api.CmisObject; import org.apache.commons.httpclient.HttpStatus; import org.apache.http.HttpResponse; @@ -73,6 +74,8 @@ import org.springframework.stereotype.Component; @Component public class RMRolesAndActionsAPI extends BaseAPI { + public static final String HOLDS_CONTAINER = "Holds"; + /** The URI to view the configured roles and capabilities. */ private static final String RM_ROLES = "{0}rma/admin/rmroles"; /** 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 String MOVE_ACTIONS_API = "action/rm-move-to/site/rm/documentLibrary/{0}"; 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 */ @Autowired @@ -92,9 +97,6 @@ public class RMRolesAndActionsAPI extends BaseAPI @Autowired private UserService userService; - @Autowired - private ContentService contentService; - /** * Get all the configured RM roles. * @@ -105,7 +107,8 @@ public class RMRolesAndActionsAPI extends BaseAPI public Set getConfiguredRoles(String adminUser, String adminPassword) { // 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(); } @@ -119,11 +122,31 @@ public class RMRolesAndActionsAPI extends BaseAPI */ public Set 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)); 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 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. * @@ -135,13 +158,8 @@ public class RMRolesAndActionsAPI extends BaseAPI */ public void createRole(String adminUser, String adminPassword, String roleName, String roleDisplayLabel, Set capabilities) { - JSONObject requestBody = new JSONObject(); - requestBody.put("name", roleName); - 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); + doPostJsonRequest(adminUser, adminPassword, HttpStatus.SC_OK, roleRequestBody(roleName, roleDisplayLabel, capabilities), + RM_ROLES); } /** @@ -155,13 +173,8 @@ public class RMRolesAndActionsAPI extends BaseAPI */ public void updateRole(String adminUser, String adminPassword, String roleName, String roleDisplayLabel, Set capabilities) { - JSONObject requestBody = new JSONObject(); - requestBody.put("name", 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); + doPutJsonRequest(adminUser, adminPassword, HttpStatus.SC_OK, roleRequestBody(roleName, roleDisplayLabel, capabilities), + RM_ROLES_ROLE, roleName); } /** @@ -174,8 +187,8 @@ public class RMRolesAndActionsAPI extends BaseAPI public void deleteRole(String adminUser, String adminPassword, String roleName) { doDeleteRequest(adminUser, adminPassword, MessageFormat.format(RM_ROLES_ROLE, "{0}", roleName)); - boolean success = !getConfiguredRoles(adminUser, adminPassword).contains(roleName); - assertTrue("Failed to delete role " + roleName + " with " + adminUser, success); + assertFalse("Failed to delete role " + roleName + " with " + adminUser, + getConfiguredRoles(adminUser, adminPassword).contains(roleName)); } /** @@ -274,7 +287,7 @@ public class RMRolesAndActionsAPI extends BaseAPI } catch (JSONException | IOException e) { - e.printStackTrace(); + LOGGER.error(e.toString()); } 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 password the user's password * @param contentName the content name * @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) { - String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, contentName); - JSONObject requestParams = new JSONObject(); - requestParams.put("name", action.getAction()); - requestParams.put("nodeRef", recNodeRef); + final JSONObject actionParams = new JSONObject(); if (date != null) { - String thisMoment = date.format(ISO_INSTANT_FORMATTER); - requestParams.put("params", new JSONObject() - .put("asOfDate", new JSONObject() - .put("iso8601", thisMoment) - ) - ); + actionParams.put("asOfDate", new JSONObject().put("iso8601", ISO_INSTANT_FORMATTER.format(date))); } + final JSONObject requestParams = actionsRequestBody(user, password, contentName, action, actionParams); 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) { - 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(); - String formattedDate = ISO_INSTANT_FORMATTER.format(date); - requestParams.put("params", new JSONObject() - .put("eventName", event.getEventName()) - .put("eventCompletedBy", user) - .put("eventCompletedAt", new JSONObject() - .put("iso8601", formattedDate) - ) - ); - + final JSONObject actionParams = new JSONObject().put("eventName", event.getEventName()) + .put("eventCompletedBy", user) + .put("eventCompletedAt", new JSONObject() + .put("iso8601", ISO_INSTANT_FORMATTER.format(date)) + ); + final JSONObject requestParams = actionsRequestBody(user, password, nodeName, RM_ACTIONS.COMPLETE_EVENT, + actionParams); 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) { - String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, contentName); - JSONObject requestParams = new JSONObject(); - requestParams.put("name", RM_ACTIONS.UNDO_EVENT.getAction()); - requestParams.put("nodeRef", recNodeRef); - requestParams.put("params", new JSONObject() - .put("eventName", event.getEventName())); - + final JSONObject requestParams = actionsRequestBody(user, password, contentName, RM_ACTIONS.UNDO_EVENT, + new JSONObject().put("eventName", event.getEventName())); return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API); } @@ -416,8 +435,8 @@ public class RMRolesAndActionsAPI extends BaseAPI { item.delete(); } - boolean success = !(contentService.getFolderObject(contentService.getCMISSession(username, password), siteId, containerName).getChildren().getHasMoreItems()); - assertTrue("Not all items were deleted from " + containerName, success); + assertFalse("Not all items were deleted from " + containerName, + 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) { - deleteItem(username, password, "/Holds/" + holdName); + deleteItem(username, password, String.format("/%s/%s", HOLDS_CONTAINER, holdName)); } - /** * 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) { // if the hold already exists don't try to create it again - String holdsContainerPath = getFilePlanPath() + "/Holds"; - String fullHoldPath = holdsContainerPath + "/" + holdName; - CmisObject hold = getObjectByPath(user, password, fullHoldPath); + final String fullHoldPath = Utility.buildPath(getFilePlanPath(), HOLDS_CONTAINER) + holdName; + final CmisObject hold = getObjectByPath(user, password, fullHoldPath); if (hold != null) { return null; } // 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("prop_cm_name", holdName); requestParams.put("prop_cm_description", description); requestParams.put("prop_rma_holdReason", reason); // 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, getObjectByPath(user, password, fullHoldPath)); 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 * diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordFoldersAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordFoldersAPI.java index 82a50deb94..cae9768e39 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordFoldersAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordFoldersAPI.java @@ -28,14 +28,12 @@ package org.alfresco.rest.v0; import static org.apache.http.HttpStatus.SC_OK; -import org.alfresco.dataprep.ContentService; import org.alfresco.rest.core.v0.BaseAPI; import org.apache.http.HttpResponse; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** @@ -49,9 +47,6 @@ public class RecordFoldersAPI extends BaseAPI { private static final Logger LOGGER = LoggerFactory.getLogger(RecordFoldersAPI.class); - @Autowired - private ContentService contentService; - /** * Close the record folder * diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordsAPI.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordsAPI.java index ac2fe6933f..0598a95d06 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordsAPI.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/RecordsAPI.java @@ -33,7 +33,6 @@ import java.text.MessageFormat; import java.util.Map; import org.alfresco.dataprep.CMISUtil.DocumentType; -import org.alfresco.dataprep.ContentService; import org.alfresco.rest.core.v0.BaseAPI; import org.apache.chemistry.opencmis.client.api.CmisObject; import org.apache.commons.lang3.tuple.Pair; @@ -42,7 +41,6 @@ import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; 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"; - @Autowired - private ContentService contentService; - /** * Declare documents as records * diff --git a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/RoleService.java b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/RoleService.java index ccf2785cd8..a5bdff72c0 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/RoleService.java +++ b/rm-automation/rm-automation-community-rest-api/src/main/java/org/alfresco/rest/v0/service/RoleService.java @@ -26,12 +26,22 @@ */ 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.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.v0.RMRolesAndActionsAPI; +import org.alfresco.utility.constants.UserRole; 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.stereotype.Service; @@ -45,11 +55,29 @@ import org.springframework.stereotype.Service; public class RoleService { @Autowired + @Getter (value = PROTECTED) private RMRolesAndActionsAPI rmRolesAndActionsAPI; @Autowired + @Getter (value = PROTECTED) 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 getRoleCapabilities(String roleName) + { + return getRmRolesAndActionsAPI().getCapabilitiesForRole(getDataUser().getAdminUser().getUsername(), + getDataUser().getAdminUser().getPassword(), roleName); + } + /** * Add capabilities to a role * @@ -58,12 +86,10 @@ public class RoleService */ public void addCapabilitiesToRole(UserRoles role, Set capabilities) { - Set roleCapabilities = new HashSet<>(); - roleCapabilities.addAll(rmRolesAndActionsAPI.getCapabilitiesForRole(dataUser.getAdminUser().getUsername(), - dataUser.getAdminUser().getPassword(), role.roleId)); - capabilities.stream().forEach(cap -> roleCapabilities.add(cap)); + Set roleCapabilities = new HashSet<>(getRoleCapabilities(role.roleId)); + roleCapabilities.addAll(capabilities); - rmRolesAndActionsAPI.updateRole(dataUser.getAdminUser().getUsername(), dataUser.getAdminUser().getPassword(), + getRmRolesAndActionsAPI().updateRole(getDataUser().getAdminUser().getUsername(), getDataUser().getAdminUser().getPassword(), role.roleId, role.displayName, roleCapabilities); } @@ -75,10 +101,75 @@ public class RoleService */ public void removeCapabilitiesFromRole(UserRoles role, Set capabilities) { - Set roleCapabilities = rmRolesAndActionsAPI.getCapabilitiesForRole(dataUser.getAdminUser().getUsername(), - dataUser.getAdminUser().getPassword(), role.roleId); + Set roleCapabilities = getRoleCapabilities(role.roleId); roleCapabilities.removeAll(capabilities); - rmRolesAndActionsAPI.updateRole(dataUser.getAdminUser().getUsername(), dataUser.getAdminUser().getPassword(), + getRmRolesAndActionsAPI().updateRole(getDataUser().getAdminUser().getUsername(), getDataUser().getAdminUser().getPassword(), 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; + } } diff --git a/rm-automation/rm-automation-community-rest-api/src/main/resources/config.properties b/rm-automation/rm-automation-community-rest-api/src/main/resources/config.properties index f66389d1f5..5d54d6c02d 100644 --- a/rm-automation/rm-automation-community-rest-api/src/main/resources/config.properties +++ b/rm-automation/rm-automation-community-rest-api/src/main/resources/config.properties @@ -1,3 +1,6 @@ alfresco.server=localhost alfresco.port=8080 -rest.rmPath=alfresco/api/-default-/public/gs/versions/1 \ No newline at end of file +rest.rmPath=alfresco/api/-default-/public/gs/versions/1 + +# Docker properties values +docker.host=tcp://127.0.0.1:2375 \ No newline at end of file diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java index 15e831dc9a..baa37afc28 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/BaseRMRestTest.java @@ -52,8 +52,10 @@ import static org.testng.Assert.assertTrue; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; +import lombok.Getter; import org.alfresco.dataprep.ContentService; import org.alfresco.rest.RestTest; 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.RecordCategoryChild; 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.site.RMSite; 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.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.RecordCategoryAPI; 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.SearchNodeModel; import org.alfresco.rest.search.SearchRequest; -import org.alfresco.rest.v0.RMRolesAndActionsAPI; import org.alfresco.rest.v0.SearchAPI; +import org.alfresco.utility.Utility; import org.alfresco.utility.data.DataUser; import org.alfresco.utility.model.ContentModel; +import org.alfresco.utility.model.FileModel; import org.alfresco.utility.model.FolderModel; import org.alfresco.utility.model.SiteModel; import org.alfresco.utility.model.UserModel; @@ -88,8 +93,6 @@ import org.springframework.http.HttpStatus; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; -import lombok.Getter; - /** * Base class for all GS REST API Tests * @@ -111,10 +114,6 @@ public class BaseRMRestTest extends RestTest @Getter(value = PROTECTED) private ContentService contentService; - @Autowired - @Getter(value = PROTECTED) - private RMRolesAndActionsAPI rmRolesAndActionsAPI; - @Autowired @Getter(value = PROTECTED) private SearchAPI searchApi; @@ -481,32 +480,32 @@ public class BaseRMRestTest extends RestTest 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); } - public UnfiledContainer getUnfiledContainer(String componentId) throws Exception + public UnfiledContainer getUnfiledContainer(String 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); } - public TransferContainer getTransferContainer(String componentId) throws Exception + public TransferContainer getTransferContainer(String 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); } - public FilePlan getFilePlan(String componentId) throws Exception + public FilePlan getFilePlan(String componentId) { return getFilePlanAsUser(getAdminUser(), componentId); } @@ -614,21 +613,6 @@ public class BaseRMRestTest extends RestTest 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 * @@ -658,6 +642,8 @@ public class BaseRMRestTest extends RestTest } catch (InterruptedException e) { + // Restore interrupted state... + Thread.currentThread().interrupt(); } } @@ -706,6 +692,8 @@ public class BaseRMRestTest extends RestTest } catch (InterruptedException e) { + // Restore interrupted state... + Thread.currentThread().interrupt(); } } @@ -755,6 +743,8 @@ public class BaseRMRestTest extends RestTest } catch (InterruptedException e) { + // Restore interrupted state... + Thread.currentThread().interrupt(); } } result = searchApi.searchForNodePropertyAsUser(user.getUsername(), user.getPassword(), nodeRef, @@ -794,4 +784,86 @@ public class BaseRMRestTest extends RestTest 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 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 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; + } + } } diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/DataProviderClass.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/DataProviderClass.java index b4b39f70b8..5f90e68072 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/DataProviderClass.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/base/DataProviderClass.java @@ -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.UNFILED_CONTAINER_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; @@ -105,7 +104,7 @@ public class DataProviderClass * @return file plan component alias */ @DataProvider - public static String[][] categoryTypes() + public static Object[][] categoryTypes() { return new String[][] { { FOLDER_TYPE }, diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/files/DeclareAndFileDocumentAsRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/files/DeclareAndFileDocumentAsRecordTests.java new file mode 100644 index 0000000000..ab89fe6869 --- /dev/null +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/files/DeclareAndFileDocumentAsRecordTests.java @@ -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 . + * #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 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); + } +} diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/files/DeclareDocumentAsRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/files/DeclareDocumentAsRecordTests.java index 077703bca5..af871ccabe 100644 --- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/files/DeclareDocumentAsRecordTests.java +++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/files/DeclareDocumentAsRecordTests.java @@ -100,10 +100,16 @@ public class DeclareDocumentAsRecordTests extends BaseRMRestTest * And it is now a record * And it remains a secondary child of the starting location where I can still view it *
+     *
+     * 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
      */
     @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
     {
         // create document in a folder in a collaboration site
@@ -156,8 +162,8 @@ public class DeclareDocumentAsRecordTests extends BaseRMRestTest
         try
         (
             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));
         }
diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/recordcategories/RecordCategoryTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/recordcategories/RecordCategoryTests.java
index 9cd8b476b6..8580839556 100644
--- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/recordcategories/RecordCategoryTests.java
+++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/recordcategories/RecordCategoryTests.java
@@ -775,7 +775,6 @@ public class RecordCategoryTests extends BaseRMRestTest
         {
             //is unfiled container
             containerId = getRestAPIFactory().getUnfiledContainersAPI().getUnfiledContainer(containerAlias).getId();
-            ;
         }
 
         // Create a record folder
diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java
index d5ca79d7e3..cdd9fe2644 100644
--- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java
+++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/CompleteRecordTests.java
@@ -42,8 +42,6 @@ import java.util.List;
 
 import org.alfresco.rest.rm.community.base.BaseRMRestTest;
 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.RecordsAPI;
 import org.alfresco.test.AlfrescoTest;
diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/DeleteRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/DeleteRecordTests.java
index ef63360a39..bc88c6a6d6 100644
--- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/DeleteRecordTests.java
+++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/DeleteRecordTests.java
@@ -49,7 +49,6 @@ import static org.springframework.http.HttpStatus.NO_CONTENT;
 import static org.springframework.http.HttpStatus.OK;
 
 import org.alfresco.dataprep.CMISUtil;
-import org.alfresco.rest.core.JsonBodyGenerator;
 import org.alfresco.rest.core.RestResponse;
 import org.alfresco.rest.core.v0.BaseAPI.RM_ACTIONS;
 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.v0.RMRolesAndActionsAPI;
 import org.alfresco.rest.v0.service.DispositionScheduleService;
+import org.alfresco.rest.v0.service.RoleService;
 import org.alfresco.test.AlfrescoTest;
 import org.alfresco.utility.data.RandomData;
 import org.alfresco.utility.model.FileModel;
@@ -90,6 +90,8 @@ public class DeleteRecordTests extends BaseRMRestTest
     private RMRolesAndActionsAPI rmRolesAndActionsAPI;
     @Autowired
     private org.alfresco.rest.v0.RecordsAPI recordsAPI;
+    @Autowired
+    private RoleService roleService;
 
     /**
      * 
@@ -236,15 +238,12 @@ public class DeleteRecordTests extends BaseRMRestTest
     public void userWithoutDeleteRecordsCapabilityCantDeleteRecord() throws Exception
     {
         // 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);
         String username = deleteUser.getUsername();
         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
         RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
         logger.info("Random folder:" + recordFolder.getName());
diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/FileRecordsTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/FileRecordsTests.java
index 2a90dcb5bd..98a7963406 100644
--- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/FileRecordsTests.java
+++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/FileRecordsTests.java
@@ -68,7 +68,7 @@ public class FileRecordsTests extends BaseRMRestTest
 {
     private UnfiledContainerChild electronicRecord = UnfiledContainerChild.builder()
                                                                   .name(ELECTRONIC_RECORD_NAME)
-                                                                  .nodeType(CONTENT_TYPE.toString())
+                                                                  .nodeType(CONTENT_TYPE)
                                                                   .content(RecordContent.builder().mimeType("text/plain").build())
                                                                   .build();
 
@@ -78,14 +78,14 @@ public class FileRecordsTests extends BaseRMRestTest
                                                                                                             .title("Title")
                                                                                                             .build())
                                                                      .name(NONELECTRONIC_RECORD_NAME)
-                                                                     .nodeType(NON_ELECTRONIC_RECORD_TYPE.toString())
+                                                                     .nodeType(NON_ELECTRONIC_RECORD_TYPE)
                                                                      .build();
 
     /**
      * Invalid  containers where electronic and non-electronic records can be filed
      */
     @DataProvider (name = "invalidContainersToFile")
-    public String[][] getFolderContainers() throws Exception
+    public Object[][] getFolderContainers() throws Exception
     {
         return new String[][] {
             { FILE_PLAN_ALIAS},
diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/ReadRecordTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/ReadRecordTests.java
index 06b513ccac..e2c48d8695 100644
--- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/ReadRecordTests.java
+++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/ReadRecordTests.java
@@ -269,7 +269,7 @@ public class ReadRecordTests extends BaseRMRestTest
         try
         (
             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));
diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/UpdateRecordsTests.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/UpdateRecordsTests.java
index 2f8f3af510..35c2eee056 100644
--- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/UpdateRecordsTests.java
+++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/records/UpdateRecordsTests.java
@@ -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.UnfiledContainerAPI;
 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.utility.constants.UserRole;
 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.DataProvider;
 import org.testng.annotations.Test;
@@ -87,6 +89,9 @@ public class UpdateRecordsTests extends BaseRMRestTest
     /* to be used to append to modifications */
     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 */
     @DataProvider(name = "incompleteRecords")
     public Object[][] getIncompleteRecords() throws Exception
@@ -234,15 +239,12 @@ public class UpdateRecordsTests extends BaseRMRestTest
     public void userWithEditMetadataCapsCanUpdateMetadata() throws Exception
     {
         RMUserAPI rmUserAPI = getRestAPIFactory().getRMUserAPI();
-        // Create test user and add it with collab. privileges
-        UserModel updateUser = getDataUser().createRandomTestUser("updateuser");
+        // Create test user and add it with collab. privileges.
+        // 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);
         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
         RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
         logger.info("random folder:" + recordFolder.getName());
diff --git a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/utils/RMSiteUtil.java b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/utils/RMSiteUtil.java
index b3574a0fcb..80062165ca 100644
--- a/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/utils/RMSiteUtil.java
+++ b/rm-automation/rm-automation-community-rest-api/src/test/java/org/alfresco/rest/rm/community/utils/RMSiteUtil.java
@@ -66,7 +66,7 @@ public class RMSiteUtil
     /**
      * 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
      */
     private static RMSite createRMSiteModel(RMSiteCompliance compliance)