Merged FILE-FOLDER-API (5.2.0) to HEAD (5.2)

118825 jkaabimofrad: RA-655: manual merge of SFS module to FILE-FOLDER-API.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@126351 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jamal Kaabi-Mofrad
2016-05-10 10:27:38 +00:00
parent 09eac586f6
commit d8eb979be3
11 changed files with 1803 additions and 931 deletions

View File

@@ -428,10 +428,23 @@
</list>
</property>
</bean>
<bean id="nodes" class="org.alfresco.rest.api.impl.NodesImpl">
<bean id="nodes.ignoreTypes" class="org.springframework.beans.factory.config.SetFactoryBean">
<property name="sourceSet">
<set>
<value>cm:systemfolder</value>
<value>fm:forums</value>
<value>fm:forum</value>
<value>fm:topic</value>
<value>fm:post</value>
</set>
</property>
</bean>
<bean id="nodes" class="org.alfresco.rest.api.impl.NodesImpl" init-method="init">
<property name="serviceRegistry" ref="ServiceRegistry"/>
<property name="repositoryHelper" ref="repositoryHelper"/>
<property name="ignoreTypes" ref="nodes.ignoreTypes"/>
</bean>
<bean id="Nodes" class="org.springframework.aop.framework.ProxyFactoryBean">

View File

