Merged BRANCHES/DEV/HEAD_QUICK_SHARE_TMP to HEAD:

41501: Creating Quick Share branch for merging into head
   41524: Merged THOR1 & THOR1_SPRINTS to HEAD_QUICK_SHARE_TMP 
        30997: Firefox scrollbars removed on "invitation" and "signup" pages (now using new helper method Alfresco.util.createYUIOverlay)
        36011: Merged BRANCHES/DEV/THOR1_QUICK_SHARE to BRANCHES/DEV/THOR1_SPRINTS:
           34685: Creating Quick Share branch
           34826: First cut of THOR-1270 "F387: As the link receiver, I can view the Document Preview in the browser without having to login"
           34868: More on THOR-1270 "F387: As the link receiver, I can view the Document Preview in the browser without having to login"
           34901: QuickShare REST API - WIP ... note: API will change :-)
           34933: QuickShare REST API - WIP 
           34934: QuickShare REST API - WIP 
           34941: QuickShare REST API - WIP ... note: API will change :-)
           34989: QuickShare REST API - WIP 
           34995: QuickShare REST API - WIP
           34996: QuickShare REST API - WIP
           35011: QuickShare/PublicView REST API
           35025: F387: As the link receiver, I can view the Document Preview in the browser without having to login
           35035: QuickShare/PublicView REST API
           35052: QuickShare/PublicView REST API
           35069: More on THOR-1270 "F387 As the link receiver, I can view the Document Preview in the browser without having to login"
           35094: Removed cpnfig property that was commited by mistake
           35111: First cut of THOR-1268 "F378: As a user I can choose to share a document"
           35252: THOR-1271 "F388: From the view page, I can easily sign up or login for Alfresco. Sign Up is embedded in the page and Login will redirect you to the Alfresco Login page" partial commit
           35254: First cut of THOR-1268 "F378: As a user I can choose to share a document" part 2
           35255: THOR-1270 "F387: As the link receiver, I can view the Document Preview in the browser without having to login"
           35264: QuickShare/PublicView REST API
           35317: THOR-1322: New metadata doesn't return "webpreview" in thumbnails (part 1)
           35319: QuickShare REST API - fix tenant ref when share'ing
           35330: QuickShare REST API - fix THOR-1322: New metadata doesn't return "webpreview" in thumbnails (part 2)
           35368: QuickShare REST API - THOR-1336: (F418) Get context (nodeRef, siteId, tenantDomain) for a shared_id
           35376: QuickShare REST API - fix THOR-1273 (unshare document)
           35424: THOR-1271 "F388: From the view page, I can easily sign up or login for Alfresco. Sign Up is embedded in the page and Login will redirect you to the Alfresco Login page" partial commit
           35425: THOR-1271 "F388: From the view page, I can easily sign up or login for Alfresco. Sign Up is embedded in the page and Login will redirect you to the Alfresco Login page" partial commit
           35566: Fixed THOR-1268 "F378: As a user I can choose to share a document"
           35617: THOR-1350: Update Slingshot API (doclib2) - make the "qshare:sharedBy" return full details (instead of just userName)
           35624: THOR-1339: QuickShare REST API
           35682: Fixed THOR-1268, THOR-1339 & THOR-1269   
           35935: QuickShare REST API - add "system.quickshare.enabled" prop (if set to false then disables QuickShare service/API)
           35996: Fixed THOR-1369 & THOR-1270  
           35997: Fixed THOR-1369 & THOR-1270 part 2  
           36000: Fixed THOR-1369 & THOR-1270 part 3   
   41550: Merged THOR1 & THOR1_SPRINTS to HEAD_QUICK_SHARE_TMP part 2
   41569: Updated web.xml to add support for URLRewrite filtering for Quick Share
   41572: Merged THOR1 & THOR1_SPRINTS to HEAD_QUICK_SHARE_TMP part 3
   41640: Merged THOR1_SPRINTS to HEAD_QUICK_SHARE_TMP
        36082: THOR-1270 "F387: As the link receiver, I can view the Document Preview in the browser without having to login"
           - Re-added "Document Details" link public share page


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@41736 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Jan Vonka
2012-09-18 14:58:38 +00:00
parent ac389dffb3
commit 4f7aee6432
23 changed files with 1654 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
/*
* Copyright (C) 2005-2012 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.repo.web.scripts.quickshare;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
import org.alfresco.service.cmr.attributes.AttributeService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.util.Pair;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.WebScriptException;
/**
* QuickShare/PublicView
*
* @author janv
*/
public abstract class AbstractQuickShareContent extends DeclarativeWebScript
{
protected NodeService nodeService;
protected AttributeService attributeService;
protected TenantService tenantService;
private boolean enabled = true;
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setAttributeService(AttributeService attributeService)
{
this.attributeService = attributeService;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
protected boolean isEnabled()
{
return this.enabled;
}
protected Pair<String, NodeRef> getTenantNodeRefFromSharedId(final String sharedId)
{
return getTenantNodeRefFromSharedId(attributeService, tenantService, sharedId);
}
/* package */ static Pair<String, NodeRef> getTenantNodeRefFromSharedId(final AttributeService attributeService, final TenantService tenantService, final String sharedId)
{
final NodeRef nodeRef = TenantUtil.runAsDefaultTenant(new TenantRunAsWork<NodeRef>()
{
public NodeRef doWork() throws Exception
{
return (NodeRef)attributeService.getAttribute(ShareContentPost.ATTR_KEY_SHAREDIDS_ROOT, sharedId);
}
});
if (nodeRef == null)
{
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find: " + sharedId);
}
// note: relies on tenant-specific (ie. mangled) nodeRef
String tenantDomain = tenantService.getDomain(nodeRef.getStoreRef().getIdentifier());
return new Pair<String, NodeRef>(tenantDomain, tenantService.getBaseName(nodeRef));
}
}

View File

@@ -0,0 +1,190 @@
/*
* Copyright (C) 2005-2012 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.repo.web.scripts.quickshare;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.thumbnail.ThumbnailDefinition;
import org.alfresco.repo.web.scripts.WebScriptUtil;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.NoSuchPersonException;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
import org.alfresco.service.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* QuickShare/PublicView
*
* GET web script to get limited metadata (including thumbnail defs) => authenticated web script (using a nodeRef)
*
* Note: authenticated web script (equivalent to unauthenticated version - see QuickShareMetaDataGet)
*
* @author janv
*/
public class MetaDataGet extends AbstractQuickShareContent
{
private static final Log logger = LogFactory.getLog(QuickShareMetaDataGet.class);
private PersonService personService;
private ThumbnailService thumbnailService;
public void setPersonService(PersonService personService)
{
this.personService = personService;
}
public void setThumbnailService(ThumbnailService thumbnailService)
{
this.thumbnailService = thumbnailService;
}
@Override
protected Map<String, Object> executeImpl(final WebScriptRequest req, Status status, Cache cache)
{
// create map of params (template vars)
Map<String, String> params = req.getServiceMatch().getTemplateVars();
final NodeRef nodeRef = WebScriptUtil.getNodeRef(params);
if (nodeRef == null)
{
String msg = "A valid NodeRef must be specified!";
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, msg);
}
try
{
Map<String, Object> model = getMetaDataModel(nodeRef);
if (logger.isDebugEnabled())
{
logger.debug("Retrieved limited metadata: "+nodeRef+" ["+model+"]");
}
return model;
}
catch (InvalidNodeRefException inre)
{
logger.error("Unable to find node: "+inre.getNodeRef());
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find nodeRef: "+inre.getNodeRef());
}
}
@SuppressWarnings("unchecked")
protected Map<String, Object> getMetaDataModel(NodeRef nodeRef)
{
QName typeQName = nodeService.getType(nodeRef);
if (! typeQName.equals(ContentModel.TYPE_CONTENT))
{
throw new InvalidNodeRefException(nodeRef);
}
Map<QName, Serializable> nodeProps = nodeService.getProperties(nodeRef);
ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
String modifierUserName = (String)nodeProps.get(ContentModel.PROP_MODIFIER);
Map<QName, Serializable> personProps = null;
if (modifierUserName != null)
{
try
{
NodeRef personRef = personService.getPerson(modifierUserName);
if (personRef != null)
{
personProps = nodeService.getProperties(personRef);
}
}
catch (NoSuchPersonException nspe)
{
// absorb this exception - eg. System (or maybe the user has been deleted)
if (logger.isInfoEnabled())
{
logger.info("MetaDataGet - no such person: "+modifierUserName);
}
}
}
Map<String, Object> metadata = new HashMap<String, Object>(8);
metadata.put("name", nodeProps.get(ContentModel.PROP_NAME));
metadata.put("title", nodeProps.get(ContentModel.PROP_TITLE));
if (contentData != null)
{
metadata.put("mimetype", contentData.getMimetype());
metadata.put("size", contentData.getSize());
}
else
{
metadata.put("size", 0L);
}
metadata.put("modified", nodeProps.get(ContentModel.PROP_MODIFIED));
if (personProps != null)
{
metadata.put("modifierFirstName", personProps.get(ContentModel.PROP_FIRSTNAME));
metadata.put("modifierLastName", personProps.get(ContentModel.PROP_LASTNAME));
}
// thumbnail defs for this nodeRef
List<String> thumbnailDefs = new ArrayList<String>(7);
if (contentData != null)
{
// Note: thumbnail defs only appear in this list if they can produce a thumbnail for the content
// found in the content property of this node. This will be determined by looking at the mimetype of the content
// and the destination mimetype of the thumbnail.
List<ThumbnailDefinition> thumbnailDefinitions = thumbnailService.getThumbnailRegistry().getThumbnailDefinitions(contentData.getMimetype(), contentData.getSize());
for (ThumbnailDefinition thumbnailDefinition : thumbnailDefinitions)
{
thumbnailDefs.add(thumbnailDefinition.getName());
}
}
metadata.put("thumbnailDefinitions", thumbnailDefs);
// thumbnail instances for this nodeRef
List<NodeRef> thumbnailRefs = thumbnailService.getThumbnails(nodeRef, ContentModel.PROP_CONTENT, null, null);
List<String> thumbnailNames = new ArrayList<String>(thumbnailRefs.size());
for (NodeRef thumbnailRef : thumbnailRefs)
{
thumbnailNames.add((String)nodeService.getProperty(thumbnailRef, ContentModel.PROP_NAME));
}
metadata.put("thumbnailNames", thumbnailNames);
metadata.put("lastThumbnailModificationData", (List<String>)nodeProps.get(ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA));
Map<String, Object> model = new HashMap<String, Object>(1);
model.put("item", metadata);
return model;
}
}

