Merge branch 'master' into feature/RM-4488_Refactor_RM_Automation

This commit is contained in:
Tuna Aksoy
2016-12-22 18:51:08 +00:00
49 changed files with 1757 additions and 1155 deletions

View File

@@ -97,6 +97,7 @@
<modules>
<module>rm-enterprise</module>
<module>rm-automation</module>
<module>rm-benchmark</module>
</modules>
</profile>
</profiles>
@@ -296,6 +297,11 @@
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>

View File

@@ -24,7 +24,6 @@
</modules>
<properties>
<alfresco.installer.host>releases</alfresco.installer.host>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<suiteXmlFile>testng.xml</suiteXmlFile>
@@ -109,22 +108,18 @@
<echo>Recreating database...</echo>
<sql driver="org.postgresql.Driver" url="jdbc:postgresql:template1" userid="alfresco" password="alfresco" autocommit="true">drop database if exists alfresco; create database alfresco</sql>
<echo>Downloading Alfresco installer...</echo>
<get src="https://${alfresco.installer.host}.alfresco.com/${installer.path}" dest="target/alf-installer.bin" />
<get src="${installer.url}" dest="target/alf-installer.bin" />
<chmod file="target/alf-installer.bin" perm="a+x" verbose="true" />
<echo>Installing Alfresco...</echo>
<exec executable="${basedir}/target/alf-installer.bin" dir="target" failonerror="true">
<arg line="--mode unattended --alfresco_admin_password admin --disable-components postgres,alfrescowcmqs --jdbc_username alfresco --jdbc_password alfresco --prefix ${basedir}/target/alf-installation" />
</exec>
<delete file="target/alf-installer.bin" verbose="true" />
</target>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-jsch</artifactId>
<version>1.8.2</version>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>

View File

@@ -6,3 +6,4 @@
/.idea/
*.iml
/test-output/
.factorypath

View File

@@ -54,5 +54,11 @@
<artifactId>fluent-json</artifactId>
<version>${fluent.json.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -28,12 +28,19 @@ package org.alfresco.rest.rm.community.model.fileplancomponents;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.ALLOWABLE_OPERATIONS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.IS_CLOSED;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.PATH;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.PROPERTIES;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.RELATIVE_PATH;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* POJO for file plan component
*
@@ -41,6 +48,10 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* @author Rodica Sutu
* @since 2.6
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FilePlanComponent
{
@JsonProperty (required = true)
@@ -88,6 +99,7 @@ public class FilePlanComponent
@JsonProperty (required = false)
private FilePlanComponentContent content;
@JsonProperty (value = PATH)
private FilePlanComponentPath path;
@JsonProperty (required = true)
@@ -99,324 +111,7 @@ public class FilePlanComponent
@JsonProperty (required = true)
private FilePlanComponentUserInfo modifiedByUser;
@JsonProperty (value = RELATIVE_PATH)
private String relativePath;
/**Helper constructor for creating the file plan component using
*
* @param name File Plan Component name
* @param nodeType File Plan Component node type
* @param properties File Plan Component properties
*/
public FilePlanComponent(String name, String nodeType, FilePlanComponentProperties properties)
{
this.name = name;
this.nodeType = nodeType;
this.properties = properties;
}
/**
* Helper constructor to create empty file plan component
*/
public FilePlanComponent() { }
/**
* Helper constructor for creating the file plan component using
*
* @param name File Plan Component name
*/
public FilePlanComponent(String name)
{
this.name = name;
}
/**
* Helper constructor for creating the file plan component using
*
* @param name File Plan Component name
* @param properties File Plan Component properties
*/
public FilePlanComponent(String name, FilePlanComponentProperties properties)
{
this.name = name;
this.properties = properties;
}
/**
* @return the id
*/
public String getId()
{
return this.id;
}
/**
* @param id the id to set
*/
public void setId(String id)
{
this.id = id;
}
/**
* @return the parentId
*/
public String getParentId()
{
return this.parentId;
}
/**
* @param parentId the parentId to set
*/
public void setParentId(String parentId)
{
this.parentId = parentId;
}
/**
* @return the name
*/
public String getName()
{
return this.name;
}
/**
* @param name the name to set
*/
public void setName(String name)
{
this.name = name;
}
/**
* @return the nodeType
*/
public String getNodeType()
{
return this.nodeType;
}
/**
* @param nodeType the nodeType to set
*/
public void setNodeType(String nodeType)
{
this.nodeType = nodeType;
}
/**
* @return the isCategory
*/
public Boolean isCategory()
{
return this.isCategory;
}
/**
* @param isCategory the isCategory to set
*/
public void setCategory(Boolean isCategory)
{
this.isCategory = isCategory;
}
/**
* @return the isRecordFolder
*/
public Boolean isRecordFolder()
{
return this.isRecordFolder;
}
/**
* @param isRecordFolder the isRecordFolder to set
*/
public void setRecordFolder(Boolean isRecordFolder)
{
this.isRecordFolder = isRecordFolder;
}
/**
* @return the isFile
*/
public Boolean isFile()
{
return this.isFile;
}
/**
* @param isFile the isFile to set
*/
public void setFile(Boolean isFile)
{
this.isFile = isFile;
}
/**
* @return the hasRetentionSchedule
*/
public Boolean hasRetentionSchedule()
{
return this.hasRetentionSchedule;
}
/**
* @param hasRetentionSchedule the hasRetentionSchedule to set
*/
public void setHasRetentionSchedule(Boolean hasRetentionSchedule)
{
this.hasRetentionSchedule = hasRetentionSchedule;
}
/**
* @return the properties
*/
public FilePlanComponentProperties getProperties()
{
return properties;
}
/**
* @param properties the properties to set
*/
public void setProperties(FilePlanComponentProperties properties)
{
this.properties = properties;
}
/**
* @return the aspectNames
*/
public List<String> getAspectNames()
{
return this.aspectNames;
}
/**
* @param aspectNames the aspectNames to set
*/
public void setAspectNames(List<String> aspectNames)
{
this.aspectNames = aspectNames;
}
/**
* @return the createdByUser
*/
public FilePlanComponentUserInfo getCreatedByUser()
{
return this.createdByUser;
}
/**
* @param createdByUser the createdByUser to set
*/
public void setCreatedByUser(FilePlanComponentUserInfo createdByUser)
{
this.createdByUser = createdByUser;
}
/**
* @return the allowableOperations
*/
public List<String> getAllowableOperations()
{
return this.allowableOperations;
}
/**
* @return the path
*/
public FilePlanComponentPath getPath()
{
return this.path;
}
/**
* @param path the path to set
*/
public void setPath(FilePlanComponentPath path)
{
this.path = path;
}
/**
* @param modifiedAt the modifiedAt to set
*/
public void setModifiedAt(String modifiedAt)
{
this.modifiedAt = modifiedAt;
}
/**
* @param createdAt the createdAt to set
*/
public void setCreatedAt(String createdAt)
{
this.createdAt = createdAt;
}
/**
* @param modifiedByUser the modifiedByUser to set
*/
public void setModifiedByUser(FilePlanComponentUserInfo modifiedByUser)
{
this.modifiedByUser = modifiedByUser;
}
/**
* @return the modifiedAt
*/
public String getModifiedAt()
{
return this.modifiedAt;
}
/**
* @return the createdAt
*/
public String getCreatedAt()
{
return this.createdAt;
}
/**
* @return the modifiedByUser
*/
public FilePlanComponentUserInfo getModifiedByUser()
{
return this.modifiedByUser;
}
/**
* @return the isClosed
*/
public Boolean isClosed()
{
return this.isClosed;
}
/**
* @param closed the isClosed to set
*/
public void setClosed(Boolean closed)
{
this.isClosed = closed;
}
/**
* @return the isCompleted
*/
public Boolean isCompleted()
{
return this.isCompleted;
}
/**
* @param completed the isCompleted to set
*/
public void setCompleted(Boolean completed)
{
this.isCompleted = completed;
}
}

View File

@@ -47,67 +47,4 @@ public class FilePlanComponentContent
@JsonProperty (required = true)
private Integer sizeInBytes;
/**
* @return the encoding
*/
public String getEncoding()
{
return this.encoding;
}
/**
* @param encoding the encoding to set
*/
public void setEncoding(String encoding)
{
this.encoding = encoding;
}
/**
* @return the mimeType
*/
public String getMimeType()
{
return this.mimeType;
}
/**
* @param mimeType the mimeType to set
*/
public void setMimeType(String mimeType)
{
this.mimeType = mimeType;
}
/**
* @return the mimeTypeName
*/
public String getMimeTypeName()
{
return this.mimeTypeName;
}
/**
* @param mimeTypeName the mimeTypeName to set
*/
public void setMimeTypeName(String mimeTypeName)
{
this.mimeTypeName = mimeTypeName;
}
/**
* @return the sizeInBytes
*/
public Integer getSizeInBytes()
{
return this.sizeInBytes;
}
/**
* @param sizeInBytes the sizeInBytes to set
*/
public void setSizeInBytes(Integer sizeInBytes)
{
this.sizeInBytes = sizeInBytes;
}
}

View File

@@ -30,6 +30,10 @@ import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanCo
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.alfresco.rest.core.RestModels;
/**
@@ -38,13 +42,13 @@ import org.alfresco.rest.core.RestModels;
* @author Tuna Aksoy
* @since 2.6
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FilePlanComponentEntry extends RestModels<FilePlanComponent, FilePlanComponentEntry>
{
@JsonProperty(ENTRY)
FilePlanComponent filePlanComponent;
public FilePlanComponent getFilePlanComponent()
{
return filePlanComponent;
}
}

View File

@@ -58,4 +58,7 @@ public class FilePlanComponentFields
public static final String PROPERTIES_SHELF = "rma:shelf";
public static final String PROPERTIES_STORAGE_LOCATION = "rma:storageLocation";
//RelativePath specifies the container structure to create relative to the node nodeId.
public static final String RELATIVE_PATH = "relativePath";
public static final String PATH = "path";
}

View File

@@ -26,46 +26,24 @@
*/
package org.alfresco.rest.rm.community.model.fileplancomponents;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* POJO for id/name pair
*
* @author Kristijan Conkas
* @since 2.6
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FilePlanComponentIdNamePair
{
public String id;
public String name;
/**
* @return the id
*/
public String getId()
{
return this.id;
}
/**
* @param id the id to set
*/
public void setId(String id)
{
this.id = id;
}
/**
* @return the name
*/
public String getName()
{
return this.name;
}
/**
* @param name the name to set
*/
public void setName(String name)
{
this.name = name;
}
}

View File

@@ -30,12 +30,21 @@ import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* POJO for FilePlanComponent path parameter
* <br>
* @author Kristijan Conkas
* @since 2.6
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class FilePlanComponentPath
{
@@ -43,51 +52,4 @@ public class FilePlanComponentPath
private Boolean isComplete;
private List<FilePlanComponentIdNamePair> elements;
/**
* @return the name
*/
public String getName()
{
return this.name;
}
/**
* @param name the name to set
*/
public void setName(String name)
{
this.name = name;
}
/**
* @return the isComplete
*/
public Boolean isComplete()
{
return this.isComplete;
}
/**
* @param isComplete the isComplete to set
*/
public void setComplete(Boolean isComplete)
{
this.isComplete = isComplete;
}
/**
* @return the elements
*/
public List<FilePlanComponentIdNamePair> getElements()
{
return this.elements;
}
/**
* @param elements the elements to set
*/
public void setElements(List<FilePlanComponentIdNamePair> elements)
{
this.elements = elements;
}
}

View File

