Merged HEAD (5.2) to 5.2.N (5.2.1)

126351 jkaabimofrad: 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/BRANCHES/DEV/5.2.N/root@126696 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Ancuta Morarasu
2016-05-11 10:46:38 +00:00
parent 38f735e453
commit d05f7bb484
11 changed files with 1793 additions and 921 deletions

View File

@@ -428,10 +428,23 @@
</list> </list>
</property> </property>
</bean> </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="serviceRegistry" ref="ServiceRegistry"/>
<property name="repositoryHelper" ref="repositoryHelper"/> <property name="repositoryHelper" ref="repositoryHelper"/>
<property name="ignoreTypes" ref="nodes.ignoreTypes"/>
</bean> </bean>
<bean id="Nodes" class="org.springframework.aop.framework.ProxyFactoryBean"> <bean id="Nodes" class="org.springframework.aop.framework.ProxyFactoryBean">

View File

@@ -36,6 +36,7 @@ import org.alfresco.rest.api.model.Document;
import org.alfresco.rest.api.model.Folder; import org.alfresco.rest.api.model.Folder;
import org.alfresco.rest.api.model.Node; import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.PathInfo; 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.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.content.BasicContentInfo; import org.alfresco.rest.framework.resource.content.BasicContentInfo;
@@ -53,11 +54,14 @@ import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.model.FileFolderService; import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo; import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.model.FileNotFoundException; 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.ContentData;
import org.alfresco.service.cmr.repository.ContentWriter; import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.InvalidNodeRefException; import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; 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.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus; import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService; import org.alfresco.service.cmr.security.PermissionService;
@@ -76,6 +80,7 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
/** /**
@@ -83,6 +88,7 @@ import java.util.Set;
* *
* @author steveglover * @author steveglover
* @author janv * @author janv
* @author Jamal Kaabi-Mofrad
* *
* @since publicapi1.0 * @since publicapi1.0
*/ */
@@ -90,22 +96,36 @@ public class NodesImpl implements Nodes
{ {
private static enum Type private static enum Type
{ {
// Note: ordered // Note: ordered
DOCUMENT, FOLDER; DOCUMENT, FOLDER;
}; };
private final static String PATH_ROOT = "-root-"; private final static String PATH_ROOT = "-root-";
private final static String PATH_MY = "-my-"; private final static String PATH_MY = "-my-";
private final static String PATH_SHARED = "-shared-"; private final static String PATH_SHARED = "-shared-";
private NodeService nodeService; private NodeService nodeService;
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
private FileFolderService fileFolderService; private FileFolderService fileFolderService;
private NamespaceService namespaceService; private NamespaceService namespaceService;
private PermissionService permissionService; private PermissionService permissionService;
private Repository repositoryHelper; private Repository repositoryHelper;
private ServiceRegistry sr; 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) { public void setServiceRegistry(ServiceRegistry sr) {
this.sr = sr; this.sr = sr;
@@ -121,6 +141,11 @@ public class NodesImpl implements Nodes
this.repositoryHelper = repositoryHelper; this.repositoryHelper = repositoryHelper;
} }
public void setIgnoreTypes(Set<String> ignoreTypes)
{
this.defaultIgnoreTypes = ignoreTypes;
}
private static final List<QName> EXCLUDED_ASPECTS = Arrays.asList( private static final List<QName> EXCLUDED_ASPECTS = Arrays.asList(
ContentModel.ASPECT_REFERENCEABLE, ContentModel.ASPECT_REFERENCEABLE,
ContentModel.ASPECT_LOCALIZED); ContentModel.ASPECT_LOCALIZED);
@@ -176,47 +201,46 @@ public class NodesImpl implements Nodes
new HashSet<>(Arrays.asList(new String[] {PARAM_ISFOLDER})); new HashSet<>(Arrays.asList(new String[] {PARAM_ISFOLDER}));
/* /*
* * Note: assumes workspace://SpacesStore
* Note: assumes workspace://SpacesStore */
*/ public NodeRef validateNode(String nodeId)
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)
{ {
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()); throw new EntityNotFoundException(nodeRef.getId());
} }
@@ -226,35 +250,35 @@ public class NodesImpl implements Nodes
protected boolean typeMatches(QName type, Set<QName> expectedTypes, Set<QName> excludedTypes) protected boolean typeMatches(QName type, Set<QName> expectedTypes, Set<QName> excludedTypes)
{ {
Set<QName> allExpectedTypes = new HashSet<>(); Set<QName> allExpectedTypes = new HashSet<>();
if (expectedTypes != null) if (expectedTypes != null)
{ {
for (QName expectedType : expectedTypes) for (QName expectedType : expectedTypes)
{ {
allExpectedTypes.addAll(dictionaryService.getSubTypes(expectedType, true)); allExpectedTypes.addAll(dictionaryService.getSubTypes(expectedType, true));
} }
} }
Set<QName> allExcludedTypes = new HashSet<>(); Set<QName> allExcludedTypes = new HashSet<>();
if (excludedTypes != null) if (excludedTypes != null)
{ {
for (QName excludedType : excludedTypes) for (QName excludedType : excludedTypes)
{ {
allExcludedTypes.addAll(dictionaryService.getSubTypes(excludedType, true)); allExcludedTypes.addAll(dictionaryService.getSubTypes(excludedType, true));
} }
} }
boolean inExpected = allExpectedTypes.contains(type); boolean inExpected = allExpectedTypes.contains(type);
boolean excluded = allExcludedTypes.contains(type); boolean excluded = allExcludedTypes.contains(type);
return(inExpected && !excluded); return (inExpected && !excluded);
} }
/** /**
* @deprecated review usage (backward compat') * @deprecated review usage (backward compat')
*/ */
public Node getNode(String nodeId) public Node getNode(String nodeId)
{ {
NodeRef nodeRef = validateNode(nodeId); NodeRef nodeRef = validateNode(nodeId);
return new Node(nodeRef, null, nodeService.getProperties(nodeRef), sr); return new Node(nodeRef, null, nodeService.getProperties(nodeRef), sr);
} }
@@ -266,17 +290,17 @@ public class NodesImpl implements Nodes
{ {
return new Node(nodeRef, null, nodeService.getProperties(nodeRef), sr); return new Node(nodeRef, null, nodeService.getProperties(nodeRef), sr);
} }
private Type getType(NodeRef nodeRef) private Type getType(NodeRef nodeRef)
{ {
return getType(nodeService.getType(nodeRef)); return getType(nodeService.getType(nodeRef));
} }
private Type getType(QName type) private Type getType(QName type)
{ {
boolean isContainer = Boolean.valueOf((dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true && boolean isContainer = Boolean.valueOf((dictionaryService.isSubClass(type, ContentModel.TYPE_FOLDER) == true
!dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER))); && !dictionaryService.isSubClass(type, ContentModel.TYPE_SYSTEM_FOLDER)));
return isContainer ? Type.FOLDER : Type.DOCUMENT; return isContainer ? Type.FOLDER : Type.DOCUMENT;
} }
/** /**
@@ -284,14 +308,14 @@ public class NodesImpl implements Nodes
*/ */
public Document getDocument(NodeRef nodeRef) public Document getDocument(NodeRef nodeRef)
{ {
Type type = getType(nodeRef); Type type = getType(nodeRef);
if (type.equals(Type.DOCUMENT)) if (type.equals(Type.DOCUMENT))
{ {
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef); Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
Document doc = new Document(nodeRef, getParentNodeRef(nodeRef), properties, sr); 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); ContentData cd = (ContentData) properties.get(ContentModel.PROP_CONTENT);
if (cd != null) if (cd != null)
{ {
@@ -300,12 +324,12 @@ public class NodesImpl implements Nodes
} }
setCommonProps(doc, nodeRef, properties); setCommonProps(doc, nodeRef, properties);
return doc; return doc;
} }
else else
{ {
throw new InvalidArgumentException("Node is not a file"); throw new InvalidArgumentException("Node is not a file");
} }
} }
private void setCommonProps(Node node, NodeRef nodeRef, Map<QName,Serializable> properties) private void setCommonProps(Node node, NodeRef nodeRef, Map<QName,Serializable> properties)
@@ -316,25 +340,25 @@ public class NodesImpl implements Nodes
node.setModifiedBy((String)properties.get(ContentModel.PROP_MODIFIER)); node.setModifiedBy((String)properties.get(ContentModel.PROP_MODIFIER));
node.setCreatedBy((String)properties.get(ContentModel.PROP_CREATOR)); node.setCreatedBy((String)properties.get(ContentModel.PROP_CREATOR));
} }
/** /**
* @deprecated note: currently required for backwards compat' (Favourites API) * @deprecated note: currently required for backwards compat' (Favourites API)
*/ */
public Folder getFolder(NodeRef nodeRef) public Folder getFolder(NodeRef nodeRef)
{ {
Type type = getType(nodeRef); Type type = getType(nodeRef);
if (type.equals(Type.FOLDER)) if (type.equals(Type.FOLDER))
{ {
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef); 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); setCommonProps(folder, nodeRef, properties);
return folder; return folder;
} }
else else
{ {
throw new InvalidArgumentException("Node is not a folder"); throw new InvalidArgumentException("Node is not a folder");
} }
} }
private NodeRef getParentNodeRef(final NodeRef nodeRef) { private NodeRef getParentNodeRef(final NodeRef nodeRef) {
@@ -346,38 +370,44 @@ public class NodesImpl implements Nodes
return nodeService.getPrimaryParent(nodeRef).getParentRef(); return nodeService.getPrimaryParent(nodeRef).getParentRef();
} }
private NodeRef validateOrLookupNode(String nodeId, String path) {
NodeRef parentNodeRef;
if (nodeId.equals(PATH_ROOT)) private NodeRef validateOrLookupNode(String nodeId, String path)
{ {
parentNodeRef = repositoryHelper.getCompanyHome(); NodeRef parentNodeRef;
}
if (nodeId.equals(PATH_ROOT))
{
parentNodeRef = repositoryHelper.getCompanyHome();
}
else if (nodeId.equals(PATH_SHARED)) else if (nodeId.equals(PATH_SHARED))
{ {
parentNodeRef = repositoryHelper.getSharedHome(); parentNodeRef = repositoryHelper.getSharedHome();
} }
else if (nodeId.equals(PATH_MY)) else if (nodeId.equals(PATH_MY))
{ {
NodeRef person = repositoryHelper.getPerson(); NodeRef person = repositoryHelper.getPerson();
if (person == null) if (person == null)
{ {
throw new IllegalArgumentException("Unexpected: cannot use "+PATH_MY); throw new InvalidArgumentException("Unexpected: cannot use " + PATH_MY);
} }
parentNodeRef = repositoryHelper.getUserHome(person); parentNodeRef = repositoryHelper.getUserHome(person);
} if (parentNodeRef == null)
else {
{ throw new EntityNotFoundException(nodeId);
parentNodeRef = validateNode(nodeId); }
} }
else
{
parentNodeRef = validateNode(nodeId);
}
if (path != null) { if (path != null)
{
// resolve path relative to current nodeId // resolve path relative to current nodeId
parentNodeRef = resolveNodeByPath(parentNodeRef, path, true); parentNodeRef = resolveNodeByPath(parentNodeRef, path, true);
} }
return parentNodeRef; return parentNodeRef;
} }
protected NodeRef resolveNodeByPath(final NodeRef parentNodeRef, String path, boolean checkForCompanyHome) protected NodeRef resolveNodeByPath(final NodeRef parentNodeRef, String path, boolean checkForCompanyHome)
@@ -431,116 +461,176 @@ public class NodesImpl implements Nodes
return fileInfo.getNodeRef(); 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); public Node getFolderOrDocument(String nodeId, Parameters parameters)
return getFolderOrDocument(nodeRef, getParentNodeRef(nodeRef), typeQName, false);
}
private Node getFolderOrDocument(final NodeRef nodeRef, NodeRef parentNodeRef, QName typeQName, boolean minimalnfo)
{ {
PathInfo pathInfo = null; String path = parameters.getParameter("path");
if (! minimalnfo) 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); pathInfo = lookupPathInfo(nodeRef);
} }
Type type = getType(typeQName); Type type = getType(typeQName);
Node node; Node node;
Map<QName, Serializable> properties = nodeService.getProperties(nodeRef); Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);
if (type.equals(Type.DOCUMENT)) if (type.equals(Type.DOCUMENT))
{ {
node = new Document(nodeRef, parentNodeRef, properties, sr); node = new Document(nodeRef, parentNodeRef, properties, sr);
} }
else if (type.equals(Type.FOLDER)) else if (type.equals(Type.FOLDER))
{ {
// container/folder // container/folder
node = new Folder(nodeRef, parentNodeRef, properties, sr); node = new Folder(nodeRef, parentNodeRef, properties, sr);
} }
else else
{ {
throw new InvalidArgumentException("Node is not a folder or file"); throw new InvalidArgumentException("Node is not a folder or file");
} }
if (! minimalnfo) { if (!minimalnfo)
node.setProperties(mapProperties(properties)); {
node.setProperties(mapProperties(properties, selectedProperties));
node.setAspectNames(mapAspects(nodeService.getAspects(nodeRef))); node.setAspectNames(mapAspects(nodeService.getAspects(nodeRef)));
} }
node.setNodeType(typeQName.toPrefixString(namespaceService)); node.setNodeType(typeQName.toPrefixString(namespaceService));
node.setPath(pathInfo); node.setPath(pathInfo);
return node; return node;
} }
protected PathInfo lookupPathInfo(NodeRef nodeRefIn) protected PathInfo lookupPathInfo(NodeRef nodeRefIn)
{ {
List<PathInfo.ElementInfo> elements = new ArrayList<>(5); // TODO which implementation?
return getPathInfo(nodeRefIn);
NodeRef companyHomeNodeRef = repositoryHelper.getCompanyHome(); // List<PathInfo.ElementInfo> elements = new ArrayList<>(5);
boolean isComplete = true; //
// 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; private PathInfo getPathInfo(NodeRef nodeRef)
while (pNodeRef != null) {
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; ChildAssociationRef elementRef = ((Path.ChildAssocElement) element).getRef();
} if (elementRef.getParentRef() != null)
else {
pNodeRef = nodeService.getPrimaryParent(pNodeRef).getParentRef();
if (pNodeRef == null)
{ {
// belts-and-braces - is it even possible to get here ? NodeRef childNodeRef = elementRef.getChildRef();
isComplete = false; if (permissionService.hasPermission(childNodeRef, PermissionService.READ) == AccessStatus.ALLOWED)
}
else
{
if (permissionService.hasPermission(pNodeRef, PermissionService.READ) == AccessStatus.ALLOWED)
{ {
String name = (String) nodeService.getProperty(pNodeRef, ContentModel.PROP_NAME); Serializable nameProp = nodeService.getProperty(childNodeRef, ContentModel.PROP_NAME);
elements.add(0, new PathInfo().new ElementInfo(pNodeRef.getId(), name)); pathElements.add(0, new ElementInfo(childNodeRef, nameProp.toString()));
} }
else else
{ {
isComplete = false; // Just return the pathInfo up to the location where the user has access
pNodeRef = null; isComplete = Boolean.FALSE;
break;
} }
} }
} }
} }
StringBuilder sb = new StringBuilder(); String pathStr = null;
for (PathInfo.ElementInfo e : elements) 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();
} }
else
return new PathInfo(sb.toString(), isComplete, elements); {
// 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()); Map<String, Object> props = null;
if (!selectedProperties.isEmpty())
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)
{ {
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; return props;
@@ -568,12 +658,19 @@ public class NodesImpl implements Nodes
public CollectionWithPagingInfo<Node> getChildren(String parentFolderNodeId, Parameters parameters) 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 - where (filter) properties - including isFolder
// map - orderBy (sort) properties - including isFolder // map - orderBy (sort) properties - including isFolder
// TODO refactor & fix ! // TODO refactor & fix !
final boolean minimalnfo = (parameters.getSelectedProperties().size() == 0); final boolean minimalnfo = (parameters.getSelectedProperties().size() == 0);
final List<QName> requestedProperties = createQNames(parameters.getSelectedProperties());
boolean includeFolders = true; boolean includeFolders = true;
boolean includeFiles = true; boolean includeFiles = true;
@@ -604,7 +701,7 @@ public class NodesImpl implements Nodes
QName propQname = MAP_PARAM_QNAME.get(sortCol.column); QName propQname = MAP_PARAM_QNAME.get(sortCol.column);
if (propQname == null) if (propQname == null)
{ {
propQname = QName.resolveToQName(namespaceService, sortCol.column); propQname = createQName(sortCol.column);
} }
if (propQname != null) if (propQname != null)
@@ -623,46 +720,40 @@ public class NodesImpl implements Nodes
Paging paging = parameters.getPaging(); 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)) if (! nodeMatches(parentNodeRef, Collections.singleton(ContentModel.TYPE_FOLDER), null))
{ {
throw new InvalidArgumentException("NodeId of folder is expected"); throw new InvalidArgumentException("NodeId of folder is expected");
} }
PagingRequest pagingRequest = Util.getPagingRequest(paging); PagingRequest pagingRequest = Util.getPagingRequest(paging);
final PagingResults<FileInfo> pagingResults = fileFolderService.list(parentNodeRef, includeFiles, includeFolders, null, sortProps, pagingRequest); final PagingResults<FileInfo> pagingResults = fileFolderService.list(parentNodeRef, includeFiles, includeFolders, ignoreTypeQNames, sortProps, pagingRequest);
final List<FileInfo> page = pagingResults.getPage(); final List<FileInfo> page = pagingResults.getPage();
List<Node> nodes = new AbstractList<Node>() List<Node> nodes = new AbstractList<Node>()
{ {
@Override @Override
public Node get(int index) public Node get(int index)
{ {
FileInfo fInfo = page.get(index); FileInfo fInfo = page.get(index);
// basic info by default (unless "select"ed otherwise) // 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 @Override
public int size() public int size()
{ {
return page.size(); return page.size();
} }
}; };
return CollectionWithPagingInfo.asPaged(paging, nodes, pagingResults.hasMoreItems(), pagingResults.getTotalResultCount().getFirst()); return CollectionWithPagingInfo.asPaged(paging, nodes, pagingResults.hasMoreItems(), pagingResults.getTotalResultCount().getFirst());
} }
public void deleteNode(String nodeId) public void deleteNode(String nodeId)
{ {
NodeRef nodeRef = validateNode(nodeId); NodeRef nodeRef = validateNode(nodeId);
fileFolderService.delete(nodeRef); fileFolderService.delete(nodeRef);
} }
@@ -689,8 +780,8 @@ public class NodesImpl implements Nodes
throw new InvalidArgumentException("Node type is expected: "+parentNodeRef+","+nodeName); throw new InvalidArgumentException("Node type is expected: "+parentNodeRef+","+nodeName);
} }
// check that requested type is a (sub-) type of folder or content // check that requested type is a (sub-) type of folder or content
QName nodeTypeQName = QName.resolveToQName(namespaceService, nodeType); QName nodeTypeQName = createQName(nodeType);
Set<QName> contentAndFolders = new HashSet<>(Arrays.asList(ContentModel.TYPE_FOLDER, ContentModel.TYPE_CONTENT)); Set<QName> contentAndFolders = new HashSet<>(Arrays.asList(ContentModel.TYPE_FOLDER, ContentModel.TYPE_CONTENT));
if (! typeMatches(nodeTypeQName, contentAndFolders, null)) { if (! typeMatches(nodeTypeQName, contentAndFolders, null)) {
@@ -703,7 +794,7 @@ public class NodesImpl implements Nodes
if (nodeInfo.getProperties() != null) 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); QName propQName = QName.createQName((String)entry.getKey(), namespaceService);
props.put(propQName, (Serializable)entry.getValue()); props.put(propQName, (Serializable)entry.getValue());
@@ -741,7 +832,7 @@ public class NodesImpl implements Nodes
if (nodeInfo.getProperties() != null) 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); QName propQName = QName.createQName((String)entry.getKey(), namespaceService);
props.put(propQName, (Serializable)entry.getValue()); props.put(propQName, (Serializable)entry.getValue());
@@ -807,4 +898,58 @@ public class NodesImpl implements Nodes
// TODO - hmm - we may wish to return json info !! // TODO - hmm - we may wish to return json info !!
return; 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

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