View File

@@ -0,0 +1,174 @@
/*
* Copyright (C) 2005-2012 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.repo.web.scripts.quickshare;
import java.io.IOException;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.model.QuickShareModel;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
import org.alfresco.repo.web.scripts.content.ContentGet;
import org.alfresco.service.cmr.attributes.AttributeService;
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.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
/**
* QuickShare/PublicView
*
* GET web script to get stream "shared" content (ie. enabled for public/unauthenticated access) from the repository
*
* WARNING: **unauthenticated** web script (equivalent to authenticated version - see ContentGet.java)
*
* @author janv
*/
public class QuickShareContentGet extends ContentGet
{
private static final Log logger = LogFactory.getLog(QuickShareContentGet.class);
private NodeService nodeService;
private NamespaceService namespaceService;
private AttributeService attributeService;
private TenantService tenantService;
private boolean enabled = true;
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
super.setNodeService(nodeService);
}
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
super.setNamespaceService(namespaceService);
}
public void setAttributeService(AttributeService attributeService)
{
this.attributeService = attributeService;
}
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
public void setEnabled(boolean enabled)
{
this.enabled = enabled;
}
protected boolean isEnabled()
{
return this.enabled;
}
@Override
public void execute(final WebScriptRequest req, final WebScriptResponse res) throws IOException
{
if (! isEnabled())
{
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "QuickShare is disabled system-wide");
}
// create map of template vars (params)
final Map<String, String> params = req.getServiceMatch().getTemplateVars();
final String sharedId = params.get("shared_id");
if (sharedId == null)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "A valid sharedId must be specified !");
}
try
{
Pair<String, NodeRef> pair = ShareContentPost.getTenantNodeRefFromSharedId(attributeService, tenantService, sharedId);
final String tenantDomain = pair.getFirst();
final NodeRef nodeRef = pair.getSecond();
TenantUtil.runAsSystemTenant(new TenantRunAsWork<Void>()
{
public Void doWork() throws Exception
{
if (! nodeService.getAspects(nodeRef).contains(QuickShareModel.ASPECT_QSHARE))
{
throw new InvalidNodeRefException(nodeRef);
}
executeImpl(nodeRef, params, req, res, null);
return null;
}
}, tenantDomain);
if (logger.isDebugEnabled())
{
logger.debug("QuickShare - retrieved content: "+sharedId+" ["+nodeRef+"]");
}
}
catch (InvalidNodeRefException inre)
{
logger.error("Unable to find: "+sharedId+" ["+inre.getNodeRef()+"]");
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find: "+sharedId);
}
}
protected void executeImpl(NodeRef nodeRef, Map<String, String> templateVars, WebScriptRequest req, WebScriptResponse res, Map<String, Object> model) throws IOException
{
// render content
QName propertyQName = ContentModel.PROP_CONTENT;
String contentPart = templateVars.get("property");
if (contentPart.length() > 0 && contentPart.charAt(0) == ';')
{
if (contentPart.length() < 2)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "Content property malformed");
}
String propertyName = contentPart.substring(1);
if (propertyName.length() > 0)
{
propertyQName = QName.createQName(propertyName, namespaceService);
}
}
// determine attachment
boolean attach = Boolean.valueOf(req.getParameter("a"));
// Stream the content
streamContent(req, res, nodeRef, propertyQName, attach, model);
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2005-2012 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.repo.web.scripts.quickshare;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.QuickShareModel;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* QuickShare/PublicView
*
* GET web script to get limited metadata (including thumbnail defs) for some "shared" content
*
* WARNING: **unauthenticated** web script (equivalent to authenticated version - see MetaDataGet.java)
*
* @author janv
*/
public class QuickShareMetaDataGet extends MetaDataGet
{
private static final Log logger = LogFactory.getLog(QuickShareMetaDataGet.class);
@Override
protected Map<String, Object> executeImpl(final WebScriptRequest req, Status status, Cache cache)
{
if (! isEnabled())
{
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "QuickShare is disabled system-wide");
}
// create map of params (template vars)
Map<String, String> params = req.getServiceMatch().getTemplateVars();
final String sharedId = params.get("shared_id");
if (sharedId == null)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "A valid sharedId must be specified !");
}
try
{
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(attributeService, tenantService, sharedId);
final String tenantDomain = pair.getFirst();
final NodeRef nodeRef = pair.getSecond();
Map<String, Object> model = TenantUtil.runAsSystemTenant(new TenantRunAsWork<Map<String, Object>>()
{
public Map<String, Object> doWork() throws Exception
{
if (! nodeService.getAspects(nodeRef).contains(QuickShareModel.ASPECT_QSHARE))
{
throw new InvalidNodeRefException(nodeRef);
}
return getMetaDataModel(nodeRef);
}
}, tenantDomain);
if (logger.isDebugEnabled())
{
logger.debug("QuickShare - retrieved metadata: "+sharedId+" ["+nodeRef+"]["+model+"]");
}
return model;
}
catch (InvalidNodeRefException inre)
{
logger.error("Unable to find: "+sharedId+" ["+inre.getNodeRef()+"]");
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find: "+sharedId);
}
}
}