@@ -48,6 +48,11 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.alfresco.rest.rm.community.util.ReviewPeriodSerializer;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* POJO for file plan component properties
*
@@ -56,6 +61,10 @@ import org.alfresco.rest.rm.community.util.ReviewPeriodSerializer;
*/
//FIXME: Once the fields have been added the JsonIgnoreProperties annotation should be removed
@JsonIgnoreProperties (ignoreUnknown = true)
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FilePlanComponentProperties
{
@@ -100,227 +109,4 @@ public class FilePlanComponentProperties
private Integer physicalSize;
public FilePlanComponentProperties(String title, String description)
{
this.title = title;
this.description = description;
}
public FilePlanComponentProperties(String title)
{
this.title = title;
}
public FilePlanComponentProperties()
{
}
/**
* @return the vitalRecord
*/
public Boolean isVitalRecord()
{
return this.vitalRecord;
}
/**
* @param vitalRecord the vitalRecord to set
*/
public void setVitalRecord(Boolean vitalRecord)
{
this.vitalRecord = vitalRecord;
}
/**
* @return the title
*/
public String getTitle()
{
return this.title;
}
/**
* @param title the title to set
*/
public void setTitle(String title)
{
this.title = title;
}
/**
* @return the holdReason
*/
public String getHoldReason()
{
return this.holdReason;
}
/**
* @param holdReason the holdReason to set
*/
public void setHoldReason(String holdReason)
{
this.holdReason = holdReason;
}
/**
* @param description the description to set
*/
public void setDescription(String description)
{
this.description = description;
}
/**
* @return the description
*/
public String getDescription()
{
return this.description;
}
/**
* @return the supplementalMarkingList
*/
public List<String> getSupplementalMarkingList()
{
return this.supplementalMarkingList;
}
/**
* @param supplementalMarkingList the supplementalMarkingList to set
*/
public void setSupplementalMarkingList(List<String> supplementalMarkingList)
{
this.supplementalMarkingList = supplementalMarkingList;
}
/**
* @return the reviewPeriod
*/
public ReviewPeriod getReviewPeriod()
{
return reviewPeriod;
}
/**
* @param reviewPeriod the reviewPeriod to set
*/
public void setReviewPeriod(ReviewPeriod reviewPeriod)
{
this.reviewPeriod = reviewPeriod;
}
/**
* @return the location
*/
public String getLocation()
{
return location;
}
/**
* @param location the location to set
*/
public void setLocation(String location)
{
this.location = location;
}
/**
* @return the box
*/
public String getBox()
{
return this.box;
}
/**
* @param box the box to set
*/
public void setBox(String box)
{
this.box = box;
}
/**
* @return the file
*/
public String getFile()
{
return this.file;
}
/**
* @param file the file to set
*/
public void setFile(String file)
{
this.file = file;
}
/**
* @return the shelf
*/
public String getShelf()
{
return this.shelf;
}
/**
* @param shelf the shelf to set
*/
public void setShelf(String shelf)
{
this.shelf = shelf;
}
/**
* @return the numberOfCopies
*/
public Integer getNumberOfCopies()
{
return this.numberOfCopies;
}
/**
* @param numberOfCopies the numberOfCopies to set
*/
public void setNumberOfCopies(Integer numberOfCopies)
{
this.numberOfCopies = numberOfCopies;
}
/**
* @return the physicalSize
*/
public Integer getPhysicalSize()
{
return this.physicalSize;
}
/**
* @param physicalSize the physicalSize to set
*/
public void setPhysicalSize(Integer physicalSize)
{
this.physicalSize = physicalSize;
}
/**
* @return the isClosed
*/
public Boolean getIsClosed()
{
return this.isClosed;
}
/**
* @param isClosed the isClosed to set
*/
public void setIsClosed(Boolean isClosed)
{
this.isClosed = isClosed;
}
}

View File

@@ -26,46 +26,24 @@
*/
package org.alfresco.rest.rm.community.model.fileplancomponents;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* POJO for file plan component created by object
*
* @author Kristijan Conkas
* @since 2.6
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FilePlanComponentUserInfo
{
private String id;
private String displayName;
/**
* @return the id
*/
public String getId()
{
return this.id;
}
/**
* @param id the id to set
*/
public void setId(String id)
{
this.id = id;
}
/**
* @return the displayName
*/
public String getDisplayName()
{
return this.displayName;
}
/**
* @param displayName the displayName to set
*/
public void setDisplayName(String displayName)
{
this.displayName = displayName;
}
}

View File

@@ -26,66 +26,23 @@
*/
package org.alfresco.rest.rm.community.model.fileplancomponents;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* POJO for the review period
*
* @author Rodica Sutu
* @since 2.6
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ReviewPeriod
{
private String periodType;
private String expression;
/**
* Helper constructor with
*
* @param periodType
* @param expression
*/
public ReviewPeriod(String periodType, String expression)
{
this.periodType = periodType;
this.expression = expression;
}
/**
* Helper constructor
*/
public ReviewPeriod()
{
}
/**
* @return the periodType
*/
public String getPeriodType()
{
return this.periodType;
}
/**
* @param periodType the periodType to set
*/
public void setPeriodType(String periodType)
{
this.periodType = periodType;
}
/**
* @return the expression
*/
public String getExpression()
{
return this.expression;
}
/**
* @param expression the expression to set
*/
public void setExpression(String expression)
{
this.expression = expression;
}
}

View File

@@ -30,6 +30,10 @@ import static org.alfresco.rest.rm.community.model.site.RMSiteFields.COMPLIANCE;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.alfresco.rest.model.RestSiteModel;
/**
@@ -38,59 +42,13 @@ import org.alfresco.rest.model.RestSiteModel;
* @author Rodica Sutu
* @since 2.6
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RMSite extends RestSiteModel
{
@JsonProperty (value = COMPLIANCE,required = true)
private RMSiteCompliance compliance;
/**
* Helper constructor to create RM Site object using
*
* @param title
* @param description
* @param compliance
*/
public RMSite(String title, String description, RMSiteCompliance compliance)
{
this.title=title;
this.description=description;
this.compliance=compliance;
}
/**
* Helper constructor for creating the RM Site
*/
public RMSite() { }
/**
* Helper constructor to create RM Site object using
*
* @param compliance RM Site Compliance
*/
public RMSite(RMSiteCompliance compliance)
{
super();
this.compliance = compliance;
}
/**
* Helper method to set RM site compliance
*
* @param compliance {@link RMSiteCompliance} the compliance to set
*/
public void setCompliance(RMSiteCompliance compliance)
{
this.compliance = compliance;
}
/**
* Helper method to get RM site compliance
*
* @return compliance the RM Site compliance to get
*/
public RMSiteCompliance getCompliance()
{
return compliance;
}
}

View File

@@ -0,0 +1,40 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.model.user;
/**
* Constants for RM user capabilities
*
* @author Kristijan Conkas
* @since 2.6
*/
public class UserPermissions
{
public static final String PERMISSION_FILING = "Filing";
public static final String PERMISSION_READ_RECORDS = "ReadRecords";
public static final String PERMISSION_FILE_RECORDS = "FileRecords";
}

View File

@@ -0,0 +1,42 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.model.user;
/**
* Constants for RM user roles
*
* @author Kristijan Conkas
* @since 2.6
*/
public class UserRoles
{
public static final String ROLE_RM_ADMIN = "Administrator";
public static final String ROLE_RM_MANAGER = "RecordsManager";
public static final String ROLE_RM_POWER_USER = "PowerUser";
public static final String ROLE_RM_SECURITY_OFFICER = "SecurityOfficer";
public static final String ROLE_RM_USER = "User";
}

View File

@@ -26,6 +26,7 @@
*/
package org.alfresco.rest.rm.community.requests;
import static com.jayway.restassured.RestAssured.basic;
import static com.jayway.restassured.RestAssured.given;
import static org.alfresco.rest.core.RestRequest.requestWithBody;
@@ -40,8 +41,12 @@ import static org.springframework.http.HttpMethod.PUT;
import static org.testng.Assert.fail;
import java.io.File;
import java.util.Iterator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.io.Resources;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.response.Response;
@@ -169,15 +174,40 @@ public class FilePlanComponentAPI extends RestAPI<FilePlanComponentAPI>
fail("Only electronic records are supported");
}
UserModel currentUser = usingRestWrapper().getTestUser();
/*
* For file uploads nodeBodyCreate is ignored hence can't be used. Append all FilePlanComponent fields
* to the request.
*/
RequestSpecBuilder builder = new RequestSpecBuilder();
builder.setAuth(basic(currentUser.getUsername(), currentUser.getPassword()));
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(toJson(electronicRecordModel));
Iterator<String> fieldNames = root.fieldNames();
while (fieldNames.hasNext())
{
String f = fieldNames.next();
try
{
builder.addMultiPart(f, root.get(f).asText(), ContentType.JSON.name());
}
catch (Exception error)
{
LOG.error("Failed to set " + f + " error: " + error);
}
}
builder.addMultiPart("filedata", recordContent, ContentType.BINARY.name());
/*
* RestWrapper adds some headers which break multipart/form-data uploads and also assumes json POST requests.
* Upload the file using RestAssured library.
*/
UserModel currentUser = usingRestWrapper().getTestUser();
Response response = given()
.auth().basic(currentUser.getUsername(), currentUser.getPassword())
.multiPart("nodeBodyCreate", toJson(electronicRecordModel), ContentType.JSON.name())
.multiPart("filedata", recordContent, ContentType.BINARY.name())
.spec(builder.build())
.when()
.post("fileplan-components/{fileplanComponentId}/children?{parameters}", parentId, getParameters())
.andReturn();

View File

@@ -0,0 +1,86 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.requests;
import static com.jayway.restassured.RestAssured.given;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.response.Response;
import com.jayway.restassured.specification.RequestSpecification;
import org.alfresco.dataprep.AlfrescoHttpClient;
import org.alfresco.dataprep.AlfrescoHttpClientFactory;
import org.alfresco.rest.core.RestAPI;
import org.alfresco.utility.data.DataUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* RM user management API
*
* @author Kristijan Conkas
* @since 2.6
*/
// FIXME: As of December 2016 there is no v1-style API for managing RM users and users'
// roles. Until such APIs have become available, methods in this class are just proxies to
// "old-style" API calls.
@Component
@Scope (value = "prototype")
public class RMUserAPI extends RestAPI<RMUserAPI>
{
@Autowired
private DataUser dataUser;
@Autowired
private AlfrescoHttpClientFactory alfrescoHttpClientFactory;
public void assignRoleToUser(String userName, String userRole) throws Exception
{
// get an "old-style" REST API client
AlfrescoHttpClient client = alfrescoHttpClientFactory.getObject();
// override v1 baseURI and basePath
RequestSpecification spec = new RequestSpecBuilder()
.setBaseUri(client.getApiUrl())
.setBasePath("/")
.build();
Response response = given()
.spec(spec)
.log().all()
.pathParam("role", userRole)
.pathParam("authority", userName)
.param("alf_ticket", client.getAlfTicket(
dataUser.getAdminUser().getUsername(), dataUser.getAdminUser().getPassword()))
.when()
.post("/rm/roles/{role}/authorities/{authority}")
.prettyPeek()
.andReturn();
usingRestWrapper().setStatusCode(Integer.toString(response.getStatusCode()));
}
}

View File

