CMIS Allowable Actions REST binding (part 1)

- add getAllowableActions()
- update getProperties(), getChildren() with includeAllowableActions flag
- testAllowableActions()

TODO:
- add includeAllowableActions flag for all other required methods
- Abdera extension to parse allowable actions

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13834 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
David Caruana
2009-04-03 21:19:31 +00:00
parent 697f6da71b
commit f11b1e8ffa
22 changed files with 154 additions and 30 deletions

View File

@@ -15,7 +15,7 @@
[#-- ATOM Entry for Document --] [#-- ATOM Entry for Document --]
[#-- --] [#-- --]
[#macro document node propfilter="*" ns=""] [#macro document node propfilter="*" includeallowableactions=false includerelationships="none" ns=""]
[@entry ns] [@entry ns]
<author><name>${node.properties.creator!""}</name></author> <author><name>${node.properties.creator!""}</name></author>
[@contentstream node/] [@contentstream node/]
@@ -31,6 +31,7 @@
<updated>${xmldate(node.properties.modified)}</updated> <updated>${xmldate(node.properties.modified)}</updated>
<cmis:object> <cmis:object>
[@documentCMISProps node propfilter/] [@documentCMISProps node propfilter/]
[#if includeallowableactions][@allowableactions node/][/#if]
</cmis:object> </cmis:object>
<cmis:terminator/> <cmis:terminator/>
<app:edited>${xmldate(node.properties.modified)}</app:edited> <app:edited>${xmldate(node.properties.modified)}</app:edited>
@@ -93,7 +94,7 @@
[#-- ATOM Entry for Private Working Copy --] [#-- ATOM Entry for Private Working Copy --]
[#-- --] [#-- --]
[#macro pwc node propfilter="*" ns=""] [#macro pwc node propfilter="*" includeallowableactions=false includerelationships="none" ns=""]
[@entry ns] [@entry ns]
<author><name>${node.properties.creator}</name></author> <author><name>${node.properties.creator}</name></author>
[@contentstream node/] [@contentstream node/]
@@ -123,7 +124,7 @@
[#-- ATOM Entry for Folder --] [#-- ATOM Entry for Folder --]
[#-- --] [#-- --]
[#macro folder node propfilter="*" typesfilter="any" ns="" depth=1 maxdepth=1] [#macro folder node propfilter="*" typesfilter="any" includeallowableactions=false includerelationships="none" ns="" depth=1 maxdepth=1]
[@entry ns] [@entry ns]
<author><name>${node.properties.creator}</name></author> <author><name>${node.properties.creator}</name></author>
<content>${node.id}</content> [#-- TODO --] <content>${node.id}</content> [#-- TODO --]
@@ -138,14 +139,15 @@
<cmis:object> <cmis:object>
[#-- recurse for depth greater than 1 --] [#-- recurse for depth greater than 1 --]
[@folderCMISProps node propfilter/] [@folderCMISProps node propfilter/]
[#if includeallowableactions][@allowableactions node/][/#if]
</cmis:object> </cmis:object>
[#if depth < maxdepth || depth == -1] [#if depth < maxdepth || depth == -1]
[#list cmischildren(node, typesfilter) as child] [#list cmischildren(node, typesfilter) as child]
[#if child.isDocument] [#if child.isDocument]
[@entryLib.document child propfilter/] [@entryLib.document child propfilter includeallowableactions includerelationships/]
[#else] [#else]
[@entryLib.folder child propfilter/] [@entryLib.folder child propfilter includeallowableactions includerelationships/]
[@folder child propfilter typesfilter ns depth+1 maxdepth/] [@folder child propfilter typesfilter includeallowableactions includerelationships ns depth+1 maxdepth/]
[/#if] [/#if]
[/#list] [/#list]
[/#if] [/#if]
@@ -304,6 +306,25 @@
[#macro idvalue value]<cmis:value>${value}</cmis:value>[/#macro] [#macro idvalue value]<cmis:value>${value}</cmis:value>[/#macro]
[#-- --]
[#-- CMIS Allowable Actions --]
[#-- --]
[#macro allowableactions node ns=""]
<cmis:allowableActions[#if ns != ""] ${ns}[/#if]>
[#nested]
[#assign typedef = cmistype(node)]
[#list typedef.actionEvaluators?values as actionevaluator]
[@allowableaction node actionevaluator/]
[/#list]
</cmis:allowableActions>
[/#macro]
[#macro allowableaction node actionevaluator]
<cmis:${actionevaluator.action.label}>${actionevaluator.isAllowed(node.nodeRef)?string}</cmis:${actionevaluator.action.label}>
[/#macro]
[#-- --] [#-- --]
[#-- ATOM Entry for Type Definition --] [#-- ATOM Entry for Type Definition --]
[#-- --] [#-- --]

View File

@@ -7,3 +7,4 @@
[#macro serviceNS]xmlns="[@appNS/]" xmlns:atom="[@atomNS/]" xmlns:cmis="[@cmisNS/]" xmlns:alf="[@alfNS/]"[/#macro] [#macro serviceNS]xmlns="[@appNS/]" xmlns:atom="[@atomNS/]" xmlns:cmis="[@cmisNS/]" xmlns:alf="[@alfNS/]"[/#macro]
[#macro feedNS]xmlns="[@atomNS/]" xmlns:app="[@appNS/]" xmlns:cmis="[@cmisNS/]" xmlns:alf="[@alfNS/]" xmlns:opensearch="[@opensearchNS/]"[/#macro] [#macro feedNS]xmlns="[@atomNS/]" xmlns:app="[@appNS/]" xmlns:cmis="[@cmisNS/]" xmlns:alf="[@alfNS/]" xmlns:opensearch="[@opensearchNS/]"[/#macro]
[#macro entryNS]xmlns="[@atomNS/]" xmlns:app="[@appNS/]" xmlns:cmis="[@cmisNS/]" xmlns:alf="[@alfNS/]"[/#macro] [#macro entryNS]xmlns="[@atomNS/]" xmlns:app="[@appNS/]" xmlns:cmis="[@cmisNS/]" xmlns:alf="[@alfNS/]"[/#macro]
[#macro allowableactionsNS]xmlns:cmis="[@cmisNS/]"[/#macro]

View File

@@ -0,0 +1,13 @@
[#ftl]
[#import "/org/alfresco/cmis/ns.lib.atom.ftl" as nsLib/]
[#import "/org/alfresco/cmis/atomentry.lib.atom.ftl" as entryLib/]
[#compress]
<?xml version="1.0" encoding="UTF-8"?>
[#assign namespace][@nsLib.allowableactionsNS/][/#assign]
[@entryLib.allowableactions node=node ns=namespace]
<cmis:parentId>${cmisproperty(node, "ObjectId")}</cmis:parentId>
<cmis:parentUrl>${absurl(url.serviceContext)}/api/node/${node.nodeRef.storeRef.protocol}/${node.nodeRef.storeRef.identifier}/${node.nodeRef.id}</cmis:parentUrl>
[/@entryLib.allowableactions]
[/#compress]

View File

@@ -0,0 +1,9 @@
<webscript>
<shortname>Retrieve Allowable Actions</shortname>
<description>Retrieve Allowable Actions</description>
<url>/api/node/{store_type}/{store_id}/{id}/permissions</url>
<url>/api/path/{store_type}/{store_id}/{id}/permissions</url>
<authentication>guest</authentication>
<format default="atomentry">argument</format>
<family>CMIS</family>
</webscript>

View File

@@ -0,0 +1,17 @@
script:
{
// locate node
var pathSegments = url.match.split("/");
var reference = [ url.templateArgs.store_type, url.templateArgs.store_id ].concat(url.templateArgs.id.split("/"));
model.node = cmis.findNode(pathSegments[2], reference);
if (model.node === null)
{
status.code = 404;
status.message = "Repository " + pathSegments[2] + " " + reference.join("/") + " not found";
status.redirect = true;
break script;
}
// TODO: handle version??
}

View File

@@ -14,7 +14,7 @@
[#list results as child] [#list results as child]
[#if child.isDocument] [#if child.isDocument]
[@entryLib.pwc child filter/] [@entryLib.pwc node=child propfilter=filter includeallowableactions=false includerelationships="none"/]
[/#if] [/#if]
[/#list] [/#list]

View File

@@ -5,6 +5,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
[#assign namespace][@nsLib.entryNS/][/#assign] [#assign namespace][@nsLib.entryNS/][/#assign]
[@entryLib.pwc node=pwc ns=namespace/] [@entryLib.pwc node=pwc includeallowableactions=true includerelationships="none" ns=namespace/]
[/#compress] [/#compress]

View File

@@ -14,9 +14,9 @@
[#list results as child] [#list results as child]
[#if child.isDocument] [#if child.isDocument]
[@entryLib.document child filter/] [@entryLib.document node=child propfilter=filter includeallowableactions=includeAllowableActions/]
[#else] [#else]
[@entryLib.folder child filter/] [@entryLib.folder node=child propfilter=filter includeallowableactions=includeAllowableActions/]
[/#if] [/#if]
[/#list] [/#list]

View File

@@ -34,8 +34,8 @@ If “includeAllowableActions” is TRUE, the repository will return the allowab
If no “maxItems” value is provided, then the Repository will determine an appropriate number of items to return. How the Repository determines this value is repository-specific and opaque to CMIS.<br> If no “maxItems” value is provided, then the Repository will determine an appropriate number of items to return. How the Repository determines this value is repository-specific and opaque to CMIS.<br>
]]> ]]>
</description> </description>
<url>/api/node/{store_type}/{store_id}/{id}/children?types={types}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}</url> <url>/api/node/{store_type}/{store_id}/{id}/children?types={types}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<url>/api/path/{store_type}/{store_id}/{id}/children?types={types}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}</url> <url>/api/path/{store_type}/{store_id}/{id}/children?types={types}&amp;filter={filter?}&amp;skipCount={skipCount?}&amp;maxItems={maxItems?}&amp;includeAllowableActions={includeAllowableActions?}</url>
<authentication>guest</authentication> <authentication>guest</authentication>
<format default="atomfeed">argument</format> <format default="atomfeed">argument</format>
<family>CMIS</family> <family>CMIS</family>

View File

@@ -29,6 +29,10 @@ script:
model.filter = "*"; model.filter = "*";
} }
// include allowable actions
var includeAllowableActions = cmis.findArg(args.includeAllowableActions, headers["CMIS-includeAllowableActions"]);
model.includeAllowableActions = (includeAllowableActions == "true" ? true : false);
// retrieve children // retrieve children
var page = paging.createPageOrWindow(args, headers); var page = paging.createPageOrWindow(args, headers);
var paged = cmis.queryChildren(model.node, model.types, page); var paged = cmis.queryChildren(model.node, model.types, page);

View File

@@ -7,9 +7,9 @@
[#assign namespace][@nsLib.entryNS/][/#assign] [#assign namespace][@nsLib.entryNS/][/#assign]
[#if node.isDocument] [#if node.isDocument]
[@entryLib.document node=node ns=namespace/] [@entryLib.document node=node propfilter="*" includeallowableactions=true includerelationships=true ns=namespace/]
[#else] [#else]
[@entryLib.folder node=node ns=namespace/] [@entryLib.folder node=node propfilter="*" includeallowableactions=true includerelationships=true ns=namespace/]
[/#if] [/#if]
[/#compress] [/#compress]

View File

@@ -12,9 +12,9 @@
[#if depth &gt; 0 || depth == -1] [#if depth &gt; 0 || depth == -1]
[#list cmischildren(node, typesFilter) as child] [#list cmischildren(node, typesFilter) as child]
[#if child.isDocument] [#if child.isDocument]
[@entryLib.document node=child propfilter=propFilter/] [@entryLib.document node=child propfilter=propFilter includeallowableactions=false includerelationships=false/]
[#else] [#else]
[@entryLib.folder node=child propfilter=propFilter typesfilter=typeFilter depth=1 maxdepth=depth/] [@entryLib.folder node=child propfilter=propFilter typesfilter=typeFilter includeallowableactions=false includerelationships=false depth=1 maxdepth=depth/]
[/#if] [/#if]
[/#list] [/#list]
[/#if] [/#if]

View File

@@ -8,9 +8,9 @@
[#assign namespace][@nsLib.entryNS/][/#assign] [#assign namespace][@nsLib.entryNS/][/#assign]
[#if node.isDocument] [#if node.isDocument]
[@entryLib.document node=node ns=namespace/] [@entryLib.document node=node propfilter="*" includeallowableactions=false includerelationships="none" ns=namespace/]
[#else] [#else]
[@entryLib.folder node=node ns=namespace/] [@entryLib.folder node=node propfilter="*" includeallowableactions=false includerelationships="none" ns=namespace/]
[/#if] [/#if]
[/#compress] [/#compress]

View File

@@ -7,9 +7,9 @@
[#assign namespace][@nsLib.entryNS/][/#assign] [#assign namespace][@nsLib.entryNS/][/#assign]
[#if node.isDocument] [#if node.isDocument]
[@entryLib.document node=node propfilter=filter ns=namespace/] [@entryLib.document node=node propfilter=filter includeallowableactions=includeAllowableActions includerelationships="none" ns=namespace/]
[#else] [#else]
[@entryLib.folder node=node propfilter=filter ns=namespace/] [@entryLib.folder node=node propfilter=filter includeallowableactions=includeAllowableActions includerelationships="none" ns=namespace/]
[/#if] [/#if]
[/#compress] [/#compress]

View File

@@ -21,4 +21,7 @@ script:
model.filter = "*"; model.filter = "*";
} }
// include allowable actions
var includeAllowableActions = cmis.findArg(args.includeAllowableActions, headers["CMIS-includeAllowableActions"]);
model.includeAllowableActions = (includeAllowableActions == "true" ? true : false);
} }

View File

@@ -7,9 +7,9 @@
[#assign namespace][@nsLib.entryNS/][/#assign] [#assign namespace][@nsLib.entryNS/][/#assign]
[#if node.isDocument] [#if node.isDocument]
[@entryLib.document node=node ns=namespace/] [@entryLib.document node=node includeallowableactions=true includerelationships="none" ns=namespace/]
[#else] [#else]
[@entryLib.folder node=node ns=namespace/] [@entryLib.folder node=node includeallowableactions=true includerelationships="none" ns=namespace/]
[/#if] [/#if]
[/#compress] [/#compress]

View File

@@ -18,7 +18,7 @@
[#macro parent node recurse=false] [#macro parent node recurse=false]
[#if node?exists && node.isContainer] [#if node?exists && node.isContainer]
[@entryLib.folder node filter/] [@entryLib.folder node=node propfilter=filter includeallowableactions=false includerelationships="none"/]
[#if recurse && node.id != rootNode.id] [#if recurse && node.id != rootNode.id]
[@parent node.parent true/] [@parent node.parent true/]
[/#if] [/#if]

View File

@@ -18,7 +18,7 @@
[#macro parent node recurse=false] [#macro parent node recurse=false]
[#if node?exists && node.isContainer] [#if node?exists && node.isContainer]
[@entryLib.folder node filter/] [@entryLib.folder node=node propfilter=filter includeallowableactions=false includerelationships="none"/]
[#if recurse && node.id != rootNode.id] [#if recurse && node.id != rootNode.id]
[@parent node.parent true/] [@parent node.parent true/]
[/#if] [/#if]

View File

@@ -6,6 +6,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
[#assign namespace][@nsLib.entryNS/][/#assign] [#assign namespace][@nsLib.entryNS/][/#assign]
[@entryLib.pwc node=node ns=namespace/] [@entryLib.pwc node=node includeallowableactions=false includerelationships="none" ns=namespace/]
[/#compress] [/#compress]

View File

@@ -7,9 +7,9 @@
[#assign namespace][@nsLib.entryNS/][/#assign] [#assign namespace][@nsLib.entryNS/][/#assign]
[#if checkin] [#if checkin]
[@entryLib.document node=node ns=namespace/] [@entryLib.document node=node includeallowableactions=true includerelationships="none" ns=namespace/]
[#else] [#else]
[@entryLib.pwc node=node ns=namespace/] [@entryLib.pwc node=node includeallowableactions=true includerelationships="none" ns=namespace/]
[/#if] [/#if]
[/#compress] [/#compress]

View File

@@ -34,5 +34,5 @@ script:
// handle property definitions // handle property definitions
// TODO: spec issue 34 // TODO: spec issue 34
var returnPropertyDefinitions = cmis.findArg(args.includePropertyDefinitions, headers["CMIS-includePropertyDefinitions"]); var returnPropertyDefinitions = cmis.findArg(args.includePropertyDefinitions, headers["CMIS-includePropertyDefinitions"]);
model.returnPropertyDefinitions = returnPropertyDefinitions == "true" ? true : false; model.returnPropertyDefinitions = (returnPropertyDefinitions == "true" ? true : false);
} }

View File

@@ -1,6 +1,6 @@
/* /*
*
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
*
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 * as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
@@ -554,6 +554,62 @@ public class CMISTest extends BaseCMISWebScriptTest
assertEquals("updated content " + guid, contentRes.getContentAsString()); assertEquals("updated content " + guid, contentRes.getContentAsString());
} }
public void testAllowableActions()
throws Exception
{
// retrieve test folder for allowable actions
Entry testFolder = createTestFolder("testAllowableActions");
Link childrenLink = testFolder.getLink(CMISConstants.REL_CHILDREN);
assertNotNull(childrenLink);
// test allowable actions for folder
{
Entry child = createFolder(childrenLink.getHref(), "testFolderAllowableActions");
assertNotNull(child);
Link allowableActions = child.getLink(CMISConstants.REL_ALLOWABLEACTIONS);
Response allowableActionsRes = sendRequest(new GetRequest(allowableActions.getHref().toString()), 200, getAtomValidator());
assertNotNull(allowableActionsRes);
// TODO: parse response with Abdera extension
// retrieve getProperties() with includeAllowableActions flag
Map<String, String> args = new HashMap<String, String>();
args.put("includeAllowableActions", "true");
Response getPropertiesRes = sendRequest(new GetRequest(child.getSelfLink().getHref().toString()).setArgs(args), 200, getAtomValidator());
assertNotNull(getPropertiesRes);
// TODO: parse response with Abdera extension
// TODO: test equality between getAllowableActions and getProperties
}
// test allowable actions for document
{
Entry child = createDocument(childrenLink.getHref(), "testDocumentAllowableActions");
assertNotNull(child);
Link allowableActions = child.getLink(CMISConstants.REL_ALLOWABLEACTIONS);
Response allowableActionsRes = sendRequest(new GetRequest(allowableActions.getHref().toString()), 200, getAtomValidator());
assertNotNull(allowableActionsRes);
// TODO: parse response with Abdera extension
// retrieve getProperties() with includeAllowableActions flag
Map<String, String> args = new HashMap<String, String>();
args.put("includeAllowableActions", "true");
Response getPropertiesRes = sendRequest(new GetRequest(child.getSelfLink().getHref().toString()).setArgs(args), 200, getAtomValidator());
assertNotNull(getPropertiesRes);
// TODO: parse response with Abdera extension
// TODO: test equality between getAllowableActions and getProperties
}
// test allowable actions for children
{
Map<String, String> args = new HashMap<String, String>();
args.put("includeAllowableActions", "true");
Response allowableActionsRes = sendRequest(new GetRequest(childrenLink.getHref().toString()).setArgs(args), 200, getAtomValidator());
assertNotNull(allowableActionsRes);
// TODO: parse response with Abdera extension
}
}
public void testGetCheckedOut() public void testGetCheckedOut()
throws Exception throws Exception
{ {