From 029ee26fec022f442c6045df14282dc0b6756ad7 Mon Sep 17 00:00:00 2001 From: Andrew Hind Date: Wed, 21 May 2008 11:14:22 +0000 Subject: [PATCH] Merged V2.9 to HEAD 9194:Merged V2.2 to V2.9 8557: Fix for WCM-1120 8580: Fix remainder of WCM-1120 git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@9200 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../web-client-config-wcm-actions.xml | 1 + .../evaluator/WCMContentManagerEvaluator.java | 57 +++++ .../web/bean/wcm/CreateWebappDialog.java | 46 +++- .../web/bean/wcm/DeleteWebsiteDialog.java | 242 +++++++++--------- .../alfresco/web/bean/wcm/SandboxFactory.java | 47 ++++ 5 files changed, 265 insertions(+), 128 deletions(-) create mode 100644 source/java/org/alfresco/web/action/evaluator/WCMContentManagerEvaluator.java diff --git a/config/alfresco/web-client-config-wcm-actions.xml b/config/alfresco/web-client-config-wcm-actions.xml index e6144bba33..6b5b9bc489 100644 --- a/config/alfresco/web-client-config-wcm-actions.xml +++ b/config/alfresco/web-client-config-wcm-actions.xml @@ -164,6 +164,7 @@ CreateChildren + org.alfresco.web.action.evaluator.WCMContentManagerEvaluator create_webapp /images/icons/create_webapp.gif dialog:createWebappFolder diff --git a/source/java/org/alfresco/web/action/evaluator/WCMContentManagerEvaluator.java b/source/java/org/alfresco/web/action/evaluator/WCMContentManagerEvaluator.java new file mode 100644 index 0000000000..4dd3573044 --- /dev/null +++ b/source/java/org/alfresco/web/action/evaluator/WCMContentManagerEvaluator.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2005-2007 Alfresco Software Limited. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program 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 General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing + */ +package org.alfresco.web.action.evaluator; + +import javax.faces.context.FacesContext; + +import org.alfresco.model.WCMAppModel; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.web.action.ActionEvaluator; +import org.alfresco.web.bean.repository.Node; +import org.alfresco.web.bean.repository.Repository; +import org.alfresco.web.bean.wcm.SandboxFactory; + +/** + * Evaluator to return true if the current user is a content manager for the current website. + * + * @author Gavin Cornwell + */ +public class WCMContentManagerEvaluator extends BaseActionEvaluator +{ + private static final long serialVersionUID = 2588681368739253602L; + + /** + * @return true if the item is not locked by another user + */ + public boolean evaluate(final Node node) + { + FacesContext facesContext = FacesContext.getCurrentInstance(); + NodeService nodeService = Repository.getServiceRegistry(facesContext).getNodeService(); + + String storeId = (String)nodeService.getProperty(node.getNodeRef(), WCMAppModel.PROP_AVMSTORE); + + return SandboxFactory.isContentManager(storeId); + } +} diff --git a/source/java/org/alfresco/web/bean/wcm/CreateWebappDialog.java b/source/java/org/alfresco/web/bean/wcm/CreateWebappDialog.java index 35772fc17c..58a7283cee 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateWebappDialog.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateWebappDialog.java @@ -30,8 +30,11 @@ import org.alfresco.model.ApplicationModel; import org.alfresco.model.ContentModel; import org.alfresco.model.WCMAppModel; import org.alfresco.repo.avm.AVMNodeConverter; -import org.alfresco.service.cmr.dictionary.DataTypeDefinition; import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.security.permissions.AccessDeniedException; +import org.alfresco.service.cmr.dictionary.DataTypeDefinition; /** * Bean implementation for the AVM "Create Webapp Folder" dialog. @@ -54,22 +57,37 @@ public class CreateWebappDialog extends CreateFolderDialog protected String finishImpl(FacesContext context, String outcome) throws Exception { final String stagingStore = this.avmBrowseBean.getStagingStore(); - final String parent = AVMUtil.buildSandboxRootPath( stagingStore ); - this.getAvmService().createDirectory(parent, this.name); - this.path = AVMNodeConverter.ExtendAVMPath(parent, this.name); - this.getAvmService().addAspect(this.path, ApplicationModel.ASPECT_UIFACETS); - this.getAvmService().addAspect(this.path, WCMAppModel.ASPECT_WEBAPP); - if (this.description != null && this.description.length() != 0) + if (SandboxFactory.isContentManager(stagingStore)) { - this.getAvmService().setNodeProperty(path, - ContentModel.PROP_DESCRIPTION, - new PropertyValue(DataTypeDefinition.TEXT, - this.description)); - } + AuthenticationUtil.runAs(new RunAsWork(){ - // Snapshot the store with the empty webapp - this.getAvmService().createSnapshot(stagingStore, null, null); + public Object doWork() throws Exception + { + final String parent = AVMUtil.buildSandboxRootPath( stagingStore ); + CreateWebappDialog.this.getAvmService().createDirectory(parent, CreateWebappDialog.this.name); + + CreateWebappDialog.this.path = AVMNodeConverter.ExtendAVMPath(parent, CreateWebappDialog.this.name); + CreateWebappDialog.this.getAvmService().addAspect(CreateWebappDialog.this.path, ApplicationModel.ASPECT_UIFACETS); + CreateWebappDialog.this.getAvmService().addAspect(CreateWebappDialog.this.path, WCMAppModel.ASPECT_WEBAPP); + if (CreateWebappDialog.this.description != null && CreateWebappDialog.this.description.length() != 0) + { + CreateWebappDialog.this.getAvmService().setNodeProperty(path, + ContentModel.PROP_DESCRIPTION, + new PropertyValue(DataTypeDefinition.TEXT, + CreateWebappDialog.this.description)); + } + + // Snapshot the store with the empty webapp + CreateWebappDialog.this.getAvmService().createSnapshot(stagingStore, null, null); + return null; + }}, AuthenticationUtil.getSystemUserName()); + + } + else + { + throw new AccessDeniedException("Only content managers may create new webapp folders"); + } return outcome; } diff --git a/source/java/org/alfresco/web/bean/wcm/DeleteWebsiteDialog.java b/source/java/org/alfresco/web/bean/wcm/DeleteWebsiteDialog.java index 653e94bbf3..2aaddb61ca 100644 --- a/source/java/org/alfresco/web/bean/wcm/DeleteWebsiteDialog.java +++ b/source/java/org/alfresco/web/bean/wcm/DeleteWebsiteDialog.java @@ -29,6 +29,9 @@ import java.util.List; import javax.faces.context.FacesContext; import org.alfresco.model.WCMAppModel; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork; +import org.alfresco.repo.security.permissions.AccessDeniedException; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.repository.ChildAssociationRef; import org.alfresco.service.namespace.RegexQNamePattern; @@ -37,127 +40,138 @@ import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.bean.spaces.DeleteSpaceDialog; /** - * Bean implementation for the "Delete Website" dialog. - * Removes all user stores and the main staging and preview stores. + * Bean implementation for the "Delete Website" dialog. Removes all user stores and the main staging and preview stores. * * @author kevinr */ public class DeleteWebsiteDialog extends DeleteSpaceDialog { - private static final long serialVersionUID = -3598950865168230942L; - - transient private AVMService avmService; - - // ------------------------------------------------------------------------------ - // Bean property getters and setters - - /** - * @param avmService The AVMService to set. - */ - public void setAvmService(AVMService avmService) - { - this.avmService = avmService; - } - - protected AVMService getAvmService() - { - if (avmService == null) - { - avmService = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getAVMService(); - } - return avmService; - } - - - // ------------------------------------------------------------------------------ - // Dialog implementation - - /** - * @see org.alfresco.web.bean.dialog.BaseDialogBean#finishImpl(javax.faces.context.FacesContext, java.lang.String) - */ - @Override - protected String finishImpl(FacesContext context, String outcome) throws Exception - { - Node websiteNode = this.browseBean.getActionSpace(); - - if (websiteNode != null) - { - // delete all attached website sandboxes in reverse order to the layering - String storeRoot = (String)websiteNode.getProperties().get(WCMAppModel.PROP_AVMSTORE); - - if (storeRoot != null) - { - // Notifiy virtualization server about removing this website - // - // Implementation note: - // - // Because the removal of virtual webapps in the virtualization - // server is recursive, it only needs to be given the name of - // the main staging store. - // - // This notification must occur *prior* to purging content - // within the AVM because the virtualization server must list - // the avm_webapps dir in each store to discover which - // virtual webapps must be unloaded. The virtualization - // server traverses the sandbox's stores in most-to-least - // dependent order, so clients don't have to worry about - // accessing a preview layer whose main layer has been torn - // out from under it. - // - // It does not matter what webapp name we give here, so "/ROOT" - // is as sensible as anything else. It's all going away. - - String sandbox = AVMUtil.buildStagingStoreName(storeRoot); - String path = AVMUtil.buildStoreWebappPath(sandbox, "/ROOT"); - AVMUtil.removeAllVServerWebapps(path, true); - - // get the list of users who have a sandbox in the website - List userInfoRefs = getNodeService().getChildAssocs( - websiteNode.getNodeRef(), WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL); - for (ChildAssociationRef ref : userInfoRefs) + private static final long serialVersionUID = -3598950865168230942L; + + transient private AVMService avmService; + + // ------------------------------------------------------------------------------ + // Bean property getters and setters + + /** + * @param avmService + * The AVMService to set. + */ + public void setAvmService(AVMService avmService) + { + this.avmService = avmService; + } + + protected AVMService getAvmService() + { + if (avmService == null) + { + avmService = Repository.getServiceRegistry(FacesContext.getCurrentInstance()).getAVMService(); + } + return avmService; + } + + // ------------------------------------------------------------------------------ + // Dialog implementation + + /** + * @see org.alfresco.web.bean.dialog.BaseDialogBean#finishImpl(javax.faces.context.FacesContext, java.lang.String) + */ + @Override + protected String finishImpl(FacesContext context, String outcome) throws Exception + { + Node websiteNode = this.browseBean.getActionSpace(); + + if (websiteNode != null) + { + // delete all attached website sandboxes in reverse order to the layering + String storeRoot = (String) websiteNode.getProperties().get(WCMAppModel.PROP_AVMSTORE); + + if (storeRoot != null) { - String username = (String)getNodeService().getProperty(ref.getChildRef(), WCMAppModel.PROP_WEBUSERNAME); + // Notifiy virtualization server about removing this website + // + // Implementation note: + // + // Because the removal of virtual webapps in the virtualization + // server is recursive, it only needs to be given the name of + // the main staging store. + // + // This notification must occur *prior* to purging content + // within the AVM because the virtualization server must list + // the avm_webapps dir in each store to discover which + // virtual webapps must be unloaded. The virtualization + // server traverses the sandbox's stores in most-to-least + // dependent order, so clients don't have to worry about + // accessing a preview layer whose main layer has been torn + // out from under it. + // + // It does not matter what webapp name we give here, so "/ROOT" + // is as sensible as anything else. It's all going away. - // delete the preview store for this user - deleteStore(AVMUtil.buildUserPreviewStoreName(storeRoot, username)); + String sandbox = AVMUtil.buildStagingStoreName(storeRoot); + String path = AVMUtil.buildStoreWebappPath(sandbox, "/ROOT"); + AVMUtil.removeAllVServerWebapps(path, true); - // delete the main store for this user - deleteStore(AVMUtil.buildUserMainStoreName(storeRoot, username)); + // get the list of users who have a sandbox in the website + List userInfoRefs = getNodeService().getChildAssocs(websiteNode.getNodeRef(), WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL); + for (ChildAssociationRef ref : userInfoRefs) + { + String username = (String) getNodeService().getProperty(ref.getChildRef(), WCMAppModel.PROP_WEBUSERNAME); + + // delete the preview store for this user + deleteStore(AVMUtil.buildUserPreviewStoreName(storeRoot, username)); + + // delete the main store for this user + deleteStore(AVMUtil.buildUserMainStoreName(storeRoot, username)); + } + + // remove the main staging and preview stores + deleteStore(AVMUtil.buildStagingPreviewStoreName(storeRoot)); + deleteStore(AVMUtil.buildStagingStoreName(storeRoot)); } - - // remove the main staging and preview stores - deleteStore(AVMUtil.buildStagingPreviewStoreName(storeRoot)); - deleteStore(AVMUtil.buildStagingStoreName(storeRoot)); - } - } - - // use the super implementation to delete the node itself - return super.finishImpl(context, outcome); - } - - /** - * Delete a store, checking for its existance first. - * - * @param store - */ - private void deleteStore(String store) - { - // check it exists before we try to remove it - if (this.getAvmService().getStore(store) != null) - { - this.getAvmService().purgeStore(store); - } - } - - /** - * Returns the message bundle id of the confirmation message to display to - * the user before deleting the website. - * - * @return The message bundle id - */ - @Override - protected String getConfirmMessageId() - { - return "delete_website_confirm"; - } + } + + // use the super implementation to delete the node itself + return super.finishImpl(context, outcome); + } + + /** + * Delete a store, checking for its existance first. + * + * @param store + */ + private void deleteStore(final String store) + { + // check it exists before we try to remove it + if (this.getAvmService().getStore(store) != null) + { + if (SandboxFactory.isContentManager(store)) + { + AuthenticationUtil.runAs(new RunAsWork(){ + + public Object doWork() throws Exception + { + DeleteWebsiteDialog.this.getAvmService().purgeStore(store); + return null; + }}, AuthenticationUtil.getSystemUserName()); + + } + else + { + throw new AccessDeniedException("Only content managers may delete websites"); + } + } + } + + /** + * Returns the message bundle id of the confirmation message to display to the user before deleting the website. + * + * @return The message bundle id + */ + @Override + protected String getConfirmMessageId() + { + return "delete_website_confirm"; + } } diff --git a/source/java/org/alfresco/web/bean/wcm/SandboxFactory.java b/source/java/org/alfresco/web/bean/wcm/SandboxFactory.java index 70f5956695..b004a89d15 100644 --- a/source/java/org/alfresco/web/bean/wcm/SandboxFactory.java +++ b/source/java/org/alfresco/web/bean/wcm/SandboxFactory.java @@ -33,6 +33,7 @@ import org.alfresco.config.JNDIConstants; import org.alfresco.model.WCMAppModel; import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.domain.PropertyValue; +import org.alfresco.repo.security.authentication.AuthenticationUtil; import org.alfresco.sandbox.SandboxConstants; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.avm.AVMService; @@ -251,6 +252,52 @@ public final class SandboxFactory } } + public static boolean isContentManager(String storeId) + { + ServiceRegistry services = Repository.getServiceRegistry(FacesContext.getCurrentInstance()); + AVMService avmService = services.getAVMService(); + NodeService nodeService = services.getNodeService(); + + String userName = AuthenticationUtil.getCurrentUserName(); + + String storeName = extractStagingAreaName(storeId); + PropertyValue pValue = avmService.getStoreProperty(storeName, SandboxConstants.PROP_WEB_PROJECT_NODE_REF); + + if (pValue != null) + { + NodeRef webProjectNodeRef = (NodeRef) pValue.getValue(DataTypeDefinition.NODE_REF); + + // Apply sepcific user permissions as set on the web project + List userInfoRefs = nodeService.getChildAssocs(webProjectNodeRef, WCMAppModel.ASSOC_WEBUSER, RegexQNamePattern.MATCH_ALL); + for (ChildAssociationRef ref : userInfoRefs) + { + NodeRef userInfoRef = ref.getChildRef(); + String user = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERNAME); + String role = (String) nodeService.getProperty(userInfoRef, WCMAppModel.PROP_WEBUSERROLE); + + if(userName.equals(user) && role.equals(AVMUtil.ROLE_CONTENT_MANAGER)) + { + return true; + } + } + return false; + } + else + { + return false; + } + } + + private static String extractStagingAreaName(String name) + { + int index = name.indexOf("--"); + if (index == -1) + { + return name; + } + return name.substring(0, index); + } + public static void addStagingAreaUser(String storeId, String authority, String role) { // The stores have the mask set in updateSandboxManagers