@@ -28,6 +28,8 @@ package org.alfresco.rest.rm.community.base;
import static java.lang.Integer.parseInt;
import static com.jayway.restassured.RestAssured.given;
import static org.alfresco.rest.rm.community.base.TestData.CATEGORY_TITLE;
import static org.alfresco.rest.rm.community.base.TestData.FOLDER_TITLE;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
@@ -37,11 +39,19 @@ import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanCo
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.UNFILED_RECORD_FOLDER_TYPE;
import static org.alfresco.rest.rm.community.model.site.RMSiteCompliance.STANDARD;
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
import static org.jglue.fluentjson.JsonBuilderFactory.buildObject;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.OK;
import com.google.gson.JsonObject;
import com.jayway.restassured.RestAssured;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.response.Response;
import com.jayway.restassured.specification.RequestSpecification;
import org.alfresco.dataprep.AlfrescoHttpClient;
import org.alfresco.dataprep.AlfrescoHttpClientFactory;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponent;
@@ -96,6 +106,9 @@ public class BaseRestTest extends RestTest
@Autowired
public FilePlanComponentAPI filePlanComponentAPI;
@Autowired
private AlfrescoHttpClientFactory alfrescoHttpClientFactory;
// Constants
public static final String RM_ID = "rm";
public static final String RM_TITLE = "Records Management";
@@ -141,7 +154,9 @@ public class BaseRestTest extends RestTest
rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
// Create the RM site
RMSite rmSite = new RMSite(RM_TITLE, RM_DESCRIPTION, STANDARD);
RMSite rmSite = RMSite.builder().compliance(STANDARD).build();
rmSite.setTitle(RM_TITLE);
rmSite.setDescription(RM_DESCRIPTION);
rmSiteAPI.createRMSite(rmSite);
// Verify the status code
@@ -202,7 +217,13 @@ public class BaseRestTest extends RestTest
{
RestWrapper restWrapper = filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
FilePlanComponent filePlanComponent = new FilePlanComponent(componentName, componentType.toString(),new FilePlanComponentProperties(componentTitle));
FilePlanComponent filePlanComponent = FilePlanComponent.builder()
.name(componentName)
.nodeType(componentType.toString())
.properties(FilePlanComponentProperties.builder()
.title(componentTitle)
.build())
.build();
FilePlanComponent fpc = filePlanComponentAPI.createFilePlanComponent(filePlanComponent, parentComponentId);
restWrapper.assertStatusCodeIs(CREATED);
@@ -211,7 +232,7 @@ public class BaseRestTest extends RestTest
/**
* Helper method to close folder
* @param folderToClose
* @param folderId
* @return
* @throws Exception
*/
@@ -260,4 +281,47 @@ public class BaseRestTest extends RestTest
filePlanComponentAPI.usingRestWrapper().authenticateUser(user);
return filePlanComponentAPI.getFilePlanComponent(componentId);
}
/**
* Helper method to add permission on a component to user
* @param component {@link FilePlanComponent} on which permission should be given
* @param user {@link UserModel} for a user to be granted permission
* @param permission {@link UserPermissions} to be granted
*/
// FIXME: As of December 2016 there is no v1-style API for managing RM permissions.
// Until such APIs have become available, this method is just a proxy to an "old-style"
// API call.
public void addUserPermission(FilePlanComponent component, UserModel user, String permission)
{
// get an "old-style" REST API client
AlfrescoHttpClient client = alfrescoHttpClientFactory.getObject();
JsonObject bodyJson = buildObject()
.addArray("permissions")
.addObject()
.add("authority", user.getUsername())
.add("role", permission)
.end()
.getJson();
// override v1 baseURI and basePath
RequestSpecification spec = new RequestSpecBuilder()
.setBaseUri(client.getApiUrl())
.setBasePath("/")
.build();
// execute an "old-style" API call
Response response = given()
.spec(spec)
.auth().basic(dataUser.getAdminUser().getUsername(), dataUser.getAdminUser().getPassword())
.contentType(ContentType.JSON)
.body(bodyJson.toString())
.pathParam("nodeId", component.getId())
.log().all()
.when()
.post("/node/workspace/SpacesStore/{nodeId}/rmpermissions")
.prettyPeek()
.andReturn();
filePlanComponentAPI.usingRestWrapper().setStatusCode(Integer.toString(response.getStatusCode()));
}
}

View File

@@ -0,0 +1,280 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rm.community.fileplancomponents;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_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.CONTENT_TYPE;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.NON_ELECTRONIC_RECORD_TYPE;
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
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.NO_CONTENT;
import static org.springframework.http.HttpStatus.OK;
import org.alfresco.rest.rm.community.base.BaseRestTest;
import org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponent;
import org.alfresco.rest.rm.community.model.user.UserPermissions;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.rm.community.requests.FilePlanComponentAPI;
import org.alfresco.rest.rm.community.requests.RMSiteAPI;
import org.alfresco.rest.rm.community.requests.RMUserAPI;
import org.alfresco.test.AlfrescoTest;
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.testng.annotations.Test;
/**
* Create/File electronic records tests
* <br>
* These tests only test the creation and filing of electronic records, update at
* present isn't implemented in the API under test.
* <p>
* @author Kristijan Conkas
* @since 2.6
*/
public class DeleteRecordTests extends BaseRestTest
{
@Autowired
private FilePlanComponentAPI filePlanComponentAPI;
@Autowired
private RMUserAPI rmUserAPI;
@Autowired
private DataUser dataUser;
@Autowired
private RMSiteAPI rmSiteAPI;
/** image resource file to be used for records body */
private static final String IMAGE_FILE = "money.JPG";
/**
* <pre>
* Given a record
* And that I have the "Delete Record" capability
* And write permissions
* When I delete the record
* Then it is deleted from the file plan
* </pre>
*
* @param container
* @throws Exception
*/
@Test
(
dataProvider = "validRootContainers",
description = "Admin user can delete an electronic record"
)
@AlfrescoTest(jira="RM-4363")
public void adminCanDeleteElectronicRecord(FilePlanComponent container) throws Exception
{
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
// create an electronic record
FilePlanComponent record = FilePlanComponent.builder()
.name("Record " + getRandomAlphanumeric())
.nodeType(CONTENT_TYPE.toString())
.build();
FilePlanComponent newRecord = filePlanComponentAPI.createElectronicRecord(record, IMAGE_FILE, container.getId());
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(CREATED);
deleteAndVerify(newRecord);
}
/**
* <pre>
* Given a record
* And that I have the "Delete Record" capability
* And write permissions
* When I delete the record
* Then it is deleted from the file plan
* </pre>
*
* @param container
* @throws Exception
*/
@Test
(
dataProvider = "validRootContainers",
description = "Admin user can delete a non-electronic record"
)
@AlfrescoTest(jira="RM-4363")
public void adminCanDeleteNonElectronicRecord(FilePlanComponent container) throws Exception
{
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
// create a non-electronic record
FilePlanComponent record = FilePlanComponent.builder()
.name("Record " + getRandomAlphanumeric())
.nodeType(NON_ELECTRONIC_RECORD_TYPE.toString())
.build();
FilePlanComponent newRecord = filePlanComponentAPI.createFilePlanComponent(
record,
container.getId());
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(CREATED);
deleteAndVerify(newRecord);
}
/**
* <pre>
* Given a record
* And that I don't have write permissions
* When I try to delete the record
* Then nothing happens
* And error gets reported
* </pre>
*
* @param container
* @throws Exception
*/
@Test
(
description = "User without write permissions can't delete a record"
)
@AlfrescoTest(jira="RM-4363")
public void userWithoutWritePermissionsCantDeleteRecord() throws Exception
{
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
// create a non-electronic record in unfiled records
FilePlanComponent record = FilePlanComponent.builder()
.name("Record " + getRandomAlphanumeric())
.nodeType(NON_ELECTRONIC_RECORD_TYPE.toString())
.build();
FilePlanComponent newRecord = filePlanComponentAPI.createFilePlanComponent(
record,
UNFILED_RECORDS_CONTAINER_ALIAS.toString());
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(CREATED);
// create test user and add it with collab. privileges
UserModel deleteUser = dataUser.createRandomTestUser("delnoperm");
deleteUser.setUserRole(UserRole.SiteCollaborator);
logger.info("test user: " + deleteUser.getUsername());
dataUser.addUserToSite(deleteUser, new SiteModel(rmSiteAPI.getSite().getId()), UserRole.SiteCollaborator);
// add RM role to user
rmUserAPI.assignRoleToUser(deleteUser.getUsername(), UserRoles.ROLE_RM_POWER_USER);
rmUserAPI.usingRestWrapper().assertStatusCodeIs(OK);
// log in as deleteUser
filePlanComponentAPI.usingRestWrapper().authenticateUser(deleteUser);
// try to delete newRecord
filePlanComponentAPI.deleteFilePlanComponent(newRecord.getId());
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(FORBIDDEN);
}
/**
* <pre>
* Given a record
* And that I don't have the "Delete Record" capability
* When I try to delete the record
* Then nothing happens
* And error gets reported
* </pre>
*
* @param container
* @throws Exception
*/
@Test
(
description = "User without delete records capability can't delete a record"
)
@AlfrescoTest(jira="RM-4363")
public void userWithoutDeleteRecordsCapabilityCantDeleteRecord() throws Exception
{
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
// create test user and add it with collab. privileges
UserModel deleteUser = dataUser.createRandomTestUser("delnoperm");
deleteUser.setUserRole(UserRole.SiteCollaborator);
dataUser.addUserToSite(deleteUser, new SiteModel(rmSiteAPI.getSite().getId()), UserRole.SiteCollaborator);
logger.info("test user: " + deleteUser.getUsername());
// add RM role to user, RM Power User doesn't have the Delete Record capabilities
rmUserAPI.assignRoleToUser(deleteUser.getUsername(), UserRoles.ROLE_RM_POWER_USER);
rmUserAPI.usingRestWrapper().assertStatusCodeIs(OK);
// create random folder
FilePlanComponent randomFolder = createCategoryFolderInFilePlan(dataUser.getAdminUser(), FILE_PLAN_ALIAS.toString());
logger.info("random folder:" + randomFolder.getName());
// grant deleteUser Filing privileges on randomFolder category, this will be
// inherited to randomFolder
addUserPermission(filePlanComponentAPI.getFilePlanComponent(randomFolder.getParentId()),
deleteUser, UserPermissions.PERMISSION_FILING);
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(OK);
// create a non-electronic record in randomFolder
FilePlanComponent record = FilePlanComponent.builder()
.name("Record " + getRandomAlphanumeric())
.nodeType(NON_ELECTRONIC_RECORD_TYPE.toString())
.build();
FilePlanComponent newRecord = filePlanComponentAPI.createFilePlanComponent(
record,
randomFolder.getId());
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(CREATED);
// log in as deleteUser
filePlanComponentAPI.usingRestWrapper().authenticateUser(deleteUser);
// verify the user can see the newRecord
filePlanComponentAPI.getFilePlanComponent(newRecord.getId());
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(OK);
// try to delete newRecord
filePlanComponentAPI.deleteFilePlanComponent(newRecord.getId());
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(FORBIDDEN);
}
/**
* Utility method to delete a record and verify successful deletion
* @param record
* @throws Exception
*/
private void deleteAndVerify(FilePlanComponent record) throws Exception
{
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
// delete it and verify status
filePlanComponentAPI.deleteFilePlanComponent(record.getId());
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(NO_CONTENT);
// try to get deleted file plan component
filePlanComponentAPI.getFilePlanComponent(record.getId());
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(NOT_FOUND);
}
}

View File

@@ -41,7 +41,6 @@ import static org.testng.Assert.assertTrue;
import org.alfresco.rest.rm.community.base.BaseRestTest;
import org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponent;
import org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentProperties;
import org.alfresco.rest.rm.community.requests.FilePlanComponentAPI;
import org.alfresco.utility.data.DataUser;
import org.springframework.beans.factory.annotation.Autowired;
@@ -103,8 +102,11 @@ public class ElectronicRecordTests extends BaseRestTest
{
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
FilePlanComponent record = new FilePlanComponent("Record " + getRandomAlphanumeric(), CONTENT_TYPE.toString(),
new FilePlanComponentProperties());
// Build object the filePlan
FilePlanComponent record = FilePlanComponent.builder()
.name("Record " + getRandomAlphanumeric())
.nodeType(CONTENT_TYPE.toString())
.build();
filePlanComponentAPI.createElectronicRecord(record, IMAGE_FILE, container.getId());
// verify the create request status code
@@ -134,8 +136,10 @@ public class ElectronicRecordTests extends BaseRestTest
closeFolder(recordFolder.getId());
// try to create it, this should fail
FilePlanComponent record = new FilePlanComponent("Record " + getRandomAlphanumeric(), CONTENT_TYPE.toString(),
new FilePlanComponentProperties());
FilePlanComponent record = FilePlanComponent.builder()
.name("Record " + getRandomAlphanumeric())
.nodeType(CONTENT_TYPE.toString())
.build();
filePlanComponentAPI.createElectronicRecord(record, IMAGE_FILE, recordFolder.getId());
// verify the status code
@@ -179,9 +183,9 @@ public class ElectronicRecordTests extends BaseRestTest
}
// component without name
FilePlanComponent record = new FilePlanComponent();
record.setNodeType(CONTENT_TYPE.toString());
record.setProperties(new FilePlanComponentProperties());
FilePlanComponent record = FilePlanComponent.builder()
.nodeType(CONTENT_TYPE.toString())
.build();
// try to create it
filePlanComponentAPI.createFilePlanComponent(record, container.getId());
@@ -216,8 +220,42 @@ public class ElectronicRecordTests extends BaseRestTest
{
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
FilePlanComponent record = new FilePlanComponent("Record " + getRandomAlphanumeric(), CONTENT_TYPE.toString(),
new FilePlanComponentProperties());
FilePlanComponent record = FilePlanComponent.builder()
.name("Record " + getRandomAlphanumeric())
.nodeType(CONTENT_TYPE.toString())
.build();
String newRecordId = filePlanComponentAPI.createElectronicRecord(record, IMAGE_FILE, container.getId()).getId();
// verify the create request status code
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(CREATED);
// get newly created electonic record and verify its properties
FilePlanComponent electronicRecord = filePlanComponentAPI.getFilePlanComponent(newRecordId);
// created record will have record identifier inserted in its name but will be prefixed with
// the name it was created as
assertTrue(electronicRecord.getName().startsWith(record.getName()));
}
/**
* This test verified that in the test client implementation if record name isn't specified it
* defaults to filed file name.
* @param container valid record container
* @throws Exception if record creation failed
*/
@Test
(
dataProvider = "validRootContainers",
description = "Electronic records can be created in unfiled record folder or unfiled record root"
)
public void recordNameDerivedFromFileName(FilePlanComponent container) throws Exception
{
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
// record object without name set
FilePlanComponent record = FilePlanComponent.builder()
.nodeType(CONTENT_TYPE.toString())
.build();
String newRecordId = filePlanComponentAPI.createElectronicRecord(record, IMAGE_FILE, container.getId()).getId();
// verify the create request status code

View File

@@ -199,9 +199,12 @@ public class FilePlanTests extends BaseRestTest
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
// Build object for updating the filePlan
FilePlanComponent filePlanComponent = new FilePlanComponent();
FilePlanComponentProperties filePlanComponentProperties=new FilePlanComponentProperties(FILE_PLAN_TITLE, FILE_PLAN_DESCRIPTION);
filePlanComponent.setProperties(filePlanComponentProperties);
FilePlanComponent filePlanComponent = FilePlanComponent.builder()
.properties(FilePlanComponentProperties.builder()
.title(FILE_PLAN_TITLE)
.description(FILE_PLAN_DESCRIPTION)
.build())
.build();
// Update the record category
FilePlanComponent renamedFilePlanComponent = filePlanComponentAPI.updateFilePlanComponent(filePlanComponent,FILE_PLAN_ALIAS.toString());
@@ -301,7 +304,12 @@ public class FilePlanTests extends BaseRestTest
String name = filePlanAlias + getRandomAlphanumeric();
// Build the file plan root properties
FilePlanComponent filePlanComponent = new FilePlanComponent(name,rmType.toString(),new FilePlanComponentProperties());
FilePlanComponent filePlanComponent = FilePlanComponent.builder()
.name(name)
.nodeType(rmType.toString())
.properties(FilePlanComponentProperties.builder()
.build())
.build();
// Authenticate with admin user
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());