View File

@@ -0,0 +1,260 @@
/*
* Copyright (C) 2005-2012 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.repo.web.scripts.quickshare;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.ContentModel;
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;
import org.alfresco.repo.web.scripts.BaseWebScriptTest;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.AccessStatus;
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.namespace.QName;
import org.alfresco.util.PropertyMap;
import org.json.JSONObject;
import org.json.JSONTokener;
import org.springframework.extensions.webscripts.TestWebScriptServer.DeleteRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.PostRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.Response;
/**
* This class tests QuickShare REST API
*
* @author janv
* @since Cloud/4.1
*/
public class QuickShareRestApiTest extends BaseWebScriptTest
{
private static final String USER_ONE = "UserOne";
private static final String USER_TWO = "UserTwo";
private final static String SHARE_URL = "/api/internal/shared/share/{node_ref_3}";
private final static String UNSHARE_URL = "/api/internal/shared/unshare/{shared_id}";
private final static String SHARE_METADATA_URL = "/api/internal/shared/node/{shared_id}/metadata";
private final static String SHARE_CONTENT_URL = "/api/internal/shared/node/{shared_id}/content";
private final static String SHARE_CONTENT_THUMBNAIL_URL = "/api/internal/shared/node/{shared_id}/content/thumbnails/{thumbnailname}?c=force";
// note: node_ref_3 => three segments, eg. store_protocol/store_id/node_uuid
private final static String AUTH_METADATA_URL = "/api/node/{node_ref_3}/metadata";
private final static String AUTH_CONTENT_URL = "/api/node/{node_ref_3}/content";
private final static String AUTH_CONTENT_THUMBNAIL_URL = "/api/node/{node_ref_3}/content/thumbnails/{thumbnailname}?c=force";
private static final String APPLICATION_JSON = "application/json";
private NodeRef testNode;
private final static String TEST_NAME = "test node";
private final static String TEST_CONTENT = "test content";
private final static String TEST_MIMETYPE_TEXT_PLAIN = MimetypeMap.MIMETYPE_TEXT_PLAIN;
private final static String TEST_MIMETYPE_IMAGE_PNG = MimetypeMap.MIMETYPE_IMAGE_PNG;
private MutableAuthenticationService authenticationService;
private NodeService nodeService;
private PersonService personService;
private PermissionService permissionService;
private ContentService contentService;
private Repository repositoryHelper;
private RetryingTransactionHelper transactionHelper;
@Override
protected void setUp() throws Exception
{
super.setUp();
authenticationService = (MutableAuthenticationService) getServer().getApplicationContext().getBean("AuthenticationService");
nodeService = (NodeService) getServer().getApplicationContext().getBean("NodeService");
contentService = (ContentService) getServer().getApplicationContext().getBean("ContentService");
personService = (PersonService) getServer().getApplicationContext().getBean("PersonService");
permissionService = (PermissionService) getServer().getApplicationContext().getBean("PermissionService");
repositoryHelper = (Repository) getServer().getApplicationContext().getBean("repositoryHelper");
transactionHelper = (RetryingTransactionHelper)getServer().getApplicationContext().getBean("retryingTransactionHelper");
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
createUser(USER_ONE);
createUser(USER_TWO);
AuthenticationUtil.setFullyAuthenticatedUser(USER_ONE);
testNode = transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<NodeRef>()
{
public NodeRef execute() throws Throwable
{
Map<QName, Serializable> props = new HashMap<QName, Serializable>(1);
props.put(ContentModel.PROP_NAME, TEST_NAME);
ChildAssociationRef result = nodeService.createNode(repositoryHelper.getUserHome(personService.getPerson(USER_ONE)),
ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS,
ContentModel.TYPE_CONTENT, props);
NodeRef nodeRef = result.getChildRef();
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
writer.setMimetype(TEST_MIMETYPE_TEXT_PLAIN);
writer.putContent(TEST_CONTENT);
return nodeRef;
}
});
AuthenticationUtil.setFullyAuthenticatedUser(USER_TWO);
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(testNode, PermissionService.READ));
}
@Override
public void tearDown() throws Exception
{
super.tearDown();
AuthenticationUtil.setFullyAuthenticatedUser(USER_ONE);
transactionHelper.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
public Void execute() throws Throwable
{
if (testNode != null && nodeService.exists(testNode))
{
nodeService.deleteNode(testNode);
}
return null;
}
});
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
deleteUser(USER_ONE);
deleteUser(USER_TWO);
}
public void testSanityCheckUrls() throws Exception
{
final int expectedStatusOK = 200;
final int expectedStatusNotFound = 404;
final int expectedStatusServerError = 500; // currently mapped from AccessDenied (should it be 403, 404 or does it depend on use-case)
String testNodeRef_3 = testNode.toString().replace("://", "/");
// As user one ...
// get metadata for node (authenticated)
Response rsp = sendRequest(new GetRequest(AUTH_METADATA_URL.replace("{node_ref_3}", testNodeRef_3)), expectedStatusOK, USER_ONE);
JSONObject jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
String name = jsonRsp.getString("name");
assertEquals(TEST_NAME, name);
String mimetype = jsonRsp.getString("mimetype");
assertEquals(TEST_MIMETYPE_TEXT_PLAIN, mimetype);
// get content for node (authenticated)
rsp = sendRequest(new GetRequest(AUTH_CONTENT_URL.replace("{node_ref_3}", testNodeRef_3)), expectedStatusOK, USER_ONE);
String content = rsp.getContentAsString();
assertEquals(TEST_CONTENT, content);
// get content thumbnail for node (authenticated)
rsp = sendRequest(new GetRequest(AUTH_CONTENT_THUMBNAIL_URL.replace("{node_ref_3}", testNodeRef_3).replace("{thumbnailname}", "doclib")), expectedStatusOK, USER_ONE);
String type = rsp.getContentType();
assertEquals(TEST_MIMETYPE_IMAGE_PNG, type);
// As user two ...
rsp = sendRequest(new GetRequest(AUTH_METADATA_URL.replace("{node_ref_3}", testNodeRef_3)), expectedStatusServerError, USER_TWO);
rsp = sendRequest(new GetRequest(AUTH_CONTENT_URL.replace("{node_ref_3}", testNodeRef_3)), expectedStatusServerError, USER_TWO);
rsp = sendRequest(new GetRequest(AUTH_CONTENT_THUMBNAIL_URL.replace("{node_ref_3}", testNodeRef_3).replace("{thumbnailname}", "doclib")), expectedStatusServerError, USER_TWO);
// As user one ...
// share
rsp = sendRequest(new PostRequest(SHARE_URL.replace("{node_ref_3}", testNodeRef_3), "", APPLICATION_JSON), expectedStatusOK, USER_ONE);
jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
String sharedId = jsonRsp.getString("sharedId");
assertNotNull(sharedId);
assertEquals(22, sharedId.length()); // note: we may have to adjust/remove this check if we change length of id (or it becomes variable length)
// As user two ...
// get metadata for share (note: can be unauthenticated)
rsp = sendRequest(new GetRequest(SHARE_METADATA_URL.replace("{shared_id}", sharedId)), expectedStatusOK, USER_TWO);
jsonRsp = new JSONObject(new JSONTokener(rsp.getContentAsString()));
name = jsonRsp.getString("name");
assertEquals(TEST_NAME, name);
mimetype = jsonRsp.getString("mimetype");
assertEquals(TEST_MIMETYPE_TEXT_PLAIN, mimetype);
// get content for share (note: can be unauthenticated)
rsp = sendRequest(new GetRequest(SHARE_CONTENT_URL.replace("{shared_id}", sharedId)), expectedStatusOK, USER_TWO);
content = rsp.getContentAsString();
assertEquals(TEST_CONTENT, content);
// get content thumbnail for share (note: can be unauthenticated)
rsp = sendRequest(new GetRequest(SHARE_CONTENT_THUMBNAIL_URL.replace("{shared_id}", sharedId).replace("{thumbnailname}", "doclib")), expectedStatusOK, USER_TWO);
type = rsp.getContentType();
assertEquals(TEST_MIMETYPE_IMAGE_PNG, type);
// As user one ...
// unshare
rsp = sendRequest(new DeleteRequest(UNSHARE_URL.replace("{shared_id}", sharedId)), expectedStatusOK, USER_ONE);
// As user two ...
// -ve test (should not be able to get metadata or content via sharedId) - whether authenticated or not
rsp = sendRequest(new GetRequest(SHARE_METADATA_URL.replace("{shared_id}", sharedId)), expectedStatusNotFound, USER_TWO);
rsp = sendRequest(new GetRequest(SHARE_CONTENT_URL.replace("{shared_id}", sharedId)), expectedStatusNotFound, USER_TWO);
rsp = sendRequest(new GetRequest(SHARE_CONTENT_THUMBNAIL_URL.replace("{shared_id}", sharedId).replace("{thumbnailname}", "doclib")), expectedStatusNotFound, USER_TWO);
}
private void createUser(String userName)
{
if (! authenticationService.authenticationExists(userName))
{
authenticationService.createAuthentication(userName, "PWD".toCharArray());
}
if (! personService.personExists(userName))
{
PropertyMap ppOne = new PropertyMap(4);
ppOne.put(ContentModel.PROP_USERNAME, userName);
ppOne.put(ContentModel.PROP_FIRSTNAME, "firstName");
ppOne.put(ContentModel.PROP_LASTNAME, "lastName");
ppOne.put(ContentModel.PROP_EMAIL, "email@email.com");
ppOne.put(ContentModel.PROP_JOBTITLE, "jobTitle");
personService.createPerson(ppOne);
}
}
private void deleteUser(String userName)
{
if (personService.personExists(userName))
{
personService.deletePerson(userName);
}
}
}