@@ -29,6 +29,7 @@ import org.alfresco.rest.api.model.Document;
import org.alfresco.rest.api.model.Folder;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.PathInfo;
import org.alfresco.rest.api.model.PathInfo.ElementInfo;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.content.BasicContentInfo;
@@ -46,11 +47,14 @@ import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.Path;
import org.alfresco.service.cmr.repository.Path.Element;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
@@ -69,6 +73,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
@@ -76,6 +81,7 @@ import java.util.Set;
*
* @author steveglover
* @author janv
* @author Jamal Kaabi-Mofrad
*
* @since publicapi1.0
*/
@@ -83,21 +89,35 @@ public class NodesImpl implements Nodes
{
private static enum Type
{
// Note: ordered
DOCUMENT, FOLDER;
// Note: ordered
DOCUMENT, FOLDER;
};
private final static String PATH_ROOT = "-root-";
private final static String PATH_MY = "-my-";
private final static String PATH_SHARED = "-shared-";
private NodeService nodeService;
private NodeService nodeService;
private DictionaryService dictionaryService;
private FileFolderService fileFolderService;
private NamespaceService namespaceService;
private PermissionService permissionService;
private Repository repositoryHelper;
private ServiceRegistry sr;
private Set<String> defaultIgnoreTypes;
private Set<QName> ignoreTypeQNames;
public void init()
{
if (defaultIgnoreTypes != null)
{
ignoreTypeQNames = new HashSet<>(defaultIgnoreTypes.size());
for (String type : defaultIgnoreTypes)
{
ignoreTypeQNames.add(createQName(type));
}
}
}
public void setServiceRegistry(ServiceRegistry sr) {
this.sr = sr;
@@ -114,6 +134,11 @@ public class NodesImpl implements Nodes
this.repositoryHelper = repositoryHelper;
}
public void setIgnoreTypes(Set<String> ignoreTypes)
{
this.defaultIgnoreTypes = ignoreTypes;
}
private static final List<QName> EXCLUDED_ASPECTS = Arrays.asList(
ContentModel.ASPECT_REFERENCEABLE,
ContentModel.ASPECT_LOCALIZED);
@@ -169,47 +194,46 @@ public class NodesImpl implements Nodes
new HashSet<>(Arrays.asList(new String[] {PARAM_ISFOLDER}));
/*
*
* Note: assumes workspace://SpacesStore
*/
public NodeRef validateNode(String nodeId)
{
return validateNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId);
}
public NodeRef validateNode(StoreRef storeRef, String nodeId)
{
String versionLabel = null;
int idx = nodeId.indexOf(";");
if(idx != -1)
{
versionLabel = nodeId.substring(idx + 1);
nodeId = nodeId.substring(0, idx);
if(versionLabel.equals("pwc"))
{
// TODO correct exception?
throw new EntityNotFoundException(nodeId);
}
}
NodeRef nodeRef = new NodeRef(storeRef, nodeId);
return validateNode(nodeRef);
}
public NodeRef validateNode(NodeRef nodeRef)
{
if (! nodeService.exists(nodeRef))
{
throw new EntityNotFoundException(nodeRef.getId());
}
return nodeRef;
}
public boolean nodeMatches(NodeRef nodeRef, Set<QName> expectedTypes, Set<QName> excludedTypes)
* Note: assumes workspace://SpacesStore
*/
public NodeRef validateNode(String nodeId)
{
if (! nodeService.exists(nodeRef))
return validateNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, nodeId);
}
public NodeRef validateNode(StoreRef storeRef, String nodeId)
{
String versionLabel = null;
int idx = nodeId.indexOf(";");
if (idx != -1)
{
versionLabel = nodeId.substring(idx + 1);
nodeId = nodeId.substring(0, idx);
if (versionLabel.equals("pwc"))
{
// TODO correct exception?
throw new EntityNotFoundException(nodeId);
}
}
NodeRef nodeRef = new NodeRef(storeRef, nodeId);
return validateNode(nodeRef);
}
public NodeRef validateNode(NodeRef nodeRef)
{
if (!nodeService.exists(nodeRef))
{
throw new EntityNotFoundException(nodeRef.getId());
}
return nodeRef;
}
public boolean nodeMatches(NodeRef nodeRef, Set<QName> expectedTypes, Set<QName> excludedTypes)
{
if (!nodeService.exists(nodeRef))
{
throw new EntityNotFoundException(nodeRef.getId());
}
@@ -219,35 +243,35 @@ public class NodesImpl implements Nodes
protected boolean typeMatches(QName type, Set<QName> expectedTypes, Set<QName> excludedTypes)
{
Set<QName> allExpectedTypes = new HashSet<>();
if (expectedTypes != null)
{
for (QName expectedType : expectedTypes)
{
allExpectedTypes.addAll(dictionaryService.getSubTypes(expectedType, true));
}
}
Set<QName> allExpectedTypes = new HashSet<>();
if (expectedTypes != null)
{
for (QName expectedType : expectedTypes)
{
allExpectedTypes.addAll(dictionaryService.getSubTypes(expectedType, true));
}
}
Set<QName> allExcludedTypes = new HashSet<>();
if (excludedTypes != null)
{
for (QName excludedType : excludedTypes)
{
allExcludedTypes.addAll(dictionaryService.getSubTypes(excludedType, true));
}
}
Set<QName> allExcludedTypes = new HashSet<>();
if (excludedTypes != null)
{
for (QName excludedType : excludedTypes)
{
allExcludedTypes.addAll(dictionaryService.getSubTypes(excludedType, true));
}
}
boolean inExpected = allExpectedTypes.contains(type);
boolean excluded = allExcludedTypes.contains(type);
return(inExpected && !excluded);
}
boolean inExpected = allExpectedTypes.contains(type);
boolean excluded = allExcludedTypes.contains(type);
return (inExpected && !excluded);
}
/**
* @deprecated review usage (backward compat')
*/
public Node getNode(String nodeId)
{
NodeRef nodeRef = validateNode(nodeId);
NodeRef nodeRef = validateNode(nodeId);
return new Node(nodeRef, null, nodeService.getProperties(nodeRef), sr);
}
@@ -259,17 +283,17 @@ public class NodesImpl implements Nodes
{
return new Node(nodeRef, null, nodeService.getProperties(nodeRef), sr);
}
private Type getType(NodeRef nodeRef)
{
return getType(nodeService.getType(nodeRef));
}
private Type getType(QName type)
{
boolean isContainer = Boolean.valueOf((dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true &&
!dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER)));
return isContainer ? Type.FOLDER : Type.DOCUMENT;
boolean isContainer = Boolean.valueOf((dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true
&& !dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER)));
return isContainer ? Type.FOLDER : Type.DOCUMENT;
}
/**
@@ -277,14 +301,14 @@ public class NodesImpl implements Nodes
*/
public Document getDocument(NodeRef nodeRef)
{
Type type = getType(nodeRef);
if (type.equals(Type.DOCUMENT))
Type type = getType(nodeRef);
if (type.equals(Type.DOCUMENT))
{
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
Document doc = new Document(nodeRef, getParentNodeRef(nodeRef), properties, sr);
doc.setVersionLabel((String)properties.get(ContentModel.PROP_VERSION_LABEL));
doc.setVersionLabel((String) properties.get(ContentModel.PROP_VERSION_LABEL));
ContentData cd = (ContentData) properties.get(ContentModel.PROP_CONTENT);
if (cd != null)
{
@@ -293,12 +317,12 @@ public class NodesImpl implements Nodes
}
setCommonProps(doc, nodeRef, properties);
return doc;
}
else
{
throw new InvalidArgumentException("Node is not a file");
}
return doc;
}
else
{
throw new InvalidArgumentException("Node is not a file");
}
}
private void setCommonProps(Node node, NodeRef nodeRef, Map<QName,Serializable> properties)
@@ -309,25 +333,25 @@ public class NodesImpl implements Nodes
node.setModifiedBy((String)properties.get(ContentModel.PROP_MODIFIER));
node.setCreatedBy((String)properties.get(ContentModel.PROP_CREATOR));
}
/**
* @deprecated note: currently required for backwards compat' (Favourites API)
*/
public Folder getFolder(NodeRef nodeRef)
{
Type type = getType(nodeRef);
if (type.equals(Type.FOLDER))
{
Type type = getType(nodeRef);
if (type.equals(Type.FOLDER))
{
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
Folder folder = new Folder(nodeRef, getParentNodeRef(nodeRef), properties, sr);
Folder folder = new Folder(nodeRef, getParentNodeRef(nodeRef), properties, sr);
setCommonProps(folder, nodeRef, properties);
return folder;
}
else
{
throw new InvalidArgumentException("Node is not a folder");
}
return folder;
}
else
{
throw new InvalidArgumentException("Node is not a folder");
}
}
private NodeRef getParentNodeRef(final NodeRef nodeRef) {
@@ -339,38 +363,44 @@ public class NodesImpl implements Nodes
return nodeService.getPrimaryParent(nodeRef).getParentRef();
}
private NodeRef validateOrLookupNode(String nodeId, String path) {
NodeRef parentNodeRef;
if (nodeId.equals(PATH_ROOT))
{
parentNodeRef = repositoryHelper.getCompanyHome();
}
private NodeRef validateOrLookupNode(String nodeId, String path)
{
NodeRef parentNodeRef;
if (nodeId.equals(PATH_ROOT))
{
parentNodeRef = repositoryHelper.getCompanyHome();
}
else if (nodeId.equals(PATH_SHARED))
{
parentNodeRef = repositoryHelper.getSharedHome();
}
else if (nodeId.equals(PATH_MY))
{
NodeRef person = repositoryHelper.getPerson();
if (person == null)
{
throw new IllegalArgumentException("Unexpected: cannot use "+PATH_MY);
}
parentNodeRef = repositoryHelper.getUserHome(person);
}
else
{
parentNodeRef = validateNode(nodeId);
}
else if (nodeId.equals(PATH_MY))
{
NodeRef person = repositoryHelper.getPerson();
if (person == null)
{
throw new InvalidArgumentException("Unexpected: cannot use " + PATH_MY);
}
parentNodeRef = repositoryHelper.getUserHome(person);
if (parentNodeRef == null)
{
throw new EntityNotFoundException(nodeId);
}
}
else
{
parentNodeRef = validateNode(nodeId);
}
if (path != null) {
if (path != null)
{
// resolve path relative to current nodeId
parentNodeRef = resolveNodeByPath(parentNodeRef, path, true);
}
return parentNodeRef;
return parentNodeRef;
}
protected NodeRef resolveNodeByPath(final NodeRef parentNodeRef, String path, boolean checkForCompanyHome)
@@ -424,116 +454,176 @@ public class NodesImpl implements Nodes
return fileInfo.getNodeRef();
}
public Node getFolderOrDocument(String nodeId, Parameters parameters)
{
String path = parameters.getParameter("path");
NodeRef nodeRef = validateOrLookupNode(nodeId, path);
QName typeQName = nodeService.getType(nodeRef);
return getFolderOrDocument(nodeRef, getParentNodeRef(nodeRef), typeQName, false);
}
private Node getFolderOrDocument(final NodeRef nodeRef, NodeRef parentNodeRef, QName typeQName, boolean minimalnfo)
public Node getFolderOrDocument(String nodeId, Parameters parameters)
{
PathInfo pathInfo = null;
if (! minimalnfo)
String path = parameters.getParameter("path");
NodeRef nodeRef = validateOrLookupNode(nodeId, path);
QName typeQName = nodeService.getType(nodeRef);
List<QName> requestedProperties = createQNames(parameters.getSelectedProperties());
return getFolderOrDocument(nodeRef, getParentNodeRef(nodeRef), typeQName, requestedProperties, false);
}
private Node getFolderOrDocument(final NodeRef nodeRef, NodeRef parentNodeRef, QName typeQName, List<QName> selectedProperties, boolean minimalnfo)
{
PathInfo pathInfo = null;
if (!minimalnfo)
{
pathInfo = lookupPathInfo(nodeRef);
}
Type type = getType(typeQName);
Node node;
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
if (type.equals(Type.DOCUMENT))
{
node = new Document(nodeRef, parentNodeRef, properties, sr);
}
else if (type.equals(Type.FOLDER))
{
// container/folder
node = new Folder(nodeRef, parentNodeRef, properties, sr);
}
else
{
throw new InvalidArgumentException("Node is not a folder or file");
}
if (type.equals(Type.DOCUMENT))
{
node = new Document(nodeRef, parentNodeRef, properties, sr);
}
else if (type.equals(Type.FOLDER))
{
// container/folder
node = new Folder(nodeRef, parentNodeRef, properties, sr);
}
else
{
throw new InvalidArgumentException("Node is not a folder or file");
}
if (! minimalnfo) {
node.setProperties(mapProperties(properties));
if (!minimalnfo)
{
node.setProperties(mapProperties(properties, selectedProperties));
node.setAspectNames(mapAspects(nodeService.getAspects(nodeRef)));
}
node.setNodeType(typeQName.toPrefixString(namespaceService));
node.setPath(pathInfo);
node.setPath(pathInfo);
return node;
return node;
}
protected PathInfo lookupPathInfo(NodeRef nodeRefIn)
{
List<PathInfo.ElementInfo> elements = new ArrayList<>(5);
// TODO which implementation?
return getPathInfo(nodeRefIn);
NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome();
boolean isComplete = true;
// List<PathInfo.ElementInfo> elements = new ArrayList<>(5);
//
// NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome();
// boolean isComplete = true;
//
// NodeRef pNodeRef = nodeRefIn;
// while (pNodeRef != null)
// {
// if (pNodeRef.equals(companyHomeNodeRef))
// {
// pNodeRef = null;
// }
// else {
// pNodeRef = nodeService.getPrimaryParent(pNodeRef).getParentRef();
//
// if (pNodeRef == null)
// {
// // belts-and-braces - is it even possible to get here ?
// isComplete = false;
// }
// else
// {
// if (permissionService.hasPermission(pNodeRef, PermissionService.READ)
// == AccessStatus.ALLOWED)
// {
// String name = (String) nodeService.getProperty(pNodeRef,
// ContentModel.PROP_NAME);
// elements.add(0, new ElementInfo(pNodeRef, name));
// }
// else
// {
// isComplete = false;
// pNodeRef = null;
// }
// }
// }
// }
//
// StringBuilder sb = new StringBuilder();
// for (PathInfo.ElementInfo e : elements)
// {
// sb.append("/").append(e.getName());
// }
//
// return new PathInfo(sb.toString(), isComplete, elements);
}
NodeRef pNodeRef = nodeRefIn;
while (pNodeRef != null)
private PathInfo getPathInfo(NodeRef nodeRef)
{
final Path nodePath = nodeService.getPath(nodeRef);
List<ElementInfo> pathElements = new ArrayList<>();
Boolean isComplete = Boolean.TRUE;
// 2 => as we don't want to include the given node in the path as well.
for (int i = nodePath.size() - 2; i >= 0; i--)
{
if (pNodeRef.equals(companyHomeNodeRef))
Element element = nodePath.get(i);
if (element instanceof Path.ChildAssocElement)
{
pNodeRef = null;
}
else {
pNodeRef = nodeService.getPrimaryParent(pNodeRef).getParentRef();
if (pNodeRef == null)
ChildAssociationRef elementRef = ((Path.ChildAssocElement) element).getRef();
if (elementRef.getParentRef() != null)
{
// belts-and-braces - is it even possible to get here ?
isComplete = false;
}
else
{
if (permissionService.hasPermission(pNodeRef, PermissionService.READ) == AccessStatus.ALLOWED)
NodeRef childNodeRef = elementRef.getChildRef();
if (permissionService.hasPermission(childNodeRef, PermissionService.READ) == AccessStatus.ALLOWED)
{
String name = (String) nodeService.getProperty(pNodeRef, ContentModel.PROP_NAME);
elements.add(0, new PathInfo().new ElementInfo(pNodeRef.getId(), name));
Serializable nameProp = nodeService.getProperty(childNodeRef, ContentModel.PROP_NAME);
pathElements.add(0, new ElementInfo(childNodeRef, nameProp.toString()));
}
else
{
isComplete = false;
pNodeRef = null;
// Just return the pathInfo up to the location where the user has access
isComplete = Boolean.FALSE;
break;
}
}
}
}
StringBuilder sb = new StringBuilder();
for (PathInfo.ElementInfo e : elements)
String pathStr = null;
if(pathElements.size() > 0)
{
sb.append("/").append(e.getName());
StringBuilder sb = new StringBuilder(120);
for (PathInfo.ElementInfo e : pathElements)
{
sb.append("/").append(e.getName());
}
pathStr = sb.toString();
}
return new PathInfo(sb.toString(), isComplete, elements);
else
{
// There is no path element, so set it to null in order to be
// ignored by Jackson during serialisation
isComplete = null;
}
return new PathInfo(pathStr, isComplete, pathElements);
}
protected Map<String, Serializable> mapProperties(Map<QName, Serializable> nodeProps)
protected Map<String, Object> mapProperties(Map<QName, Serializable> nodeProps, List<QName> selectedProperties)
{
Map<String, Serializable> props = new HashMap<>(nodeProps.size());
for (Map.Entry<QName, Serializable> entry : nodeProps.entrySet()) {
QName propQName = entry.getKey();
if (!EXCLUDED_PROPS.contains(propQName))
{
props.put(entry.getKey().toPrefixString(namespaceService), entry.getValue());
}
}
if (props.size() == 0)
Map<String, Object> props = null;
if (!selectedProperties.isEmpty())
{
props = null; // no props to return
props = new HashMap<>(selectedProperties.size());
for (QName qName : selectedProperties)
{
Serializable value = nodeProps.get(qName);
if (value != null)
{
props.put(qName.toPrefixString(namespaceService), value);
}
}
if (props.isEmpty())
{
props = null; // set to null so it doesn't show up as an empty object in the JSON response.
}
}
return props;
@@ -561,12 +651,19 @@ public class NodesImpl implements Nodes
public CollectionWithPagingInfo<Node> getChildren(String parentFolderNodeId, Parameters parameters)
{
// TODO
// TODO do we want to support path with list folder children ?
String path = null;
// String path = parameters.getParameter("path");
final NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId, path);
// TODO
// map - where (filter) properties - including isFolder
// map - orderBy (sort) properties - including isFolder
// TODO refactor & fix !
final boolean minimalnfo = (parameters.getSelectedProperties().size() == 0);
final List<QName> requestedProperties = createQNames(parameters.getSelectedProperties());
boolean includeFolders = true;
boolean includeFiles = true;
@@ -597,7 +694,7 @@ public class NodesImpl implements Nodes
QName propQname = MAP_PARAM_QNAME.get(sortCol.column);
if (propQname == null)
{
propQname = QName.resolveToQName(namespaceService, sortCol.column);
propQname = createQName(sortCol.column);
}
if (propQname != null)
@@ -616,46 +713,40 @@ public class NodesImpl implements Nodes
Paging paging = parameters.getPaging();
// TODO do we want to support path with list folder children ?
String path = null;
//String path = parameters.getParameter("path");
final NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId, path);
if (! nodeMatches(parentNodeRef, Collections.singleton(ContentModel.TYPE_FOLDER), null))
{
throw new InvalidArgumentException("NodeId of folder is expected");
}
PagingRequest pagingRequest = Util.getPagingRequest(paging);
final PagingResults<FileInfo> pagingResults = fileFolderService.list(parentNodeRef, includeFiles, includeFolders, null, sortProps, pagingRequest);
final List<FileInfo> page = pagingResults.getPage();
List<Node> nodes = new AbstractList<Node>()
{
@Override
public Node get(int index)
{
FileInfo fInfo = page.get(index);
PagingRequest pagingRequest = Util.getPagingRequest(paging);
final PagingResults<FileInfo> pagingResults = fileFolderService.list(parentNodeRef, includeFiles, includeFolders, ignoreTypeQNames, sortProps, pagingRequest);
final List<FileInfo> page = pagingResults.getPage();
List<Node> nodes = new AbstractList<Node>()
{
@Override
public Node get(int index)
{
FileInfo fInfo = page.get(index);
// basic info by default (unless "select"ed otherwise)
return getFolderOrDocument(fInfo.getNodeRef(), parentNodeRef, fInfo.getType(), minimalnfo);
}
return getFolderOrDocument(fInfo.getNodeRef(), parentNodeRef, fInfo.getType(), requestedProperties, minimalnfo);
}
@Override
public int size()
{
return page.size();
}
};
@Override
public int size()
{
return page.size();
}
};
return CollectionWithPagingInfo.asPaged(paging, nodes, pagingResults.hasMoreItems(), pagingResults.getTotalResultCount().getFirst());
}
public void deleteNode(String nodeId)
{
NodeRef nodeRef = validateNode(nodeId);
NodeRef nodeRef = validateNode(nodeId);
fileFolderService.delete(nodeRef);
}
@@ -682,8 +773,8 @@ public class NodesImpl implements Nodes
throw new InvalidArgumentException("Node type is expected: "+parentNodeRef+","+nodeName);
}
// check that requested type is a (sub-) type of folder or content
QName nodeTypeQName = QName.resolveToQName(namespaceService, nodeType);
// check that requested type is a (sub-) type of folder or content
QName nodeTypeQName = createQName(nodeType);
Set<QName> contentAndFolders = new HashSet<>(Arrays.asList(ContentModel.TYPE_FOLDER, ContentModel.TYPE_CONTENT));
if (! typeMatches(nodeTypeQName, contentAndFolders, null)) {
@@ -696,7 +787,7 @@ public class NodesImpl implements Nodes
if (nodeInfo.getProperties() != null)
{
for (Map.Entry entry : (Set<Map.Entry<String, Serializable>>)nodeInfo.getProperties().entrySet())
for (Entry<String, Object> entry : nodeInfo.getProperties().entrySet())
{
QName propQName = QName.createQName((String)entry.getKey(), namespaceService);
props.put(propQName, (Serializable)entry.getValue());
@@ -734,7 +825,7 @@ public class NodesImpl implements Nodes
if (nodeInfo.getProperties() != null)
{
for (Map.Entry entry : (Set<Map.Entry<String, Serializable>>)nodeInfo.getProperties().entrySet())
for (Entry<String, Object> entry : nodeInfo.getProperties().entrySet())
{
QName propQName = QName.createQName((String)entry.getKey(), namespaceService);
props.put(propQName, (Serializable)entry.getValue());
@@ -800,4 +891,58 @@ public class NodesImpl implements Nodes
// TODO - hmm - we may wish to return json info !!
return;
}
/**
* Helper to create a QName from either a fully qualified or short-name QName string
*
* @param qnameStr Fully qualified or short-name QName string
* @return QName
*/
protected QName createQName(String qnameStr)
{
try
{
QName qname;
if (qnameStr.indexOf(QName.NAMESPACE_BEGIN) != -1)
{
qname = QName.createQName(qnameStr);
}
else
{
qname = QName.createQName(qnameStr, namespaceService);
}
return qname;
}
catch (Exception ex)
{
String msg = ex.getMessage();
if (msg == null)
{
msg = "";
}
throw new InvalidArgumentException(qnameStr + " isn't a valid QName. " + msg);
}
}
/**
* Helper to create a QName from either a fully qualified or short-name QName string
*
* @param qnameStrList list of fully qualified or short-name QName string
* @return a list of {@code QName} objects
*/
protected List<QName> createQNames(List<String> qnameStrList)
{
List<QName> result = new ArrayList<>(qnameStrList.size());
for (String str : qnameStrList)
{
str = str.replaceFirst("_", ":"); // FIXME remove this when we have fixed the framework.
QName name = createQName(str);
if (!EXCLUDED_PROPS.contains(name))
{
result.add(name);
}
}
return result;
}
}

View File

@@ -39,6 +39,11 @@ public class Document extends Node
{
private ContentInfo contentInfo;
// instance init block
{
this.isFolder = Boolean.FALSE;
}
public Document() {
super();
}
@@ -57,76 +62,76 @@ public class Document extends Node
}
}
public Boolean getIsFolder()
{
return false;
}
public ContentInfo getContent()
{
return contentInfo;
}
@Override
public String toString()
{
return "Document [contentInfo=" + contentInfo.toString() + ", nodeRef="
+ nodeRef + ", name=" + name + ", createdAt=" + createdAt
+ ", modifiedAt=" + modifiedAt + ", createdBy=" + createdBy
+ ", modifiedBy=" + modifiedBy + "]";
}
public void setContent(ContentInfo contentInfo)
{
this.contentInfo = contentInfo;
}
// TODO for backwards compat' - set explicitly when needed (ie. favourites)
private String mimeType;
private BigInteger sizeInBytes;
private String versionLabel;
@Override
public String toString()
{
return "Document [contentInfo=" + contentInfo.toString() + ", nodeRef="
+ nodeRef + ", name=" + name + ", createdAt=" + createdAt
+ ", modifiedAt=" + modifiedAt + ", createdBy=" + createdBy
+ ", modifiedBy=" + modifiedBy + "]";
}
/**
* @deprecated
// TODO for backwards compat' - set explicitly when needed (ie. favourites)
private String mimeType;
private BigInteger sizeInBytes;
private String versionLabel;
/**
* @deprecated
*/
public String getMimeType()
{
return mimeType;
}
public String getMimeType()
{
return mimeType;
}
/**
* @deprecated
*/
public BigInteger getSizeInBytes()
{
return sizeInBytes;
}
/**
* @deprecated
*/
public BigInteger getSizeInBytes()
{
return sizeInBytes;
}
/**
* @deprecated
*/
public String getVersionLabel()
{
return versionLabel;
}
/**
* @deprecated
*/
public String getVersionLabel()
{
return versionLabel;
}
/**
* @deprecated
*/
public void setMimeType(String mimeType)
{
this.mimeType = mimeType;
}
/**
* @deprecated
*/
public void setMimeType(String mimeType)
{
this.mimeType = mimeType;
}
/**
* @deprecated
*/
public void setSizeInBytes(BigInteger sizeInBytes)
{
this.sizeInBytes = sizeInBytes;
}
/**
* @deprecated
*/
public void setSizeInBytes(BigInteger sizeInBytes)
{
this.sizeInBytes = sizeInBytes;
}
/**
* @deprecated
*/
public void setVersionLabel(String versionLabel)
{
this.versionLabel = versionLabel;
}
/**
* @deprecated
*/
public void setVersionLabel(String versionLabel)
{
this.versionLabel = versionLabel;
}
}

View File

@@ -16,6 +16,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.rest.api.model;
import java.io.Serializable;
@@ -30,31 +31,30 @@ import org.alfresco.service.namespace.QName;
*
* @author steveglover
* @author janv
*
*/
public class Folder extends Node
{
public Folder()
{
super();
}
// instance init block
{
this.isFolder = Boolean.TRUE;
}
public Folder()
{
super();
}
public Folder(NodeRef nodeRef, NodeRef parentNodeRef, Map<QName, Serializable> nodeProps, ServiceRegistry sr)
{
super(nodeRef, parentNodeRef, nodeProps, sr);
}
public Boolean getIsFolder()
{
return true;
}
@Override
public String toString()
{
return "Folder [nodeRef=" + nodeRef + ", name=" + name + ", title="
+ title + ", description=" + description + ", createdAt="
+ createdAt + ", modifiedAt=" + modifiedAt + ", createdBy="
+ createdBy + ", modifiedBy=" + modifiedBy + "]";
}
@Override
public String toString()
{
return "Folder [nodeRef=" + nodeRef + ", name=" + name + ", title="
+ title + ", description=" + description + ", createdAt="
+ createdAt + ", modifiedAt=" + modifiedAt + ", createdBy="
+ createdBy + ", modifiedBy=" + modifiedBy + "]";
}
}

View File

@@ -50,13 +50,15 @@ public class Node implements Comparable<Node>
protected UserInfo createdByUser;
protected UserInfo modifiedByUser;
protected Boolean isFolder;
protected NodeRef parentNodeRef;
protected PathInfo pathInfo;
protected String prefixTypeQName;
protected List<String> aspectNames;
protected Map<String, Serializable> props;
protected Map<String, Object> properties;
// TODO fixme !
// also need to optionally pass in user map - eg. when listing children (to avoid multiple lookups for same user)
@@ -183,12 +185,12 @@ public class Node implements Comparable<Node>
this.prefixTypeQName = prefixType;
}
public Map getProperties() {
return this.props;
public Map<String, Object> getProperties() {
return this.properties;
}
public void setProperties(Map props) {
this.props = props;
public void setProperties(Map<String, Object> props) {
this.properties = props;
}
public List<String> getAspectNames() {
@@ -204,6 +206,21 @@ public class Node implements Comparable<Node>
return parentNodeRef;
}
public void setParentId(NodeRef parentNodeRef)
{
this.parentNodeRef = parentNodeRef;
}
public Boolean getIsFolder()
{
return isFolder;
}
public void setIsFolder(Boolean isFolder)
{
this.isFolder=isFolder;
}
public boolean equals(Object other)
{
if(this == other)

View File

@@ -1,64 +1,92 @@
package org.alfresco.rest.api.model;
import java.util.List;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Representation of a path info
*
* @author janv
*
*/
public class PathInfo
{
private String name;
private Boolean isComplete;
private List<ElementInfo> elements;
private String name;
private Boolean isComplete;
private List<ElementInfo> elements;
public PathInfo()
{
}
public PathInfo()
{
}
public PathInfo(String name, Boolean isComplete, List<ElementInfo> elements)
{
this.name = name;
this.isComplete = isComplete;
this.elements = elements;
}
public PathInfo(String name, Boolean isComplete, List<ElementInfo> elements)
{
this.name = name;
this.isComplete = isComplete;
this.elements = elements;
}
public String getName() {
return name;
}
public String getName()
{
return name;
}
public Boolean getIsComplete() {
return isComplete;
}
public Boolean getIsComplete()
{
return isComplete;
}
public List<ElementInfo> getElements() {
return elements;
}
public List<ElementInfo> getElements()
{
return elements;
}
public class ElementInfo {
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder(120);
sb.append("PathInfo [name='").append(name)
.append(", isComplete=").append(isComplete)
.append(", elements=").append(elements)
.append(']');
return sb.toString();
}
private String id;
public static class ElementInfo
{
private String name;
private NodeRef id;
private String name;
public ElementInfo()
{
}
public ElementInfo()
{
}
public ElementInfo(String id, String name)
{
this.id = id;
this.name = name;
}
public ElementInfo(NodeRef id, String name)
{
this.id = id;
this.name = name;
}
public String getName() {
return name;
}
public String getName()
{
return name;
}
public String getId() {
return id;
}
}
public NodeRef getId()
{
return id;
}
@Override
public String toString()
{
final StringBuilder sb = new StringBuilder(250);
sb.append("PathElement [id=").append(id)
.append(", name='").append(name)
.append(']');
return sb.toString();
}
}
}

View File

@@ -16,41 +16,42 @@
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/
package org.alfresco.rest.api.model;
/**
* Representation of a user info
*
* @author janv
*
*/
public class UserInfo
{
private String userName;
private String displayName;
private String userName;
private String displayName;
public UserInfo()
{
}
public UserInfo()
{
}
public UserInfo(String userName, String firstName, String lastName)
{
this.userName = userName;
this.displayName = ((firstName != null ? firstName + " " : "") + (lastName != null ? lastName : "")).replaceAll("^\\s+|\\s+$", "");
}
public UserInfo(String userName, String firstName, String lastName)
{
this.userName = userName;
this.displayName = ((firstName != null ? firstName + " " : "") + (lastName != null ? lastName : "")).trim();
}
public String getDisplayName() {
return displayName;
}
public String getDisplayName()
{
return displayName;
}
public String getUserName() {
return userName;
}
public String getUserName()
{
return userName;
}
@Override
public String toString()
{
return "User [userName=" + userName + ", displayName=" + displayName + "]";
}
@Override
public String toString()
{
return "User [userName=" + userName + ", displayName=" + displayName + "]";
}
}

View File

@@ -19,10 +19,17 @@
package org.alfresco.rest.api.tests;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertNotNull;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.rest.api.tests.RepoService.SiteInformation;
import org.alfresco.rest.api.tests.RepoService.TestNetwork;
import org.alfresco.rest.api.tests.RepoService.TestPerson;
import org.alfresco.rest.api.tests.RepoService.TestSite;
import org.alfresco.rest.api.tests.client.HttpResponse;
import org.alfresco.rest.api.tests.client.PublicApiClient;
import org.alfresco.rest.api.tests.client.RequestContext;
import org.alfresco.service.cmr.site.SiteVisibility;
import java.util.Map;
@@ -75,9 +82,14 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
}
protected HttpResponse getAll(String url, String runAsUser, PublicApiClient.Paging paging, int expectedStatus) throws Exception
{
return getAll(url, runAsUser, paging, null, expectedStatus);
}
protected HttpResponse getAll(String url, String runAsUser, PublicApiClient.Paging paging, Map<String, String> otherParams, int expectedStatus) throws Exception
{
publicApiClient.setRequestContext(new RequestContext(runAsUser));
Map<String, String> params = (paging == null) ? null : createParams(paging, null);
Map<String, String> params = (paging == null) ? null : createParams(paging, otherParams);
HttpResponse response = publicApiClient.get(getScope(), url, null, null, null, params);
checkStatus(expectedStatus, response.getStatusCode());
@@ -85,6 +97,16 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
return response;
}
protected HttpResponse getAll(Class<?> entityResource, String runAsUser, PublicApiClient.Paging paging, Map<String, String> otherParams, int expectedStatus) throws Exception
{
publicApiClient.setRequestContext(new RequestContext(runAsUser));
HttpResponse response = publicApiClient.get(entityResource, null, null, otherParams);
checkStatus(expectedStatus, response.getStatusCode());
return response;
}
protected HttpResponse getSingle(String url, String runAsUser, String entityId, int expectedStatus) throws Exception
{
publicApiClient.setRequestContext(new RequestContext(runAsUser));
@@ -95,6 +117,16 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
return response;
}
protected HttpResponse getSingle(Class<?> entityResource, String runAsUser, String entityId, Map<String, String> params, int expectedStatus) throws Exception
{
publicApiClient.setRequestContext(new RequestContext(runAsUser));
HttpResponse response = publicApiClient.get(entityResource, entityId, null, params);
checkStatus(expectedStatus, response.getStatusCode());
return response;
}
protected HttpResponse put(String url, String runAsUser, String entityId, String body, String queryString, int expectedStatus) throws Exception
{
publicApiClient.setRequestContext(new RequestContext(runAsUser));
@@ -125,6 +157,23 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
return person.getId();
}
protected TestSite createSite(final TestNetwork testNetwork, TestPerson user, final SiteVisibility siteVisibility)
{
final String siteName = "RandomSite" + System.currentTimeMillis();
final TestSite site = TenantUtil.runAsUserTenant(new TenantUtil.TenantRunAsWork<TestSite>()
{
@Override
public TestSite doWork() throws Exception
{
SiteInformation siteInfo = new SiteInformation(siteName, siteName, siteName, siteVisibility);
return repoService.createSite(testNetwork, siteInfo);
}
}, user.getId(), testNetwork.getId());
assertNotNull(site);
return site;
}
protected void checkStatus(int expectedStatus, int actualStatus)
{
if (expectedStatus > 0 && expectedStatus != actualStatus)

View File

@@ -0,0 +1,485 @@
/*
* Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* 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/>.
*/
package org.alfresco.rest.api.tests;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import org.alfresco.model.ContentModel;
import org.alfresco.model.ForumModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.model.Repository;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.rest.api.model.Document;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.PathInfo;
import org.alfresco.rest.api.model.PathInfo.ElementInfo;
import org.alfresco.rest.api.model.UserInfo;
import org.alfresco.rest.api.nodes.NodesEntityResource;
import org.alfresco.rest.api.tests.RepoService.TestNetwork;
import org.alfresco.rest.api.tests.RepoService.TestPerson;
import org.alfresco.rest.api.tests.RepoService.TestSite;
import org.alfresco.rest.api.tests.client.HttpResponse;
import org.alfresco.rest.api.tests.client.PublicApiClient.ExpectedPaging;
import org.alfresco.rest.api.tests.client.PublicApiClient.Paging;
import org.alfresco.rest.api.tests.client.data.SiteRole;
import org.alfresco.rest.api.tests.util.JacksonUtil;
import org.alfresco.rest.api.tests.util.RestApiUtil;
import org.alfresco.rest.framework.jacksonextensions.JacksonHelper;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.MutableAuthenticationService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.site.SiteVisibility;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* API tests for:
* <ul>
* <li> {@literal host:port/alfresco/api/{networkId}/public/alfresco/versions/1/nodes/{nodeId}} </li>
* <li> {@literal host:port/alfresco/api/{networkId}/public/alfresco/versions/1/nodes/{nodeId}/children} </li>
* </ul>
*
* @author Jamal Kaabi-Mofrad
*/
public class NodeApiTest extends AbstractBaseApiTest
{
/**
* User one from network one
*/
private TestPerson userOneN1;
/**
* User two from network one
*/
private TestPerson userTwoN1;
/**
* Private site of user one from network one
*/
private TestSite userOneN1Site;
private String user1;
private String user2;
private List<String> users = new ArrayList<>();
protected MutableAuthenticationService authenticationService;
protected PersonService personService;
protected Repository repositoryHelper;
protected JacksonUtil jacksonUtil;
protected PermissionService permissionService;
@Before
public void setup() throws Exception
{
authenticationService = applicationContext.getBean("authenticationService", MutableAuthenticationService.class);
personService = applicationContext.getBean("personService", PersonService.class);
repositoryHelper = applicationContext.getBean("repositoryHelper", Repository.class);
jacksonUtil = new JacksonUtil(applicationContext.getBean("jsonHelper", JacksonHelper.class));
permissionService = applicationContext.getBean("permissionService", PermissionService.class);
user1 = createUser("user1" + System.currentTimeMillis());
user2 = createUser("user2" + System.currentTimeMillis());
// We just need to clean the on-premise-users,
// so the tests for the specific network would work.
users.add(user1);
users.add(user2);
TestNetwork networkOne = getTestFixture().getRandomNetwork();
userOneN1 = networkOne.createUser();
userTwoN1 = networkOne.createUser();
userOneN1Site = createSite(networkOne, userOneN1, SiteVisibility.PRIVATE);
}
@After
public void tearDown() throws Exception
{
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
for (final String user : users)
{
transactionHelper.doInTransaction(new RetryingTransactionCallback<Void>()
{
@Override
public Void execute() throws Throwable
{
if (personService.personExists(user))
{
authenticationService.deleteAuthentication(user);
personService.deletePerson(user);
}
return null;
}
});
}
users.clear();
AuthenticationUtil.clearCurrentSecurityContext();
}
@Test
public void testListDocLibChildren() throws Exception
{
AuthenticationUtil.setFullyAuthenticatedUser(userOneN1.getId());
NodeRef docLibNodeRef = userOneN1Site.getContainerNodeRef(("documentLibrary"));
String folder1 = "folder" + System.currentTimeMillis() + "_1";
repoService.addToDocumentLibrary(userOneN1Site, folder1, ContentModel.TYPE_FOLDER);
String folder2 = "folder" + System.currentTimeMillis() + "_2";
repoService.addToDocumentLibrary(userOneN1Site, folder2, ContentModel.TYPE_FOLDER);
String content1 = "content" + System.currentTimeMillis() + "_1";
repoService.addToDocumentLibrary(userOneN1Site, content1, ContentModel.TYPE_CONTENT);
String content2 = "content" + System.currentTimeMillis() + "_2";
repoService.addToDocumentLibrary(userOneN1Site, content2, ContentModel.TYPE_CONTENT);
String forum1 = "forum" + System.currentTimeMillis() + "_1";
repoService.createObjectOfCustomType(docLibNodeRef, forum1, ForumModel.TYPE_TOPIC.toString());
Paging paging = getPaging(0, 100);
HttpResponse response = getAll(getChildrenUrl(docLibNodeRef), userOneN1.getId(), paging, 200);
List<Node> nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class);
assertEquals(4, nodes.size()); // forum is part of the default ignored types
// Paging
ExpectedPaging expectedPaging = RestApiUtil.parsePaging(response.getJsonResponse());
assertEquals(4, expectedPaging.getCount().intValue());
assertEquals(0, expectedPaging.getSkipCount().intValue());
assertEquals(100, expectedPaging.getMaxItems().intValue());
assertFalse(expectedPaging.getHasMoreItems().booleanValue());
// Order by folders and modified date first
Map<String, String> orderBy = Collections.singletonMap("orderBy", "isFolder DESC,modifiedAt DESC");
response = getAll(getChildrenUrl(docLibNodeRef), userOneN1.getId(), paging, orderBy, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class);
assertEquals(4, nodes.size());
assertEquals(folder2, nodes.get(0).getName());
assertTrue(nodes.get(0).getIsFolder());
assertEquals(folder1, nodes.get(1).getName());
assertTrue(nodes.get(1).getIsFolder());
assertEquals(content2, nodes.get(2).getName());
assertFalse(nodes.get(2).getIsFolder());
assertEquals(content1, nodes.get(3).getName());
assertFalse(nodes.get(3).getIsFolder());
// Order by folders last and modified date first
orderBy = Collections.singletonMap("orderBy", "isFolder ASC,modifiedAt DESC");
response = getAll(getChildrenUrl(docLibNodeRef), userOneN1.getId(), paging, orderBy, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class);
assertEquals(4, nodes.size());
assertEquals(content2, nodes.get(0).getName());
assertEquals(content1, nodes.get(1).getName());
assertEquals(folder2, nodes.get(2).getName());
assertEquals(folder1, nodes.get(3).getName());
// Order by folders and modified date last
orderBy = Collections.singletonMap("orderBy", "isFolder,modifiedAt");
response = getAll(getChildrenUrl(docLibNodeRef), userOneN1.getId(), paging, orderBy, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class);
assertEquals(4, nodes.size());
assertEquals(content1, nodes.get(0).getName());
assertEquals(content2, nodes.get(1).getName());
assertEquals(folder1, nodes.get(2).getName());
assertEquals(folder2, nodes.get(3).getName());
// Order by folders and modified date first
orderBy = Collections.singletonMap("orderBy", "isFolder DESC,modifiedAt DESC");
// SkipCount=0,MaxItems=2
paging = getPaging(0, 2);
response = getAll(getChildrenUrl(docLibNodeRef), userOneN1.getId(), paging, orderBy, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class);
assertEquals(2, nodes.size());
assertEquals(folder2, nodes.get(0).getName());
assertEquals(folder1, nodes.get(1).getName());
expectedPaging = RestApiUtil.parsePaging(response.getJsonResponse());
assertEquals(2, expectedPaging.getCount().intValue());
assertEquals(0, expectedPaging.getSkipCount().intValue());
assertEquals(2, expectedPaging.getMaxItems().intValue());
assertTrue(expectedPaging.getHasMoreItems().booleanValue());
// SkipCount=2,MaxItems=4
paging = getPaging(2, 4);
response = getAll(getChildrenUrl(docLibNodeRef), userOneN1.getId(), paging, orderBy, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Node.class);
assertEquals(2, nodes.size());
assertEquals(content2, nodes.get(0).getName());
assertEquals(content1, nodes.get(1).getName());
expectedPaging = RestApiUtil.parsePaging(response.getJsonResponse());
assertEquals(2, expectedPaging.getCount().intValue());
assertEquals(2, expectedPaging.getSkipCount().intValue());
assertEquals(4, expectedPaging.getMaxItems().intValue());
assertFalse(expectedPaging.getHasMoreItems().booleanValue());
// userTwoN1 tries to access userOneN1's docLib
AuthenticationUtil.setFullyAuthenticatedUser(userTwoN1.getId());
paging = getPaging(0, Integer.MAX_VALUE);
getAll(getChildrenUrl(docLibNodeRef), userTwoN1.getId(), paging, 403);
}
@Test
public void testListMyFilesChildren() throws Exception
{
AuthenticationUtil.setFullyAuthenticatedUser(user1);
NodeRef myFilesNodeRef = repositoryHelper.getUserHome(personService.getPerson(user1));
String folder1 = "folder" + System.currentTimeMillis() + "_1";
repoService.createFolder(myFilesNodeRef, folder1);
String folder2 = "folder" + System.currentTimeMillis() + "_2";
repoService.createFolder(myFilesNodeRef, folder2);
String content1 = "content" + System.currentTimeMillis() + "_1";
NodeRef contentNodeRef = repoService.createDocument(myFilesNodeRef, content1, "The quick brown fox jumps over the lazy dog.");
repoService.getNodeService().setProperty(contentNodeRef, ContentModel.PROP_OWNER, user1);
repoService.getNodeService().setProperty(contentNodeRef, ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA,
(Serializable) Collections.singletonList("doclib:1444660852296"));
Paging paging = getPaging(0, Integer.MAX_VALUE);
HttpResponse response = getAll(getChildrenUrl(myFilesNodeRef), user1, paging, 200);
List<Document> nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Document.class);
assertEquals(3, nodes.size());
// Order by folders and modified date first
Map<String, String> orderBy = Collections.singletonMap("orderBy", "isFolder DESC,modifiedAt DESC");
response = getAll(getChildrenUrl(myFilesNodeRef), user1, paging, orderBy, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Document.class);
assertEquals(3, nodes.size());
assertEquals(folder2, nodes.get(0).getName());
assertEquals(folder1, nodes.get(1).getName());
Document node = (Document) nodes.get(2);
assertEquals(content1, node.getName());
assertEquals("cm:content", node.getNodeType());
assertEquals(contentNodeRef.getId(), node.getNodeRef().getId());
UserInfo createdByUser = node.getCreatedByUser();
assertEquals(user1, createdByUser.getUserName());
assertEquals(user1 + " " + user1, createdByUser.getDisplayName());
UserInfo modifiedByUser = node.getModifiedByUser();
assertEquals(user1, modifiedByUser.getUserName());
assertEquals(user1 + " " + user1, modifiedByUser.getDisplayName());
assertEquals(MimetypeMap.MIMETYPE_BINARY, node.getContent().getMimeType());
assertNotNull(node.getContent().getMimeTypeName());
assertNotNull(node.getContent().getEncoding());
assertTrue(node.getContent().getSizeInBytes() > 0);
// Invalid QName (Namespace prefix cm... is not mapped to a namespace URI) for the orderBy parameter.
orderBy = Collections.singletonMap("orderBy", "isFolder DESC,cm" + System.currentTimeMillis() + ":modified DESC");
getAll(getChildrenUrl(myFilesNodeRef), user1, paging, orderBy, 400);
AuthenticationUtil.setFullyAuthenticatedUser(user2);
// user2 tries to access user1's home folder
getAll(getChildrenUrl(myFilesNodeRef), user2, paging, 403);
AuthenticationUtil.setFullyAuthenticatedUser(user1);
// request property via select
Map<String, String> params = new LinkedHashMap<>();
params.put("select", "cm_lastThumbnailModification");// TODO replace the underscore with colon when the framework is fixed.
params.put("orderBy", "isFolder DESC,modifiedAt DESC");
response = getAll(getChildrenUrl(myFilesNodeRef), user1, paging, params, 200);
nodes = jacksonUtil.parseEntries(response.getJsonResponse(), Document.class);
assertEquals(3, nodes.size());
assertNull("There shouldn't be a 'properties' object in the response.", nodes.get(0).getProperties());
assertNull("There shouldn't be a 'properties' object in the response.", nodes.get(1).getProperties());
assertNotNull("There should be a 'properties' object in the response.", nodes.get(2).getProperties());
Set<Entry<String, Object>> props = nodes.get(2).getProperties().entrySet();
assertEquals(1, props.size());
Entry<String, Object> entry = props.iterator().next();
assertEquals("cm:lastThumbnailModification", entry.getKey());
assertEquals("doclib:1444660852296", ((List<?>) entry.getValue()).get(0));
}
@Test
public void testGetPathElements_DocLib() throws Exception
{
AuthenticationUtil.setFullyAuthenticatedUser(userOneN1.getId());
userOneN1Site.inviteToSite(userTwoN1.getEmail(), SiteRole.SiteConsumer);
NodeRef docLibNodeRef = userOneN1Site.getContainerNodeRef(("documentLibrary"));
// /Company Home/Sites/RandomSite<timestamp>/documentLibrary/folder<timestamp>_A
String folderA = "folder" + System.currentTimeMillis() + "_A";
NodeRef folderA_Ref = repoService.createFolder(docLibNodeRef, folderA);
// /Company Home/Sites/RandomSite<timestamp>/documentLibrary/folder<timestamp>_A/folder<timestamp>_B
String folderB = "folder" + System.currentTimeMillis() + "_B";
NodeRef folderB_Ref = repoService.createFolder(folderA_Ref, folderB);
// /Company Home/Sites/RandomSite<timestamp>/documentLibrary/folder<timestamp>_A/folder<timestamp>_B/folder<timestamp>_C
String folderC = "folder" + System.currentTimeMillis() + "_C";
NodeRef folderC_Ref = repoService.createFolder(folderB_Ref, folderC);
// /Company Home/Sites/RandomSite<timestamp>/documentLibrary/folder<timestamp>_A/folder<timestamp>_B/folder<timestamp>_C/content<timestamp>
String content = "content" + System.currentTimeMillis();
NodeRef contentNodeRef = repoService.createDocument(folderC_Ref, content, "The quick brown fox jumps over the lazy dog.");
// Revoke folderB inherited permissions
permissionService.setInheritParentPermissions(folderB_Ref, false);
// Grant userTwoN1 permission for folderC
permissionService.setPermission(folderC_Ref, userTwoN1.getId(), PermissionService.CONSUMER, true);
//...nodes/nodeId?select=path
Map<String, String> params = Collections.singletonMap("select", "path");
HttpResponse response = getSingle(NodesEntityResource.class, userOneN1.getId(), contentNodeRef.getId(), params, 200);
Document node = jacksonUtil.parseEntry(response.getJsonResponse(), Document.class);
PathInfo path = node.getPath();
assertNotNull(path);
assertTrue(path.getIsComplete());
assertNotNull(path.getName());
// the path should only include the parents (not the requested node)
assertFalse(path.getName().endsWith(content));
assertTrue(path.getName().startsWith("/Company Home"));
List<ElementInfo> pathElements = path.getElements();
assertEquals(7, pathElements.size());
assertEquals("Company Home", pathElements.get(0).getName());
assertEquals("Sites", pathElements.get(1).getName());
assertEquals(userOneN1Site.getSiteId(), pathElements.get(2).getName());
assertEquals("documentLibrary", pathElements.get(3).getName());
assertEquals(folderA, pathElements.get(4).getName());
assertEquals(folderB, pathElements.get(5).getName());
assertEquals(folderC, pathElements.get(6).getName());
// Try the above tests with userTwoN1 (site consumer)
AuthenticationUtil.setFullyAuthenticatedUser(userTwoN1.getId());
response = getSingle(NodesEntityResource.class, userTwoN1.getId(), contentNodeRef.getId(), params, 200);
node = jacksonUtil.parseEntry(response.getJsonResponse(), Document.class);
path = node.getPath();
assertNotNull(path);
assertFalse("The path is not complete as the user doesn't have permission to access the full path.", path.getIsComplete());
assertNotNull(path.getName());
// site consumer (userTwoN1) dose not have access to the folderB
assertFalse("site consumer (userTwoN1) dose not have access to the folderB", path.getName().contains(folderB));
assertFalse(path.getName().startsWith("/Company Home"));
// Go up as far as they can, before getting access denied (i.e. "/folderC")
assertTrue(path.getName().endsWith(folderC));
pathElements = path.getElements();
assertEquals(1, pathElements.size());
assertEquals(folderC, pathElements.get(0).getName());
}
@Test
public void testGetPathElements_MyFiles() throws Exception
{
final String userNodeAlias = "-my-";
AuthenticationUtil.setFullyAuthenticatedUser(user1);
HttpResponse response = getSingle(NodesEntityResource.class, user1, userNodeAlias, null, 200);
Node node = jacksonUtil.parseEntry(response.getJsonResponse(), Node.class);
NodeRef myFilesNodeRef = node.getNodeRef();
assertNotNull(myFilesNodeRef);
assertEquals(user1, node.getName());
assertTrue(node.getIsFolder());
// /Company Home/User Homes/user<timestamp>/folder<timestamp>_A
String folderA = "folder" + System.currentTimeMillis() + "_A";
NodeRef folderA_Ref = repoService.createFolder(myFilesNodeRef, folderA);
// /Company Home/User Homes/user<timestamp>/folder<timestamp>_A/folder<timestamp>_B
String folderB = "folder" + System.currentTimeMillis() + "_B";
NodeRef folderB_Ref = repoService.createFolder(folderA_Ref, folderB);
// /Company Home/User Homes/user<timestamp>/folder<timestamp>_A/folder<timestamp>_B/folder<timestamp>_C
String folderC = "folder" + System.currentTimeMillis() + "_C";
NodeRef folderC_Ref = repoService.createFolder(folderB_Ref, folderC);
//...nodes/nodeId?select=pathInfo
Map<String, String> params = Collections.singletonMap("select", "path");
response = getSingle(NodesEntityResource.class, user1, folderC_Ref.getId(), params, 200);
node = jacksonUtil.parseEntry(response.getJsonResponse(), Node.class);
PathInfo pathInfo = node.getPath();
assertNotNull(pathInfo);
assertTrue(pathInfo.getIsComplete());
assertNotNull(pathInfo.getName());
// the pathInfo should only include the parents (not the requested node)
assertFalse(pathInfo.getName().endsWith(folderC));
assertTrue(pathInfo.getName().startsWith("/Company Home"));
List<ElementInfo> pathElements = pathInfo.getElements();
assertEquals(5, pathElements.size());
assertEquals("Company Home", pathElements.get(0).getName());
assertNotNull(pathElements.get(0).getId());
assertEquals("User Homes", pathElements.get(1).getName());
assertNotNull(pathElements.get(1).getId());
assertEquals(user1, pathElements.get(2).getName());
assertNotNull(pathElements.get(2).getId());
assertEquals(folderA, pathElements.get(3).getName());
assertNotNull(pathElements.get(3).getId());
assertEquals(folderB, pathElements.get(4).getName());
assertNotNull(pathElements.get(4).getId());
}
@Test
public void testGetNodeWithKnownAlias() throws Exception
{
final String rootNodeAlias = "-root-";
HttpResponse response = getSingle(NodesEntityResource.class, user1, rootNodeAlias, null, 200);
Node node = jacksonUtil.parseEntry(response.getJsonResponse(), Node.class);
assertEquals("Company Home", node.getName());
assertNotNull(node.getNodeRef());
PathInfo pathInfo = node.getPath();
// empty JSON object ("path":{})
assertNotNull(pathInfo);
// as this is the root node, there will be no name or path elements.
assertNull(pathInfo.getIsComplete());
assertNull(pathInfo.getName());
assertNull(pathInfo.getElements());
// unknown alias
getSingle(NodesEntityResource.class, user1, "testSomeUndefinedAlias", null, 404);
final String userNodeAlias = "-my-";
response = getSingle(NodesEntityResource.class, user1, userNodeAlias, null, 200);
node = jacksonUtil.parseEntry(response.getJsonResponse(), Node.class);
NodeRef myFilesNodeRef = node.getNodeRef();
assertNotNull(myFilesNodeRef);
assertEquals(user1, node.getName());
assertTrue(node.getIsFolder());
pathInfo = node.getPath();
assertNotNull(pathInfo);
assertTrue(pathInfo.getIsComplete());
//Delete user1's home
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
repoService.getNodeService().deleteNode(myFilesNodeRef);
AuthenticationUtil.setFullyAuthenticatedUser(user1);
getSingle(NodesEntityResource.class, user1, userNodeAlias, null, 404); // Not found
}
private String getChildrenUrl(NodeRef nodeRef)
{
return "nodes/" + nodeRef.getId() + "/children";
}
@Override
public String getScope()
{
return "public";
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2005-2015 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* 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/>.
*/
package org.alfresco.rest.api.tests.util;
import static org.junit.Assert.assertNotNull;
import org.alfresco.rest.framework.jacksonextensions.JacksonHelper;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
/**
* @author Jamal Kaabi-Mofrad
*/
public class JacksonUtil
{
private JacksonHelper jsonHelper;
public JacksonUtil(JacksonHelper jsonHelper)
{
this.jsonHelper = jsonHelper;
}
public <T> List<T> parseEntries(JSONObject jsonObject, Class<T> clazz) throws IOException
{
assertNotNull(jsonObject);
assertNotNull(clazz);
List<T> models = new ArrayList<>();
JSONObject jsonList = (JSONObject) jsonObject.get("list");
assertNotNull(jsonList);
JSONArray jsonEntries = (JSONArray) jsonList.get("entries");
assertNotNull(jsonEntries);
for (Object entry : jsonEntries)
{
JSONObject jsonEntry = (JSONObject) entry;
T pojoModel = parseEntry(jsonEntry, clazz);
models.add(pojoModel);
}
return models;
}
public <T> T parseEntry(JSONObject jsonObject, Class<T> clazz) throws IOException
{
assertNotNull(jsonObject);
assertNotNull(clazz);
JSONObject entry = (JSONObject) jsonObject.get("entry");
T pojoModel = jsonHelper.construct(new StringReader(entry.toJSONString()), clazz);
assertNotNull(pojoModel);
return pojoModel;
}
}