View File

@@ -89,17 +89,18 @@ public class NonElectronicRecordTests extends BaseRestTest
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
// non-electronic record object to be used for create tests
FilePlanComponent nonElectronicRecord = new FilePlanComponent(
"Record " + getRandomAlphanumeric(),
NON_ELECTRONIC_RECORD_TYPE.toString(),
new FilePlanComponentProperties());
FilePlanComponent nonElectronicRecord = FilePlanComponent.builder()
.name("Record " + getRandomAlphanumeric())
.nodeType(NON_ELECTRONIC_RECORD_TYPE.toString())
.build();
// create record category, non-electronic records can't be its children
FilePlanComponent recordCategory = filePlanComponentAPI.createFilePlanComponent(
new FilePlanComponent("Category " + getRandomAlphanumeric(),
RECORD_CATEGORY_TYPE.toString(),
new FilePlanComponentProperties()),
FILE_PLAN_ALIAS.toString());
FilePlanComponent recordCategoryModel = FilePlanComponent.builder()
.name("Category " + getRandomAlphanumeric())
.nodeType(RECORD_CATEGORY_TYPE.toString())
.build();
FilePlanComponent recordCategory = filePlanComponentAPI.createFilePlanComponent(recordCategoryModel, FILE_PLAN_ALIAS.toString());
// iterate through all invalid parent containers and try to create/file an electronic record
asList(FILE_PLAN_ALIAS.toString(), TRANSFERS_ALIAS.toString(), HOLDS_ALIAS.toString(), recordCategory.getId())
@@ -164,20 +165,25 @@ public class NonElectronicRecordTests extends BaseRestTest
Integer copies = random.nextInt(Integer.MAX_VALUE);
Integer size = random.nextInt(Integer.MAX_VALUE);
// set values of all available properties
FilePlanComponentProperties properties = new FilePlanComponentProperties(title, description);
properties.setBox(box);
properties.setFile(file);
properties.setShelf(shelf);
properties.setLocation(location);
properties.setNumberOfCopies(copies);
properties.setPhysicalSize(size);
// set values of all available properties for the non electronic records
FilePlanComponent filePlanComponent = FilePlanComponent.builder()
.name("Record " + getRandomAlphanumeric())
.nodeType(NON_ELECTRONIC_RECORD_TYPE.toString())
.properties(FilePlanComponentProperties.builder()
.title(title)
.description(description)
.box(box)
.file(file)
.shelf(shelf)
.location(location)
.numberOfCopies(copies)
.physicalSize(size)
.build())
.build();
// create non-electronic record
String nonElectronicId = filePlanComponentAPI.createFilePlanComponent(
new FilePlanComponent("Record " + getRandomAlphanumeric(),
NON_ELECTRONIC_RECORD_TYPE.toString(),
properties),
filePlanComponent,
container.getId()).getId();
// verify the create request status code
@@ -220,11 +226,12 @@ public class NonElectronicRecordTests extends BaseRestTest
// try to create it, this should fail and throw an exception
filePlanComponentAPI.createFilePlanComponent(
new FilePlanComponent("Record " + getRandomAlphanumeric(),
NON_ELECTRONIC_RECORD_TYPE.toString(),
new FilePlanComponentProperties()),
recordFolder.getId()).getId();
filePlanComponentAPI.createFilePlanComponent(FilePlanComponent.builder()
.name("Record " + getRandomAlphanumeric())
.nodeType(NON_ELECTRONIC_RECORD_TYPE.toString())
.build(),
recordFolder.getId())
.getId();
// verify the status code
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(UNPROCESSABLE_ENTITY);
@@ -270,8 +277,9 @@ public class NonElectronicRecordTests extends BaseRestTest
// component with title only
FilePlanComponent titleOnly = getDummyNonElectronicRecord();
FilePlanComponentProperties properties = new FilePlanComponentProperties();
properties.setTitle("Title " + getRandomAlphanumeric());
FilePlanComponentProperties properties = FilePlanComponentProperties.builder()
.title("Title " + getRandomAlphanumeric())
.build();
titleOnly.setProperties(properties);
// try to create invalid components
@@ -321,8 +329,15 @@ public class NonElectronicRecordTests extends BaseRestTest
filePlanComponentAPI.usingRestWrapper().authenticateUser(user);
// try to create a fileplan component
FilePlanComponent record = new FilePlanComponent("Record Name", NON_ELECTRONIC_RECORD_TYPE.toString(),
new FilePlanComponentProperties("Name", "Title"));
FilePlanComponent record=FilePlanComponent.builder()
.properties(FilePlanComponentProperties.builder()
.description("Description")
.title("Title")
.build())
.name("Record Name")
.nodeType(NON_ELECTRONIC_RECORD_TYPE.toString())
.build();
// this should fail and throw an exception
try
@@ -343,8 +358,9 @@ public class NonElectronicRecordTests extends BaseRestTest
*/
private FilePlanComponent getDummyNonElectronicRecord()
{
FilePlanComponent component = new FilePlanComponent();
component.setNodeType(NON_ELECTRONIC_RECORD_TYPE.toString());
FilePlanComponent component=FilePlanComponent.builder()
.nodeType(NON_ELECTRONIC_RECORD_TYPE.toString())
.build();
return component;
}

View File