View File

@@ -0,0 +1,190 @@
/*
* Copyright (C) 2005-2012 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.repo.web.scripts.quickshare;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.jscript.BaseScopableProcessorExtension;
import org.alfresco.repo.jscript.ScriptNode;
import org.alfresco.repo.thumbnail.script.ScriptThumbnailService;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.thumbnail.ThumbnailService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mozilla.javascript.Scriptable;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;
/**
* QuickShare/PublicView
*
* GET web script to stream "shared" thumbnail content (ie. enabled for public/unauthenticated access) from the repository
*
* WARNING: **unauthenticated** web script (equivalent to authenticated version - see "thumbnail.get.js")
*
* @author janv
*/
public class QuickShareThumbnailContentGet extends QuickShareContentGet
{
private static final Log logger = LogFactory.getLog(QuickShareContentGet.class);
private ThumbnailService thumbnailService;
private ScriptThumbnailService scriptThumbnailService;
private ServiceRegistry serviceRegistry;
public void setThumbnailService(ThumbnailService thumbnailService)
{
this.thumbnailService = thumbnailService;
}
public void setScriptThumbnailService(ScriptThumbnailService scriptThumbnailService)
{
this.scriptThumbnailService = scriptThumbnailService;
}
public void setServiceRegistry(ServiceRegistry services)
{
this.serviceRegistry = services;
}
@Override
protected void executeImpl(NodeRef nodeRef, Map<String, String> templateVars, WebScriptRequest req, WebScriptResponse res, Map<String, Object> model) throws IOException
{
String thumbnailName = templateVars.get("thumbnailname");
if (thumbnailName == null)
{
logger.error("Thumbnail name was not provided: "+nodeRef);
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + nodeRef);
}
// Indicate whether or not the thumbnail can be cached by the browser. Caching is allowed if the lastModified
// argument is provided as this is an indication of request uniqueness and therefore the browser will have
// the latest thumbnail image.
if (model == null)
{
model = new HashMap<String, Object>(1);
}
if (req.getParameter("lastModified") != null)
{
model.put("allowBrowserToCache", "true"); // note: must be String not boolean
}
else
{
model.put("allowBrowserToCache", "false"); // note: must be String not boolean
}
NodeRef thumbnailNodeRef = thumbnailService.getThumbnailByName(nodeRef, ContentModel.PROP_CONTENT, thumbnailName);
if (thumbnailNodeRef == null)
{
// Get the queue/force create setting
boolean qc = false;
boolean fc = false;
String c = req.getParameter("c");
if (c != null)
{
if (c.equals("queue"))
{
qc = true;
}
else if (c.equals("force"))
{
fc = true;
}
}
// Get the place holder flag
boolean ph = false;
String phString = req.getParameter("ph");
if (phString != null)
{
ph = new Boolean(phString);
}
Scriptable scope = new BaseScopableProcessorExtension().getScope(); // note: required for ValueConverter (collection)
ScriptNode node = new ScriptNode(nodeRef, serviceRegistry, scope);
// Queue the creation of the thumbnail if appropriate
if (fc)
{
ScriptNode thumbnailNode = node.createThumbnail(thumbnailName, false);
if (thumbnailNode != null)
{
thumbnailNodeRef = thumbnailNode.getNodeRef();
}
}
else
{
if (qc)
{
node.createThumbnail(thumbnailName, true);
}
}
if (thumbnailNodeRef == null)
{
if (ph == true)
{
// Try and get the place holder resource. We use a method in the thumbnail service
// that by default gives us a resource based on the content's mime type.
String phPath = null;
ContentData contentData = (ContentData)this.serviceRegistry.getNodeService().getProperty(nodeRef, ContentModel.PROP_CONTENT);
if (contentData != null)
{
phPath = scriptThumbnailService.getMimeAwarePlaceHolderResourcePath(thumbnailName, contentData.getMimetype());
}
if (phPath == null)
{
// 404 since no thumbnail was found
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Thumbnail was not found and no place holder resource set for '" + thumbnailName + "'");
}
else
{
// Set the resouce path in the model ready for the content stream to send back to the client
model.put("contentPath", phPath);
}
}
else
{
// 404 since no thumbnail was found
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Thumbnail was not found");
}
}
}
super.executeImpl(thumbnailNodeRef, templateVars, req, res, model);
if (logger.isDebugEnabled())
{
logger.debug("QuickShare - retrieved thumbnail content: "+thumbnailNodeRef+" ["+nodeRef+","+thumbnailName+"]");
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (C) 2005-2012 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.repo.web.scripts.quickshare;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.site.SiteInfo;
import org.alfresco.service.cmr.site.SiteService;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* QuickShare/PublicView
*
* GET web script to lookup some context (nodeRef, tenantDomain, siteId) for a given "Share"
*
* Note: authenticated web script
*
* @author janv
*/
public class ShareContentGet extends AbstractQuickShareContent
{
private static final Log logger = LogFactory.getLog(ShareContentPost.class);
protected SiteService siteService;
public void setSiteService(SiteService siteService)
{
this.siteService = siteService;
}
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
if (! isEnabled())
{
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "QuickShare is disabled system-wide");
}
// create map of params (template vars)
Map<String, String> params = req.getServiceMatch().getTemplateVars();
final String sharedId = params.get("shared_id");
if (sharedId == null)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "A valid sharedId must be specified !");
}
try
{
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(attributeService, tenantService, sharedId);
final String tenantDomain = pair.getFirst();
final NodeRef nodeRef = pair.getSecond();
SiteInfo siteInfo = siteService.getSite(nodeRef);
String siteId = null;
if (siteInfo != null)
{
siteId = siteInfo.getShortName();
}
Map<String, Object> model = new HashMap<String, Object>(3);
model.put("sharedId", sharedId);
model.put("nodeRef", nodeRef.toString());
model.put("siteId", siteId);
model.put("tenantDomain", tenantDomain);
if (logger.isInfoEnabled())
{
logger.info("QuickShare - get shared context: "+sharedId+" ["+model+"]");
}
return model;
}
catch (InvalidNodeRefException inre)
{
logger.error("Unable to find: "+sharedId+" ["+inre.getNodeRef()+"]");
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find: "+sharedId);
}
}
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2005-2012 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.repo.web.scripts.quickshare;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.model.QuickShareModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
import org.alfresco.repo.web.scripts.WebScriptUtil;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.safehaus.uuid.UUID;
import org.safehaus.uuid.UUIDGenerator;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* QuickShare/PublicView
*
* POST web script to "Share" access to some content (ie. enable unauthenticated access to this node)
*
* Note: authenticated web script
*
* @author janv
*/
public class ShareContentPost extends AbstractQuickShareContent
{
private static final Log logger = LogFactory.getLog(ShareContentPost.class);
/* package */ static final String ATTR_KEY_SHAREDIDS_ROOT = ".sharedIds";
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
if (! isEnabled())
{
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "QuickShare is disabled system-wide");
}
// create map of params (template vars)
Map<String, String> params = req.getServiceMatch().getTemplateVars();
final NodeRef nodeRef = WebScriptUtil.getNodeRef(params);
if (nodeRef == null)
{
String msg = "A valid NodeRef must be specified!";
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, msg);
}
try
{
QName typeQName = nodeService.getType(nodeRef);
if (! typeQName.equals(ContentModel.TYPE_CONTENT))
{
throw new InvalidNodeRefException(nodeRef);
}
final String sharedId;
if (! nodeService.getAspects(nodeRef).contains(QuickShareModel.ASPECT_QSHARE))
{
UUID uuid = UUIDGenerator.getInstance().generateRandomBasedUUID();
sharedId = Base64.encodeBase64URLSafeString(uuid.toByteArray()); // => 22 chars (eg. q3bEKPeDQvmJYgt4hJxOjw)
Map<QName,Serializable> props = new HashMap<QName,Serializable>(2);
props.put(QuickShareModel.PROP_QSHARE_SHAREDID, sharedId);
props.put(QuickShareModel.PROP_QSHARE_SHAREDBY, AuthenticationUtil.getRunAsUser());
nodeService.addAspect(nodeRef, QuickShareModel.ASPECT_QSHARE, props);
final NodeRef tenantNodeRef = tenantService.getName(nodeRef);
TenantUtil.runAsDefaultTenant(new TenantRunAsWork<Void>()
{
public Void doWork() throws Exception
{
attributeService.setAttribute(tenantNodeRef, ATTR_KEY_SHAREDIDS_ROOT, sharedId);
return null;
}
});
if (logger.isInfoEnabled())
{
logger.info("QuickShare - shared content: "+sharedId+" ["+nodeRef+"]");
}
}
else
{
sharedId = (String)nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDID);
if (logger.isDebugEnabled())
{
logger.debug("QuickShare - content already shared: "+sharedId+" ["+nodeRef+"]");
}
}
Map<String, Object> model = new HashMap<String, Object>(1);
model.put("sharedId", sharedId);
return model;
}
catch (InvalidNodeRefException inre)
{
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find node: " + nodeRef);
}
}
}

