- Flat list of Modified Files for a user sandbox, in the expandable Modified Files area of the sandbox view
 - Filename is clickable to view the content of the modified version of the file
 - Added 'creator' column to the files list when browsing a website
. Fixed DownloadContentServlet to handle AVM noderefs with space character %20 in the encoded NodeRef url element

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@3843 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Kevin Roast
2006-09-19 12:47:48 +00:00
parent e27ccc118c
commit 09fc8a5041
5 changed files with 193 additions and 22 deletions

View File

@@ -808,6 +808,8 @@ sandbox_title=Website ''{0}'' sandbox ''{1}''
sandbox_staging=Staging sandbox_staging=Staging
website_browse_folders=Browse Folders website_browse_folders=Browse Folders
website_browse_files=Browse Files website_browse_files=Browse Files
creator=Creator
modified_items=Modified Items
# Website actions and dialog messages # Website actions and dialog messages
title_import_content=Import Content into Website title_import_content=Import Content into Website

View File

@@ -19,6 +19,7 @@ package org.alfresco.web.app.servlet;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.SocketException; import java.net.SocketException;
import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Date; import java.util.Date;
@@ -146,7 +147,7 @@ public class DownloadContentServlet extends BaseServlet
// assume 'workspace' or other NodeRef based protocol for remaining URL elements // assume 'workspace' or other NodeRef based protocol for remaining URL elements
StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken()); StoreRef storeRef = new StoreRef(t.nextToken(), t.nextToken());
String id = t.nextToken(); String id = URLDecoder.decode(t.nextToken(), "UTF-8");
// build noderef from the appropriate URL elements // build noderef from the appropriate URL elements
nodeRef = new NodeRef(storeRef, id); nodeRef = new NodeRef(storeRef, id);

View File

@@ -79,6 +79,7 @@ public class AVMNode implements Map<String, Object>
this.properties.put("name", this.avmRef.getName()); this.properties.put("name", this.avmRef.getName());
this.properties.put("created", this.avmRef.getCreateDate()); this.properties.put("created", this.avmRef.getCreateDate());
this.properties.put("modified", this.avmRef.getModDate()); this.properties.put("modified", this.avmRef.getModDate());
this.properties.put("creator", this.avmRef.getCreator());
} }
return this.properties; return this.properties;

View File