@@ -94,8 +94,15 @@ public class RecordCategoryTest extends BaseRestTest
String categoryTitle = "Category title " + getRandomAlphanumeric();
// Build the record category properties
FilePlanComponent recordCategory = new FilePlanComponent(categoryName,RECORD_CATEGORY_TYPE.toString(),
new FilePlanComponentProperties(categoryTitle));
FilePlanComponent recordCategory = FilePlanComponent.builder()
.name(categoryName)
.nodeType(RECORD_CATEGORY_TYPE.toString())
.properties(
FilePlanComponentProperties.builder()
.title(categoryTitle)
.build())
.build();
// Create the record category
FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(recordCategory, FILE_PLAN_ALIAS.toString());
@@ -103,9 +110,9 @@ public class RecordCategoryTest extends BaseRestTest
restWrapper.assertStatusCodeIs(CREATED);
// Verify the returned file plan component
assertTrue(filePlanComponent.isCategory());
assertFalse(filePlanComponent.isFile());
assertFalse(filePlanComponent.isRecordFolder());
assertTrue(filePlanComponent.getIsCategory());
assertFalse(filePlanComponent.getIsFile());
assertFalse(filePlanComponent.getIsRecordFolder());
assertEquals(filePlanComponent.getName(), categoryName);
assertEquals(filePlanComponent.getNodeType(), RECORD_CATEGORY_TYPE.toString());
@@ -139,8 +146,14 @@ public class RecordCategoryTest extends BaseRestTest
String categoryTitle = "Category title " + getRandomAlphanumeric();
// Build the record category properties
FilePlanComponent recordCategory = new FilePlanComponent(categoryName, RECORD_CATEGORY_TYPE.toString(),
new FilePlanComponentProperties(categoryTitle));
FilePlanComponent recordCategory = FilePlanComponent.builder()
.name(categoryName)
.nodeType(RECORD_CATEGORY_TYPE.toString())
.properties(
FilePlanComponentProperties.builder()
.title(categoryTitle)
.build())
.build();
// Create the record category
FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(recordCategory, FILE_PLAN_ALIAS.toString());
@@ -148,7 +161,7 @@ public class RecordCategoryTest extends BaseRestTest
String newCategoryName = "Rename " + categoryName;
// Build the properties which will be updated
FilePlanComponent recordCategoryUpdated = new FilePlanComponent(newCategoryName);
FilePlanComponent recordCategoryUpdated = FilePlanComponent.builder().name(newCategoryName).build();
// Update the record category
FilePlanComponent renamedFilePlanComponent = filePlanComponentAPI.updateFilePlanComponent(recordCategoryUpdated, filePlanComponent.getId());
@@ -186,8 +199,15 @@ public class RecordCategoryTest extends BaseRestTest
String categoryTitle = "Category title " + getRandomAlphanumeric();
// Build the record category properties
FilePlanComponent recordCategory = new FilePlanComponent(categoryName, RECORD_CATEGORY_TYPE.toString(),
new FilePlanComponentProperties(categoryTitle));
FilePlanComponent recordCategory = FilePlanComponent.builder()
.name(categoryName)
.nodeType(RECORD_CATEGORY_TYPE.toString())
.properties(
FilePlanComponentProperties.builder()
.title(categoryTitle)
.build())
.build();
// Create the record category
FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(recordCategory, FILE_PLAN_ALIAS.toString());
@@ -226,9 +246,9 @@ public class RecordCategoryTest extends BaseRestTest
// Verify child category
assertEquals(childCategory.getParentId(), rootCategory.getId());
assertTrue(childCategory.isCategory());
assertFalse(childCategory.isFile());
assertFalse(childCategory.isRecordFolder());
assertTrue(childCategory.getIsCategory());
assertFalse(childCategory.getIsFile());
assertFalse(childCategory.getIsRecordFolder());
assertEquals(childCategory.getNodeType(), RECORD_CATEGORY_TYPE.toString());
}
@@ -295,19 +315,19 @@ public class RecordCategoryTest extends BaseRestTest
assertEquals(filePlanComponent.getParentId(), rootCategory.getId());
// Only categories or folders have been created
assertFalse(filePlanComponent.isFile());
assertFalse(filePlanComponent.getIsFile());
// Boolean properties related to node type
// Only RECORD_CATEGORY_TYPE and RECORD_FOLDER_TYPE have been created
if (filePlanComponent.getNodeType().equals(RECORD_CATEGORY_TYPE.toString()))
{
assertTrue(filePlanComponent.isCategory());
assertFalse(filePlanComponent.isRecordFolder());
assertTrue(filePlanComponent.getIsCategory());
assertFalse(filePlanComponent.getIsRecordFolder());
}
else
{
assertTrue(filePlanComponent.isRecordFolder());
assertFalse(filePlanComponent.isCategory());
assertTrue(filePlanComponent.getIsRecordFolder());
assertFalse(filePlanComponent.getIsCategory());
}
// Does returned object have the same contents as the created one?
@@ -348,8 +368,14 @@ public class RecordCategoryTest extends BaseRestTest
FilePlanComponent category = createCategory(FILE_PLAN_ALIAS.toString(), COMPONENT_NAME);
//Build node properties
FilePlanComponent recordCategory = new FilePlanComponent(COMPONENT_NAME,nodeType,
new FilePlanComponentProperties("Title for " + COMPONENT_NAME));
FilePlanComponent recordCategory = FilePlanComponent.builder()
.name(COMPONENT_NAME)
.nodeType(nodeType)
.properties(
FilePlanComponentProperties.builder()
.title("Title for " + COMPONENT_NAME)
.build())
.build();
//create the invalid node type
filePlanComponentAPI.createFilePlanComponent(recordCategory, category.getId());
@@ -383,8 +409,14 @@ public class RecordCategoryTest extends BaseRestTest
{
RestWrapper restWrapper = filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
//Build node properties
FilePlanComponent component = new FilePlanComponent(componentName, componentType.toString(),
new FilePlanComponentProperties("Title for " + componentName));
FilePlanComponent component = FilePlanComponent.builder()
.name(componentName)
.nodeType(componentType.toString())
.properties(FilePlanComponentProperties.builder()
.title("Title for " + componentName)
.build())
.build();
FilePlanComponent fpc = filePlanComponentAPI.createFilePlanComponent(component, parentComponentId);
restWrapper.assertStatusCodeIs(CREATED);
return fpc;

View File

@@ -31,6 +31,7 @@ import static org.alfresco.rest.rm.community.base.TestData.FOLDER_NAME;
import static org.alfresco.rest.rm.community.base.TestData.FOLDER_TITLE;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.IS_CLOSED;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.PATH;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.RECORD_FOLDER_TYPE;
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
import static org.springframework.http.HttpStatus.CREATED;
@@ -44,6 +45,7 @@ import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.fail;
import static org.testng.AssertJUnit.assertTrue;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.NoSuchElementException;
@@ -93,8 +95,13 @@ public class RecordFolderTests extends BaseRestTest
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
FilePlanComponent filePlanComponent = createCategory(FILE_PLAN_ALIAS.toString(), CATEGORY);
FilePlanComponentProperties filePlanComponentProperties = new FilePlanComponentProperties(FOLDER_TITLE);
FilePlanComponent recordFolder = new FilePlanComponent(FOLDER_NAME,RECORD_FOLDER_TYPE.toString(), filePlanComponentProperties);
FilePlanComponent recordFolder = FilePlanComponent.builder()
.name(FOLDER_NAME)
.nodeType(RECORD_FOLDER_TYPE.toString())
.properties(FilePlanComponentProperties.builder()
.title(FOLDER_TITLE)
.build())
.build();
// Create the record folder
FilePlanComponent folder = filePlanComponentAPI.createFilePlanComponent(recordFolder, filePlanComponent.getId());
@@ -105,9 +112,9 @@ public class RecordFolderTests extends BaseRestTest
// Check folder has been created within the category created
assertEquals(filePlanComponent.getId(),folder.getParentId());
// Verify the returned properties for the file plan component - record folder
assertFalse(folder.isCategory());
assertFalse(folder.isFile());
assertTrue(folder.isRecordFolder());
assertFalse(folder.getIsCategory());
assertFalse(folder.getIsFile());
assertTrue(folder.getIsRecordFolder());
assertEquals(folder.getName(), FOLDER_NAME);
assertEquals(folder.getNodeType(), RECORD_FOLDER_TYPE.toString());
@@ -138,8 +145,14 @@ public class RecordFolderTests extends BaseRestTest
String componentID = filePlanComponentAPI.getFilePlanComponent(filePlanComponent).getId();
// Build the record category properties
FilePlanComponent recordFolder = new FilePlanComponent(FOLDER_NAME,RECORD_FOLDER_TYPE.toString(),
new FilePlanComponentProperties(FOLDER_TITLE));
FilePlanComponent recordFolder = FilePlanComponent.builder()
.name(FOLDER_NAME)
.nodeType(RECORD_FOLDER_TYPE.toString())
.properties(FilePlanComponentProperties.builder()
.title(FOLDER_TITLE)
.build())
.build();
// Create a record folder
filePlanComponentAPI.createFilePlanComponent(recordFolder, componentID);
@@ -168,10 +181,10 @@ public class RecordFolderTests extends BaseRestTest
// Verify the returned properties for the file plan component - record folder
assertEquals(RECORD_FOLDER_TYPE.toString(),folderDetails.getNodeType());
assertTrue(folderDetails.isRecordFolder());
assertFalse(folderDetails.isCategory());
assertFalse(folderDetails.isFile());
assertFalse(folderDetails.isClosed());
assertTrue(folderDetails.getIsRecordFolder());
assertFalse(folderDetails.getIsCategory());
assertFalse(folderDetails.getIsFile());
assertFalse(folderDetails.getIsClosed());
assertEquals(FOLDER_NAME,folderDetails.getName());
assertEquals(dataUser.getAdminUser().getUsername(),folderDetails.getCreatedByUser().getId());
@@ -210,11 +223,16 @@ public class RecordFolderTests extends BaseRestTest
String location = "Location"+getRandomAlphanumeric();
//Create the file plan component properties to update
FilePlanComponentProperties filePlanComponentProperties = new FilePlanComponentProperties(folderTitle, folderDescription);
filePlanComponentProperties.setVitalRecord(true);
filePlanComponentProperties.setReviewPeriod( new ReviewPeriod("month","1"));
filePlanComponentProperties.setLocation(location);
FilePlanComponent recordFolder = new FilePlanComponent(folderName,filePlanComponentProperties);
FilePlanComponent recordFolder = FilePlanComponent.builder()
.name(folderName)
.properties(FilePlanComponentProperties.builder()
.title(folderTitle)
.description(folderDescription)
.vitalRecord(true)
.reviewPeriod(new ReviewPeriod("month","1"))
.location(location)
.build())
.build();
// Update the record category
FilePlanComponent folderUpdated = filePlanComponentAPI.updateFilePlanComponent(recordFolder, folder.getId());
@@ -226,7 +244,7 @@ public class RecordFolderTests extends BaseRestTest
assertEquals(folderName, folderUpdated.getName());
assertEquals(folderDescription, folderUpdated.getProperties().getDescription());
assertEquals(folderTitle, folderUpdated.getProperties().getTitle());
assertTrue(folderUpdated.getProperties().isVitalRecord());
assertTrue(folderUpdated.getProperties().getVitalRecord());
assertEquals(location, folderUpdated.getProperties().getLocation());
assertNotNull(folderUpdated.getProperties().getReviewPeriod().getPeriodType());
assertNotNull(folderUpdated.getProperties().getReviewPeriod().getExpression());
@@ -324,11 +342,11 @@ public class RecordFolderTests extends BaseRestTest
// Is parent Id set correctly
assertEquals(filePlanComponent.getParentId(), category.getId());
assertFalse(filePlanComponent.isFile());
assertFalse(filePlanComponent.getIsFile());
// Boolean properties related to node type
assertTrue(filePlanComponent.isRecordFolder());
assertFalse(filePlanComponent.isCategory());
assertTrue(filePlanComponent.getIsRecordFolder());
assertFalse(filePlanComponent.getIsCategory());
assertEquals(createdComponent.getName(), filePlanComponent.getName());
assertEquals(createdComponent.getNodeType(), filePlanComponent.getNodeType());
@@ -342,6 +360,97 @@ public class RecordFolderTests extends BaseRestTest
);
}
/**
* Given that I want to create a record folder
* When I use the API with the relativePath
* Then the categories specified in the relativePath that don't exist are created within the record folder
*
* Containers in the relativePath that do not exist are created before the node is created
*/
@Test
(
description = "Create a folder based on the relativePath. " +
"Containers in the relativePath that do not exist are created before the node is created"
)
public void createFolderWithRelativePath() throws Exception
{
//RelativePath specify the container structure to create relative to the record folder to be created
String RELATIVE_PATH = LocalDateTime.now().getYear()+"/"+ LocalDateTime.now().getMonth()+"/"+ LocalDateTime.now().getDayOfMonth();
// Authenticate with admin user
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
//The record folder to be created
FilePlanComponent recordFolder = FilePlanComponent.builder()
.name(FOLDER_NAME)
.nodeType(RECORD_FOLDER_TYPE.toString())
.relativePath(RELATIVE_PATH)
.build();
// Create the record folder
FilePlanComponent folder = filePlanComponentAPI.withParams("include="+ PATH).createFilePlanComponent(recordFolder,FILE_PLAN_ALIAS.toString());
//Check the API response code
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(CREATED);
// Verify the returned properties for the file plan component - record folder
assertFalse(folder.getIsCategory());
assertFalse(folder.getIsFile());
assertTrue(folder.getIsRecordFolder());
//Check the path return contains the RELATIVE_PATH
assertTrue(folder.getPath().getName().contains(RELATIVE_PATH));
//check the parent is a category
assertTrue(filePlanComponentAPI.getFilePlanComponent(folder.getParentId()).getIsCategory());
//check the created folder from the server
folder=filePlanComponentAPI.withParams("include=" + PATH).getFilePlanComponent(folder.getId());
//Check the API response code
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(OK);
// Verify the returned properties for the file plan component - record folder
assertFalse(folder.getIsCategory());
assertFalse(folder.getIsFile());
assertTrue(folder.getIsRecordFolder());
//Check the path return contains the RELATIVE_PATH
assertTrue(folder.getPath().getName().contains(RELATIVE_PATH));
//New Relative Path only a part of containers need to be created before the record folder
String NEW_RELATIVE_PATH = LocalDateTime.now().getYear() + "/" + LocalDateTime.now().getMonth() + "/" +( LocalDateTime.now().getDayOfMonth()+1);
//The record folder to be created
FilePlanComponent recordFolder2 = FilePlanComponent.builder()
.name(FOLDER_NAME)
.nodeType(RECORD_FOLDER_TYPE.toString())
.relativePath(NEW_RELATIVE_PATH)
.build();
// Create the record folder
FilePlanComponent folder2 = filePlanComponentAPI.withParams("include=" + PATH).createFilePlanComponent(recordFolder2, FILE_PLAN_ALIAS.toString());
//Check the API response code
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(CREATED);
// Verify the returned properties for the file plan component - record folder
assertFalse(folder2.getIsCategory());
assertFalse(folder2.getIsFile());
assertTrue(folder2.getIsRecordFolder());
//Check the path return contains the NEW_RELATIVE_PATH
assertTrue(folder2.getPath().getName().contains(NEW_RELATIVE_PATH));
//check the parent is a category
assertTrue(filePlanComponentAPI.getFilePlanComponent(folder.getParentId()).getIsCategory());
// Check the folder created on the server
folder2 = filePlanComponentAPI.withParams("include=" + PATH).getFilePlanComponent(folder2.getId());
//Check the API response code
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(OK);
// Verify the returned properties for the file plan component - record folder
assertFalse(folder2.getIsCategory());
assertFalse(folder2.getIsFile());
assertTrue(folder2.getIsRecordFolder());
//Check the path return contains the NEW_RELATIVE_PATH
assertTrue(folder2.getPath().getName().contains(NEW_RELATIVE_PATH));
}
@AfterClass (alwaysRun = true)
public void tearDown() throws Exception
{

View File

@@ -107,8 +107,14 @@ public class UnfiledRecordsFolderTests extends BaseRestTest
String folderDescription = folderName + " Description";
// Build unfiled records folder properties
FilePlanComponent unfiledFolder=new FilePlanComponent(folderName,UNFILED_RECORD_FOLDER_TYPE.toString(),
new FilePlanComponentProperties(folderTitle,folderDescription));
FilePlanComponent unfiledFolder = FilePlanComponent.builder()
.name(folderName)
.nodeType(UNFILED_RECORD_FOLDER_TYPE.toString())
.properties(FilePlanComponentProperties.builder()
.title(folderTitle)
.description(folderDescription)
.build())
.build();
FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(unfiledFolder,
UNFILED_RECORDS_CONTAINER_ALIAS.toString());
@@ -117,9 +123,9 @@ public class UnfiledRecordsFolderTests extends BaseRestTest
filePlanComponentAPI.usingRestWrapper().assertStatusCodeIs(CREATED);
// Verify the returned file plan component
assertFalse(filePlanComponent.isCategory());
assertFalse(filePlanComponent.isFile());
assertFalse(filePlanComponent.isRecordFolder()); // it is not a _normal_ record folder!
assertFalse(filePlanComponent.getIsCategory());
assertFalse(filePlanComponent.getIsFile());
assertFalse(filePlanComponent.getIsRecordFolder()); // it is not a _normal_ record folder!
assertEquals(filePlanComponent.getName(), folderName);
assertEquals(filePlanComponent.getNodeType(), UNFILED_RECORD_FOLDER_TYPE.toString());
@@ -151,8 +157,14 @@ public class UnfiledRecordsFolderTests extends BaseRestTest
logger.info("creating " + componentType.toString());
// Build unfiled records folder properties
FilePlanComponent unfiledFolder = new FilePlanComponent(folderName, componentType.toString(),
new FilePlanComponentProperties(folderTitle, folderDescription));
FilePlanComponent unfiledFolder = FilePlanComponent.builder()
.name(folderName)
.nodeType(componentType.toString())
.properties(FilePlanComponentProperties.builder()
.title(folderTitle)
.description(folderDescription)
.build())
.build();
try
{
@@ -189,8 +201,14 @@ public class UnfiledRecordsFolderTests extends BaseRestTest
assertEquals(parentFolderName, parentFolder.getName());
// Build the unfiled records folder properties
FilePlanComponent unfiledFolder = new FilePlanComponent(childFolderName, UNFILED_RECORD_FOLDER_TYPE.toString(),
new FilePlanComponentProperties(childFolderTitle, childFolderDescription));
FilePlanComponent unfiledFolder = FilePlanComponent.builder()
.name(childFolderName)
.nodeType(UNFILED_RECORD_FOLDER_TYPE.toString())
.properties(FilePlanComponentProperties.builder()
.title(childFolderTitle)
.description(childFolderDescription)
.build())
.build();
// Create it as a child of parentFolder
FilePlanComponent childFolder = filePlanComponentAPI.createFilePlanComponent(unfiledFolder,
@@ -200,9 +218,9 @@ public class UnfiledRecordsFolderTests extends BaseRestTest
restWrapper.assertStatusCodeIs(CREATED);
// Verify the returned file plan component
assertFalse(childFolder.isCategory());
assertFalse(childFolder.isFile());
assertFalse(childFolder.isRecordFolder()); // it is not a _normal_ record folder!
assertFalse(childFolder.getIsCategory());
assertFalse(childFolder.getIsFile());
assertFalse(childFolder.getIsRecordFolder()); // it is not a _normal_ record folder!
assertEquals(childFolder.getName(), childFolderName);
assertEquals(childFolder.getNodeType(), UNFILED_RECORD_FOLDER_TYPE.toString());
@@ -251,9 +269,14 @@ public class UnfiledRecordsFolderTests extends BaseRestTest
assertEquals(folderName, folderToModify.getName());
// Build the properties which will be updated
FilePlanComponent folderToUpdate = new FilePlanComponent(modified + folderToModify.getName(),
new FilePlanComponentProperties(modified + folderToModify.getProperties().getTitle(),
modified + folderToModify.getProperties().getDescription()));
FilePlanComponent folderToUpdate = FilePlanComponent.builder()
.name(modified + folderToModify.getName())
.properties(FilePlanComponentProperties.builder().
title(modified + folderToModify.getProperties().getTitle()).
description(modified + folderToModify.getProperties().getDescription())
.build())
.build();
// Update the unfiled records folder
filePlanComponentAPI.updateFilePlanComponent(folderToUpdate, folderToModify.getId());
// Verify the status code

View File

@@ -95,7 +95,10 @@ public class RMSiteTests extends BaseRestTest
}
// Create the RM site
RMSite rmSite = new RMSite(RM_TITLE, RM_DESCRIPTION, STANDARD);
RMSite rmSite =RMSite.builder().compliance(STANDARD).build();
rmSite.setTitle(RM_TITLE);
rmSite.setDescription(RM_DESCRIPTION);
RMSite rmSiteResponse = rmSiteAPI.createRMSite(rmSite);
// Verify the status code
@@ -132,7 +135,10 @@ public class RMSiteTests extends BaseRestTest
String newDescription = RM_DESCRIPTION + "createRMSiteWhenSiteExists";
// Create the RM site
RMSite rmSite = new RMSite(newTitle, newDescription, STANDARD);
RMSite rmSite = RMSite.builder().compliance(STANDARD).build();
rmSite.setTitle(newTitle);
rmSite.setDescription(newDescription);
rmSiteAPI.createRMSite(rmSite);
// Verify the status code
@@ -236,7 +242,9 @@ public class RMSiteTests extends BaseRestTest
rmSiteAPI.usingRestWrapper().authenticateUser(userModel);
// Create the RM site
RMSite rmSite = new RMSite(RM_TITLE, RM_DESCRIPTION, DOD5015);
RMSite rmSite = RMSite.builder().compliance(DOD5015).build();
rmSite.setTitle(RM_TITLE);
rmSite.setDescription(RM_DESCRIPTION);
rmSite=rmSiteAPI.createRMSite(rmSite);
// Verify the status code
@@ -325,7 +333,7 @@ public class RMSiteTests extends BaseRestTest
createRMSiteIfNotExists();
// Build the RM site properties
RMSite rmSiteToUpdate = new RMSite(DOD5015);
RMSite rmSiteToUpdate = RMSite.builder().compliance(DOD5015).build();
// Update the RM site
rmSiteAPI.updateRMSite(rmSiteToUpdate);

View File

@@ -21,3 +21,4 @@ rm.service.final-version=Final
rm.service.final-version-description=The final archived record version
rm.service.enable-autoversion-on-record-creation=Auto Version on Record Creation
rm.service.add-children-to-closed-record-folder=You can't add new items to a closed record folder
rm.service.update-record-content=Could not update content property as it's immutable for records.

View File

@@ -45,16 +45,21 @@
</property>
</bean>
<bean class="org.alfresco.rm.rest.api.nodes.FileplanComponentsEntityResource">
<bean class="org.alfresco.rm.rest.api.fileplancomponents.FileplanComponentsEntityResource">
<property name="nodes" ref="rm.Nodes" />
</bean>
<bean class="org.alfresco.rm.rest.api.nodes.RecordsEntityResource">
<bean class="org.alfresco.rm.rest.api.fileplancomponents.FileplanComponentChildrenRelation">
<property name="nodes" ref="rm.Nodes" />
</bean>
<bean class="org.alfresco.rm.rest.api.nodes.FileplanComponentChildrenRelation">
<bean class="org.alfresco.rm.rest.api.records.RecordsEntityResource">
<property name="nodes" ref="rm.Nodes" />
<property name="records" ref="Records" />
</bean>
<bean class="org.alfresco.rm.rest.api.files.FilesEntityResource">
<property name="records" ref="Records" />
</bean>
<!-- extended sites bean definition -->
@@ -84,6 +89,30 @@
<property name="sites" ref="rm.Sites" />
</bean>
<bean id="records" class="org.alfresco.rm.rest.api.impl.RecordsImpl">
<property name="recordService" ref="RecordService"/>
<property name="filePlanService" ref="FilePlanService"/>
<property name="nodes" ref="rm.nodes"/>
<property name="nodeService" ref="NodeService"/>
<property name="fileFolderService" ref="FileFolderService"/>
<property name="dictionaryService" ref="DictionaryService"/>
</bean>
<bean id="Records" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>org.alfresco.rm.rest.api.Records</value>
</property>
<property name="target">
<ref bean="records" />
</property>
<property name="interceptorNames">
<list>
<idref bean="legacyExceptionInterceptor" />
</list>
</property>
</bean>
<!-- Map RM exceptions to HTML status codes -->
<bean id="rm.simpleMappingExceptionResolver" abstract="true" parent="simpleMappingExceptionResolver">
<property name="exceptionMappings">

View File

@@ -25,6 +25,7 @@
<alfresco.rm.artifactId>alfresco-rm-community-repo</alfresco.rm.artifactId>
<skip.integrationtests>true</skip.integrationtests>
<alfresco.solr.home>${project.build.directory}/solr/home</alfresco.solr.home>
<api.explorer.version>1.4</api.explorer.version>
</properties>
<build>
@@ -532,11 +533,19 @@
<contextPath>/solr4</contextPath>
<contextFile>${alfresco.solr.home}/context.xml</contextFile>
</webapp>
<webapp>
<groupId>org.alfresco</groupId>
<artifactId>api-explorer</artifactId>
<version>${api.explorer.version}</version>
<contextPath>/api-explorer</contextPath>
<type>war</type>
<asWebapp>true</asWebapp>
</webapp>
<webapp>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-rm-community-rest-api-explorer</artifactId>
<version>${project.version}</version>
<contextPath>/api-explorer</contextPath>
<contextPath>/ig-api-explorer</contextPath>
<type>war</type>
<asWebapp>true</asWebapp>
</webapp>

View File

@@ -37,20 +37,24 @@ import org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies;
import org.alfresco.module.org_alfresco_module_rm.model.behaviour.AbstractDisposableItem;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService;
import org.alfresco.repo.content.ContentServicePolicies;
import org.alfresco.repo.copy.CopyBehaviourCallback;
import org.alfresco.repo.copy.CopyDetails;
import org.alfresco.repo.copy.CopyServicePolicies;
import org.alfresco.repo.copy.DefaultCopyBehaviourCallback;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.policy.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.ScriptService;
import org.alfresco.service.namespace.QName;
import org.springframework.extensions.surf.util.I18NUtil;
/**
* rma:record behaviour bean
@@ -67,7 +71,8 @@ public class RecordAspect extends AbstractDisposableItem
RecordsManagementPolicies.OnCreateReference,
RecordsManagementPolicies.OnRemoveReference,
NodeServicePolicies.OnMoveNodePolicy,
CopyServicePolicies.OnCopyCompletePolicy
CopyServicePolicies.OnCopyCompletePolicy,
ContentServicePolicies.OnContentPropertyUpdatePolicy
{
/** Well-known location of the scripts folder. */
// TODO make configurable
@@ -82,6 +87,9 @@ public class RecordAspect extends AbstractDisposableItem
/** record service */
protected RecordService recordService;
/** I18N */
private static final String MSG_CANNOT_UPDATE_RECORD_CONTENT = "rm.service.update-record-content";
/**
* @param extendedSecurityService extended security service
*/
@@ -336,4 +344,19 @@ public class RecordAspect extends AbstractDisposableItem
extendedSecurityService.remove(targetNodeRef);
}
}
@Override
@Behaviour
(
kind = BehaviourKind.CLASS,
notificationFrequency = NotificationFrequency.FIRST_EVENT
)
public void onContentPropertyUpdate(NodeRef nodeRef, QName propertyQName, ContentData beforeValue, ContentData afterValue)
{
// Allow creation of content but not update
if (beforeValue != null)
{
throw new IntegrityException(I18NUtil.getMessage(MSG_CANNOT_UPDATE_RECORD_CONTENT), null);
}
}
}