View File

@@ -0,0 +1,173 @@
/*
* Copyright (C) 2005-2012 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.repo.web.scripts.quickshare;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.model.QuickShareModel;
import org.alfresco.repo.node.NodeServicePolicies;
import org.alfresco.repo.policy.JavaBehaviour;
import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.repo.tenant.TenantUtil.TenantRunAsWork;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.EqualsHelper;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* QuickShare/PublicView
*
* DELETE web script to "Unshare" access to some content (ie. disable unauthenticated access to this node)
*
* Note: authenticated web script
*
* @author janv
*/
public class UnshareContentDelete extends AbstractQuickShareContent implements NodeServicePolicies.BeforeDeleteNodePolicy
{
private static final Log logger = LogFactory.getLog(ShareContentPost.class);
protected PolicyComponent policyComponent;
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
/**
* The initialise method
*/
public void init()
{
// Register interest in the beforeDeleteNode policy - note: currently for content only !!
policyComponent.bindClassBehaviour(
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
ContentModel.TYPE_CONTENT,
new JavaBehaviour(this, "beforeDeleteNode"));
}
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache)
{
if (! isEnabled())
{
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "QuickShare is disabled system-wide");
}
// create map of params (template vars)
Map<String, String> params = req.getServiceMatch().getTemplateVars();
final String sharedId = params.get("shared_id");
if (sharedId == null)
{
throw new WebScriptException(HttpServletResponse.SC_BAD_REQUEST, "A valid sharedId must be specified !");
}
try
{
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(attributeService, tenantService, sharedId);
final String tenantDomain = pair.getFirst();
final NodeRef nodeRef = pair.getSecond();
TenantUtil.runAsSystemTenant(new TenantRunAsWork<Void>()
{
public Void doWork() throws Exception
{
QName typeQName = nodeService.getType(nodeRef);
if (! typeQName.equals(ContentModel.TYPE_CONTENT))
{
throw new InvalidNodeRefException(nodeRef);
}
String nodeSharedId = (String)nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDID);
if (! EqualsHelper.nullSafeEquals(nodeSharedId, sharedId))
{
logger.warn("SharedId mismatch: expected="+sharedId+",actual="+nodeSharedId);
}
nodeService.removeAspect(nodeRef, QuickShareModel.ASPECT_QSHARE);
return null;
}
}, tenantDomain);
removeSharedId(sharedId);
if (logger.isInfoEnabled())
{
logger.info("QuickShare - unshared content: "+sharedId+" ["+nodeRef+"]");
}
Map<String, Object> model = new HashMap<String, Object>(1);
model.put("success", Boolean.TRUE);
return model;
}
catch (InvalidNodeRefException inre)
{
logger.error("Unable to find: "+sharedId+" ["+inre.getNodeRef()+"]");
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find: "+sharedId);
}
}
// behaviour - currently registered for content only !!
// note: will remove "share" even if node is only being archived (ie. moved to trash) => a subsequent restore will *not* restore the "share"
public void beforeDeleteNode(final NodeRef nodeRef)
{
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
String sharedId = (String)nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDID);
if (sharedId != null)
{
removeSharedId(sharedId);
}
return null;
}
});
}
private void removeSharedId(final String sharedId)
{
TenantUtil.runAsDefaultTenant(new TenantRunAsWork<Void>()
{
public Void doWork() throws Exception
{
attributeService.removeAttribute(ShareContentPost.ATTR_KEY_SHAREDIDS_ROOT, sharedId);
return null;
}
});
}
}