@@ -34,12 +34,18 @@ import javax.faces.el.ValueBinding;
import javax.transaction.UserTransaction; import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel; import org.alfresco.model.ContentModel;
import org.alfresco.repo.avm.AVMNodeConverter;
import org.alfresco.service.cmr.avm.AVMNodeDescriptor;
import org.alfresco.service.cmr.avm.AVMService; import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.avm.AVMStoreDescriptor; import org.alfresco.service.cmr.avm.AVMStoreDescriptor;
import org.alfresco.service.cmr.avmsync.AVMDifference;
import org.alfresco.service.cmr.avmsync.AVMSyncService;
import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService; import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.namespace.QName; import org.alfresco.service.namespace.QName;
import org.alfresco.web.app.Application; import org.alfresco.web.app.Application;
import org.alfresco.web.app.servlet.DownloadContentServlet;
import org.alfresco.web.bean.BrowseBean;
import org.alfresco.web.bean.repository.Repository; import org.alfresco.web.bean.repository.Repository;
import org.alfresco.web.bean.wcm.AVMConstants; import org.alfresco.web.bean.wcm.AVMConstants;
import org.alfresco.web.ui.common.ComponentConstants; import org.alfresco.web.ui.common.ComponentConstants;
@@ -48,11 +54,14 @@ import org.alfresco.web.ui.common.PanelGenerator;
import org.alfresco.web.ui.common.Utils; import org.alfresco.web.ui.common.Utils;
import org.alfresco.web.ui.common.component.SelfRenderingComponent; import org.alfresco.web.ui.common.component.SelfRenderingComponent;
import org.alfresco.web.ui.common.component.UIActionLink; import org.alfresco.web.ui.common.component.UIActionLink;
import org.alfresco.web.ui.common.converter.ByteSizeConverter;
import org.alfresco.web.ui.common.converter.XMLDateConverter;
import org.alfresco.web.ui.repo.component.UIActions; import org.alfresco.web.ui.repo.component.UIActions;
import org.alfresco.web.ui.wcm.WebResources; import org.alfresco.web.ui.wcm.WebResources;
import org.apache.myfaces.taglib.UIComponentTagUtils; import org.apache.myfaces.taglib.UIComponentTagUtils;
import org.springframework.web.jsf.FacesContextUtils; import org.springframework.web.jsf.FacesContextUtils;
import sun.security.krb5.internal.crypto.f;
import sun.swing.UIAction; import sun.swing.UIAction;
/** /**
@@ -60,15 +69,24 @@ import sun.swing.UIAction;
*/ */
public class UIUserSandboxes extends SelfRenderingComponent public class UIUserSandboxes extends SelfRenderingComponent
{ {
private static final String MSG_MODIFIED_ITEMS = "modified_items";
private static final String MSG_DATETIME_PATTERN = "date_time_pattern";
private static final String MSG_SIZE = "size";
private static final String MSG_CREATED = "created_date";
private static final String MSG_USERNAME = "username"; private static final String MSG_USERNAME = "username";
private static final String MSG_NAME = "name"; private static final String MSG_NAME = "name";
private static final String MSG_DESCRIPTION = "description"; private static final String MSG_DESCRIPTION = "description";
private static final String MSG_MODIFIED = "modified_date"; private static final String MSG_MODIFIED = "modified_date";
private static final String MSG_ACTIONS = "actions"; private static final String MSG_ACTIONS = "actions";
private static final String SPACE_ICON = "/images/icons/" + BrowseBean.SPACE_SMALL_DEFAULT + ".gif";
/** website to show sandboxes for */ /** website to show sandboxes for */
private NodeRef value; private NodeRef value;
private ByteSizeConverter sizeConverter = null;
private XMLDateConverter dateConverter = null;
private Set<String> expandedPanels = new HashSet<String>(); private Set<String> expandedPanels = new HashSet<String>();
@@ -230,7 +248,9 @@ public class UIUserSandboxes extends SelfRenderingComponent
} }
out.write(Utils.buildImageTag(context, panelImage, 11, 11, "", out.write(Utils.buildImageTag(context, panelImage, 11, 11, "",
Utils.generateFormSubmit(context, this, getClientId(context), username))); Utils.generateFormSubmit(context, this, getClientId(context), username)));
out.write("&nbsp;<b>Modified Items (3)</b>"); out.write("&nbsp;<b>");
out.write(bundle.getString(MSG_MODIFIED_ITEMS));
out.write("</b>");
if (this.expandedPanels.contains(username)) if (this.expandedPanels.contains(username))
{ {
out.write("<div style='padding:2px'></div>"); out.write("<div style='padding:2px'></div>");
@@ -240,26 +260,19 @@ public class UIUserSandboxes extends SelfRenderingComponent
out.write("<tr align=left><th width=16></th><th>"); out.write("<tr align=left><th width=16></th><th>");
out.write(bundle.getString(MSG_NAME)); out.write(bundle.getString(MSG_NAME));
out.write("</th><th>"); out.write("</th><th>");
out.write(bundle.getString(MSG_DESCRIPTION)); out.write(bundle.getString(MSG_CREATED));
out.write("</th><th>"); out.write("</th><th>");
out.write(bundle.getString(MSG_MODIFIED)); out.write(bundle.getString(MSG_MODIFIED));
out.write("</th><th>"); out.write("</th><th>");
out.write(bundle.getString(MSG_SIZE));
out.write("</th><th>");
out.write(bundle.getString(MSG_ACTIONS)); out.write(bundle.getString(MSG_ACTIONS));
out.write("</th></tr>"); out.write("</th></tr>");
// row per modified doc item // row per modified doc item for this sandbox user
// TODO: add modified items list for this sandbox user renderUserFiles(context, out, username, storeRoot);
out.write("<tr><td width=16>(O)</td><td>");
out.write("Some document.html");
out.write("</td><td>");
out.write("A description would go here");
out.write("</td><td>");
out.write("01-01-2006 11:58am");
out.write("</td><td>");
// TODO: add UI actions for this item
out.write("(P)&nbsp;(E)&nbsp;(T)&nbsp;(D)");
out.write("</td></tr>");
// end table
out.write("</table>"); out.write("</table>");
} }
out.write("</td></tr></table>"); out.write("</td></tr></table>");
@@ -286,6 +299,119 @@ public class UIUserSandboxes extends SelfRenderingComponent
} }
} }
/**
* Render the list of user modified files/folders in the layered sandbox area.
*
* @param fc FacesContext
* @param out ResponseWriter
* @param username The username to render the modified files for
* @param storeRoot Root name of the store containing the users sandbox
*
* @throws IOException
*/
private void renderUserFiles(FacesContext fc, ResponseWriter out, String username, String storeRoot)
throws IOException
{
AVMSyncService avmSyncService = getAVMSyncService(fc);
AVMService avmService = getAVMService(fc);
// build the paths to the stores to compare
String userStore = AVMConstants.buildAVMUserMainStoreName(storeRoot, username) + ":/";
String stagingStore = AVMConstants.buildAVMStagingStoreName(storeRoot) + ":/";
// use the sync service to get the list of diffs between the stores
List<AVMDifference> diffs = avmSyncService.compare(-1, userStore, -1, stagingStore);
for (AVMDifference diff : diffs)
{
//if (diff.getDifferenceCode() == AVMDifference.NEWER)
//{
String sourcePath = diff.getSourcePath();
AVMNodeDescriptor node = avmService.lookup(-1, sourcePath);
if (node != null)
{
// icon and name of the file/folder - files are clickable to see the content
String name = node.getName();
String linkPrefix =
"<a href=\"" +
fc.getExternalContext().getRequestContextPath() +
DownloadContentServlet.generateBrowserURL(AVMNodeConverter.ToNodeRef(-1, sourcePath), name) +
"\" target='new'>";
out.write("<tr><td width=16>");
if (node.isFile())
{
out.write(linkPrefix);
out.write(Utils.buildImageTag(fc, Utils.getFileTypeImage(fc, name, true), ""));
out.write("</a></td><td>");
out.write(linkPrefix);
out.write(name);
out.write("</a>");
}
else
{
out.write(Utils.buildImageTag(fc, SPACE_ICON, 16, 16, ""));
out.write("</td><td>");
out.write(name);
}
out.write("</td><td>");
// created date
out.write(getDateConverter().getAsString(fc, this, node.getCreateDate()));
out.write("</td><td>");
// modified date
out.write(getDateConverter().getAsString(fc, this, node.getModDate()));
out.write("</td><td>");
if (node.isFile())
{
// size of files
out.write(getSizeConverter().getAsString(fc, this, node.getLength()));
}
out.write("</td><td>");
// TODO: add UI actions for this item
out.write("(P)&nbsp;(E)&nbsp;(T)&nbsp;(D)");
out.write("</td></tr>");
}
//}
}
}
/**
* @return Byte size converter
*/
private ByteSizeConverter getSizeConverter()
{
if (this.sizeConverter == null)
{
this.sizeConverter = new ByteSizeConverter();
}
return this.sizeConverter;
}
/**
* @return Date format converter
*/
private XMLDateConverter getDateConverter()
{
if (this.dateConverter == null)
{
this.dateConverter = new XMLDateConverter();
this.dateConverter.setPattern(
Application.getMessage(FacesContext.getCurrentInstance(), MSG_DATETIME_PATTERN));
}
return this.dateConverter;
}
/**
* Aquire a UIActionLink component for the specified action
*
* @param fc FacesContext
* @param store Root store name for the user sandbox
* @param username Username of the user for the action
* @param name Action name - will be used for I18N message lookup
* @param icon Icon to display for the actio n
* @param actionListener Actionlistener for the action
* @param outcome Navigation outcome for the action
*
* @return UIActionLink component
*/
private UIActionLink aquireAction(FacesContext fc, String store, String username, private UIActionLink aquireAction(FacesContext fc, String store, String username,
String name, String icon, String actionListener, String outcome) String name, String icon, String actionListener, String outcome)
{ {
@@ -297,6 +423,13 @@ public class UIUserSandboxes extends SelfRenderingComponent
return action; return action;
} }
/**
* Locate a child UIActionLink component by name.
*
* @param name Of the action component to find
*
* @return UIActionLink component if found, else null if not created yet
*/
private UIActionLink findAction(String name) private UIActionLink findAction(String name)
{ {
UIActionLink action = null; UIActionLink action = null;
@@ -312,6 +445,19 @@ public class UIUserSandboxes extends SelfRenderingComponent
return action; return action;
} }
/**
* Create a UIActionLink child component.
*
* @param fc FacesContext
* @param store Root store name for the user sandbox
* @param username Username of the user for the action
* @param name Action name - will be used for I18N message lookup
* @param icon Icon to display for the actio n
* @param actionListener Actionlistener for the action
* @param outcome Navigation outcome for the action
*
* @return UIActionLink child component
*/
private UIActionLink createAction(FacesContext fc, String store, String username, private UIActionLink createAction(FacesContext fc, String store, String username,
String name, String icon, String actionListener, String outcome) String name, String icon, String actionListener, String outcome)
{ {
@@ -358,6 +504,11 @@ public class UIUserSandboxes extends SelfRenderingComponent
return Repository.getServiceRegistry(fc).getNodeService(); return Repository.getServiceRegistry(fc).getNodeService();
} }
private AVMSyncService getAVMSyncService(FacesContext fc)
{
return (AVMSyncService)FacesContextUtils.getRequiredWebApplicationContext(fc).getBean("AVMSyncService");
}
// ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------
// Strongly typed component property accessors // Strongly typed component property accessors