View File

@@ -28,6 +28,8 @@
package org.alfresco.rm.rest.api;
import org.alfresco.rest.api.Nodes;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/**
* RM Nodes API
@@ -45,4 +47,15 @@ public interface RMNodes extends Nodes
public static String PARAM_INCLUDE_HAS_RETENTION_SCHEDULE = "hasRetentionSchedule";
public static String PARAM_INCLUDE_IS_CLOSED = "isClosed";
public static String PARAM_INCLUDE_IS_COMPLETED = "isCompleted";
/**
* Gets or creates the relative path starting from the provided parent folder.
* The method decides the type of the created elements considering the
* parent container's type and the type of the node to be created.
* @param parentFolderNodeId the parent folder to start from
* @param relativePath the relative path
* @param nodeTypeQName the type of the node to be created
* @return reference to the last element of the created path
*/
public NodeRef getOrCreatePath(String parentFolderNodeId, String relativePath, QName nodeTypeQName);
}

View File

@@ -0,0 +1,63 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rm.rest.api;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rm.rest.api.model.TargetContainer;
/**
* Records API
*
* @author Ana Bozianu
* @since 2.6
*/
public interface Records
{
public static final String PARAM_HIDE_RECORD = "hideRecord";
/**
* Creates a record from a file
*
* @param fileId the id of a non record file
* @param parameters the {@link Parameters} object to get the parameters passed into the request
* @return information about the created record
*/
public Node declareFileAsRecord(String fileId, Parameters parameters);
/**
* Files a record into th fileplan.
* If the record is already filed it links the record to the target folder
*
* @param recordId the id of the record do file/link
* @param target the target parent folder
* @param parameters the {@link Parameters} object to get the parameters passed into the request
* @return information about the new state of the record
*/
public Node fileOrLinkRecord(String recordId, TargetContainer target, Parameters parameters);
}

