mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
Merged HEAD (5.2) to 5.2.N (5.2.1)
126525 jkaabimofrad: Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2) 123064 jvonka: Nodes (FileFolder) API - WIP create or update (versionable) content with optional majorVersion &/or comment - via query params for PUT - via form-data fields for POST (when overwrite field is true) - return updated "cm:versionLabel" - TODO tests + api def (hence WIP) RA-690, RA-637, RA-640 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@126869 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -466,6 +466,7 @@
|
|||||||
<property name="serviceRegistry" ref="ServiceRegistry"/>
|
<property name="serviceRegistry" ref="ServiceRegistry"/>
|
||||||
<property name="repositoryHelper" ref="repositoryHelper"/>
|
<property name="repositoryHelper" ref="repositoryHelper"/>
|
||||||
<property name="quickShareLinks" ref="QuickShareLinks"/>
|
<property name="quickShareLinks" ref="QuickShareLinks"/>
|
||||||
|
<property name="behaviourFilter" ref="policyBehaviourFilter"/>
|
||||||
<property name="ignoreTypes" ref="nodes.ignoreTypes"/>
|
<property name="ignoreTypes" ref="nodes.ignoreTypes"/>
|
||||||
<property name="nonAttachContentTypes" ref="nodes.nonAttachContentTypes"/>
|
<property name="nonAttachContentTypes" ref="nodes.nonAttachContentTypes"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
@@ -215,4 +215,7 @@ public interface Nodes
|
|||||||
String PARAM_MIMETYPE = "mimeType";
|
String PARAM_MIMETYPE = "mimeType";
|
||||||
String PARAM_SIZEINBYTES = "sizeInBytes";
|
String PARAM_SIZEINBYTES = "sizeInBytes";
|
||||||
String PARAM_NODETYPE = "nodeType";
|
String PARAM_NODETYPE = "nodeType";
|
||||||
|
|
||||||
|
String PARAM_VERSION_MAJOR = "majorVersion"; // true if major, false if minor
|
||||||
|
String PARAM_VERSION_COMMENT = "comment";
|
||||||
}
|
}
|
||||||
|
@@ -36,6 +36,7 @@ import java.util.Collections;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -45,12 +46,15 @@ import org.alfresco.model.ContentModel;
|
|||||||
import org.alfresco.model.QuickShareModel;
|
import org.alfresco.model.QuickShareModel;
|
||||||
import org.alfresco.query.PagingRequest;
|
import org.alfresco.query.PagingRequest;
|
||||||
import org.alfresco.query.PagingResults;
|
import org.alfresco.query.PagingResults;
|
||||||
|
import org.alfresco.repo.action.executer.ContentMetadataExtracter;
|
||||||
import org.alfresco.repo.content.ContentLimitViolationException;
|
import org.alfresco.repo.content.ContentLimitViolationException;
|
||||||
import org.alfresco.repo.model.Repository;
|
import org.alfresco.repo.model.Repository;
|
||||||
import org.alfresco.repo.model.filefolder.FileFolderServiceImpl;
|
import org.alfresco.repo.model.filefolder.FileFolderServiceImpl;
|
||||||
import org.alfresco.repo.node.getchildren.GetChildrenCannedQuery;
|
import org.alfresco.repo.node.getchildren.GetChildrenCannedQuery;
|
||||||
|
import org.alfresco.repo.policy.BehaviourFilter;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||||
|
import org.alfresco.repo.version.VersionModel;
|
||||||
import org.alfresco.rest.antlr.WhereClauseParser;
|
import org.alfresco.rest.antlr.WhereClauseParser;
|
||||||
import org.alfresco.rest.api.Nodes;
|
import org.alfresco.rest.api.Nodes;
|
||||||
import org.alfresco.rest.api.QuickShareLinks;
|
import org.alfresco.rest.api.QuickShareLinks;
|
||||||
@@ -71,6 +75,7 @@ import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
|
|||||||
import org.alfresco.rest.framework.core.exceptions.RequestEntityTooLargeException;
|
import org.alfresco.rest.framework.core.exceptions.RequestEntityTooLargeException;
|
||||||
import org.alfresco.rest.framework.resource.content.BasicContentInfo;
|
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.content.ContentInfoImpl;
|
||||||
import org.alfresco.rest.framework.resource.content.NodeBinaryResource;
|
import org.alfresco.rest.framework.resource.content.NodeBinaryResource;
|
||||||
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
|
||||||
import org.alfresco.rest.framework.resource.parameters.Paging;
|
import org.alfresco.rest.framework.resource.parameters.Paging;
|
||||||
@@ -111,6 +116,7 @@ import org.alfresco.service.cmr.security.PermissionService;
|
|||||||
import org.alfresco.service.cmr.security.PersonService;
|
import org.alfresco.service.cmr.security.PersonService;
|
||||||
import org.alfresco.service.cmr.usage.ContentQuotaException;
|
import org.alfresco.service.cmr.usage.ContentQuotaException;
|
||||||
import org.alfresco.service.cmr.version.VersionService;
|
import org.alfresco.service.cmr.version.VersionService;
|
||||||
|
import org.alfresco.service.cmr.version.VersionType;
|
||||||
import org.alfresco.service.namespace.NamespaceService;
|
import org.alfresco.service.namespace.NamespaceService;
|
||||||
import org.alfresco.service.namespace.QName;
|
import org.alfresco.service.namespace.QName;
|
||||||
import org.alfresco.util.Pair;
|
import org.alfresco.util.Pair;
|
||||||
@@ -127,7 +133,9 @@ import org.springframework.http.MediaType;
|
|||||||
*
|
*
|
||||||
* Note:
|
* Note:
|
||||||
* This class was originally used for returning some basic node info when listing Favourites.
|
* This class was originally used for returning some basic node info when listing Favourites.
|
||||||
* It has now been re-purposed and extended to implement the new File Folder (RESTful) API.
|
*
|
||||||
|
* It has now been re-purposed and extended to implement the new Nodes (RESTful) API for
|
||||||
|
* managing files & folders, as well as custom node types.
|
||||||
*
|
*
|
||||||
* @author steveglover
|
* @author steveglover
|
||||||
* @author janv
|
* @author janv
|
||||||
@@ -158,6 +166,8 @@ public class NodesImpl implements Nodes
|
|||||||
private OwnableService ownableService;
|
private OwnableService ownableService;
|
||||||
private AuthorityService authorityService;
|
private AuthorityService authorityService;
|
||||||
|
|
||||||
|
private BehaviourFilter behaviourFilter;
|
||||||
|
|
||||||
// note: circular - Nodes/QuickShareLinks currently use each other (albeit for different methods)
|
// note: circular - Nodes/QuickShareLinks currently use each other (albeit for different methods)
|
||||||
private QuickShareLinks quickShareLinks;
|
private QuickShareLinks quickShareLinks;
|
||||||
|
|
||||||
@@ -205,6 +215,11 @@ public class NodesImpl implements Nodes
|
|||||||
this.sr = sr;
|
this.sr = sr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBehaviourFilter(BehaviourFilter behaviourFilter)
|
||||||
|
{
|
||||||
|
this.behaviourFilter = behaviourFilter;
|
||||||
|
}
|
||||||
|
|
||||||
public void setRepositoryHelper(Repository repositoryHelper)
|
public void setRepositoryHelper(Repository repositoryHelper)
|
||||||
{
|
{
|
||||||
this.repositoryHelper = repositoryHelper;
|
this.repositoryHelper = repositoryHelper;
|
||||||
@@ -1564,11 +1579,69 @@ public class NodesImpl implements Nodes
|
|||||||
throw new InvalidArgumentException("NodeId of content is expected: " + nodeRef.getId());
|
throw new InvalidArgumentException("NodeId of content is expected: " + nodeRef.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Boolean versionMajor = null;
|
||||||
|
String str = parameters.getParameter(PARAM_VERSION_MAJOR);
|
||||||
|
if (str != null)
|
||||||
|
{
|
||||||
|
versionMajor = new Boolean(str);
|
||||||
|
}
|
||||||
|
String versionComment = parameters.getParameter(PARAM_VERSION_COMMENT);
|
||||||
|
|
||||||
|
return updateExistingFile(nodeRef, contentInfo, stream, parameters, versionMajor, versionComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node updateExistingFile(NodeRef nodeRef, BasicContentInfo contentInfo, InputStream stream, Parameters parameters, Boolean versionMajor, String versionComment)
|
||||||
|
{
|
||||||
|
boolean isVersioned = versionService.isVersioned(nodeRef);
|
||||||
|
|
||||||
|
behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
writeContent(nodeRef, contentInfo, stream);
|
||||||
|
|
||||||
|
if ((isVersioned) || (versionMajor != null) || (versionComment != null) )
|
||||||
|
{
|
||||||
|
VersionType versionType = VersionType.MINOR;
|
||||||
|
if ((versionMajor != null) && (versionMajor == true))
|
||||||
|
{
|
||||||
|
versionType = VersionType.MAJOR;
|
||||||
|
}
|
||||||
|
createVersion(nodeRef, isVersioned, versionType, versionComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
extractMetadata(nodeRef);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
behaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return getFolderOrDocumentFullInfo(nodeRef, null, null, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeContent(NodeRef nodeRef, BasicContentInfo contentInfo, InputStream stream)
|
||||||
|
{
|
||||||
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
|
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
|
||||||
setWriterContentType(writer, new ContentInfoWrapper(contentInfo), nodeRef, true);
|
setWriterContentType(writer, new ContentInfoWrapper(contentInfo), nodeRef, true);
|
||||||
writer.putContent(stream);
|
writer.putContent(stream);
|
||||||
|
}
|
||||||
|
|
||||||
return getFolderOrDocumentFullInfo(nodeRef, null, null, parameters);
|
protected void createVersion(NodeRef nodeRef, boolean isVersioned, VersionType versionType, String reason)
|
||||||
|
{
|
||||||
|
if (! isVersioned)
|
||||||
|
{
|
||||||
|
// Ensure the file is versionable (autoVersion = true, autoVersionProps = false)
|
||||||
|
ensureVersioningEnabled(nodeRef, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Serializable> versionProperties = new HashMap<>(2);
|
||||||
|
versionProperties.put(VersionModel.PROP_VERSION_TYPE, versionType);
|
||||||
|
if (reason != null)
|
||||||
|
{
|
||||||
|
versionProperties.put(VersionModel.PROP_DESCRIPTION, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
versionService.createVersion(nodeRef, versionProperties);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setWriterContentType(ContentWriter writer, ContentInfoWrapper contentInfo, NodeRef nodeRef, boolean guessEncodingIfNull)
|
private void setWriterContentType(ContentWriter writer, ContentInfoWrapper contentInfo, NodeRef nodeRef, boolean guessEncodingIfNull)
|
||||||
@@ -1598,6 +1671,7 @@ public class NodesImpl implements Nodes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Node upload(String parentFolderNodeId, FormData formData, Parameters parameters)
|
public Node upload(String parentFolderNodeId, FormData formData, Parameters parameters)
|
||||||
{
|
{
|
||||||
@@ -1618,6 +1692,8 @@ public class NodesImpl implements Nodes
|
|||||||
boolean autoRename = false;
|
boolean autoRename = false;
|
||||||
QName nodeTypeQName = null;
|
QName nodeTypeQName = null;
|
||||||
boolean overwrite = false; // If a fileName clashes for a versionable file
|
boolean overwrite = false; // If a fileName clashes for a versionable file
|
||||||
|
Boolean majorVersion = null;
|
||||||
|
String versionComment = null;
|
||||||
Map<String, Object> qnameStrProps = new HashMap<>();
|
Map<String, Object> qnameStrProps = new HashMap<>();
|
||||||
Map<QName, Serializable> properties = null;
|
Map<QName, Serializable> properties = null;
|
||||||
|
|
||||||
@@ -1649,9 +1725,17 @@ public class NodesImpl implements Nodes
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// case "overwrite":
|
case "overwrite":
|
||||||
// overwrite = Boolean.valueOf(field.getValue());
|
overwrite = Boolean.valueOf(field.getValue());
|
||||||
// break;
|
break;
|
||||||
|
|
||||||
|
case "majorversion":
|
||||||
|
majorVersion = Boolean.valueOf(field.getValue());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "comment":
|
||||||
|
versionComment = getStringOrNull(field.getValue());
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
@@ -1691,28 +1775,23 @@ public class NodesImpl implements Nodes
|
|||||||
NodeRef existingFile = nodeService.getChildByName(parentNodeRef, ContentModel.ASSOC_CONTAINS, fileName);
|
NodeRef existingFile = nodeService.getChildByName(parentNodeRef, ContentModel.ASSOC_CONTAINS, fileName);
|
||||||
if (existingFile != null)
|
if (existingFile != null)
|
||||||
{
|
{
|
||||||
|
// TODO throw 400 error if both autoRename and overwrite are true ?
|
||||||
|
|
||||||
// File already exists, decide what to do
|
// File already exists, decide what to do
|
||||||
if (autoRename)
|
if (autoRename)
|
||||||
{
|
{
|
||||||
|
// attempt to find a unique name
|
||||||
fileName = findUniqueName(parentNodeRef, fileName);
|
fileName = findUniqueName(parentNodeRef, fileName);
|
||||||
}
|
}
|
||||||
// TODO uncomment when we decide on uploading a new version vs overwriting
|
else if (overwrite && nodeService.hasAspect(existingFile, ContentModel.ASPECT_VERSIONABLE))
|
||||||
// else if (overwrite && nodeService.hasAspect(existingFile, ContentModel.ASPECT_VERSIONABLE))
|
{
|
||||||
// {
|
// overwrite existing (versionable) file
|
||||||
// // Upload component was configured to overwrite files if name clashes
|
BasicContentInfo contentInfo = new ContentInfoImpl(content.getMimetype(), content.getEncoding(), -1, null);
|
||||||
// write(existingFile, content);
|
return updateExistingFile(existingFile, contentInfo, content.getInputStream(), parameters, majorVersion, versionComment);
|
||||||
//
|
}
|
||||||
// // Extract the metadata (The overwrite policy controls
|
|
||||||
// // which if any parts of the document's properties are updated from this)
|
|
||||||
// extractMetadata(existingFile);
|
|
||||||
//
|
|
||||||
// // Do not clean formData temp files to
|
|
||||||
// // allow for retries. Temp files will be deleted later
|
|
||||||
// // when GC call DiskFileItem#finalize() method or by temp file cleaner.
|
|
||||||
// return createUploadResponse(parentNodeRef, existingFile);
|
|
||||||
// }
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// name clash (and no autoRename or overwrite)
|
||||||
throw new ConstraintViolatedException(fileName + " already exists.");
|
throw new ConstraintViolatedException(fileName + " already exists.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1821,10 +1900,12 @@ public class NodesImpl implements Nodes
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the given node metadata asynchronously.
|
* Extracts the given node metadata asynchronously.
|
||||||
|
*
|
||||||
|
* The overwrite policy controls which if any parts of the document's properties are updated from this.
|
||||||
*/
|
*/
|
||||||
private void extractMetadata(NodeRef nodeRef)
|
private void extractMetadata(NodeRef nodeRef)
|
||||||
{
|
{
|
||||||
final String actionName = "extract-metadata";
|
final String actionName = ContentMetadataExtracter.EXECUTOR_NAME;
|
||||||
ActionDefinition actionDef = actionService.getActionDefinition(actionName);
|
ActionDefinition actionDef = actionService.getActionDefinition(actionName);
|
||||||
if (actionDef != null)
|
if (actionDef != null)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user