View File

@@ -124,7 +124,7 @@
</a:actionLink> </a:actionLink>
</a:column> </a:column>
<%-- Description column for all view modes --%> <%-- Description column --%>
<a:column id="col4" style="text-align:left"> <a:column id="col4" style="text-align:left">
<f:facet name="header"> <f:facet name="header">
<a:sortLink id="col4-sort" label="#{msg.description}" value="description" styleClass="header"/> <a:sortLink id="col4-sort" label="#{msg.description}" value="description" styleClass="header"/>
@@ -132,7 +132,15 @@
<h:outputText id="col4-txt" value="#{r.description}" /> <h:outputText id="col4-txt" value="#{r.description}" />
</a:column> </a:column>
<%-- Created Date column for details view mode --%> <%-- Creator column --%>
<a:column id="col5" style="text-align:left">
<f:facet name="header">
<a:sortLink id="col5-sort" label="#{msg.creator}" value="creator" styleClass="header"/>
</f:facet>
<h:outputText id="col5-txt" value="#{r.creator}" />
</a:column>
<%-- Created Date column --%>
<a:column id="col6" style="text-align:left"> <a:column id="col6" style="text-align:left">
<f:facet name="header"> <f:facet name="header">
<a:sortLink id="col6-sort" label="#{msg.created}" value="created" styleClass="header"/> <a:sortLink id="col6-sort" label="#{msg.created}" value="created" styleClass="header"/>
@@ -142,7 +150,7 @@
</h:outputText> </h:outputText>
</a:column> </a:column>
<%-- Modified Date column for details/icons view modes --%> <%-- Modified Date column --%>
<a:column id="col7" style="text-align:left"> <a:column id="col7" style="text-align:left">
<f:facet name="header"> <f:facet name="header">
<a:sortLink id="col7-sort" label="#{msg.modified}" value="modified" styleClass="header"/> <a:sortLink id="col7-sort" label="#{msg.modified}" value="modified" styleClass="header"/>
@@ -195,7 +203,7 @@
<r:lockIcon id="col10-lock" value="#{r.nodeRef}" align="absmiddle" /> <r:lockIcon id="col10-lock" value="#{r.nodeRef}" align="absmiddle" />
</a:column> </a:column>
<%-- Description column for all view modes --%> <%-- Description column --%>
<a:column id="col13" style="text-align:left"> <a:column id="col13" style="text-align:left">
<f:facet name="header"> <f:facet name="header">
<a:sortLink id="col13-sort" label="#{msg.description}" value="description" styleClass="header"/> <a:sortLink id="col13-sort" label="#{msg.description}" value="description" styleClass="header"/>
@@ -203,7 +211,7 @@
<h:outputText id="col13-txt" value="#{r.description}" /> <h:outputText id="col13-txt" value="#{r.description}" />
</a:column> </a:column>
<%-- Size for details/icons view modes --%> <%-- Size column --%>
<a:column id="col15" style="text-align:left"> <a:column id="col15" style="text-align:left">
<f:facet name="header"> <f:facet name="header">
<a:sortLink id="col15-sort" label="#{msg.size}" value="size" styleClass="header"/> <a:sortLink id="col15-sort" label="#{msg.size}" value="size" styleClass="header"/>
@@ -213,7 +221,15 @@
</h:outputText> </h:outputText>
</a:column> </a:column>
<%-- Created Date column for details view mode --%> <%-- Creator column --%>
<a:column id="col15a" style="text-align:left">
<f:facet name="header">
<a:sortLink id="col15a-sort" label="#{msg.creator}" value="creator" styleClass="header"/>
</f:facet>
<h:outputText id="col15a-txt" value="#{r.creator}" />
</a:column>
<%-- Created Date column --%>
<a:column id="col16" style="text-align:left"> <a:column id="col16" style="text-align:left">
<f:facet name="header"> <f:facet name="header">
<a:sortLink id="col16-sort" label="#{msg.created}" value="created" styleClass="header"/> <a:sortLink id="col16-sort" label="#{msg.created}" value="created" styleClass="header"/>
@@ -223,7 +239,7 @@
</h:outputText> </h:outputText>
</a:column> </a:column>
<%-- Modified Date column for details/icons view modes --%> <%-- Modified Date column --%>
<a:column id="col17" style="text-align:left"> <a:column id="col17" style="text-align:left">
<f:facet name="header"> <f:facet name="header">
<a:sortLink id="col17-sort" label="#{msg.modified}" value="modified" styleClass="header"/> <a:sortLink id="col17-sort" label="#{msg.modified}" value="modified" styleClass="header"/>