View File

@@ -25,7 +25,7 @@
* #L%
*/
package org.alfresco.rm.rest.api.nodes;
package org.alfresco.rm.rest.api.fileplancomponents;
import java.util.ArrayList;
import java.util.List;

View File

@@ -25,7 +25,7 @@
* #L%
*/
package org.alfresco.rm.rest.api.nodes;
package org.alfresco.rm.rest.api.fileplancomponents;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.framework.WebApiDescription;

View File

@@ -0,0 +1,37 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/**
* Package info that defines the Information Governance Fileplan Components REST API
*
* @author Ana Bozianu
* @since 2.6
*/
@WebApi(name="ig", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rm.rest.api.fileplancomponents;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;

View File

@@ -0,0 +1,69 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rm.rest.api.files;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.framework.Operation;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.framework.webscripts.WithResponse;
import org.alfresco.rm.rest.api.Records;
import org.alfresco.rm.rest.api.model.TargetContainer;
import org.alfresco.util.ParameterCheck;
import org.springframework.beans.factory.InitializingBean;
/**
* An implementation of an Entity Resource for a file
*
* @author Ana Bozianu
* @since 2.6
*/
@EntityResource(name="files", title = "Files")
public class FilesEntityResource implements InitializingBean
{
private Records records;
public void setRecords(Records records)
{
this.records = records;
}
@Operation("declare")
@WebApiDescription(title = "Declare as record", description="Declare a file as record.")
public Node declareAsRecord(String fileId, Void body, Parameters parameters, WithResponse withResponse)
{
return records.declareFileAsRecord(fileId, parameters);
}
@Override
public void afterPropertiesSet() throws Exception
{
ParameterCheck.mandatory("records", this.records);
}
}

View File

@@ -26,12 +26,12 @@
*/
/**
* Package info that defines the Information Governance Nodes REST API
* Package info that defines the Information Governance Files REST API
*
* @author Ana Bozianu
* @since 2.6
*/
@WebApi(name="ig", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rm.rest.api.nodes;
package org.alfresco.rm.rest.api.files;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;

View File

@@ -336,25 +336,30 @@ public class RMNodesImpl extends NodesImpl implements RMNodes
public Node createNode(String parentFolderNodeId, Node nodeInfo, Parameters parameters)
{
// create RM path if needed and call the super method with the last element of the created path
NodeRef parentNodeRef = getOrCreatePath(parentFolderNodeId, nodeInfo);
String relativePath = nodeInfo.getRelativePath();
// Get the type of the node to be created
String nodeType = nodeInfo.getNodeType();
if ((nodeType == null) || nodeType.isEmpty())
{
throw new InvalidArgumentException("Node type is expected: "+parentFolderNodeId+","+nodeInfo.getName());
}
QName nodeTypeQName = createQName(nodeType);
// Get or create the path
NodeRef parentNodeRef = getOrCreatePath(parentFolderNodeId, relativePath, nodeTypeQName);
// Set relative path to null as we pass the last element from the path
nodeInfo.setRelativePath(null);
return super.createNode(parentNodeRef.getId(), nodeInfo, parameters);
}
/**
* Gets or creates the relative path specified in nodeInfo.relativePath
* starting from the provided parent folder.
* The method decides the type of the created elements considering the
* parent container's type and the type of the node to be created.
* @param parentFolderNodeId the parent folder to start from
* @param nodeInfo information about the node to be created
* @return reference to the last element of the created path
*/
protected NodeRef getOrCreatePath(String parentFolderNodeId, Node nodeInfo)
@Override
public NodeRef getOrCreatePath(String parentFolderNodeId, String relativePath, QName nodeTypeQName)
{
NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId, null);
String relativePath = nodeInfo.getRelativePath();
if (relativePath == null)
{
return parentNodeRef;
@@ -413,14 +418,6 @@ public class RMNodesImpl extends NodesImpl implements RMNodes
}
else
{
// Get the type of the node to be created
String nodeType = nodeInfo.getNodeType();
if ((nodeType == null) || nodeType.isEmpty())
{
throw new InvalidArgumentException("Node type is expected: "+parentFolderNodeId+","+nodeInfo.getName());
}
QName nodeTypeQName = createQName(nodeType);
/* Outside the unfiled record container the path elements are record categories
* except the last element which is a record folder if the created node is of type content
*/

View File

@@ -0,0 +1,198 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rm.rest.api.impl;
import java.security.InvalidParameterException;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rm.rest.api.RMNodes;
import org.alfresco.rm.rest.api.Records;
import org.alfresco.rm.rest.api.model.TargetContainer;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.model.FileExistsException;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.extensions.surf.util.ParameterCheck;
public class RecordsImpl implements Records, InitializingBean
{
protected RecordService recordService;
protected FilePlanService filePlanService;
protected NodeService nodeService;
protected FileFolderService fileFolderService;
protected DictionaryService dictionaryService;
protected RMNodes nodes;
public void setRecordService(RecordService recordService)
{
this.recordService = recordService;
}
public void setFilePlanService(FilePlanService filePlanService)
{
this.filePlanService = filePlanService;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setFileFolderService(FileFolderService fileFolderService)
{
this.fileFolderService = fileFolderService;
}
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
public void setNodes(RMNodes nodes)
{
this.nodes = nodes;
}
@Override
public Node declareFileAsRecord(String fileId, Parameters parameters)
{
// Parameter check
if ((fileId == null) || (fileId.isEmpty()))
{
throw new InvalidArgumentException("Missing fileId");
}
// Get file to be declared
NodeRef fileNodeRef = nodes.validateNode(fileId) ;
// Get fileplan
NodeRef filePlan = AuthenticationUtil.runAsSystem(new RunAsWork<NodeRef>()
{
@Override
public NodeRef doWork()
{
return filePlanService.getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID);
}
});
// default false (if not provided)
boolean hideRecord = Boolean.valueOf(parameters.getParameter(PARAM_HIDE_RECORD));
// Create the record
recordService.createRecord(filePlan, fileNodeRef, !hideRecord);
// Get information about the new record
return nodes.getFolderOrDocument(fileId, parameters);
}
@Override
public Node fileOrLinkRecord(String recordId, TargetContainer target, Parameters parameters)
{
ParameterCheck.mandatoryString("recordId", recordId);
if((target.getTargetParentId() == null || target.getTargetParentId().isEmpty()) &&
(target.getRelativePath() == null || target.getRelativePath().isEmpty()))
{
throw new InvalidParameterException("No target folder information was provided");
}
// Get record
NodeRef record = nodes.validateNode(recordId);
// Get record folder to file/link the record to
String parentContainerId = target.getTargetParentId();
if(parentContainerId == null || parentContainerId.isEmpty())
{
// If target container not provided get fileplan
parentContainerId = AuthenticationUtil.runAsSystem(new RunAsWork<String>()
{
@Override
public String doWork()
{
return filePlanService.getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID).getId();
}
});
}
NodeRef parentRecordFolder = nodes.getOrCreatePath(parentContainerId, target.getRelativePath(), ContentModel.TYPE_CONTENT);
// Check if the target is a record folder
if(!dictionaryService.isSubClass(nodeService.getType(parentRecordFolder), RecordsManagementModel.TYPE_RECORD_FOLDER))
{
throw new InvalidArgumentException("The provided target parent is not a record folder");
}
// Get the current parent type to decide if we link or move the record
NodeRef primaryParent = nodeService.getPrimaryParent(record).getParentRef();
if(dictionaryService.isSubClass(nodeService.getType(primaryParent), RecordsManagementModel.TYPE_RECORD_FOLDER))
{
recordService.link(record, parentRecordFolder);
}
else
{
try
{
fileFolderService.moveFrom(record, primaryParent, parentRecordFolder, null);
}
catch (FileExistsException e)
{
throw new IntegrityException(e.getMessage(), null);
}
catch (FileNotFoundException e)
{
throw new ConcurrencyFailureException("The record was deleted while filing it", e);
}
}
// Get the record info
return nodes.getFolderOrDocument(recordId, parameters);
}
@Override
public void afterPropertiesSet() throws Exception
{
ParameterCheck.mandatory("recordService", recordService);
ParameterCheck.mandatory("filePlanService", filePlanService);
ParameterCheck.mandatory("nodes", nodes);
ParameterCheck.mandatory("nodeService", nodeService);
ParameterCheck.mandatory("fileFolderService", fileFolderService);
ParameterCheck.mandatory("dictionaryService", dictionaryService);
}
}

View File

@@ -0,0 +1,74 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rm.rest.api.model;
/**
* A target container object
*
* @author Ana Bozianu
* @since 2.6
*/
public class TargetContainer
{
String targetParentId;
String relativePath;
public TargetContainer()
{
}
public String getTargetParentId()
{
return targetParentId;
}
public void setTargetParentId(String targetParentId)
{
this.targetParentId = targetParentId;
}
public String getRelativePath()
{
return relativePath;
}
public void setRelativePath(String relativePath)
{
this.relativePath = relativePath;
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder("NodeTarget{");
sb.append("targetParentId=").append(targetParentId);
sb.append(", relativePath='").append(relativePath).append('\'');
sb.append('}');
return sb.toString();
}
}

View File

@@ -25,20 +25,21 @@
* #L%
*/
package org.alfresco.rm.rest.api.nodes;
import java.io.InputStream;
package org.alfresco.rm.rest.api.records;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.framework.BinaryProperties;
import org.alfresco.rest.framework.Operation;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.actions.interfaces.BinaryResourceAction;
import org.alfresco.rest.framework.resource.content.BasicContentInfo;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.framework.webscripts.WithResponse;
import org.alfresco.rm.rest.api.RMNodes;
import org.alfresco.rm.rest.api.Records;
import org.alfresco.rm.rest.api.model.TargetContainer;
import org.alfresco.util.ParameterCheck;
import org.springframework.beans.factory.InitializingBean;
@@ -49,22 +50,21 @@ import org.springframework.beans.factory.InitializingBean;
* @since 2.6
*/
@EntityResource(name="records", title = "Records")
public class RecordsEntityResource implements BinaryResourceAction.Update<Node>,
BinaryResourceAction.Read,
public class RecordsEntityResource implements BinaryResourceAction.Read,
InitializingBean
{
private RMNodes nodes;
private Records records;
public void setNodes(RMNodes nodes)
{
this.nodes = nodes;
}
@Override
public void afterPropertiesSet() throws Exception
public void setRecords(Records records)
{
ParameterCheck.mandatory("nodes", this.nodes);
this.records = records;
}
/**
@@ -83,24 +83,22 @@ public class RecordsEntityResource implements BinaryResourceAction.Update<Node>,
return nodes.getContent(recordId, parameters, true);
}
/**
* Upload new version of content
*
* This allow binary content update of an existing record.
*
* Note: alternatively, can upload via POST (multipart/form-data) with existing file name and form "overwrite=true".
*
* @param recordId the id of the record to set the content for
* @param contentInfo Basic information about the content stream
* @param stream an inputstream representing the new content of the node
* @param parameters {@link Parameters}
* @return information about the record that has been updated
*/
@Override
@WebApiDescription(title = "Upload content", description = "Upload content")
@BinaryProperties({"content"})
public Node updateProperty(String recordId, BasicContentInfo contentInfo, InputStream stream, Parameters parameters)
@Operation("file")
@WebApiDescription(title = "File record", description="File a record into fileplan.")
public Node fileRecord(String recordId, TargetContainer target, Parameters parameters, WithResponse withResponse)
{
return nodes.updateContent(recordId, contentInfo, stream, parameters);
try{
return records.fileOrLinkRecord(recordId, target, parameters);
}catch(Exception ex)
{
throw ex;
}
}
@Override
public void afterPropertiesSet() throws Exception
{
ParameterCheck.mandatory("nodes", this.nodes);
ParameterCheck.mandatory("records", this.records);
}
}

View File

@@ -0,0 +1,37 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
* -
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* -
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* -
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/**
* Package info that defines the Information Governance Records REST API
*
* @author Ana Bozianu
* @since 2.6
*/
@WebApi(name="ig", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rm.rest.api.records;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;

View File

@@ -25,7 +25,7 @@
* #L%
*/
package org.alfresco.rm.rest.api.nodes;
package org.alfresco.rm.rest.api.fileplancomponents;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

View File

@@ -90,8 +90,7 @@ public class RMNodesImplRelativePathUnitTest extends BaseUnitTest
* When trying to create a node in the parent node with no relative path
*/
Node nodeInfo = mock(Node.class);
when(nodeInfo.getRelativePath()).thenReturn(null);
NodeRef returnedPath = rmNodesImpl.getOrCreatePath(parentNode.getId(), nodeInfo);
NodeRef returnedPath = rmNodesImpl.getOrCreatePath(parentNode.getId(), null, ContentModel.TYPE_CONTENT);
/*
* Then the parent node is returned and no node is created
@@ -126,8 +125,7 @@ public class RMNodesImplRelativePathUnitTest extends BaseUnitTest
* When trying to create a node in the parent node with the relative path c1/f1
*/
Node nodeInfo = mock(Node.class);
when(nodeInfo.getRelativePath()).thenReturn(category + "/" + recordFolder);
NodeRef returnedPath = rmNodesImpl.getOrCreatePath(parentNode.getId(), nodeInfo);
NodeRef returnedPath = rmNodesImpl.getOrCreatePath(parentNode.getId(), category + "/" + recordFolder, ContentModel.TYPE_CONTENT);
/*
* Then the node f1 is returned and no node is created
@@ -166,9 +164,6 @@ public class RMNodesImplRelativePathUnitTest extends BaseUnitTest
/*
* When trying to create a content node in the relative path c1/c2/c3/f1
*/
Node nodeInfo = mock(Node.class);
when(nodeInfo.getNodeType()).thenReturn("cm:content");
// c3
String category3 = "c3";
NodeRef categoryNode3 = AlfMock.generateNodeRef(mockedNodeService);
@@ -182,8 +177,7 @@ public class RMNodesImplRelativePathUnitTest extends BaseUnitTest
when(mockedFileFolderService.create(categoryNode3, recordFolder, RecordsManagementModel.TYPE_RECORD_FOLDER)).thenReturn(recordFolderFileInfo);
// call the class under tests
when(nodeInfo.getRelativePath()).thenReturn(category1 + "/" + category2 + "/" + category3 + "/" + recordFolder);
NodeRef returnedPath = rmNodesImpl.getOrCreatePath(fileplanNodeRef.getId(), nodeInfo);
NodeRef returnedPath = rmNodesImpl.getOrCreatePath(fileplanNodeRef.getId(), category1 + "/" + category2 + "/" + category3 + "/" + recordFolder, ContentModel.TYPE_CONTENT);
/*
* Then the category c1 and the record folder f1 should be created and f1 should be returned
@@ -232,9 +226,7 @@ public class RMNodesImplRelativePathUnitTest extends BaseUnitTest
when(mockedFileFolderService.create(folderNode2, folder3, RecordsManagementModel.TYPE_UNFILED_RECORD_FOLDER)).thenReturn(folderFileInfo3);
// call the class under tests
Node nodeInfo = mock(Node.class);
when(nodeInfo.getRelativePath()).thenReturn(folder1 + "/" + folder2 + "/" + folder3);
NodeRef returnedParentNode = rmNodesImpl.getOrCreatePath(unfiledRecordContainer.getId(), nodeInfo);
NodeRef returnedParentNode = rmNodesImpl.getOrCreatePath(unfiledRecordContainer.getId(), folder1 + "/" + folder2 + "/" + folder3, ContentModel.TYPE_CONTENT);
/*
* Then the category c1 and the record folder rf1 should be created
@@ -267,9 +259,6 @@ public class RMNodesImplRelativePathUnitTest extends BaseUnitTest
/*
* When trying to create a folder node in the relative path c1/c2/c3
*/
Node nodeInfo = mock(Node.class);
when(nodeInfo.getNodeType()).thenReturn("rma:recordFolder");
// c1
String category1 = "c1";
NodeRef categoryNode1 = AlfMock.generateNodeRef(mockedNodeService);
@@ -286,8 +275,7 @@ public class RMNodesImplRelativePathUnitTest extends BaseUnitTest
when(mockedFilePlanService.createRecordCategory(categoryNode2, category3)).thenReturn(categoryNode3);
// call the class under tests
when(nodeInfo.getRelativePath()).thenReturn(category1 + "/" + category2 + "/" + category3);
NodeRef returnedParentNode = rmNodesImpl.getOrCreatePath(fileplanNodeRef.getId(), nodeInfo);
NodeRef returnedParentNode = rmNodesImpl.getOrCreatePath(fileplanNodeRef.getId(), category1 + "/" + category2 + "/" + category3, RecordsManagementModel.TYPE_RECORD_FOLDER);
/*
* Then the categories c1, c2 and c3 should be created and c3 should be returned

View File

@@ -11,8 +11,7 @@
</parent>
<properties>
<alfresco.api.explorer.version>2.0-SNAPSHOT</alfresco.api.explorer.version>
<swagger-ui.version>2.1.4</swagger-ui.version>
<alfresco.api.explorer.version>1.4</alfresco.api.explorer.version>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -30,6 +29,9 @@
<overlay>
<groupId>org.alfresco</groupId>
<artifactId>api-explorer</artifactId>
<excludes>
<exclude>definitions/*</exclude>
</excludes>
</overlay>
</overlays>
</configuration>

View File

@@ -21,6 +21,8 @@ tags:
description: Retrieve and manage the RM site
- name: records
description: Perform record specific operations
- name: files
description: Perform operations on non-record files
paths:
'/fileplan-components/{fileplanComponentId}':
get:
@@ -377,7 +379,10 @@ paths:
- $ref: '#/parameters/fieldsParam'
- in: body
name: nodeBodyCreate
description: The node information to create.
description: |
The node information to create.
This field is ignored for multipart/form-data content uploads.
required: true
schema:
$ref: '#/definitions/RMNodeBodyCreate'
@@ -564,7 +569,6 @@ paths:
$ref: '#/definitions/Error'
'/records/{recordId}/content':
get:
x-alfresco-since: "5.2"
tags:
- records
summary: Get record content
@@ -583,75 +587,48 @@ paths:
description: Content has not been modified since the date provided in the If-Modified-Since header
'400':
description: |
Invalid parameter: **nodeId** is not a valid format, or is not a file
Invalid parameter: **recordId** is not a valid format, or is not a record
'401':
description: Authentication failed
'404':
description: |
**nodeId** does not exist
**recordId** does not exist
default:
description: Unexpected error
schema:
$ref: '#/definitions/Error'
put:
x-alfresco-since: "5.2"
'/records/{recordId}/file':
post:
tags:
- records
summary: Update record content
summary: File a record
description: |
Updates the content of the record with identifier **recordId**.
Files the record **recordId** in the target record folder.
The request body for this endpoint can be any text or binary stream.
You can specify the target record folder by providing its id **targetParentId**
or by providing the id of a parent container **targetParentId** and a relative path **relativePath**.
The **majorVersion** and **comment** parameters can be used to control versioning behaviour. If the content is versionable,
a new minor version is created by default.
The **relativePath** specifies the container structure relative to the node **targetParentId**.
If targetParentId is missing the path will be relative to the fileplan.
The relativePath is made of record containers and a record folder as the last element.
Containers that are missing from relativePath will be created before filing.
Optionally a new **name** parameter can also be specified that must be unique within the parent folder. If specified and valid then this
will rename the node. If invalid then an error is returned and the content is not updated.
**Note:** This API method accepts any content type, but for testing with this tool text based content can be provided.
This is because the OpenAPI Specification does not allow a wildcard to be provided or the ability for
tooling to accept an arbitrary file.
operationId: updateRecordContent
If the record is already filed, a link to the target record folder is created.
operationId: fileRecord
parameters:
- $ref: '#/parameters/recordIdParam'
- name: majorVersion
in: query
description: |
If **true**, create a major version.
Setting this parameter also enables versioning of this node, if it is not already versioned.
required: false
type: boolean
default: false
- name: comment
in: query
description: |
Add a version comment which will appear in version history.
Setting this parameter also enables versioning of this node, if it is not already versioned.
required: false
type: string
- name: name
in: query
description: |
Optional new name. This should include the file extension.
The name must not contain spaces or the following special characters: * " < > \ / ? : and |.
The character `.` must not be used at the end of the name.
required: false
type: string
pattern: "^(?!(.*[\\\"\\*\\\\\\>\\<\\?\\/\\:\\|]+.*)|(.*[\\.]?.*[\\.]+$)|(.*[ ]+$))"
- $ref: '#/parameters/IGNodeEntryIncludeParam'
- $ref: '#/parameters/fieldsParam'
- in: body
name: contentBodyUpdate
description: The binary content
name: nodeBodyFile
description: The target record folder id
required: true
schema:
type: string
format: binary
$ref: '#/definitions/RequestBodyFile'
consumes:
- application/json
produces:
- application/json
consumes:
- application/octet-stream
responses:
'200':
description: Successful response
@@ -659,22 +636,64 @@ paths:
$ref: '#/definitions/IGNodeEntry'
'400':
description: |
Invalid parameter: **recordId** is not a valid format, or is not a file
Invalid parameter: **recordIdParam** or **targetParentId** is not a valid format,
**recordIdParam** is not a record, **targetParentId** is not a record container or **nodeBodyFile** is invalid
'401':
description: Authentication failed
'403':
description: Current user does not have permission to update **recordId**
description: Current user does not have permission to create children of **nodeId**
'404':
description: |
**recordId** does not exist
'409':
description: Optional new name clashes with an existing node in the current parent folder
'413':
description: Content exceeds individual file size limit (configured for network/system)
**recordIdParam** or **targetParentId** does not exist
'422':
description: Model integrity exception including a file name containing invalid characters
'507':
description: Content exceeds overall storage quota limit configured for the network/system
description: |
Model integrity exception: the action breaks system's integrity restrictions
default:
description: Unexpected error
schema:
$ref: '#/definitions/Error'
'/files/{fileId}/declare':
post:
tags:
- files
summary: Declare as record
description: Declares the file **fileId** in the unfiled record container.
operationId: declareRecord
parameters:
- name: fileId
in: path
description: The identifier of a non-record file.
required: true
type: string
- name: hideRecord
in: query
description: Flag to indicate whether the record should be hiden from the curent parent folder.
type: boolean
default: false
- $ref: '#/parameters/IGNodeEntryIncludeParam'
- $ref: '#/parameters/fieldsParam'
consumes:
- application/json
produces:
- application/json
responses:
'200':
description: Successful response
schema:
$ref: '#/definitions/IGNodeEntry'
'400':
description: |
Invalid parameter: **fileId** is not a valid format
'401':
description: Authentication failed
'403':
description: Current user does not have permission to declare a record
'404':
description: |
**fileId** does not exist
'422':
description: |
Model integrity exception: the action breaks system's integrity restrictions
default:
description: Unexpected error
schema:
@@ -958,6 +977,13 @@ definitions:
type: object
additionalProperties:
type: string
RequestBodyFile:
type: object
properties:
targetParentId:
type: string
relativePath:
type: string
## Core definition
ChildAssociationInfo:
type: object

View File

@@ -32,7 +32,7 @@
<script type="text/javascript">
$(function () {
window.swaggerUi = new SwaggerUi({
url: "definitions/alfresco-core.yaml",
url: "definitions/ig-core-api.yaml",
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
onComplete: function(swaggerApi, swaggerUi){
@@ -91,10 +91,6 @@
<form id="api_selector">
<div class="input" id="select-wrapper">
<select id="select_baseUrl" name="select_baseUrl">
<option value="definitions/alfresco-core.yaml">Core API</option>
<option value="definitions/alfresco-search.yaml">Search API</option>
<option value="definitions/alfresco-auth.yaml">Authentication API</option>
<option value="definitions/alfresco-workflow.yaml">Workflow API</option>
<option value="definitions/ig-core-api.yaml">IG Core API</option>
</select>
</div>