diff --git a/config/alfresco/messages/webclient.properties b/config/alfresco/messages/webclient.properties index b712edd362..e6b95ef85d 100644 --- a/config/alfresco/messages/webclient.properties +++ b/config/alfresco/messages/webclient.properties @@ -793,7 +793,7 @@ create_website_step1_desc=Enter the information about the website. create_website_finish_instruction=To close this wizard and create your website space click Finish. To review or change your selections click Back. # Browse Website and Sandboxes messages -title_browse_website=Browse Website Sandboxes +title_browse_website=Browse Website website_info=Use this view to browse the staging area and user sandboxes for a website. staging_sandbox=Staging Sandbox user_sandboxes=User Sandboxes @@ -801,6 +801,12 @@ sandbox_preview=Preview Website sandbox_create=Create New Content sandbox_browse=Browse Website import_website_content=Import Website Content +title_browse_sandbox=Browse Sandbox +sandbox_info=Use this view to browse the files and folders within the sandbox for a website. +sandbox_title=Website ''{0}'' sandbox ''{1}'' +sandbox_staging=Staging +website_browse_folders=Browse Folders +website_browse_files=Browse Files # Website actions and dialog messages title_import_content=Import Content into Website diff --git a/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java b/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java index 87716d4daf..0acf1f626c 100644 --- a/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java +++ b/source/java/org/alfresco/web/bean/wcm/AVMBrowseBean.java @@ -16,18 +16,29 @@ */ package org.alfresco.web.bean.wcm; -import javax.faces.context.FacesContext; +import java.text.MessageFormat; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import javax.faces.context.FacesContext; +import javax.faces.event.ActionEvent; + +import org.alfresco.model.ContentModel; import org.alfresco.service.cmr.dictionary.DictionaryService; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.search.SearchService; import org.alfresco.service.namespace.NamespaceService; +import org.alfresco.web.app.Application; import org.alfresco.web.app.context.IContextListener; import org.alfresco.web.app.context.UIContextService; import org.alfresco.web.bean.BrowseBean; import org.alfresco.web.bean.NavigationBean; +import org.alfresco.web.bean.repository.Node; +import org.alfresco.web.ui.common.component.UIActionLink; import org.alfresco.web.ui.common.component.data.UIRichList; +import org.alfresco.web.ui.wcm.WebResources; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -40,6 +51,16 @@ public class AVMBrowseBean implements IContextListener { private static Log logger = LogFactory.getLog(AVMBrowseBean.class); + private static final String MSG_SANDBOXTITLE = "sandbox_title"; + private static final String MSG_SANDBOXSTAGING = "sandbox_staging"; + + private String sandbox; + private String username; + private String sandboxTitle = null; + + private UIRichList foldersRichList; + private UIRichList filesRichList; + /** The NodeService to be used by the bean */ protected NodeService nodeService; @@ -118,34 +139,164 @@ public class AVMBrowseBean implements IContextListener /** * @param navigator The NavigationBean to set. */ - public void setNavigator(NavigationBean navigator) + public void setNavigationBean(NavigationBean navigator) { this.navigator = navigator; } /** - * @param avmRichList The avmRichList to set. + * @param foldersRichList The foldersRichList to set. */ - /*public void setAvmRichList(UIRichList avmRichList) + public void setFoldersRichList(UIRichList foldersRichList) { - this.forumsRichList = forumsRichList; - if (this.forumsRichList != null) + this.foldersRichList = foldersRichList; + /*if (this.foldersRichList != null) { // set the initial sort column and direction - this.forumsRichList.setInitialSortColumn( + this.foldersRichList.setInitialSortColumn( this.viewsConfig.getDefaultSortColumn(PAGE_NAME_FORUMS)); - this.forumsRichList.setInitialSortDescending( + this.foldersRichList.setInitialSortDescending( this.viewsConfig.hasDescendingSort(PAGE_NAME_FORUMS)); - } - }*/ + }*/ + } /** - * @return Returns the forumsRichList. + * @return Returns the foldersRichList. */ - /*public UIRichList getForumsRichList() + public UIRichList getFoldersRichList() { - return this.forumsRichList; - }*/ + return this.foldersRichList; + } + + /** + * @return Returns the filesRichList. + */ + public UIRichList getFilesRichList() + { + return this.filesRichList; + } + + /** + * @param filesRichList The filesRichList to set. + */ + public void setFilesRichList(UIRichList filesRichList) + { + this.filesRichList = filesRichList; + } + + /** + * @return Returns the sandbox. + */ + public String getSandbox() + { + return this.sandbox; + } + + /** + * @param sandbox The sandbox to set. + */ + public void setSandbox(String sandbox) + { + this.sandbox = sandbox; + } + + /** + * @return Returns the username. + */ + public String getUsername() + { + return this.username; + } + + /** + * @param username The username to set. + */ + public void setUsername(String username) + { + this.username = username; + } + + /** + * @return Returns the sandboxTitle. + */ + public String getSandboxTitle() + { + if (this.sandboxTitle == null) + { + String forUser = username; + if (forUser == null) + { + forUser = Application.getMessage(FacesContext.getCurrentInstance(), MSG_SANDBOXSTAGING); + } + this.sandboxTitle = MessageFormat.format(Application.getMessage( + FacesContext.getCurrentInstance(), MSG_SANDBOXTITLE), + this.navigator.getCurrentNode().getName(), + forUser); + } + return this.sandboxTitle; + } + + /** + * @param sandboxTitle The sandboxTitle to set. + */ + public void setSandboxTitle(String sandboxTitle) + { + this.sandboxTitle = sandboxTitle; + } + + /** + * @return icon image for the appropriate sandbox type + */ + public String getIcon() + { + return this.username == null ? WebResources.IMAGE_SANDBOX_32 : WebResources.IMAGE_USERSANDBOX_32; + } + + public Node getWebsite() + { + return this.navigator.getCurrentNode(); + } + + public List getFolders() + { + return Collections.emptyList(); + } + + public List getFiles() + { + return Collections.emptyList(); + } + + /** + * Setup the context for a sandbox browse action + */ + public void setupSandboxAction(ActionEvent event) + { + UIActionLink link = (UIActionLink)event.getComponent(); + Map params = link.getParameterMap(); + String store = params.get("store"); + String username = params.get("username"); + + // can be null if it's the staging store - i.e. not a user specific store + setUsername(username); + + // the store can be either a user store or the staging store if this is null + if (store != null) + { + setSandbox(store); + } + else + { + // get the staging store from the current website node + setSandbox(AVMConstants.buildAVMStagingStoreName( + (String)getWebsite().getProperties().get(ContentModel.PROP_AVMSTORE))); + } + + this.sandboxTitle = null; + + // update UI state ready for return to the previous screen + UIContextService.getInstance(FacesContext.getCurrentInstance()).notifyBeans(); + } // ------------------------------------------------------------------------------ @@ -156,6 +307,10 @@ public class AVMBrowseBean implements IContextListener */ public void contextUpdated() { + if (this.foldersRichList != null) + { + this.foldersRichList.setValue(null); + } /* // clear the value for the list components - will cause re-bind to it's data and refresh if (this.forumsRichList != null) diff --git a/source/java/org/alfresco/web/bean/wcm/AVMConstants.java b/source/java/org/alfresco/web/bean/wcm/AVMConstants.java index 2ddea36465..0185ceec7d 100644 --- a/source/java/org/alfresco/web/bean/wcm/AVMConstants.java +++ b/source/java/org/alfresco/web/bean/wcm/AVMConstants.java @@ -28,6 +28,31 @@ public final class AVMConstants { } + public static String buildAVMStagingStoreName(String store) + { + return store + AVMConstants.STORE_STAGING; + } + + public static String buildAVMStagingPreviewStoreName(String store) + { + return store + AVMConstants.STORE_PREVIEW; + } + + public static String buildAVMUserMainStoreName(String store, String username) + { + return store + '-' + username + AVMConstants.STORE_MAIN; + } + + public static String buildAVMUserPreviewStoreName(String store, String username) + { + return store + '-' + username + AVMConstants.STORE_PREVIEW; + } + + public static String buildAVMStoreRootPath(String store) + { + return store + ":/" + DIR_APPBASE + '/' + DIR_WEBAPPS + '/'; + } + // names of the stores representing the layers for an AVM website public final static String STORE_STAGING = "-staging"; public final static String STORE_MAIN = "-main"; diff --git a/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java b/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java index c847a4fad9..731ac133f5 100644 --- a/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java +++ b/source/java/org/alfresco/web/bean/wcm/CreateWebsiteWizard.java @@ -27,6 +27,7 @@ import javax.faces.context.FacesContext; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ContentModel; +import org.alfresco.repo.avm.AVMNodeConverter; import org.alfresco.repo.domain.PropertyValue; import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.dictionary.DataTypeDefinition; @@ -124,7 +125,7 @@ public class CreateWebsiteWizard extends BaseWizardBean } /** - * @param avmService The avmService to set. + * @param avmService The AVMService to set. */ public void setAvmService(AVMService avmService) { @@ -240,16 +241,18 @@ public class CreateWebsiteWizard extends BaseWizardBean private void createStagingSandbox(String name) { // create the 'staging' store for the website - String stagingStore = name + AVMConstants.STORE_STAGING; + String stagingStore = AVMConstants.buildAVMStagingStoreName(name); this.avmService.createAVMStore(stagingStore); if (logger.isDebugEnabled()) logger.debug("Created staging sandbox store: " + stagingStore); // create the system directories 'appBase' and 'avm_webapps' String path = stagingStore + ":/"; - this.avmService.createDirectory(path, AVMConstants.DIR_APPBASE); + //this.avmService.createDirectory(path, AVMConstants.DIR_APPBASE); + this.fileFolderService.create(AVMNodeConverter.ToNodeRef(-1, path), AVMConstants.DIR_APPBASE, ContentModel.TYPE_AVM_PLAIN_FOLDER); path += AVMConstants.DIR_APPBASE; - this.avmService.createDirectory(path, AVMConstants.DIR_WEBAPPS); + //this.avmService.createDirectory(path, AVMConstants.DIR_WEBAPPS); + this.fileFolderService.create(AVMNodeConverter.ToNodeRef(-1, path), AVMConstants.DIR_WEBAPPS, ContentModel.TYPE_AVM_PLAIN_FOLDER); // tag the store with the store type this.avmService.setStoreProperty(stagingStore, @@ -261,7 +264,7 @@ public class CreateWebsiteWizard extends BaseWizardBean // create the 'preview' store for the website - String previewStore = name + AVMConstants.STORE_PREVIEW; + String previewStore = AVMConstants.buildAVMStagingPreviewStoreName(name); this.avmService.createAVMStore(previewStore); if (logger.isDebugEnabled()) logger.debug("Created staging sandbox store: " + previewStore); @@ -270,6 +273,7 @@ public class CreateWebsiteWizard extends BaseWizardBean path = previewStore + ":/"; String targetPath = name + AVMConstants.STORE_STAGING + ":/" + AVMConstants.DIR_APPBASE; this.avmService.createLayeredDirectory(targetPath, path, AVMConstants.DIR_APPBASE); + //this.fileFolderService.create(AVMNodeConverter.ToNodeRef(-1, path), AVMConstants.DIR_APPBASE, ContentModel.TYPE_AVM_PLAIN_FOLDER); // tag the store with the store type this.avmService.setStoreProperty(stagingStore, @@ -308,7 +312,7 @@ public class CreateWebsiteWizard extends BaseWizardBean private void createUserSandbox(String name, String username) { // create the user 'main' store - String userStore = name + '-' + username + AVMConstants.STORE_MAIN; + String userStore = AVMConstants.buildAVMUserMainStoreName(name, username); this.avmService.createAVMStore(userStore); if (logger.isDebugEnabled()) logger.debug("Created staging sandbox store: " + userStore); @@ -328,7 +332,7 @@ public class CreateWebsiteWizard extends BaseWizardBean // create the user 'preview' store - String previewStore = name + '-' + username + AVMConstants.STORE_PREVIEW; + String previewStore = AVMConstants.buildAVMUserPreviewStoreName(name, username); this.avmService.createAVMStore(previewStore); if (logger.isDebugEnabled()) logger.debug("Created staging sandbox store: " + previewStore); diff --git a/source/java/org/alfresco/web/bean/wcm/ImportWebsiteDialog.java b/source/java/org/alfresco/web/bean/wcm/ImportWebsiteDialog.java index 982c28ccdb..2f03159306 100644 --- a/source/java/org/alfresco/web/bean/wcm/ImportWebsiteDialog.java +++ b/source/java/org/alfresco/web/bean/wcm/ImportWebsiteDialog.java @@ -16,29 +16,106 @@ */ package org.alfresco.web.bean.wcm; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; import java.text.MessageFormat; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.zip.ZipException; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; import javax.transaction.UserTransaction; +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.avm.AVMNodeConverter; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.avm.AVMService; +import org.alfresco.service.cmr.model.FileExistsException; +import org.alfresco.service.cmr.model.FileFolderService; +import org.alfresco.service.cmr.model.FileInfo; +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.MimetypeService; +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.TempFileProvider; import org.alfresco.web.app.AlfrescoNavigationHandler; import org.alfresco.web.app.Application; import org.alfresco.web.bean.FileUploadBean; +import org.alfresco.web.bean.NavigationBean; import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.ui.common.Utils; +import org.apache.tools.zip.ZipEntry; +import org.apache.tools.zip.ZipFile; /** + * Backing bean for the Import Website Content dialog. + * + * This dialog manages the upload of a ZIP archive file, which is then unpacked and loaded into + * the AVM store with the complete folder and file structure. + * * @author Kevin Roast */ public class ImportWebsiteDialog { + private static final int BUFFER_SIZE = 16384; + protected File file; protected String fileName; - private boolean isFinished = false; + protected boolean isFinished = false; + + protected FileFolderService fileFolderService; + protected ContentService contentService; + protected NavigationBean navigationBean; + protected AVMService avmService; + /** + * @param contentService The ContentService to set. + */ + public void setContentService(ContentService contentService) + { + this.contentService = contentService; + } + + /** + * @param fileFolderService The FileFolderService to set. + */ + public void setFileFolderService(FileFolderService fileFolderService) + { + this.fileFolderService = fileFolderService; + } + + /** + * @param navigationBean The NavigationBean to set. + */ + public void setNavigationBean(NavigationBean navigationBean) + { + this.navigationBean = navigationBean; + } + + /** + * @param avmService The AVMService to set. + */ + public void setAvmService(AVMService avmService) + { + this.avmService = avmService; + } + /** * @return Returns the name of the file */ @@ -115,8 +192,27 @@ public class ImportWebsiteDialog tx.begin(); // - // TODO: import the content + // TODO: import the content into the appropriate store for the website // + String storeRoot = (String)this.navigationBean.getCurrentNode().getProperties().get( + ContentModel.PROP_AVMSTORE); + if (storeRoot != null) + { + String store = AVMConstants.buildAVMStagingStoreName(storeRoot); + if (this.avmService.getAVMStore(store) != null) + { + // get the root path to the webapps import area of the store + String rootPath = AVMConstants.buildAVMStoreRootPath(store); + + // convert the AVM path to a NodeRef so we can use the NodeService to perform import + NodeRef importRef = AVMNodeConverter.ToNodeRef(-1, rootPath); + processZipImport(this.file, importRef); + } + } + else + { + // TODO: output an error to indicate we cannot find the store property on the website + } tx.commit(); @@ -128,7 +224,7 @@ public class ImportWebsiteDialog try { if (tx != null) {tx.rollback();} } catch (Exception ex) {} Utils.addErrorMessage(MessageFormat.format( Application.getMessage(FacesContext.getCurrentInstance(), Repository.ERROR_GENERIC), - e.getMessage(), e)); + e.getMessage()), e); } finally { @@ -185,4 +281,174 @@ public class ImportWebsiteDialog FacesContext ctx = FacesContext.getCurrentInstance(); ctx.getExternalContext().getSessionMap().remove(FileUploadBean.FILE_UPLOAD_BEAN_NAME); } + + /** + * Process ZIP file for import into an AVM repository store location + * + * @param file ZIP format file + * @param rootRef Root reference of the AVM location to import into + */ + public void processZipImport(File file, NodeRef rootRef) + { + try + { + // NOTE: This encoding allows us to workaround bug: + // http://bugs.sun.com/bugdatabase/view_bug.do;:WuuT?bug_id=4820807 + ZipFile zipFile = new ZipFile(file, "Cp437"); + File alfTempDir = TempFileProvider.getTempDir(); + // build a temp dir name based on the name of the file we are importing + File tempDir = new File(alfTempDir.getPath() + File.separatorChar + file.getName() + "_unpack"); + try + { + // TODO: improve this code to directly pipe the zip stream output into the repo objects - + // to remove the need to expand to the filesystem first. + extractFile(zipFile, tempDir.getPath()); + importDirectory(tempDir.getPath(), rootRef); + } + finally + { + deleteDir(tempDir); + } + } + catch (IOException e) + { + throw new AlfrescoRuntimeException("Unable to process Zip file. File may not be of the expected format.", e); + } + } + + /** + * Extract the file and folder structure of a ZIP file into the specified directory + * + * @param archive The ZIP archive to extract + * @param extractDir The directory to extract into + */ + private void extractFile(ZipFile archive, String extractDir) + { + String fileName; + String destFileName; + byte[] buffer = new byte[BUFFER_SIZE]; + extractDir = extractDir + File.separator; + try + { + for (Enumeration e = archive.getEntries(); e.hasMoreElements();) + { + ZipEntry entry = (ZipEntry) e.nextElement(); + if (!entry.isDirectory()) + { + fileName = entry.getName(); + fileName = fileName.replace('/', File.separatorChar); + destFileName = extractDir + fileName; + File destFile = new File(destFileName); + String parent = destFile.getParent(); + if (parent != null) + { + File parentFile = new File(parent); + if (!parentFile.exists()) parentFile.mkdirs(); + } + InputStream in = new BufferedInputStream(archive.getInputStream(entry), BUFFER_SIZE); + OutputStream out = new BufferedOutputStream(new FileOutputStream(destFileName), BUFFER_SIZE); + int count; + while ((count = in.read(buffer)) != -1) + { + out.write(buffer, 0, count); + } + in.close(); + out.close(); + } + else + { + File newdir = new File(extractDir + entry.getName()); + newdir.mkdir(); + } + } + } + catch (ZipException e) + { + throw new AlfrescoRuntimeException("Failed to process ZIP file.", e); + } + catch (FileNotFoundException e) + { + throw new AlfrescoRuntimeException("Failed to process ZIP file.", e); + } + catch (IOException e) + { + throw new AlfrescoRuntimeException("Failed to process ZIP file.", e); + } + } + + /** + * Recursively import a directory structure into the specified root node + * + * @param dir The directory of files and folders to import + * @param root The root node to import into + */ + private void importDirectory(String dir, NodeRef root) + { + ServiceRegistry services = Repository.getServiceRegistry(FacesContext.getCurrentInstance()); + NodeService nodeService = services.getNodeService(); + MimetypeService mimetypeService = services.getMimetypeService(); + File topdir = new File(dir); + for (File file : topdir.listFiles()) + { + try + { + if (file.isFile()) + { + String avmPath = (String)AVMNodeConverter.ToAVMVersionPath(root)[1]; + avmService.createFile(avmPath, file.getName(), new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE)); + // create content node based on the filename + /*FileInfo contentFile = fileFolderService.create(root, fileName, ContentModel.TYPE_AVM_PLAIN_CONTENT); + NodeRef content = contentFile.getNodeRef(); + + // add titled aspect (for Web Client display) + //Map titledProps = new HashMap(); + //titledProps.put(ContentModel.PROP_TITLE, fileName); + //titledProps.put(ContentModel.PROP_DESCRIPTION, fileName); + //nodeService.addAspect(content, ContentModel.ASPECT_TITLED, titledProps); + + InputStream contentStream = new BufferedInputStream(new FileInputStream(file), BUFFER_SIZE); + + ContentWriter writer = contentService.getWriter(content, ContentModel.PROP_CONTENT, true); + writer.setMimetype(mimetypeService.guessMimetype(file.getAbsolutePath())); + // TODO: what should we set this too? (definitely not Cp437...!) + //writer.setEncoding("Cp437"); + writer.putContent(contentStream);*/ + } + else + { + //FileInfo fileInfo = fileFolderService.create(root, file.getName(), ContentModel.TYPE_AVM_PLAIN_FOLDER); + String avmPath = (String)AVMNodeConverter.ToAVMVersionPath(root)[1]; + avmService.createDirectory(avmPath, file.getName()); + + importDirectory(file.getPath(), AVMNodeConverter.ToNodeRef(-1, avmPath + '/' + file.getName()));//fileInfo.getNodeRef() + } + } + catch (FileNotFoundException e) + { + // TODO: add failed file info to status message? + throw new AlfrescoRuntimeException("Failed to process ZIP file.", e); + } + catch (FileExistsException e) + { + // TODO: add failed file info to status message? + throw new AlfrescoRuntimeException("Failed to process ZIP file.", e); + } + } + } + + /** + * Recursively delete a dir of files and directories + * + * @param dir directory to delete + */ + private void deleteDir(File dir) + { + File elenco = new File(dir.getPath()); + for (File file : elenco.listFiles()) + { + if (file.isFile()) file.delete(); + else deleteDir(file); + } + dir.delete(); + } } diff --git a/source/java/org/alfresco/web/ui/repo/component/UIActions.java b/source/java/org/alfresco/web/ui/repo/component/UIActions.java index 2fa792385a..2e1bd33be3 100644 --- a/source/java/org/alfresco/web/ui/repo/component/UIActions.java +++ b/source/java/org/alfresco/web/ui/repo/component/UIActions.java @@ -70,7 +70,7 @@ public class UIActions extends SelfRenderingComponent public static final String COMPONENT_PERMISSIONEVAL = "org.alfresco.faces.PermissionEvaluator"; public static final String COMPONENT_ACTIONEVAL = "org.alfresco.faces.ActionInstanceEvaluator"; - private final static Class ACTION_CLASS_ARGS[] = {javax.faces.event.ActionEvent.class}; + public final static Class ACTION_CLASS_ARGS[] = {javax.faces.event.ActionEvent.class}; /** * @see javax.faces.component.UIComponent#getFamily() diff --git a/source/java/org/alfresco/web/ui/wcm/WebResources.java b/source/java/org/alfresco/web/ui/wcm/WebResources.java index 4f82c3db45..0eac43f1b0 100644 --- a/source/java/org/alfresco/web/ui/wcm/WebResources.java +++ b/source/java/org/alfresco/web/ui/wcm/WebResources.java @@ -23,4 +23,5 @@ public class WebResources extends org.alfresco.web.ui.repo.WebResources { // Image paths public static final String IMAGE_SANDBOX_32 = "/images/icons/sandbox_large.gif"; + public static final String IMAGE_USERSANDBOX_32 = "/images/icons/user_sandbox_large.gif"; } diff --git a/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java b/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java index 3cb23cce00..d3d6e90e9a 100644 --- a/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java +++ b/source/java/org/alfresco/web/ui/wcm/component/UIUserSandboxes.java @@ -27,6 +27,7 @@ import java.util.Set; import javax.faces.component.NamingContainer; import javax.faces.component.UIComponent; +import javax.faces.component.UIParameter; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.faces.el.ValueBinding; @@ -41,12 +42,15 @@ import org.alfresco.service.namespace.QName; import org.alfresco.web.app.Application; import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.bean.wcm.AVMConstants; +import org.alfresco.web.ui.common.ComponentConstants; +import org.alfresco.web.ui.common.ConstantMethodBinding; import org.alfresco.web.ui.common.PanelGenerator; import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.component.SelfRenderingComponent; import org.alfresco.web.ui.common.component.UIActionLink; import org.alfresco.web.ui.repo.component.UIActions; import org.alfresco.web.ui.wcm.WebResources; +import org.apache.myfaces.taglib.UIComponentTagUtils; import org.springframework.web.jsf.FacesContextUtils; import sun.swing.UIAction; @@ -176,7 +180,7 @@ public class UIUserSandboxes extends SelfRenderingComponent String username = users.get(i); // build the name of the main store for the user - String mainStore = storeRoot + '-' + username + AVMConstants.STORE_MAIN; + String mainStore = AVMConstants.buildAVMUserMainStoreName(storeRoot, username); // check it exists before we render the view if (avmService.getAVMStore(mainStore) != null) @@ -189,7 +193,7 @@ public class UIUserSandboxes extends SelfRenderingComponent // components for the current username, preview, browse and modified items inner list out.write(""); // modified items panel @@ -273,12 +282,13 @@ public class UIUserSandboxes extends SelfRenderingComponent } } - private UIActionLink aquireAction(FacesContext fc, String name, String icon) + private UIActionLink aquireAction(FacesContext fc, String store, String username, + String name, String icon, String actionListener, String outcome) { UIActionLink action = findAction(name); if (action == null) { - action = createAction(fc, name, icon); + action = createAction(fc, store, username, name, icon, actionListener, outcome); } return action; } @@ -298,7 +308,8 @@ public class UIUserSandboxes extends SelfRenderingComponent return action; } - private UIActionLink createAction(FacesContext fc, String name, String icon) + private UIActionLink createAction(FacesContext fc, String store, String username, + String name, String icon, String actionListener, String outcome) { javax.faces.application.Application facesApp = fc.getApplication(); UIActionLink control = (UIActionLink)facesApp.createComponent(UIActions.COMPONENT_ACTIONLINK); @@ -309,6 +320,25 @@ public class UIUserSandboxes extends SelfRenderingComponent control.setShowLink(false); control.setImage(icon); + if (actionListener != null) + { + control.setActionListener(facesApp.createMethodBinding( + actionListener, UIActions.ACTION_CLASS_ARGS)); + + UIParameter param = (UIParameter)facesApp.createComponent(ComponentConstants.JAVAX_FACES_PARAMETER); + param.setName("store"); + param.setValue(store); + control.getChildren().add(param); + param = (UIParameter)facesApp.createComponent(ComponentConstants.JAVAX_FACES_PARAMETER); + param.setName("username"); + param.setValue(username); + control.getChildren().add(param); + } + if (outcome != null) + { + control.setAction(new ConstantMethodBinding(outcome)); + } + this.getChildren().add(control); return control; diff --git a/source/web/WEB-INF/faces-config-beans.xml b/source/web/WEB-INF/faces-config-beans.xml index 7445ea38c0..3a51125d2b 100644 --- a/source/web/WEB-INF/faces-config-beans.xml +++ b/source/web/WEB-INF/faces-config-beans.xml @@ -565,11 +565,40 @@ - The bean that backs up the Create Website Wizard + The bean that backs up the Import Website Dialog ImportWebsiteDialog org.alfresco.web.bean.wcm.ImportWebsiteDialog session + + fileFolderService + #{FileFolderService} + + + contentService + #{ContentService} + + + navigationBean + #{NavigationBean} + + + avmService + #{AVMService} + + + + + + The bean that backs up the website file/folder browsing screens + + AVMBrowseBean + org.alfresco.web.bean.wcm.AVMBrowseBean + session + + navigationBean + #{NavigationBean} + diff --git a/source/web/WEB-INF/faces-config-navigation.xml b/source/web/WEB-INF/faces-config-navigation.xml index 8da01294b3..5a4767d272 100644 --- a/source/web/WEB-INF/faces-config-navigation.xml +++ b/source/web/WEB-INF/faces-config-navigation.xml @@ -913,6 +913,10 @@ importContent /jsp/wcm/import-content-dialog.jsp + + browseSandbox + /jsp/wcm/browse-sandbox.jsp + diff --git a/source/web/images/icons/website_large.gif b/source/web/images/icons/website_large.gif index 1d1c87eb73..3690c4d4fc 100644 Binary files a/source/web/images/icons/website_large.gif and b/source/web/images/icons/website_large.gif differ diff --git a/source/web/jsp/wcm/browse-sandbox.jsp b/source/web/jsp/wcm/browse-sandbox.jsp new file mode 100644 index 0000000000..03ea044621 --- /dev/null +++ b/source/web/jsp/wcm/browse-sandbox.jsp @@ -0,0 +1,157 @@ +<%-- + Copyright (C) 2005 Alfresco, Inc. + + Licensed under the Mozilla Public License version 1.1 + with a permitted attribution clause. You may obtain a + copy of the License at + + http://www.alfresco.org/legal/license.txt + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + either express or implied. See the License for the specific + language governing permissions and limitations under the + License. +--%> + +<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> +<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> +<%@ taglib uri="/WEB-INF/alfresco.tld" prefix="a" %> +<%@ taglib uri="/WEB-INF/repo.tld" prefix="r" %> +<%@ taglib uri="/WEB-INF/wcm.tld" prefix="w" %> + +<%@ page buffer="64kb" contentType="text/html;charset=UTF-8" %> +<%@ page isELIgnored="false" %> +<%@ page import="org.alfresco.web.ui.common.PanelGenerator" %> + + + + + <%-- load a bundle of properties with I18N strings --%> + + + + + <%-- Main outer table --%> +
"); - out.write(Utils.buildImageTag(context, WebResources.IMAGE_SANDBOX_32, 32, 32, "")); + out.write(Utils.buildImageTag(context, WebResources.IMAGE_USERSANDBOX_32, 32, 32, "")); out.write(""); out.write(""); out.write(bundle.getString(MSG_USERNAME)); @@ -199,13 +203,18 @@ public class UIUserSandboxes extends SelfRenderingComponent // direct actions for a sandbox Utils.encodeRecursive(context, aquireAction( - context, "sandbox_preview", "/images/icons/preview_website.gif")); + context, mainStore, username, "sandbox_preview", "/images/icons/preview_website.gif", + null, null)); out.write("  "); + Utils.encodeRecursive(context, aquireAction( - context, "sandbox_create", "/images/icons/new_content.gif")); + context, mainStore, username, "sandbox_create", "/images/icons/new_content.gif", + null, null)); out.write("  "); + Utils.encodeRecursive(context, aquireAction( - context, "sandbox_browse", "/images/icons/space_small.gif")); + context, mainStore, username, "sandbox_browse", "/images/icons/space_small.gif", + "#{AVMBrowseBean.setupSandboxAction}", "browseSandbox")); out.write("
+ + <%-- Title bar --%> + + + + + <%-- Main area --%> + + <%-- Shelf --%> + + + <%-- Work Area --%> + + +
+ <%@ include file="../parts/titlebar.jsp" %> +
+ <%@ include file="../parts/shelf.jsp" %> + + + <%-- Breadcrumb --%> + <%@ include file="../parts/breadcrumb.jsp" %> + + <%-- Status and Actions --%> + + + + + + + <%-- separator row with gradient shadow --%> + + + + + + + <%-- Details - Folders --%> + + + + + + + <%-- Details - Files --%> + + + + + + + <%-- Error Messages --%> + + + + + + + <%-- separator row with bottom panel graphics --%> + + + + + + +
+ + <%-- Status and Actions inner contents table --%> + <%-- Generally this consists of an icon, textual summary and actions for the current object --%> + + + + + +
+ + <%-- Summary --%> +
+
+
+
+ +
+ + + + + + + + + +
+ + + + + + + + + +
+ <%-- messages tag to show messages not handled by other specific message tags --%> + +
+
+ + + + + + diff --git a/source/web/jsp/wcm/browse-website.jsp b/source/web/jsp/wcm/browse-website.jsp index 83e4b6938f..7f13977c32 100644 --- a/source/web/jsp/wcm/browse-website.jsp +++ b/source/web/jsp/wcm/browse-website.jsp @@ -102,15 +102,18 @@ <% PanelGenerator.generatePanelStart(out, request.getContextPath(), "blue", "#D3E6FE"); %> - + - + - @@ -145,6 +148,7 @@ diff --git a/source/web/jsp/wcm/import-content-dialog.jsp b/source/web/jsp/wcm/import-content-dialog.jsp index c2027df4cb..cde7321413 100644 --- a/source/web/jsp/wcm/import-content-dialog.jsp +++ b/source/web/jsp/wcm/import-content-dialog.jsp @@ -70,7 +70,7 @@
(P) (E) (T) (D) + (P) (E) (T) (D)  + +
- Last Updated: 20th September 2006

- 12 items currently being modified

+

+ Last Updated: 20th September 2006

+ 12 items currently being modified

3 items pending approval

<%-- messages tag to show messages not handled by other specific message tags --%> +
-