View File

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

View File

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

View File

@@ -1,64 +1,92 @@
package org.alfresco.rest.api.model; package org.alfresco.rest.api.model;
import java.util.List; import java.util.List;
import org.alfresco.service.cmr.repository.NodeRef;
/** /**
* Representation of a path info * Representation of a path info
* *
* @author janv * @author janv
*
*/ */
public class PathInfo public class PathInfo
{ {
private String name; private String name;
private Boolean isComplete; private Boolean isComplete;
private List<ElementInfo> elements; private List<ElementInfo> elements;
public PathInfo() public PathInfo()
{ {
} }
public PathInfo(String name, Boolean isComplete, List<ElementInfo> elements) public PathInfo(String name, Boolean isComplete, List<ElementInfo> elements)
{ {
this.name = name; this.name = name;
this.isComplete = isComplete; this.isComplete = isComplete;
this.elements = elements; this.elements = elements;
} }
public String getName() { public String getName()
return name; {
} return name;
}
public Boolean getIsComplete() { public Boolean getIsComplete()
return isComplete; {
} return isComplete;
}
public List<ElementInfo> getElements() { public List<ElementInfo> getElements()
return elements; {
} 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) public ElementInfo(NodeRef id, String name)
{ {
this.id = id; this.id = id;
this.name = name; this.name = name;
} }
public String getName() { public String getName()
return name; {
} return name;
}
public String getId() { public NodeRef getId()
return id; {
} 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 * You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.alfresco.rest.api.model; package org.alfresco.rest.api.model;
/** /**
* Representation of a user info * Representation of a user info
* *
* @author janv * @author janv
*
*/ */
public class UserInfo public class UserInfo
{ {
private String userName; private String userName;
private String displayName; private String displayName;
public UserInfo() public UserInfo()
{ {
} }
public UserInfo(String userName, String firstName, String lastName) public UserInfo(String userName, String firstName, String lastName)
{ {
this.userName = userName; this.userName = userName;
this.displayName = ((firstName != null ? firstName + " " : "") + (lastName != null ? lastName : "")).replaceAll("^\\s+|\\s+$", ""); this.displayName = ((firstName != null ? firstName + " " : "") + (lastName != null ? lastName : "")).trim();
} }
public String getDisplayName() { public String getDisplayName()
return displayName; {
} return displayName;
}
public String getUserName() { public String getUserName()
return userName; {
} return userName;
}
@Override
@Override public String toString()
public String toString() {
{ return "User [userName=" + userName + ", displayName=" + displayName + "]";
return "User [userName=" + userName + ", displayName=" + displayName + "]"; }
}
} }

View File

@@ -26,10 +26,17 @@
package org.alfresco.rest.api.tests; package org.alfresco.rest.api.tests;
import static org.junit.Assert.fail; 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.HttpResponse;
import org.alfresco.rest.api.tests.client.PublicApiClient; import org.alfresco.rest.api.tests.client.PublicApiClient;
import org.alfresco.rest.api.tests.client.RequestContext; import org.alfresco.rest.api.tests.client.RequestContext;
import org.alfresco.service.cmr.site.SiteVisibility;
import java.util.Map; import java.util.Map;
@@ -82,9 +89,14 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
} }
protected HttpResponse getAll(String url, String runAsUser, PublicApiClient.Paging paging, int expectedStatus) throws Exception 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)); 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); HttpResponse response = publicApiClient.get(getScope(), url, null, null, null, params);
checkStatus(expectedStatus, response.getStatusCode()); checkStatus(expectedStatus, response.getStatusCode());
@@ -92,6 +104,16 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
return response; 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 protected HttpResponse getSingle(String url, String runAsUser, String entityId, int expectedStatus) throws Exception
{ {
publicApiClient.setRequestContext(new RequestContext(runAsUser)); publicApiClient.setRequestContext(new RequestContext(runAsUser));
@@ -102,6 +124,16 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
return response; 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 protected HttpResponse put(String url, String runAsUser, String entityId, String body, String queryString, int expectedStatus) throws Exception
{ {
publicApiClient.setRequestContext(new RequestContext(runAsUser)); publicApiClient.setRequestContext(new RequestContext(runAsUser));
@@ -132,6 +164,23 @@ public abstract class AbstractBaseApiTest extends EnterpriseTestApi
return person.getId(); 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) protected void checkStatus(int expectedStatus, int actualStatus)
{ {
if (expectedStatus > 0 && expectedStatus != 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;
}
}