Merge branch 'feature/RM-5639_PreventClassificationBeyondParent_JavaAPI' into feature/RM-5647_PreventClassifedItemsBeingMoved_JavaApi

This commit is contained in:
Ramona Popa
2017-10-03 16:02:21 +03:00
16 changed files with 844 additions and 91 deletions

View File

@@ -24,7 +24,6 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.core;
import com.jayway.restassured.builder.RequestSpecBuilder;
@@ -154,17 +153,15 @@ public class RMRestWrapper
}
/**
* You can handle the request sent to server by calling this method. If for example you want to sent multipart form
* data you can use:
*
* <pre>
* restClient.configureRequestSpec().addMultiPart("filedata", Utility.getResourceTestDataFile("restapi-resource"))
* .addFormParam("renditions", "doclib").addFormParam("autoRename", true);
* You can handle the request sent to server by calling this method.
* If for example you want to sent multipart form data you can use: <pre>
* restClient.configureRequestSpec()
* .addMultiPart("filedata", Utility.getResourceTestDataFile("restapi-resource"))
* .addFormParam("renditions", "doclib")
* .addFormParam("autoRename", true);
*
* restClient.withCoreAPI().usingNode(ContentModel.my()).createNode();
* </pre>
*
* This will create the node using the multipart data defined.
* </pre> This will create the node using the multipart data defined.
*/
public RequestSpecBuilder configureRequestSpec()
{

View File

@@ -24,7 +24,6 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.core;
import static lombok.AccessLevel.PROTECTED;
@@ -67,7 +66,7 @@ import lombok.Setter;
public class RestAPIFactory
{
@Autowired
@Getter(value = PROTECTED)
@Getter (value = PROTECTED)
private DataUser dataUser;
@Resource(name = "RMRestWrapper")

View File

@@ -74,7 +74,7 @@ public abstract class BaseAPI
/** exception key in JSON response body */
private static final String EXCEPTION_KEY = "exception";
protected static final String NODE_PREFIX = "workspace/SpacesStore/";
public static final String NODE_PREFIX = "workspace/SpacesStore/";
protected static final String UPDATE_METADATA_API = "{0}node/{1}/formprocessor";
protected static final String ACTIONS_API = "{0}actionQueue";
protected static final String RM_ACTIONS_API = "{0}rma/actions/ExecutionQueue";
@@ -87,7 +87,7 @@ public abstract class BaseAPI
@Autowired
private ContentService contentService;
private static final String NODE_REF_WORKSPACE_SPACES_STORE = "workspace://SpacesStore/";
protected static final String NODE_REF_WORKSPACE_SPACES_STORE = "workspace://SpacesStore/";
private static final String FILE_PLAN_PATH = "/Sites/rm/documentLibrary";
/**

View File

@@ -0,0 +1,63 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.model.custom;
/**
* List of existing records management custom references.
*
* @author Rodica Sutu
* @since 2.6
*/
public enum CustomDefinitions
{
ATTACHMENT("Attachment"),
MESSAGE("Message"),
NEXT_VERSION("Next Version"),
RENDITION("Rendition");
/**
* The name of custom reference.
*/
private String definition;
/**
* Private constructor.
*/
CustomDefinitions(String definition)
{
this.definition = definition;
}
/**
* Get the name of the custom reference.
*
* @return The value of custom reference.
*/
public String getDefinition()
{
return definition;
}
}

View File

@@ -34,6 +34,8 @@ import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanCo
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_TITLE;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_VITAL_RECORD_INDICATOR;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
@@ -59,6 +61,7 @@ import lombok.NoArgsConstructor;
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties (ignoreUnknown = true)
public class RecordCategoryProperties extends TestModel
{
/*************************/

View File

@@ -40,6 +40,8 @@ import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanCo
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_TITLE;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.PROPERTIES_VITAL_RECORD_INDICATOR;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
@@ -65,6 +67,7 @@ import lombok.NoArgsConstructor;
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties (ignoreUnknown = true)
public class RecordFolderProperties extends TestModel
{
/*************************/

View File

@@ -0,0 +1,153 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.v0;
import java.text.MessageFormat;
import org.alfresco.rest.core.v0.BaseAPI;
import org.alfresco.rest.rm.community.model.custom.CustomDefinitions;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
/**
* Methods to make API requests using v0 API on Records Management Custom Model Reference Definitions
*
* @author Rodica Sutu
* @since 2.6
*/
@Component
public class CustomDefinitionsAPI extends BaseAPI
{
/**
* custom references endpoint
*/
private static final String CUSTOM_REFERENCE_API_ENDPOINT = "{0}rma/admin/customreferencedefinitions";
/**
* create reference endpoint
*/
private static final String CREATE_RELATIONSHIP_API_ENDPOINT = "{0}node/{1}/customreferences";
/**
* logger
*/
private static final Logger LOGGER = LoggerFactory.getLogger(CustomDefinitionsAPI.class);
/**
* Helper method to get the reference id for a custom reference
*
* @param adminUser user with administrative privileges
* @param adminPassword password for adminUser
* @param customDefinition custom reference definition name
* @return <code>reference id</code> if the customDefinition is found
* <code> null </code> otherwise
*
*/
public String getCustomReferenceId(String adminUser, String adminPassword, String customDefinition)
{
JSONObject getResponse = doGetRequest(adminUser, adminPassword, CUSTOM_REFERENCE_API_ENDPOINT);
if (getResponse != null)
{
try
{
JSONArray customDefinitions = getResponse.getJSONObject("data").getJSONArray("customReferences");
for (int i = 0; i < customDefinitions.length(); i++)
{
JSONObject item = customDefinitions.getJSONObject(i);
boolean hasSource = customDefinition.equalsIgnoreCase(
item.has("source") ? item.getString("source") : null
);
boolean hasTarget = customDefinition.equalsIgnoreCase(
item.has("target") ? item.getString("target") : null
);
boolean hasLabel = customDefinition.equalsIgnoreCase(
item.has("label") ? item.getString("label") : null
);
if ( hasSource || hasTarget || hasLabel)
{
return item.getString("refId");
}
}
}
catch (JSONException error)
{
LOGGER.error("Unable to get the refId for the custom reference definition " + customDefinition);
}
}
return null;
}
/**
* Helper method to add custom reference instance to the specified record node
*
* @param adminUser user with administrative privileges
* @param adminPassword password for adminUser
* @param recordNodeIdFrom node ref to set a custom reference
* @param recordNodeIdTo node ref of the to record
* @param relationshipType relation type to be created
* @return <code>true</code> if creating relationship was successful,
* <code>false</code> otherwise
*/
public boolean createRelationship(
String adminUser,
String adminPassword,
String recordNodeIdFrom,
String recordNodeIdTo,
CustomDefinitions relationshipType)
{
try
{
//create the request body
JSONObject requestParams = new JSONObject();
requestParams.put("toNode", NODE_REF_WORKSPACE_SPACES_STORE + recordNodeIdTo);
requestParams.put("refId", getCustomReferenceId(adminUser, adminPassword, relationshipType
.getDefinition()));
//send the API request to create the relationship
JSONObject setRelationshipStatus = doPostRequest(adminUser, adminPassword, requestParams,
MessageFormat.format(CREATE_RELATIONSHIP_API_ENDPOINT, "{0}", NODE_PREFIX + recordNodeIdFrom));
//check the response
if (setRelationshipStatus != null)
{
return setRelationshipStatus.getBoolean("success");
}
}
catch (JSONException error)
{
LOGGER.error("Unable to extract response parameter", error);
}
return false;
}
}

View File

@@ -24,7 +24,6 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.v0;
import java.text.MessageFormat;
@@ -61,26 +60,28 @@ public class SearchAPI extends BaseAPI
private static final String RM_SEARCH_ENDPOINT = "{0}alfresco/s/slingshot/rmsearch/{1}?{2}";
/** RM document search filters */
private static final String RM_DEFAULT_RECORD_FILTERS = "records/true,undeclared/true,vital/false,folders/false,categories/false,frozen/false,cutoff/false";
private static final String RM_DEFAULT_RECORD_FILTERS =
"records/true,undeclared/true,vital/false,folders/false,categories/false,frozen/false,cutoff/false";
/**
* Perform search request on search endpoint as a user.
* <p>
* This method is applicable only to endpoints that support HTTP GET requests and return JSON body as response.
*
* @param searchEndpoint
* @param searchUser
* @param searchPassword
* @return search results as a {@link JSONObject}, please refer to API documentation for details
*/
private JSONObject doSearch(String searchEndpoint, String searchUser, String searchPassword)
private JSONObject doSearch(
String searchEndpoint,
String searchUser,
String searchPassword)
{
return facetedRequest(searchUser, searchPassword, null, searchEndpoint);
return facetedRequest(searchUser, searchPassword, null, searchEndpoint);
}
/**
* Generic rm search.
*
* @param username
* @param password
* @param site
@@ -88,36 +89,45 @@ public class SearchAPI extends BaseAPI
* @param filters
* @return search results (see API reference for more details), null for any errors
*/
public JSONObject rmSearch(String username, String password, String site, String query, String filters)
public JSONObject rmSearch(
String username,
String password,
String site,
String query,
String filters)
{
List<BasicNameValuePair> searchParameters = new ArrayList<BasicNameValuePair>();
searchParameters.add(new BasicNameValuePair("query", query));
searchParameters.add(new BasicNameValuePair("filters", filters));
String requestURL = MessageFormat.format(RM_SEARCH_ENDPOINT,
alfrescoHttpClientFactory.getObject().getAlfrescoUrl(), (site != null) ? site : RM_SITE_ID,
URLEncodedUtils.format(searchParameters, "UTF-8"));
String requestURL = MessageFormat.format(
RM_SEARCH_ENDPOINT,
alfrescoHttpClientFactory.getObject().getAlfrescoUrl(),
(site != null) ? site : RM_SITE_ID,
URLEncodedUtils.format(searchParameters, "UTF-8"));
return doSearch(requestURL, username, password);
}
/**
* Search as a user for records on site "rm" matching query, using SearchAPI.RM_DEFAULT_RECORD_FILTERS <br>
* Search as a user for records on site "rm" matching query, using SearchAPI.RM_DEFAULT_RECORD_FILTERS
* <br>
* If more fine-grained control of search parameters is required, use rmSearch() directly.
*
* @param username
* @param password
* @param query
* @return list of record names
*/
public List<String> searchForRecordsAsUser(String username, String password, String query)
public List<String> searchForRecordsAsUser(
String username,
String password,
String query)
{
return getItemNames(rmSearch(username, password, "rm", query, RM_DEFAULT_RECORD_FILTERS));
}
/**
* Generic faceted search.
*
* @param username
* @param password
* @param parameters
@@ -130,7 +140,6 @@ public class SearchAPI extends BaseAPI
/**
* Execute faceted search for term.
*
* @param searchUser
* @param searchPassword
* @param searchTerm
@@ -138,12 +147,14 @@ public class SearchAPI extends BaseAPI
*/
public JSONObject facetedSearchForTerm(String searchUser, String searchPassword, String searchTerm)
{
return facetedSearch(searchUser, searchPassword, Arrays.asList(new BasicNameValuePair("term", searchTerm)));
return facetedSearch(
searchUser,
searchPassword,
Arrays.asList(new BasicNameValuePair("term", searchTerm)));
}
/**
* Helper method to search for documents as a user using faceted search.
*
* @param username to search as
* @param password for username
* @param term search term
@@ -156,7 +167,6 @@ public class SearchAPI extends BaseAPI
/**
* Helper method to extract list of names from search result.
*
* @param searchResult
* @return list of document or record names in search result
* @throws RuntimeException for malformed search response

View File

@@ -0,0 +1,56 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.v0;
import org.alfresco.rest.core.v0.BaseAPI;
import org.springframework.stereotype.Component;
/**
* Helper methods for performing actions on user trashcan
*
* @author Oana Nechiforescu
* @since 2.6
*/
@Component
public class UserTrashcanAPI extends BaseAPI
{
private static final String EMPTY_TRASHCAN = "{0}archive/workspace/SpacesStore";
/**
* Clears the trashcan for the current user
*
* @param username the username
* @param password the password
*
* @return true if the request succeeded, false if not
*/
public boolean emptyTrashcan(String username, String password)
{
return doDeleteRequest(username, password, EMPTY_TRASHCAN) != null;
}
}

View File

@@ -24,7 +24,6 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.base;
import static lombok.AccessLevel.PROTECTED;
@@ -53,6 +52,7 @@ import static org.springframework.http.HttpStatus.OK;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import org.alfresco.dataprep.ContentService;
@@ -72,6 +72,9 @@ 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;
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.utility.data.DataUser;
import org.alfresco.utility.model.FolderModel;
@@ -94,11 +97,11 @@ import lombok.Getter;
public class BaseRMRestTest extends RestTest
{
@Autowired
@Getter(value = PROTECTED)
@Getter (value = PROTECTED)
private RestAPIFactory restAPIFactory;
@Autowired
@Getter(value = PROTECTED)
@Getter (value = PROTECTED)
private DataUser dataUser;
@Autowired
@@ -133,22 +136,22 @@ public class BaseRMRestTest extends RestTest
@DataProvider(name = "validRootContainers")
public String[][] getValidRootContainers() throws Exception
{
return new String[][] {
// an arbitrary record folder
{ createCategoryFolderInFilePlan().getId(), RECORD_FOLDER_TYPE },
// unfiled records root
{ UNFILED_RECORDS_CONTAINER_ALIAS, UNFILED_CONTAINER_TYPE },
// an arbitrary unfiled records folder
{ createUnfiledContainerChild(UNFILED_RECORDS_CONTAINER_ALIAS,
"Unfiled Folder " + getRandomAlphanumeric(), UNFILED_RECORD_FOLDER_TYPE).getId(),
UNFILED_RECORD_FOLDER_TYPE } };
return new String[][]
{
// an arbitrary record folder
{ createCategoryFolderInFilePlan().getId(), RECORD_FOLDER_TYPE},
// unfiled records root
{ UNFILED_RECORDS_CONTAINER_ALIAS, UNFILED_CONTAINER_TYPE},
// an arbitrary unfiled records folder
{ createUnfiledContainerChild(UNFILED_RECORDS_CONTAINER_ALIAS, "Unfiled Folder " + getRandomAlphanumeric(), UNFILED_RECORD_FOLDER_TYPE).getId(), UNFILED_RECORD_FOLDER_TYPE }
};
}
/**
* @see org.alfresco.rest.RestTest#checkServerHealth()
*/
@Override
@BeforeClass(alwaysRun = true)
@BeforeClass (alwaysRun = true)
public void checkServerHealth() throws Exception
{
// Create RM Site if not exist
@@ -156,7 +159,8 @@ public class BaseRMRestTest extends RestTest
}
/**
* Helper method to create the RM Site via the POST request if the site doesn't exist
* Helper method to create the RM Site via the POST request
* if the site doesn't exist
*/
public void createRMSiteIfNotExists() throws Exception
{
@@ -220,12 +224,10 @@ public class BaseRMRestTest extends RestTest
* @return The created category
* @throws Exception on unsuccessful component creation
*/
public RecordCategory createRootCategory(UserModel userModel, String categoryName, String categoryTitle)
throws Exception
public RecordCategory createRootCategory(UserModel userModel, String categoryName, String categoryTitle) throws Exception
{
RecordCategory recordCategoryModel = createRecordCategoryModel(categoryName, categoryTitle);
return getRestAPIFactory().getFilePlansAPI(userModel).createRootRecordCategory(recordCategoryModel,
FILE_PLAN_ALIAS);
return getRestAPIFactory().getFilePlansAPI(userModel).createRootRecordCategory(recordCategoryModel, FILE_PLAN_ALIAS);
}
/**
@@ -238,12 +240,10 @@ public class BaseRMRestTest extends RestTest
* @return The created {@link RecordCategoryChild}
* @throws Exception {@link RecordCategoryAPI#createRecordCategoryChild(RecordCategoryChild, String)}
*/
public RecordCategoryChild createRecordCategoryChild(UserModel user, String recordCategoryId, String name,
String type) throws Exception
public RecordCategoryChild createRecordCategoryChild(UserModel user, String recordCategoryId, String name, String type) throws Exception
{
RecordCategoryChild recordCategoryChildModel = createRecordCategoryChildModel(name, type);
return getRestAPIFactory().getRecordCategoryAPI(user).createRecordCategoryChild(recordCategoryChildModel,
recordCategoryId);
return getRestAPIFactory().getRecordCategoryAPI(user).createRecordCategoryChild(recordCategoryChildModel, recordCategoryId);
}
/**
@@ -255,8 +255,7 @@ public class BaseRMRestTest extends RestTest
* @return The created {@link RecordCategoryChild}
* @throws Exception {@link RecordCategoryAPI#createRecordCategoryChild(RecordCategoryChild, String)}
*/
public RecordCategoryChild createRecordCategoryChild(String recordCategoryId, String name, String type)
throws Exception
public RecordCategoryChild createRecordCategoryChild(String recordCategoryId, String name, String type) throws Exception
{
return createRecordCategoryChild(getAdminUser(), recordCategoryId, name, type);
}
@@ -299,8 +298,7 @@ public class BaseRMRestTest extends RestTest
public RecordCategoryChild createFolder(UserModel user, String recordCategoryId, String name) throws Exception
{
RecordCategoryChild recordFolderModel = createRecordCategoryChildModel(name, RECORD_FOLDER_TYPE);
return getRestAPIFactory().getRecordCategoryAPI(user).createRecordCategoryChild(recordFolderModel,
recordCategoryId);
return getRestAPIFactory().getRecordCategoryAPI(user).createRecordCategoryChild(recordFolderModel, recordCategoryId);
}
/**
@@ -319,18 +317,16 @@ public class BaseRMRestTest extends RestTest
/**
* Helper method to create child unfiled record folder
*
* @param user The user under whose privileges this structure is going to be created
*@param user The user under whose privileges this structure is going to be created
* @param parentId The id of the parent folder
* @param nodeType The child type
* @return The created folder
* @throws Exception on unsuccessful component creation
*/
public UnfiledContainerChild createUnfiledRecordsFolderChild(UserModel user, String parentId, String childName,
String nodeType) throws Exception
public UnfiledContainerChild createUnfiledRecordsFolderChild(UserModel user, String parentId, String childName, String nodeType) throws Exception
{
UnfiledContainerChild childModel = createUnfiledContainerChildModel(childName, nodeType);
UnfiledContainerChild child = getRestAPIFactory().getUnfiledRecordFoldersAPI(user)
.createUnfiledRecordFolderChild(childModel, parentId);
UnfiledContainerChild child = getRestAPIFactory().getUnfiledRecordFoldersAPI(user).createUnfiledRecordFolderChild(childModel, parentId);
assertStatusCode(CREATED);
return child;
@@ -344,8 +340,7 @@ public class BaseRMRestTest extends RestTest
* @return The created folder
* @throws Exception on unsuccessful component creation
*/
public UnfiledContainerChild createUnfiledRecordsFolderChild(String parentId, String childName, String nodeType)
throws Exception
public UnfiledContainerChild createUnfiledRecordsFolderChild(String parentId, String childName, String nodeType) throws Exception
{
return createUnfiledRecordsFolderChild(getAdminUser(), parentId, childName, nodeType);
}
@@ -360,16 +355,14 @@ public class BaseRMRestTest extends RestTest
* @return The created chid
* @throws Exception on unsuccessful child creation
*/
public UnfiledContainerChild createUnfiledContainerChild(UserModel user, String parentId, String childName,
String nodeType) throws Exception
public UnfiledContainerChild createUnfiledContainerChild(UserModel user, String parentId, String childName, String nodeType) throws Exception
{
UnfiledContainerChild child = null;
UnfiledContainerChild childModel = createUnfiledContainerChildModel(childName, nodeType);
if (FilePlanComponentType.CONTENT_TYPE.equals(nodeType))
{
child = getRestAPIFactory().getUnfiledContainersAPI(user).uploadRecord(childModel, parentId,
createTempFile(ELECTRONIC_RECORD_NAME, ELECTRONIC_RECORD_NAME));
child = getRestAPIFactory().getUnfiledContainersAPI(user).uploadRecord(childModel, parentId, createTempFile(ELECTRONIC_RECORD_NAME, ELECTRONIC_RECORD_NAME));
}
else
{
@@ -389,8 +382,7 @@ public class BaseRMRestTest extends RestTest
* @return The created chid
* @throws Exception on unsuccessful child creation
*/
public UnfiledContainerChild createUnfiledContainerChild(String parentId, String childName, String nodeType)
throws Exception
public UnfiledContainerChild createUnfiledContainerChild(String parentId, String childName, String nodeType) throws Exception
{
return createUnfiledContainerChild(getAdminUser(), parentId, childName, nodeType);
}
@@ -405,9 +397,11 @@ public class BaseRMRestTest extends RestTest
protected RecordFolder closeFolder(String folderId) throws Exception
{
RecordFolder recordFolderModel = RecordFolder.builder()
.properties(RecordFolderProperties.builder().isClosed(true).build()).build();
RecordFolder updateRecordFolder = getRestAPIFactory().getRecordFolderAPI().updateRecordFolder(recordFolderModel,
folderId);
.properties(RecordFolderProperties.builder()
.isClosed(true)
.build())
.build();
RecordFolder updateRecordFolder = getRestAPIFactory().getRecordFolderAPI().updateRecordFolder(recordFolderModel, folderId);
assertStatusCode(OK);
return updateRecordFolder;
@@ -517,11 +511,24 @@ public class BaseRMRestTest extends RestTest
*/
public Record createElectronicRecord(String parentId, String name) throws Exception
{
RecordFolderAPI recordFolderAPI = restAPIFactory.getRecordFolderAPI();
return createElectronicRecord(parentId, name ,null);
}
/**
* Create an electronic record
*
* @param parentId the id of the parent
* @param name the name of the record
* @return the created record
* @throws Exception
*/
public Record createElectronicRecord(String parentId, String name, UserModel user) throws Exception
{
RecordFolderAPI recordFolderAPI = restAPIFactory.getRecordFolderAPI(user);
Record recordModel = Record.builder().name(name).nodeType(CONTENT_TYPE).build();
return recordFolderAPI.createRecord(recordModel, parentId);
}
/**
* Delete a record folder
*
@@ -551,11 +558,61 @@ public class BaseRMRestTest extends RestTest
* @param categoryId the id of the category to assign permissions for
* @throws Exception
*/
public void assignFillingPermissionsOnCategory(UserModel user, String categoryId) throws Exception
public void assignFillingPermissionsOnCategory(UserModel user, String categoryId,
String userPermission, String userRole) throws Exception
{
getRestAPIFactory().getRMUserAPI().addUserPermission(categoryId, user, PERMISSION_FILING);
rmRolesAndActionsAPI.assignUserToRole(dataUser.getAdminUser().getUsername(),
dataUser.getAdminUser().getPassword(), user.getUsername(), ROLE_RM_USER);
getRestAPIFactory().getRMUserAPI().addUserPermission(categoryId, user, userPermission);
rmRolesAndActionsAPI.assignUserToRole(getAdminUser().getUsername(),
getAdminUser().getPassword(), user.getUsername(), userRole);
}
/**
* Returns search results for the given search term
*
* @param user
* @param term
* @return
* @throws Exception
*/
public List<String> searchForContentAsUser(UserModel user, String term) throws Exception
{
getRestAPIFactory().getRmRestWrapper().authenticateUser(user);
RestRequestQueryModel queryReq = new RestRequestQueryModel();
SearchRequest query = new SearchRequest(queryReq);
queryReq.setQuery("cm:name:*" + term + "*");
List<String> names = new ArrayList<>();
// wait for solr indexing
int counter = 0;
int waitInMilliSeconds = 6000;
while (counter < 3)
{
synchronized (this)
{
try
{
this.wait(waitInMilliSeconds);
} catch (InterruptedException e)
{
}
}
List<SearchNodeModel> searchResults = getRestAPIFactory().getRmRestWrapper().withSearchAPI().search(query)
.getEntries();
if ((searchResults != null && !searchResults.isEmpty()))
{
searchResults.forEach(childNode ->
{
names.add(childNode.onModel().getName());
});
break;
} else
{
counter++;
}
// double wait time to not overdo solr search
waitInMilliSeconds = (waitInMilliSeconds * 2);
}
return names;
}
}

View File

@@ -20,4 +20,22 @@
</select>
<!-- Counts the children that have at least one of the provided property values for a given property qname -->
<select id="select_CountChildrenWithPropertyValues"
parameterType="org.alfresco.module.org_alfresco_module_rm.query.ChildrenWithPropertyValuesQueryParams"
resultType="java.lang.Long">
select
count( distinct assoc.child_node_id )
from
alf_child_assoc assoc
left join alf_node_properties childProp on assoc.child_node_id = childProp.node_id
where
assoc.parent_node_id = #{parentId}
and childProp.qname_id = #{propertyQnameId}
and childProp.string_value in
<foreach item="item" index="index" collection="propertyValues" open="(" separator="," close=")">
'${item}'
</foreach>
</select>
</mapper>

View File

@@ -16,9 +16,11 @@
<constructor-arg index="0" ref="rmSqlSessionFactory"/>
</bean>
<bean id="recordsManagementQueryDAO" class="org.alfresco.module.org_alfresco_module_rm.query.RecordsManagementQueryDAOImpl">
<property name="sqlSessionTemplate" ref="rmSqlSessionTemplate"/>
<property name="qnameDAO" ref="qnameDAO"/>
</bean>
<bean id="recordsManagementQueryDAO" class="org.alfresco.module.org_alfresco_module_rm.query.RecordsManagementQueryDAOImpl">
<property name="sqlSessionTemplate" ref="rmSqlSessionTemplate" />
<property name="qnameDAO" ref="qnameDAO" />
<property name="nodeDAO" ref="nodeDAO" />
<property name="tenantService" ref="tenantService" />
</bean>
</beans>

View File

@@ -0,0 +1,73 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.module.org_alfresco_module_rm.query;
import java.util.Collection;
/**
* Select parameter for <b>select_CountChildrenWithPropertyValues</b>.
*
* @author Ana Manolache
* @since 2.6
*/
public class ChildrenWithPropertyValuesQueryParams
{
private Long parentId;
private Long propertyQnameId;
private Collection propertyValues;
public Long getParentId()
{
return parentId;
}
public void setParentId(Long parentId)
{
this.parentId = parentId;
}
public Long getPropertyQnameId()
{
return propertyQnameId;
}
public void setPropertyQnameId(Long propertyQnameId)
{
this.propertyQnameId = propertyQnameId;
}
public Collection getPropertyValues()
{
return propertyValues;
}
public void setPropertyValues(Collection propertyValues)
{
this.propertyValues = propertyValues;
}
}

View File

@@ -27,6 +27,11 @@
package org.alfresco.module.org_alfresco_module_rm.query;
import java.util.Collection;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* Records management query DAO
*
@@ -46,4 +51,15 @@ public interface RecordsManagementQueryDAO
* @return int count
*/
int getCountRmaIdentifier(String identifierValue);
/**
* Returns whether a given node contains children with one of the given values for the given property
*
* @param parent the parent to evaluate
* @param property the QName of the property to evaluate
* @param propertyValues the list of values to look for
* @return true if there is at least one child with one of the values from the list set on the given property
* false otherwise
*/
public boolean hasChildrenWithPropertyValues(NodeRef parent, QName property, Collection propertyValues);
}

View File

@@ -27,11 +27,16 @@
package org.alfresco.module.org_alfresco_module_rm.query;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.domain.node.NodeDAO;
import org.alfresco.repo.domain.qname.QNameDAO;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.mybatis.spring.SqlSessionTemplate;
@@ -45,12 +50,15 @@ import org.mybatis.spring.SqlSessionTemplate;
public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO, RecordsManagementModel
{
private static final String COUNT_IDENTIFIER = "alfresco.query.rm.select_CountRMIndentifier";
private static final String COUNT_CHILDREN_WITH_PROPERTY_VALUES = "select_CountChildrenWithPropertyValues";
/** SQL session template */
protected SqlSessionTemplate template;
/** QName DAO */
protected QNameDAO qnameDAO;
protected NodeDAO nodeDAO;
protected TenantService tenantService;
/**
* @param sqlSessionTemplate SQL session template
@@ -68,6 +76,16 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
this.qnameDAO = qnameDAO;
}
public void setNodeDAO(NodeDAO nodeDAO)
{
this.nodeDAO = nodeDAO;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.query.RecordsManagementQueryDAO#getCountRmaIdentifier(java.lang.String)
*/
@@ -97,4 +115,39 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
return result;
}
@Override
public boolean hasChildrenWithPropertyValues(NodeRef parent, QName property, Collection propertyValues)
{
if(propertyValues.isEmpty())
{
return false;
}
ChildrenWithPropertyValuesQueryParams queryParams = new ChildrenWithPropertyValuesQueryParams();
// Set the parent node id
Pair<Long, NodeRef> nodePair = nodeDAO.getNodePair(tenantService.getName(parent));
if (nodePair == null)
{
throw new InvalidNodeRefException("The parent node does not exist.", parent);
}
Long parentNodeId = nodePair.getFirst();
queryParams.setParentId(parentNodeId);
// Set the property qname id
Pair<Long, QName> pair = qnameDAO.getQName(property);
if (pair == null)
{
return false;
}
queryParams.setPropertyQnameId(pair.getFirst());
// Set the property values
queryParams.setPropertyValues(propertyValues);
// Perform the query
Long count = template.selectOne(COUNT_CHILDREN_WITH_PROPERTY_VALUES, queryParams);
return count > 0;
}
}

View File

@@ -27,10 +27,17 @@
package org.alfresco.module.org_alfresco_module_rm.test.legacy.service;
import java.util.ArrayList;
import java.util.Arrays;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.query.RecordsManagementQueryDAO;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
/**
* Records Management Query DAO
@@ -86,5 +93,248 @@ public class RecordsManagementQueryDAOImplTest extends BaseRMTestCase implements
});
}
/**
* Given a folder containing 3 files with the descriptions set
* When I check if the folder contains children having the description of file2 or file2
* Then the answer is positive
*/
@org.junit.Test
public void testHasChildrenWithPropertyValues_someChildrenWithValues() throws Exception
{
doBehaviourDrivenTest(new BehaviourDrivenTest()
{
NodeRef parentFolder;
NodeRef file1;
NodeRef file2;
NodeRef file3;
String propValue1 = "descr1"; // set on file1
String propValue2 = "descr2"; // set on file2
String propValue3 = "descr3"; // set on file3
String propValue4 = "descr4"; // not set on any file
Boolean result;
@Override
public void given() throws Exception
{
setupCollaborationSiteTestDataImpl();
parentFolder = fileFolderService.create(documentLibrary, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
file1 = fileFolderService.create(parentFolder, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
file2 = fileFolderService.create(parentFolder, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
file3 = fileFolderService.create(parentFolder, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
nodeService.setProperty(file1, PROP_DESCRIPTION, propValue1);
nodeService.setProperty(file2, PROP_DESCRIPTION, propValue2);
nodeService.setProperty(file3, PROP_DESCRIPTION, propValue3);
}
@Override
public void when() throws Exception
{
result = queryDAO.hasChildrenWithPropertyValues(parentFolder, PROP_DESCRIPTION, Arrays.asList(propValue1, propValue2, propValue4));
}
@Override
public void then() throws Exception
{
assertTrue(result);
}
@Override
public void after() throws Exception
{
if (parentFolder != null && nodeService.exists(parentFolder))
{
nodeService.deleteNode(parentFolder);
}
}
});
}
/**
* Given a folder containing 3 files with the descriptions unset
* When I check if the folder contains children having certain descriptions
* Then the answer is negative
*/
@org.junit.Test
public void testHasChildrenWithPropertyValues_propertyNotSetOnChildren() throws Exception
{
doBehaviourDrivenTest(new BehaviourDrivenTest()
{
NodeRef parentFolder;
NodeRef file1;
NodeRef file2;
NodeRef file3;
Boolean result;
@Override
public void given() throws Exception
{
setupCollaborationSiteTestDataImpl();
parentFolder = fileFolderService.create(documentLibrary, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
file1 = fileFolderService.create(parentFolder, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
file2 = fileFolderService.create(parentFolder, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
file3 = fileFolderService.create(parentFolder, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
}
@Override
public void when() throws Exception
{
result = queryDAO.hasChildrenWithPropertyValues(parentFolder, PROP_DESCRIPTION, Arrays.asList("descr1", "descr2", "descr3"));
}
@Override
public void then() throws Exception
{
assertFalse(result);
}
@Override
public void after() throws Exception
{
if (parentFolder != null && nodeService.exists(parentFolder))
{
nodeService.deleteNode(parentFolder);
}
}
});
}
/**
* Given a folder with no children but the property set on itself
* When I check if the folder contains children having certain descriptions
* Then the answer is negative
*/
@org.junit.Test
public void testHasChildrenWithPropertyValues_noChildren() throws Exception
{
doBehaviourDrivenTest(new BehaviourDrivenTest()
{
NodeRef folder;
String propValue = "descr";
Boolean result;
@Override
public void given() throws Exception
{
setupCollaborationSiteTestDataImpl();
folder = fileFolderService.create(documentLibrary, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
nodeService.setProperty(folder, PROP_DESCRIPTION, propValue);
}
@Override
public void when() throws Exception
{
result = queryDAO.hasChildrenWithPropertyValues(folder, PROP_DESCRIPTION, Arrays.asList("descr"));
}
@Override
public void then() throws Exception
{
assertFalse(result);
}
@Override
public void after() throws Exception
{
if (folder != null && nodeService.exists(folder))
{
nodeService.deleteNode(folder);
}
}
});
}
/**
* Given a folder with children and an unused property
* When I check if the folder contains children having the unused property
* Then the answer is negative
*/
@org.junit.Test
public void testHasChildrenWithPropertyValues_propertyNotUsed() throws Exception
{
doBehaviourDrivenTest(new BehaviourDrivenTest()
{
NodeRef parentFolder;
QName property;
Boolean result;
@Override
public void given() throws Exception
{
setupCollaborationSiteTestDataImpl();
parentFolder = fileFolderService.create(documentLibrary, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
fileFolderService.create(parentFolder, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
fileFolderService.create(parentFolder, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
property = QName.createQName(URI, "customProp-" + GUID.generate());
}
@Override
public void when() throws Exception
{
result = queryDAO.hasChildrenWithPropertyValues(folder, property, Arrays.asList("descr"));
}
@Override
public void then() throws Exception
{
assertFalse(result);
}
@Override
public void after() throws Exception
{
if (folder != null && nodeService.exists(folder))
{
nodeService.deleteNode(folder);
}
}
});
}
/**
* Given any folder and any property
* When I pass an empty array to the hasChildrenWithPropertyValues method
* Then the answer is negative
*/
@org.junit.Test
public void testHasChildrenWithPropertyValues_emptyArray() throws Exception
{
doBehaviourDrivenTest(new BehaviourDrivenTest()
{
NodeRef parentFolder;
NodeRef file1;
Boolean result;
@Override
public void given() throws Exception
{
setupCollaborationSiteTestDataImpl();
parentFolder = fileFolderService.create(documentLibrary, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
file1 = fileFolderService.create(parentFolder, GUID.generate(), ContentModel.TYPE_FOLDER).getNodeRef();
nodeService.setProperty(file1, PROP_DESCRIPTION, "descr1");
}
@Override
public void when() throws Exception
{
result = queryDAO.hasChildrenWithPropertyValues(folder, PROP_DESCRIPTION, new ArrayList());
}
@Override
public void then() throws Exception
{
assertFalse(result);
}
@Override
public void after() throws Exception
{
if (folder != null && nodeService.exists(folder))
{
nodeService.deleteNode(folder);
}
}
});
}
}