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

View File

@@ -24,7 +24,6 @@
</modules> </modules>
<properties> <properties>
<alfresco.installer.host>releases</alfresco.installer.host>
<maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.target>1.8</maven.compiler.target>
<suiteXmlFile>testng.xml</suiteXmlFile> <suiteXmlFile>testng.xml</suiteXmlFile>
@@ -109,22 +108,18 @@
<echo>Recreating database...</echo> <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> <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> <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" /> <chmod file="target/alf-installer.bin" perm="a+x" verbose="true" />
<echo>Installing Alfresco...</echo> <echo>Installing Alfresco...</echo>
<exec executable="${basedir}/target/alf-installer.bin" dir="target" failonerror="true"> <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" /> <arg line="--mode unattended --alfresco_admin_password admin --disable-components postgres,alfrescowcmqs --jdbc_username alfresco --jdbc_password alfresco --prefix ${basedir}/target/alf-installation" />
</exec> </exec>
<delete file="target/alf-installer.bin" verbose="true" />
</target> </target>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
<dependencies> <dependencies>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-jsch</artifactId>
<version>1.8.2</version>
</dependency>
<dependency> <dependency>
<groupId>postgresql</groupId> <groupId>postgresql</groupId>
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>

View File

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

View File

@@ -54,5 +54,11 @@
<artifactId>fluent-json</artifactId> <artifactId>fluent-json</artifactId>
<version>${fluent.json.version}</version> <version>${fluent.json.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
</project> </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.ALLOWABLE_OPERATIONS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.IS_CLOSED; 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.PROPERTIES;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentFields.RELATIVE_PATH;
import java.util.List; import java.util.List;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/** /**
* POJO for file plan component * POJO for file plan component
* *
@@ -41,6 +48,10 @@ import com.fasterxml.jackson.annotation.JsonProperty;
* @author Rodica Sutu * @author Rodica Sutu
* @since 2.6 * @since 2.6
*/ */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FilePlanComponent public class FilePlanComponent
{ {
@JsonProperty (required = true) @JsonProperty (required = true)
@@ -88,6 +99,7 @@ public class FilePlanComponent
@JsonProperty (required = false) @JsonProperty (required = false)
private FilePlanComponentContent content; private FilePlanComponentContent content;
@JsonProperty (value = PATH)
private FilePlanComponentPath path; private FilePlanComponentPath path;
@JsonProperty (required = true) @JsonProperty (required = true)
@@ -99,324 +111,7 @@ public class FilePlanComponent
@JsonProperty (required = true) @JsonProperty (required = true)
private FilePlanComponentUserInfo modifiedByUser; 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) @JsonProperty (required = true)
private Integer sizeInBytes; 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 com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.alfresco.rest.core.RestModels; import org.alfresco.rest.core.RestModels;
/** /**
@@ -38,13 +42,13 @@ import org.alfresco.rest.core.RestModels;
* @author Tuna Aksoy * @author Tuna Aksoy
* @since 2.6 * @since 2.6
*/ */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FilePlanComponentEntry extends RestModels<FilePlanComponent, FilePlanComponentEntry> public class FilePlanComponentEntry extends RestModels<FilePlanComponent, FilePlanComponentEntry>
{ {
@JsonProperty(ENTRY) @JsonProperty(ENTRY)
FilePlanComponent filePlanComponent; 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_SHELF = "rma:shelf";
public static final String PROPERTIES_STORAGE_LOCATION = "rma:storageLocation"; 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; 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 * POJO for id/name pair
* *
* @author Kristijan Conkas * @author Kristijan Conkas
* @since 2.6 * @since 2.6
*/ */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FilePlanComponentIdNamePair public class FilePlanComponentIdNamePair
{ {
public String id; public String id;
public String name; 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 com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/** /**
* POJO for FilePlanComponent path parameter * POJO for FilePlanComponent path parameter
* <br> * <br>
* @author Kristijan Conkas * @author Kristijan Conkas
* @since 2.6 * @since 2.6
*/ */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public class FilePlanComponentPath public class FilePlanComponentPath
{ {
@@ -43,51 +52,4 @@ public class FilePlanComponentPath
private Boolean isComplete; private Boolean isComplete;
private List<FilePlanComponentIdNamePair> elements; 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 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 * 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 //FIXME: Once the fields have been added the JsonIgnoreProperties annotation should be removed
@JsonIgnoreProperties (ignoreUnknown = true) @JsonIgnoreProperties (ignoreUnknown = true)
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FilePlanComponentProperties public class FilePlanComponentProperties
{ {
@@ -100,227 +109,4 @@ public class FilePlanComponentProperties
private Integer physicalSize; 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; 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 * POJO for file plan component created by object
* *
* @author Kristijan Conkas * @author Kristijan Conkas
* @since 2.6 * @since 2.6
*/ */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FilePlanComponentUserInfo public class FilePlanComponentUserInfo
{ {
private String id; private String id;
private String displayName; 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; 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 * POJO for the review period
* *
* @author Rodica Sutu * @author Rodica Sutu
* @since 2.6 * @since 2.6
*/ */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ReviewPeriod public class ReviewPeriod
{ {
private String periodType; private String periodType;
private String expression; 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 com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.alfresco.rest.model.RestSiteModel; import org.alfresco.rest.model.RestSiteModel;
/** /**
@@ -38,59 +42,13 @@ import org.alfresco.rest.model.RestSiteModel;
* @author Rodica Sutu * @author Rodica Sutu
* @since 2.6 * @since 2.6
*/ */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RMSite extends RestSiteModel public class RMSite extends RestSiteModel
{ {
@JsonProperty (value = COMPLIANCE,required = true) @JsonProperty (value = COMPLIANCE,required = true)
private RMSiteCompliance compliance; 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; package org.alfresco.rest.rm.community.requests;
import static com.jayway.restassured.RestAssured.basic;
import static com.jayway.restassured.RestAssured.given; import static com.jayway.restassured.RestAssured.given;
import static org.alfresco.rest.core.RestRequest.requestWithBody; 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 static org.testng.Assert.fail;
import java.io.File; 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.google.common.io.Resources;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.http.ContentType; import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.response.Response; import com.jayway.restassured.response.Response;
@@ -169,15 +174,40 @@ public class FilePlanComponentAPI extends RestAPI<FilePlanComponentAPI>
fail("Only electronic records are supported"); 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. * RestWrapper adds some headers which break multipart/form-data uploads and also assumes json POST requests.
* Upload the file using RestAssured library. * Upload the file using RestAssured library.
*/ */
UserModel currentUser = usingRestWrapper().getTestUser();
Response response = given() Response response = given()
.auth().basic(currentUser.getUsername(), currentUser.getPassword()) .spec(builder.build())
.multiPart("nodeBodyCreate", toJson(electronicRecordModel), ContentType.JSON.name())
.multiPart("filedata", recordContent, ContentType.BINARY.name())
.when() .when()
.post("fileplan-components/{fileplanComponentId}/children?{parameters}", parentId, getParameters()) .post("fileplan-components/{fileplanComponentId}/children?{parameters}", parentId, getParameters())
.andReturn(); .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 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.CATEGORY_TITLE;
import static org.alfresco.rest.rm.community.base.TestData.FOLDER_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; 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.fileplancomponents.FilePlanComponentType.UNFILED_RECORD_FOLDER_TYPE;
import static org.alfresco.rest.rm.community.model.site.RMSiteCompliance.STANDARD; import static org.alfresco.rest.rm.community.model.site.RMSiteCompliance.STANDARD;
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric; 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.CREATED;
import static org.springframework.http.HttpStatus.OK; import static org.springframework.http.HttpStatus.OK;
import com.google.gson.JsonObject;
import com.jayway.restassured.RestAssured; 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.RestTest;
import org.alfresco.rest.core.RestWrapper; import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponent; import org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponent;
@@ -96,6 +106,9 @@ public class BaseRestTest extends RestTest
@Autowired @Autowired
public FilePlanComponentAPI filePlanComponentAPI; public FilePlanComponentAPI filePlanComponentAPI;
@Autowired
private AlfrescoHttpClientFactory alfrescoHttpClientFactory;
// Constants // Constants
public static final String RM_ID = "rm"; public static final String RM_ID = "rm";
public static final String RM_TITLE = "Records Management"; public static final String RM_TITLE = "Records Management";
@@ -141,7 +154,9 @@ public class BaseRestTest extends RestTest
rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); rmSiteAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
// Create the RM site // 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); rmSiteAPI.createRMSite(rmSite);
// Verify the status code // Verify the status code
@@ -202,7 +217,13 @@ public class BaseRestTest extends RestTest
{ {
RestWrapper restWrapper = filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); 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); FilePlanComponent fpc = filePlanComponentAPI.createFilePlanComponent(filePlanComponent, parentComponentId);
restWrapper.assertStatusCodeIs(CREATED); restWrapper.assertStatusCodeIs(CREATED);
@@ -211,7 +232,7 @@ public class BaseRestTest extends RestTest
/** /**
* Helper method to close folder * Helper method to close folder
* @param folderToClose * @param folderId
* @return * @return
* @throws Exception * @throws Exception
*/ */
@@ -260,4 +281,47 @@ public class BaseRestTest extends RestTest
filePlanComponentAPI.usingRestWrapper().authenticateUser(user); filePlanComponentAPI.usingRestWrapper().authenticateUser(user);
return filePlanComponentAPI.getFilePlanComponent(componentId); 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.base.BaseRestTest;
import org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponent; 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.rest.rm.community.requests.FilePlanComponentAPI;
import org.alfresco.utility.data.DataUser; import org.alfresco.utility.data.DataUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -103,8 +102,11 @@ public class ElectronicRecordTests extends BaseRestTest
{ {
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
FilePlanComponent record = new FilePlanComponent("Record " + getRandomAlphanumeric(), CONTENT_TYPE.toString(), // Build object the filePlan
new FilePlanComponentProperties()); FilePlanComponent record = FilePlanComponent.builder()
.name("Record " + getRandomAlphanumeric())
.nodeType(CONTENT_TYPE.toString())
.build();
filePlanComponentAPI.createElectronicRecord(record, IMAGE_FILE, container.getId()); filePlanComponentAPI.createElectronicRecord(record, IMAGE_FILE, container.getId());
// verify the create request status code // verify the create request status code
@@ -134,8 +136,10 @@ public class ElectronicRecordTests extends BaseRestTest
closeFolder(recordFolder.getId()); closeFolder(recordFolder.getId());
// try to create it, this should fail // try to create it, this should fail
FilePlanComponent record = new FilePlanComponent("Record " + getRandomAlphanumeric(), CONTENT_TYPE.toString(), FilePlanComponent record = FilePlanComponent.builder()
new FilePlanComponentProperties()); .name("Record " + getRandomAlphanumeric())
.nodeType(CONTENT_TYPE.toString())
.build();
filePlanComponentAPI.createElectronicRecord(record, IMAGE_FILE, recordFolder.getId()); filePlanComponentAPI.createElectronicRecord(record, IMAGE_FILE, recordFolder.getId());
// verify the status code // verify the status code
@@ -179,9 +183,9 @@ public class ElectronicRecordTests extends BaseRestTest
} }
// component without name // component without name
FilePlanComponent record = new FilePlanComponent(); FilePlanComponent record = FilePlanComponent.builder()
record.setNodeType(CONTENT_TYPE.toString()); .nodeType(CONTENT_TYPE.toString())
record.setProperties(new FilePlanComponentProperties()); .build();
// try to create it // try to create it
filePlanComponentAPI.createFilePlanComponent(record, container.getId()); filePlanComponentAPI.createFilePlanComponent(record, container.getId());
@@ -216,8 +220,42 @@ public class ElectronicRecordTests extends BaseRestTest
{ {
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
FilePlanComponent record = new FilePlanComponent("Record " + getRandomAlphanumeric(), CONTENT_TYPE.toString(), FilePlanComponent record = FilePlanComponent.builder()
new FilePlanComponentProperties()); .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(); String newRecordId = filePlanComponentAPI.createElectronicRecord(record, IMAGE_FILE, container.getId()).getId();
// verify the create request status code // verify the create request status code

View File

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

View File

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

View File

@@ -94,8 +94,15 @@ public class RecordCategoryTest extends BaseRestTest
String categoryTitle = "Category title " + getRandomAlphanumeric(); String categoryTitle = "Category title " + getRandomAlphanumeric();
// Build the record category properties // Build the record category properties
FilePlanComponent recordCategory = new FilePlanComponent(categoryName,RECORD_CATEGORY_TYPE.toString(), FilePlanComponent recordCategory = FilePlanComponent.builder()
new FilePlanComponentProperties(categoryTitle)); .name(categoryName)
.nodeType(RECORD_CATEGORY_TYPE.toString())
.properties(
FilePlanComponentProperties.builder()
.title(categoryTitle)
.build())
.build();
// Create the record category // Create the record category
FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(recordCategory, FILE_PLAN_ALIAS.toString()); FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(recordCategory, FILE_PLAN_ALIAS.toString());
@@ -103,9 +110,9 @@ public class RecordCategoryTest extends BaseRestTest
restWrapper.assertStatusCodeIs(CREATED); restWrapper.assertStatusCodeIs(CREATED);
// Verify the returned file plan component // Verify the returned file plan component
assertTrue(filePlanComponent.isCategory()); assertTrue(filePlanComponent.getIsCategory());
assertFalse(filePlanComponent.isFile()); assertFalse(filePlanComponent.getIsFile());
assertFalse(filePlanComponent.isRecordFolder()); assertFalse(filePlanComponent.getIsRecordFolder());
assertEquals(filePlanComponent.getName(), categoryName); assertEquals(filePlanComponent.getName(), categoryName);
assertEquals(filePlanComponent.getNodeType(), RECORD_CATEGORY_TYPE.toString()); assertEquals(filePlanComponent.getNodeType(), RECORD_CATEGORY_TYPE.toString());
@@ -139,8 +146,14 @@ public class RecordCategoryTest extends BaseRestTest
String categoryTitle = "Category title " + getRandomAlphanumeric(); String categoryTitle = "Category title " + getRandomAlphanumeric();
// Build the record category properties // Build the record category properties
FilePlanComponent recordCategory = new FilePlanComponent(categoryName, RECORD_CATEGORY_TYPE.toString(), FilePlanComponent recordCategory = FilePlanComponent.builder()
new FilePlanComponentProperties(categoryTitle)); .name(categoryName)
.nodeType(RECORD_CATEGORY_TYPE.toString())
.properties(
FilePlanComponentProperties.builder()
.title(categoryTitle)
.build())
.build();
// Create the record category // Create the record category
FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(recordCategory, FILE_PLAN_ALIAS.toString()); FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(recordCategory, FILE_PLAN_ALIAS.toString());
@@ -148,7 +161,7 @@ public class RecordCategoryTest extends BaseRestTest
String newCategoryName = "Rename " + categoryName; String newCategoryName = "Rename " + categoryName;
// Build the properties which will be updated // Build the properties which will be updated
FilePlanComponent recordCategoryUpdated = new FilePlanComponent(newCategoryName); FilePlanComponent recordCategoryUpdated = FilePlanComponent.builder().name(newCategoryName).build();
// Update the record category // Update the record category
FilePlanComponent renamedFilePlanComponent = filePlanComponentAPI.updateFilePlanComponent(recordCategoryUpdated, filePlanComponent.getId()); FilePlanComponent renamedFilePlanComponent = filePlanComponentAPI.updateFilePlanComponent(recordCategoryUpdated, filePlanComponent.getId());
@@ -186,8 +199,15 @@ public class RecordCategoryTest extends BaseRestTest
String categoryTitle = "Category title " + getRandomAlphanumeric(); String categoryTitle = "Category title " + getRandomAlphanumeric();
// Build the record category properties // Build the record category properties
FilePlanComponent recordCategory = new FilePlanComponent(categoryName, RECORD_CATEGORY_TYPE.toString(), FilePlanComponent recordCategory = FilePlanComponent.builder()
new FilePlanComponentProperties(categoryTitle)); .name(categoryName)
.nodeType(RECORD_CATEGORY_TYPE.toString())
.properties(
FilePlanComponentProperties.builder()
.title(categoryTitle)
.build())
.build();
// Create the record category // Create the record category
FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(recordCategory, FILE_PLAN_ALIAS.toString()); FilePlanComponent filePlanComponent = filePlanComponentAPI.createFilePlanComponent(recordCategory, FILE_PLAN_ALIAS.toString());
@@ -226,9 +246,9 @@ public class RecordCategoryTest extends BaseRestTest
// Verify child category // Verify child category
assertEquals(childCategory.getParentId(), rootCategory.getId()); assertEquals(childCategory.getParentId(), rootCategory.getId());
assertTrue(childCategory.isCategory()); assertTrue(childCategory.getIsCategory());
assertFalse(childCategory.isFile()); assertFalse(childCategory.getIsFile());
assertFalse(childCategory.isRecordFolder()); assertFalse(childCategory.getIsRecordFolder());
assertEquals(childCategory.getNodeType(), RECORD_CATEGORY_TYPE.toString()); assertEquals(childCategory.getNodeType(), RECORD_CATEGORY_TYPE.toString());
} }
@@ -295,19 +315,19 @@ public class RecordCategoryTest extends BaseRestTest
assertEquals(filePlanComponent.getParentId(), rootCategory.getId()); assertEquals(filePlanComponent.getParentId(), rootCategory.getId());
// Only categories or folders have been created // Only categories or folders have been created
assertFalse(filePlanComponent.isFile()); assertFalse(filePlanComponent.getIsFile());
// Boolean properties related to node type // Boolean properties related to node type
// Only RECORD_CATEGORY_TYPE and RECORD_FOLDER_TYPE have been created // Only RECORD_CATEGORY_TYPE and RECORD_FOLDER_TYPE have been created
if (filePlanComponent.getNodeType().equals(RECORD_CATEGORY_TYPE.toString())) if (filePlanComponent.getNodeType().equals(RECORD_CATEGORY_TYPE.toString()))
{ {
assertTrue(filePlanComponent.isCategory()); assertTrue(filePlanComponent.getIsCategory());
assertFalse(filePlanComponent.isRecordFolder()); assertFalse(filePlanComponent.getIsRecordFolder());
} }
else else
{ {
assertTrue(filePlanComponent.isRecordFolder()); assertTrue(filePlanComponent.getIsRecordFolder());
assertFalse(filePlanComponent.isCategory()); assertFalse(filePlanComponent.getIsCategory());
} }
// Does returned object have the same contents as the created one? // 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); FilePlanComponent category = createCategory(FILE_PLAN_ALIAS.toString(), COMPONENT_NAME);
//Build node properties //Build node properties
FilePlanComponent recordCategory = new FilePlanComponent(COMPONENT_NAME,nodeType, FilePlanComponent recordCategory = FilePlanComponent.builder()
new FilePlanComponentProperties("Title for " + COMPONENT_NAME)); .name(COMPONENT_NAME)
.nodeType(nodeType)
.properties(
FilePlanComponentProperties.builder()
.title("Title for " + COMPONENT_NAME)
.build())
.build();
//create the invalid node type //create the invalid node type
filePlanComponentAPI.createFilePlanComponent(recordCategory, category.getId()); filePlanComponentAPI.createFilePlanComponent(recordCategory, category.getId());
@@ -383,8 +409,14 @@ public class RecordCategoryTest extends BaseRestTest
{ {
RestWrapper restWrapper = filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); RestWrapper restWrapper = filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
//Build node properties //Build node properties
FilePlanComponent component = new FilePlanComponent(componentName, componentType.toString(), FilePlanComponent component = FilePlanComponent.builder()
new FilePlanComponentProperties("Title for " + componentName)); .name(componentName)
.nodeType(componentType.toString())
.properties(FilePlanComponentProperties.builder()
.title("Title for " + componentName)
.build())
.build();
FilePlanComponent fpc = filePlanComponentAPI.createFilePlanComponent(component, parentComponentId); FilePlanComponent fpc = filePlanComponentAPI.createFilePlanComponent(component, parentComponentId);
restWrapper.assertStatusCodeIs(CREATED); restWrapper.assertStatusCodeIs(CREATED);
return fpc; 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.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.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.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.rest.rm.community.model.fileplancomponents.FilePlanComponentType.RECORD_FOLDER_TYPE;
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric; import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
import static org.springframework.http.HttpStatus.CREATED; 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.Assert.fail;
import static org.testng.AssertJUnit.assertTrue; import static org.testng.AssertJUnit.assertTrue;
import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@@ -93,8 +95,13 @@ public class RecordFolderTests extends BaseRestTest
filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser()); filePlanComponentAPI.usingRestWrapper().authenticateUser(dataUser.getAdminUser());
FilePlanComponent filePlanComponent = createCategory(FILE_PLAN_ALIAS.toString(), CATEGORY); FilePlanComponent filePlanComponent = createCategory(FILE_PLAN_ALIAS.toString(), CATEGORY);
FilePlanComponentProperties filePlanComponentProperties = new FilePlanComponentProperties(FOLDER_TITLE); FilePlanComponent recordFolder = FilePlanComponent.builder()
FilePlanComponent recordFolder = new FilePlanComponent(FOLDER_NAME,RECORD_FOLDER_TYPE.toString(), filePlanComponentProperties); .name(FOLDER_NAME)
.nodeType(RECORD_FOLDER_TYPE.toString())
.properties(FilePlanComponentProperties.builder()
.title(FOLDER_TITLE)
.build())
.build();
// Create the record folder // Create the record folder
FilePlanComponent folder = filePlanComponentAPI.createFilePlanComponent(recordFolder, filePlanComponent.getId()); 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 // Check folder has been created within the category created
assertEquals(filePlanComponent.getId(),folder.getParentId()); assertEquals(filePlanComponent.getId(),folder.getParentId());
// Verify the returned properties for the file plan component - record folder // Verify the returned properties for the file plan component - record folder
assertFalse(folder.isCategory()); assertFalse(folder.getIsCategory());
assertFalse(folder.isFile()); assertFalse(folder.getIsFile());
assertTrue(folder.isRecordFolder()); assertTrue(folder.getIsRecordFolder());
assertEquals(folder.getName(), FOLDER_NAME); assertEquals(folder.getName(), FOLDER_NAME);
assertEquals(folder.getNodeType(), RECORD_FOLDER_TYPE.toString()); assertEquals(folder.getNodeType(), RECORD_FOLDER_TYPE.toString());
@@ -138,8 +145,14 @@ public class RecordFolderTests extends BaseRestTest
String componentID = filePlanComponentAPI.getFilePlanComponent(filePlanComponent).getId(); String componentID = filePlanComponentAPI.getFilePlanComponent(filePlanComponent).getId();
// Build the record category properties // Build the record category properties
FilePlanComponent recordFolder = new FilePlanComponent(FOLDER_NAME,RECORD_FOLDER_TYPE.toString(), FilePlanComponent recordFolder = FilePlanComponent.builder()
new FilePlanComponentProperties(FOLDER_TITLE)); .name(FOLDER_NAME)
.nodeType(RECORD_FOLDER_TYPE.toString())
.properties(FilePlanComponentProperties.builder()
.title(FOLDER_TITLE)
.build())
.build();
// Create a record folder // Create a record folder
filePlanComponentAPI.createFilePlanComponent(recordFolder, componentID); filePlanComponentAPI.createFilePlanComponent(recordFolder, componentID);
@@ -168,10 +181,10 @@ public class RecordFolderTests extends BaseRestTest
// Verify the returned properties for the file plan component - record folder // Verify the returned properties for the file plan component - record folder
assertEquals(RECORD_FOLDER_TYPE.toString(),folderDetails.getNodeType()); assertEquals(RECORD_FOLDER_TYPE.toString(),folderDetails.getNodeType());
assertTrue(folderDetails.isRecordFolder()); assertTrue(folderDetails.getIsRecordFolder());
assertFalse(folderDetails.isCategory()); assertFalse(folderDetails.getIsCategory());
assertFalse(folderDetails.isFile()); assertFalse(folderDetails.getIsFile());
assertFalse(folderDetails.isClosed()); assertFalse(folderDetails.getIsClosed());
assertEquals(FOLDER_NAME,folderDetails.getName()); assertEquals(FOLDER_NAME,folderDetails.getName());
assertEquals(dataUser.getAdminUser().getUsername(),folderDetails.getCreatedByUser().getId()); assertEquals(dataUser.getAdminUser().getUsername(),folderDetails.getCreatedByUser().getId());
@@ -210,11 +223,16 @@ public class RecordFolderTests extends BaseRestTest
String location = "Location"+getRandomAlphanumeric(); String location = "Location"+getRandomAlphanumeric();
//Create the file plan component properties to update //Create the file plan component properties to update
FilePlanComponentProperties filePlanComponentProperties = new FilePlanComponentProperties(folderTitle, folderDescription); FilePlanComponent recordFolder = FilePlanComponent.builder()
filePlanComponentProperties.setVitalRecord(true); .name(folderName)
filePlanComponentProperties.setReviewPeriod( new ReviewPeriod("month","1")); .properties(FilePlanComponentProperties.builder()
filePlanComponentProperties.setLocation(location); .title(folderTitle)
FilePlanComponent recordFolder = new FilePlanComponent(folderName,filePlanComponentProperties); .description(folderDescription)
.vitalRecord(true)
.reviewPeriod(new ReviewPeriod("month","1"))
.location(location)
.build())
.build();
// Update the record category // Update the record category
FilePlanComponent folderUpdated = filePlanComponentAPI.updateFilePlanComponent(recordFolder, folder.getId()); FilePlanComponent folderUpdated = filePlanComponentAPI.updateFilePlanComponent(recordFolder, folder.getId());
@@ -226,7 +244,7 @@ public class RecordFolderTests extends BaseRestTest
assertEquals(folderName, folderUpdated.getName()); assertEquals(folderName, folderUpdated.getName());
assertEquals(folderDescription, folderUpdated.getProperties().getDescription()); assertEquals(folderDescription, folderUpdated.getProperties().getDescription());
assertEquals(folderTitle, folderUpdated.getProperties().getTitle()); assertEquals(folderTitle, folderUpdated.getProperties().getTitle());
assertTrue(folderUpdated.getProperties().isVitalRecord()); assertTrue(folderUpdated.getProperties().getVitalRecord());
assertEquals(location, folderUpdated.getProperties().getLocation()); assertEquals(location, folderUpdated.getProperties().getLocation());
assertNotNull(folderUpdated.getProperties().getReviewPeriod().getPeriodType()); assertNotNull(folderUpdated.getProperties().getReviewPeriod().getPeriodType());
assertNotNull(folderUpdated.getProperties().getReviewPeriod().getExpression()); assertNotNull(folderUpdated.getProperties().getReviewPeriod().getExpression());
@@ -324,11 +342,11 @@ public class RecordFolderTests extends BaseRestTest
// Is parent Id set correctly // Is parent Id set correctly
assertEquals(filePlanComponent.getParentId(), category.getId()); assertEquals(filePlanComponent.getParentId(), category.getId());
assertFalse(filePlanComponent.isFile()); assertFalse(filePlanComponent.getIsFile());
// Boolean properties related to node type // Boolean properties related to node type
assertTrue(filePlanComponent.isRecordFolder()); assertTrue(filePlanComponent.getIsRecordFolder());
assertFalse(filePlanComponent.isCategory()); assertFalse(filePlanComponent.getIsCategory());
assertEquals(createdComponent.getName(), filePlanComponent.getName()); assertEquals(createdComponent.getName(), filePlanComponent.getName());
assertEquals(createdComponent.getNodeType(), filePlanComponent.getNodeType()); 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) @AfterClass (alwaysRun = true)
public void tearDown() throws Exception public void tearDown() throws Exception
{ {

View File

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

View File

@@ -95,7 +95,10 @@ public class RMSiteTests extends BaseRestTest
} }
// Create the RM site // 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); RMSite rmSiteResponse = rmSiteAPI.createRMSite(rmSite);
// Verify the status code // Verify the status code
@@ -132,7 +135,10 @@ public class RMSiteTests extends BaseRestTest
String newDescription = RM_DESCRIPTION + "createRMSiteWhenSiteExists"; String newDescription = RM_DESCRIPTION + "createRMSiteWhenSiteExists";
// Create the RM site // 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); rmSiteAPI.createRMSite(rmSite);
// Verify the status code // Verify the status code
@@ -236,7 +242,9 @@ public class RMSiteTests extends BaseRestTest
rmSiteAPI.usingRestWrapper().authenticateUser(userModel); rmSiteAPI.usingRestWrapper().authenticateUser(userModel);
// Create the RM site // 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); rmSite=rmSiteAPI.createRMSite(rmSite);
// Verify the status code // Verify the status code
@@ -325,7 +333,7 @@ public class RMSiteTests extends BaseRestTest
createRMSiteIfNotExists(); createRMSiteIfNotExists();
// Build the RM site properties // Build the RM site properties
RMSite rmSiteToUpdate = new RMSite(DOD5015); RMSite rmSiteToUpdate = RMSite.builder().compliance(DOD5015).build();
// Update the RM site // Update the RM site
rmSiteAPI.updateRMSite(rmSiteToUpdate); 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.final-version-description=The final archived record version
rm.service.enable-autoversion-on-record-creation=Auto Version on Record Creation 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.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> </property>
</bean> </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" /> <property name="nodes" ref="rm.Nodes" />
</bean> </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" /> <property name="nodes" ref="rm.Nodes" />
</bean> </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="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> </bean>
<!-- extended sites bean definition --> <!-- extended sites bean definition -->
@@ -84,6 +89,30 @@
<property name="sites" ref="rm.Sites" /> <property name="sites" ref="rm.Sites" />
</bean> </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 --> <!-- Map RM exceptions to HTML status codes -->
<bean id="rm.simpleMappingExceptionResolver" abstract="true" parent="simpleMappingExceptionResolver"> <bean id="rm.simpleMappingExceptionResolver" abstract="true" parent="simpleMappingExceptionResolver">
<property name="exceptionMappings"> <property name="exceptionMappings">

View File

@@ -25,6 +25,7 @@
<alfresco.rm.artifactId>alfresco-rm-community-repo</alfresco.rm.artifactId> <alfresco.rm.artifactId>alfresco-rm-community-repo</alfresco.rm.artifactId>
<skip.integrationtests>true</skip.integrationtests> <skip.integrationtests>true</skip.integrationtests>
<alfresco.solr.home>${project.build.directory}/solr/home</alfresco.solr.home> <alfresco.solr.home>${project.build.directory}/solr/home</alfresco.solr.home>
<api.explorer.version>1.4</api.explorer.version>
</properties> </properties>
<build> <build>
@@ -532,11 +533,19 @@
<contextPath>/solr4</contextPath> <contextPath>/solr4</contextPath>
<contextFile>${alfresco.solr.home}/context.xml</contextFile> <contextFile>${alfresco.solr.home}/context.xml</contextFile>
</webapp> </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> <webapp>
<groupId>org.alfresco</groupId> <groupId>org.alfresco</groupId>
<artifactId>alfresco-rm-community-rest-api-explorer</artifactId> <artifactId>alfresco-rm-community-rest-api-explorer</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<contextPath>/api-explorer</contextPath> <contextPath>/ig-api-explorer</contextPath>
<type>war</type> <type>war</type>
<asWebapp>true</asWebapp> <asWebapp>true</asWebapp>
</webapp> </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.model.behaviour.AbstractDisposableItem;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService; import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.security.ExtendedSecurityService; 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.CopyBehaviourCallback;
import org.alfresco.repo.copy.CopyDetails; import org.alfresco.repo.copy.CopyDetails;
import org.alfresco.repo.copy.CopyServicePolicies; import org.alfresco.repo.copy.CopyServicePolicies;
import org.alfresco.repo.copy.DefaultCopyBehaviourCallback; import org.alfresco.repo.copy.DefaultCopyBehaviourCallback;
import org.alfresco.repo.node.NodeServicePolicies; 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.Behaviour.NotificationFrequency;
import org.alfresco.repo.policy.annotation.Behaviour; import org.alfresco.repo.policy.annotation.Behaviour;
import org.alfresco.repo.policy.annotation.BehaviourBean; import org.alfresco.repo.policy.annotation.BehaviourBean;
import org.alfresco.repo.policy.annotation.BehaviourKind; import org.alfresco.repo.policy.annotation.BehaviourKind;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.cmr.repository.ChildAssociationRef; 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.NodeRef;
import org.alfresco.service.cmr.repository.ScriptService; import org.alfresco.service.cmr.repository.ScriptService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.springframework.extensions.surf.util.I18NUtil;
/** /**
* rma:record behaviour bean * rma:record behaviour bean
@@ -67,7 +71,8 @@ public class RecordAspect extends AbstractDisposableItem
RecordsManagementPolicies.OnCreateReference, RecordsManagementPolicies.OnCreateReference,
RecordsManagementPolicies.OnRemoveReference, RecordsManagementPolicies.OnRemoveReference,
NodeServicePolicies.OnMoveNodePolicy, NodeServicePolicies.OnMoveNodePolicy,
CopyServicePolicies.OnCopyCompletePolicy CopyServicePolicies.OnCopyCompletePolicy,
ContentServicePolicies.OnContentPropertyUpdatePolicy
{ {
/** Well-known location of the scripts folder. */ /** Well-known location of the scripts folder. */
// TODO make configurable // TODO make configurable
@@ -82,6 +87,9 @@ public class RecordAspect extends AbstractDisposableItem
/** record service */ /** record service */
protected RecordService recordService; protected RecordService recordService;
/** I18N */
private static final String MSG_CANNOT_UPDATE_RECORD_CONTENT = "rm.service.update-record-content";
/** /**
* @param extendedSecurityService extended security service * @param extendedSecurityService extended security service
*/ */
@@ -336,4 +344,19 @@ public class RecordAspect extends AbstractDisposableItem
extendedSecurityService.remove(targetNodeRef); 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; package org.alfresco.rm.rest.api;
import org.alfresco.rest.api.Nodes; import org.alfresco.rest.api.Nodes;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
/** /**
* RM Nodes API * 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_HAS_RETENTION_SCHEDULE = "hasRetentionSchedule";
public static String PARAM_INCLUDE_IS_CLOSED = "isClosed"; public static String PARAM_INCLUDE_IS_CLOSED = "isClosed";
public static String PARAM_INCLUDE_IS_COMPLETED = "isCompleted"; 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% * #L%
*/ */
package org.alfresco.rm.rest.api.nodes; package org.alfresco.rm.rest.api.fileplancomponents;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@@ -25,7 +25,7 @@
* #L% * #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.api.model.Node;
import org.alfresco.rest.framework.WebApiDescription; 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 * @author Ana Bozianu
* @since 2.6 * @since 2.6
*/ */
@WebApi(name="ig", scope=Api.SCOPE.PUBLIC, version=1) @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.Api;
import org.alfresco.rest.framework.WebApi; 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) 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 // 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); nodeInfo.setRelativePath(null);
return super.createNode(parentNodeRef.getId(), nodeInfo, parameters); return super.createNode(parentNodeRef.getId(), nodeInfo, parameters);
} }
/** @Override
* Gets or creates the relative path specified in nodeInfo.relativePath public NodeRef getOrCreatePath(String parentFolderNodeId, String relativePath, QName nodeTypeQName)
* 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)
{ {
NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId, null); NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId, null);
String relativePath = nodeInfo.getRelativePath();
if (relativePath == null) if (relativePath == null)
{ {
return parentNodeRef; return parentNodeRef;
@@ -413,14 +418,6 @@ public class RMNodesImpl extends NodesImpl implements RMNodes
} }
else 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 /* 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 * 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% * #L%
*/ */
package org.alfresco.rm.rest.api.nodes; package org.alfresco.rm.rest.api.records;
import java.io.InputStream;
import org.alfresco.rest.api.model.Node; import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.framework.BinaryProperties; import org.alfresco.rest.framework.BinaryProperties;
import org.alfresco.rest.framework.Operation;
import org.alfresco.rest.framework.WebApiDescription; import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException; import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.resource.EntityResource; import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.actions.interfaces.BinaryResourceAction; 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.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.Parameters; 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.RMNodes;
import org.alfresco.rm.rest.api.Records;
import org.alfresco.rm.rest.api.model.TargetContainer;
import org.alfresco.util.ParameterCheck; import org.alfresco.util.ParameterCheck;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
@@ -49,22 +50,21 @@ import org.springframework.beans.factory.InitializingBean;
* @since 2.6 * @since 2.6
*/ */
@EntityResource(name="records", title = "Records") @EntityResource(name="records", title = "Records")
public class RecordsEntityResource implements BinaryResourceAction.Update<Node>, public class RecordsEntityResource implements BinaryResourceAction.Read,
BinaryResourceAction.Read,
InitializingBean InitializingBean
{ {
private RMNodes nodes; private RMNodes nodes;
private Records records;
public void setNodes(RMNodes nodes) public void setNodes(RMNodes nodes)
{ {
this.nodes = nodes; this.nodes = nodes;
} }
@Override public void setRecords(Records records)
public void afterPropertiesSet() throws Exception
{ {
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); return nodes.getContent(recordId, parameters, true);
} }
/** @Operation("file")
* Upload new version of content @WebApiDescription(title = "File record", description="File a record into fileplan.")
* public Node fileRecord(String recordId, TargetContainer target, Parameters parameters, WithResponse withResponse)
* 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)
{ {
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% * #L%
*/ */
package org.alfresco.rm.rest.api.nodes; package org.alfresco.rm.rest.api.fileplancomponents;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;

View File

@@ -25,7 +25,7 @@
* #L% * #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.assertEquals;
import static org.junit.Assert.fail; 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 * When trying to create a node in the parent node with no relative path
*/ */
Node nodeInfo = mock(Node.class); Node nodeInfo = mock(Node.class);
when(nodeInfo.getRelativePath()).thenReturn(null); NodeRef returnedPath = rmNodesImpl.getOrCreatePath(parentNode.getId(), null, ContentModel.TYPE_CONTENT);
NodeRef returnedPath = rmNodesImpl.getOrCreatePath(parentNode.getId(), nodeInfo);
/* /*
* Then the parent node is returned and no node is created * 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 * When trying to create a node in the parent node with the relative path c1/f1
*/ */
Node nodeInfo = mock(Node.class); Node nodeInfo = mock(Node.class);
when(nodeInfo.getRelativePath()).thenReturn(category + "/" + recordFolder); NodeRef returnedPath = rmNodesImpl.getOrCreatePath(parentNode.getId(), category + "/" + recordFolder, ContentModel.TYPE_CONTENT);
NodeRef returnedPath = rmNodesImpl.getOrCreatePath(parentNode.getId(), nodeInfo);
/* /*
* Then the node f1 is returned and no node is created * 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 * 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 // c3
String category3 = "c3"; String category3 = "c3";
NodeRef categoryNode3 = AlfMock.generateNodeRef(mockedNodeService); 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); when(mockedFileFolderService.create(categoryNode3, recordFolder, RecordsManagementModel.TYPE_RECORD_FOLDER)).thenReturn(recordFolderFileInfo);
// call the class under tests // call the class under tests
when(nodeInfo.getRelativePath()).thenReturn(category1 + "/" + category2 + "/" + category3 + "/" + recordFolder); NodeRef returnedPath = rmNodesImpl.getOrCreatePath(fileplanNodeRef.getId(), category1 + "/" + category2 + "/" + category3 + "/" + recordFolder, ContentModel.TYPE_CONTENT);
NodeRef returnedPath = rmNodesImpl.getOrCreatePath(fileplanNodeRef.getId(), nodeInfo);
/* /*
* Then the category c1 and the record folder f1 should be created and f1 should be returned * 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); when(mockedFileFolderService.create(folderNode2, folder3, RecordsManagementModel.TYPE_UNFILED_RECORD_FOLDER)).thenReturn(folderFileInfo3);
// call the class under tests // call the class under tests
Node nodeInfo = mock(Node.class); NodeRef returnedParentNode = rmNodesImpl.getOrCreatePath(unfiledRecordContainer.getId(), folder1 + "/" + folder2 + "/" + folder3, ContentModel.TYPE_CONTENT);
when(nodeInfo.getRelativePath()).thenReturn(folder1 + "/" + folder2 + "/" + folder3);
NodeRef returnedParentNode = rmNodesImpl.getOrCreatePath(unfiledRecordContainer.getId(), nodeInfo);
/* /*
* Then the category c1 and the record folder rf1 should be created * 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 * 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 // c1
String category1 = "c1"; String category1 = "c1";
NodeRef categoryNode1 = AlfMock.generateNodeRef(mockedNodeService); NodeRef categoryNode1 = AlfMock.generateNodeRef(mockedNodeService);
@@ -286,8 +275,7 @@ public class RMNodesImplRelativePathUnitTest extends BaseUnitTest
when(mockedFilePlanService.createRecordCategory(categoryNode2, category3)).thenReturn(categoryNode3); when(mockedFilePlanService.createRecordCategory(categoryNode2, category3)).thenReturn(categoryNode3);
// call the class under tests // call the class under tests
when(nodeInfo.getRelativePath()).thenReturn(category1 + "/" + category2 + "/" + category3); NodeRef returnedParentNode = rmNodesImpl.getOrCreatePath(fileplanNodeRef.getId(), category1 + "/" + category2 + "/" + category3, RecordsManagementModel.TYPE_RECORD_FOLDER);
NodeRef returnedParentNode = rmNodesImpl.getOrCreatePath(fileplanNodeRef.getId(), nodeInfo);
/* /*
* Then the categories c1, c2 and c3 should be created and c3 should be returned * Then the categories c1, c2 and c3 should be created and c3 should be returned

View File

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

View File

@@ -21,6 +21,8 @@ tags:
description: Retrieve and manage the RM site description: Retrieve and manage the RM site
- name: records - name: records
description: Perform record specific operations description: Perform record specific operations
- name: files
description: Perform operations on non-record files
paths: paths:
'/fileplan-components/{fileplanComponentId}': '/fileplan-components/{fileplanComponentId}':
get: get:
@@ -377,7 +379,10 @@ paths:
- $ref: '#/parameters/fieldsParam' - $ref: '#/parameters/fieldsParam'
- in: body - in: body
name: nodeBodyCreate 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 required: true
schema: schema:
$ref: '#/definitions/RMNodeBodyCreate' $ref: '#/definitions/RMNodeBodyCreate'
@@ -564,7 +569,6 @@ paths:
$ref: '#/definitions/Error' $ref: '#/definitions/Error'
'/records/{recordId}/content': '/records/{recordId}/content':
get: get:
x-alfresco-since: "5.2"
tags: tags:
- records - records
summary: Get record content 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 description: Content has not been modified since the date provided in the If-Modified-Since header
'400': '400':
description: | 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': '401':
description: Authentication failed description: Authentication failed
'404': '404':
description: | description: |
**nodeId** does not exist **recordId** does not exist
default: default:
description: Unexpected error description: Unexpected error
schema: schema:
$ref: '#/definitions/Error' $ref: '#/definitions/Error'
put: '/records/{recordId}/file':
x-alfresco-since: "5.2" post:
tags: tags:
- records - records
summary: Update record content summary: File a record
description: | 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, The **relativePath** specifies the container structure relative to the node **targetParentId**.
a new minor version is created by default. 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 If the record is already filed, a link to the target record folder is created.
will rename the node. If invalid then an error is returned and the content is not updated. operationId: fileRecord
**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
parameters: parameters:
- $ref: '#/parameters/recordIdParam' - $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/IGNodeEntryIncludeParam'
- $ref: '#/parameters/fieldsParam' - $ref: '#/parameters/fieldsParam'
- in: body - in: body
name: contentBodyUpdate name: nodeBodyFile
description: The binary content description: The target record folder id
required: true required: true
schema: schema:
type: string $ref: '#/definitions/RequestBodyFile'
format: binary consumes:
- application/json
produces: produces:
- application/json - application/json
consumes:
- application/octet-stream
responses: responses:
'200': '200':
description: Successful response description: Successful response
@@ -659,22 +636,64 @@ paths:
$ref: '#/definitions/IGNodeEntry' $ref: '#/definitions/IGNodeEntry'
'400': '400':
description: | 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': '401':
description: Authentication failed description: Authentication failed
'403': '403':
description: Current user does not have permission to update **recordId** description: Current user does not have permission to create children of **nodeId**
'404': '404':
description: | description: |
**recordId** does not exist **recordIdParam** or **targetParentId** 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)
'422': '422':
description: Model integrity exception including a file name containing invalid characters description: |
'507': Model integrity exception: the action breaks system's integrity restrictions
description: Content exceeds overall storage quota limit configured for the network/system 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: default:
description: Unexpected error description: Unexpected error
schema: schema:
@@ -958,6 +977,13 @@ definitions:
type: object type: object
additionalProperties: additionalProperties:
type: string type: string
RequestBodyFile:
type: object
properties:
targetParentId:
type: string
relativePath:
type: string
## Core definition ## Core definition
ChildAssociationInfo: ChildAssociationInfo:
type: object type: object

View File

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